Skip to content

Augmented Bonding Curves - #926

Open
JakeHartnell wants to merge 21 commits into
developmentfrom
augmented-bonding-curves
Open

Augmented Bonding Curves#926
JakeHartnell wants to merge 21 commits into
developmentfrom
augmented-bonding-curves

Conversation

@JakeHartnell

Copy link
Copy Markdown
Member

Revive cw-abc + ship cw-curves and dao-abc-factory with full audit pass

Summary

This PR revives the cw-abc (Augmented Bonding Curve) branch — last touched in May 2024, ~2 years stale — by rebasing it onto development and shipping a complete fix for all 21 findings from a fresh internal security review.

It introduces three new workspace members:

  • packages/cw-curves — bonding-curve math primitives (Constant, Linear, SquareRoot)
  • contracts/external/cw-abc — the Augmented Bonding Curve contract
  • contracts/external/dao-abc-factory — DAO-side factory wiring cw-abc into a DAO via dao-voting-token-staked

Includes an internal security review at audits/2026-05-09-cw-abc-security-review.md that documents the 21 findings, their fixes, and the remaining work for an external audit.

Closes (or builds on) the original draft: #697.

Why this exists

ABCs are a Commons-Stack-lineage primitive for community-funded project tokens — a bonding curve where buyers deposit a reserve asset and receive curve-priced tokens, augmented with a hatcher phase, a funding pool, and (now) inline vesting to combat early-arb. Used by Token Engineering Commons, Commons Stack, Giveth, Praise. They're a substrate-level addition for any DAO that wants tokenized community capitalization, and they're a precondition for meme-DAO-style launches (the bonding-curve + graduation pattern that Pump.fun popularized).

The original cw-abc work sat in a 2-year-old branch with substantial drift; reviving it means getting the rebase to a clean baseline and treating the audit findings seriously rather than carrying the partial-shape forward.

Approach

A few load-bearing design decisions, in case reviewers want to push back on them early:

  • Hatcher vesting is inline, not via per-hatcher cw-vesting instantiation. Each cw-vesting instantiate costs ~150–300k gas; a popular hatch with hundreds of hatchers would exceed any per-block gas limit at the Hatch→Open transition. Instead, we track per-hatcher state in HatcherState (contributed / minted / already_burned / vesting_started_at / claimed_refund) and compute vested amounts inline against a shared VestingSchedule.
  • Factory caller authentication is reverse-handshake, not an admin allowlist. The factory's intent is for any DAO's voting module to use it during DAO instantiation; an admin allowlist would break that. Instead, when a contract claims to be a DAO's voting module, we ask that DAO whether it agrees, and reject if the round trip doesn't close. This admits any genuinely-related voting module while rejecting impostors. Same pattern applied to dao-test-custom-factory.
  • Curve mutability is gated on Closed phase + a 1% continuity check. The previous unconditional update_curve was a clean rug: pause → swap to a curve where new_curve.supply(reserve) >> current_supply → buy 1 unit → mint flood → drain. Closing it required both restricting WHEN curves can change and a tolerance check on the (reserve, supply) invariant.
  • Failed-hatch refunds are pro-rata (reserve + funding), not just reserve. The first round of fixes shipped AbortHatch as a transition to Closed (refunds reserve only, owner keeps funding pool). This PR completes M-5 with a Refunding sub-state, snapshot-locked pro-rata math, and a permissionless ClaimRefund handler. Funding pool is locked from owner withdrawal during Refunding.

What's in this PR (by commit)

# Commit What
1 1ec2afe3e Rebase cw-abc + cw-curves + dao-abc-factory onto development. 56 commits squash-merged. New workspace members at 2.8.0-alpha.2; osmosis_tokenfactory / cosmwasm_tokenfactory / thorchain_tokenfactory feature pattern adopted to match dao-voting-token-staked.
2 429a45af2 C-1, C-2. update_curve gated on Closed phase + 1% continuity check. Factory reverse-handshake auth (dao-abc-factory + dao-test-custom-factory parity). Factory temp state cleared in reply (L-7).
3 7a3fcfced H-1..H-6. Inline hatcher vesting (VestingSchedule::{None, Cliff, Linear} + HatcherState). Removed reachable todo!() panic. Strict < 100% on entry/exit fees. decimals < 38. contribution_limits.min ≤ max.
4 29ba5e12d M-1..M-6. Priority-queue insert rewrite (partition_point instead of broken binary_search_by). cw2 migrate guard. Removed dead HATCHER_ALLOWLIST map. hatch_deadline + AbortHatch. Trust-model README.
5 84c9bf12 L-1..L-7 (except L-5), I-1..I-7. Bounded query limits, surfaced DAO-query errors, eliminated self-call auth bypass via inline allowlist setup, decimal() cast guard, cube_root precision raised 9→15. Variant cleanup, exit-fee zeroed on close, naming, doc comments.
6 3ba8862f2 Internal security review + per-finding status table at audits/2026-05-09-cw-abc-security-review.md.
7 74931ee30 L-5. Curve trait converted to Result<_, CurveError>. All unwrap()-on-overflow paths replaced with typed CurveError::{Overflow, DivisionByZero}. New ContractError::CurveError variant.
8 744e609fe M-5 full. CommonsPhase::Refunding + RefundSnapshot + ClaimRefund handler. Pro-rata (reserve + funding) refunds, snapshot-locked at AbortHatch time. Buys / sells / withdraw / close blocked in Refunding.
9 dc9a678cb 30 audit-defense unit tests in cw-abc/src/audit_tests.rs covering C-1, H-1 vesting math, H-2..H-6, M-1, M-2, M-5, L-3.
10 701dd86b1 Differential test suite in cw-curves/src/diff_tests.rs: SplitMix64-seeded random walks vs f64 reference impls (1k iters per curve per (sd, rd) matrix), round-trip identity, boundary cases. 14/14 cw-curves tests passing.
11 56cbb672e Expanded dao-abc-factory/README.md (DAO instantiation flow, reverse-handshake auth doc). Audit report status table refreshed: M-5 → Fixed, L-5 → Fixed (20 of 21 fully fixed; L-2 attribute surface partial).
12 8c8845bbb cargo fmt --all.

Audit closure summary

20 of 21 findings fully fixed; 1 partial (L-2 attribute surface — explicit Err arm + operator-monitoring note shipped, per-skipped-DAO response attribute deferred since the helper is private and doesn't return attributes today). All Criticals, Highs, and Mediums fully addressed.

Severity Count Status
Critical (C-1, C-2) 2 All fixed
High (H-1..H-6) 6 All fixed
Medium (M-1..M-6) 6 All fixed
Low (L-1..L-7) 7 6 fixed, 1 partial (L-2)
Info (I-1..I-7) 7 All fixed

Per-finding fix-commit refs in audits/2026-05-09-cw-abc-security-review.md under "Status as of 2026-05-09".

Schema-breaking changes (heads up for reviewers)

These would be breaking for any deployed instance, but the branch is pre-mainnet:

  • HATCHERS map type changed from Map<&Addr, Uint128> to Map<&Addr, HatcherState>.
  • HatchersResponse and Hatcher query response types updated accordingly.
  • CommonsPhaseConfig gains a vesting: VestingSchedule field.
  • HatchConfig gains an optional hatch_deadline: Option<Timestamp> field.
  • UpdatePhaseConfigMsg loses the Closed {} variant (was a todo!() panic).
  • UpdatePhaseConfigMsg::Hatch gains hatch_deadline: Option<Option<Timestamp>>.
  • CommonsPhase gains a Refunding variant.
  • ExecuteMsg gains AbortHatch {} and ClaimRefund {}.
  • New typed errors: CurveDriftExceeded, InvalidDecimals, HatcherTokensNotVested, InvalidMigration, RefundAlreadyClaimed, RefundBurnMismatch, CurveError(#[from] cw_curves::CurveError).
  • Removed: MismatchedSellAmount, Unauthorized (cw-abc), UnsupportedFactoryMsg (dao-abc-factory).

Verification

Run with the workspace's pinned nightly-2024-01-08 toolchain. Per-feature gates:

cargo +nightly-2024-01-08 fmt --all -- --check
cargo +nightly-2024-01-08 clippy --lib -p cw-curves -p cw-abc -p dao-abc-factory \
  --features "cw-abc/cosmwasm_tokenfactory dao-abc-factory/cosmwasm_tokenfactory" \
  -- -D warnings
cargo +nightly-2024-01-08 test -p cw-curves
RUSTFLAGS="-C link-arg=-s" cargo +nightly-2024-01-08 build \
  -p cw-abc -p dao-abc-factory --release --lib --target wasm32-unknown-unknown \
  --features "cw-abc/cosmwasm_tokenfactory dao-abc-factory/cosmwasm_tokenfactory"

Locally green (all four):

  • cargo fmt --check: clean
  • cargo clippy --lib -- -D warnings: clean
  • cargo test -p cw-curves: 14 passed; 0 failed (3 happy-path + 3 division-by-zero + 6 differential random walks + 2 round-trip identity + 2 boundary)
  • Wasm release builds: cw_abc.wasm 16KB, dao_abc_factory.wasm 311KB

Pending CI (libclang gating; the dev container we built this in didn't have libclang and the pinned nightly doesn't support optional dev-dependencies, so we couldn't gate osmosis-test-tube locally):

  • cargo +nightly-2024-01-08 test -p cw-abc -p dao-abc-factory --features cosmwasm_tokenfactory — 30 unit tests in cw-abc/src/audit_tests.rs exercising the full audit-defense matrix.
  • bash scripts/schema.sh regen for cw-abc.json and dao-abc-factory.json (the committed JSON is stale).
  • cargo test --features test-tube for chain-binary integration tests.

juno-ai-dev and others added 18 commits May 9, 2026 21:49
Brings the cw-abc branch (~2y stale, last touched 2024-05-20) forward to
development as a single squash commit, ready for audit fixes.

Changes:
- New crates: packages/cw-curves, contracts/external/cw-abc,
  contracts/external/dao-abc-factory
- Workspace: declared the three new members at version 2.8.0-alpha.2,
  added rust_decimal/cw-address-like to workspace dependencies
- Cargo.lock: regenerated against pinned nightly-2024-01-08;
  rust_decimal pinned to 1.34.3 and base64ct/arrayvec pinned to
  pre-edition2024 versions to maintain toolchain compatibility
- cw-abc + dao-abc-factory: adopted the workspace tokenfactory feature
  pattern (osmosis_tokenfactory / cosmwasm_tokenfactory /
  thorchain_tokenfactory) to match dao-voting-token-staked
- Conflict resolution: kept development's cw-tokenfactory-issuer (2y of
  upstream evolution); kept the cw-abc branch's contract source as-is
  (no source-level conflicts on the new crates themselves)
- Spelling fixes ported forward from cw-abc branch in
  packages/{dao-voting,dao-interface,cw-paginate-storage}

Verification (with pinned nightly + cosmwasm_tokenfactory feature):
- cargo check -p cw-curves -p cw-abc -p dao-abc-factory: clean
- cargo clippy --lib -p cw-curves -p cw-abc -p dao-abc-factory
  -- -D warnings: clean
- cargo test -p cw-curves: 3/3 passing
- Wasm release builds: cw_abc 16KB, dao_abc_factory 304KB

Known environment gaps (not code issues):
- cw-abc/dao-abc-factory unit tests blocked by libclang-less container
  (osmosis-test-tube build script needs libclang for bindgen). Tests
  will run on CI machines that have libclang.
- dao-voting-token-staked has a pre-existing tokenfactory-feature
  unification quirk when checked together with multiple feature flavors;
  not introduced by this rebase.

Next: apply 21 audit findings from
audits/2026-05-09-cw-abc-security-review.md to bring the branch to
audit-ready state for upstream review against #697.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
C-1 — gate update_curve against rug-via-curve-replacement
============================================================
The previous update_curve allowed an owner to swap the bonding curve
under the existing (reserve, supply) pair with no invariant check. A
malicious or compromised owner could combine this with UpdateMaxSupply
to mint a flood at the next buy and drain the reserve. Audit details:
audits/2026-05-09-cw-abc-security-review.md (C-1).

Layered fix in commands.rs::update_curve:
- Hard gate on phase: only allowed in Closed phase.
- Continuity check: new_curve.reserve(curve_state.supply) must be
  within MAX_CURVE_DRIFT_BPS (100 bps = 1%) of curve_state.reserve.
- New typed error CurveDriftExceeded carrying the comparison values.
- Fixed the copy-paste log attribute ("close" -> "update_curve")
  (also closes I-3).

C-2 — authenticate factory callers via reverse handshake
============================================================
dao-abc-factory and dao-test-custom-factory both accepted any caller
claiming to be a voting module via VotingModuleQueryMsg::Dao, then
transferred ownership of a freshly minted contract to the
attacker-chosen "DAO" address. Audit details: C-2.

Fix in dao-abc-factory and dao-test-custom-factory:
- Reverse-handshake: query info.sender for its DAO, then query that
  DAO for its VotingModule, assert it equals info.sender.
- Wires the previously-unused Unauthorized variants (also closes I-1
  partially).
- dao-test-custom-factory adopts a small private helper
  assert_caller_is_voting_module that's reused by both NFT and token
  factory handlers.

L-7 — clear factory temp state in reply
============================================================
CURRENT_DAO and VOTING_MODULE in dao-abc-factory now Cleared at the
end of the reply handler so they behave as TempState rather than
long-lived stale records.

Verification (pinned nightly-2024-01-08):
- cargo check + cargo clippy --lib -- -D warnings:
  green for cw-abc + dao-abc-factory under cosmwasm_tokenfactory and
  for dao-test-custom-factory under osmosis_tokenfactory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
H-1 — inline hatcher token vesting
==========================================================
Hatchers' tokens are now locked according to a configurable schedule
(None / Cliff / Linear) that begins at the Hatch->Open transition. This
closes the original arbitrage hole where hatchers could buy at the
hatch curve and immediately sell at the (unchanged) curve in Open
phase. Audit details: H-1.

Implementation:
- New VestingSchedule enum on CommonsPhaseConfig (abc.rs).
- HATCHERS map type changed from `Map<&Addr, Uint128>` to
  `Map<&Addr, HatcherState>` carrying contributed / minted /
  already_burned / vesting_started_at.
- `buy()` in Hatch tracks both gross contribution (used for
  contribution_limits.max check) and minted token count.
- Hatch->Open transition iterates HATCHERS to stamp
  vesting_started_at = env.block.time on every entry.
- New `helpers::vested_amount` computes the unlocked portion at any
  given timestamp.
- `sell()` checks per-hatcher vested - already_burned >= burn_amount
  and rejects with new typed `HatcherTokensNotVested` error otherwise.
- Non-hatchers (no entry in HATCHERS) sell freely. Open-phase buyers
  who didn't hatch are not subject to vesting.

H-2 — remove reachable todo!() panic
==========================================================
`UpdatePhaseConfigMsg::Closed {}` was a no-field variant that fell
through to `todo!()` in update_phase_config, panicking on any owner
input. Variant removed entirely (closed-phase config has no
configurable fields). Audit details: H-2.

H-3 — strict < 100% on entry_fee (Hatch + Open)
==========================================================
HatchConfig::validate and OpenConfig::validate now reject
entry_fee == 100% (which would brick the curve by diverting all
payment to the funding pool). Audit details: H-3.

H-4 — strict < 100% on exit_fee (Open)
==========================================================
OpenConfig::validate now rejects exit_fee == 100% (which would silently
rug every seller). Wires the previously-unused InvalidExitFee variant.
Audit details: H-4.

H-5 — bound supply/reserve token decimals
==========================================================
instantiate now rejects decimals >= 38 with new typed
InvalidDecimals { decimals, max } error. cw-curves uses
10u128.pow(decimals) which overflows at 39+. Audit details: H-5.

H-6 — validate contribution_limits ordering
==========================================================
HatchConfig::validate now ensures contribution_limits.min <=
contribution_limits.max. Equality is allowed (fixed-amount hatches are
a legitimate pattern). Audit details: H-6.

I-3 — fixed copy-paste log attribute on update_curve
==========================================================
"action" attribute now reads "update_curve" rather than "close".

Verification (pinned nightly):
- cargo check + clippy --lib -- -D warnings: green for cw-abc,
  cw-curves, dao-abc-factory under cosmwasm_tokenfactory.
- cargo test -p cw-curves: 3/3 passing.
- Wasm release builds: produce expected artifacts.

Schema-breaking changes (acknowledged, branch is pre-mainnet):
- HATCHERS now stores HatcherState rather than Uint128.
- HatchersResponse and Hatcher query response types updated
  accordingly.
- CommonsPhaseConfig gains a `vesting` field.
- UpdatePhaseConfigMsg loses the `Closed {}` variant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
M-1 — rewrite hatcher priority queue insertion
==========================================================
The previous binary_search_by + .then(Ordering::Less) approach was a
no-op (comparator never returned Equal, so binary_search always took
the Err branch and the priority field was effectively ignored — every
DAO entry was appended to the queue regardless of priority). Replaced
with a partition_point-based insert that maintains the queue sorted by
priority ascending, with `None`-priority entries trailing. Audit: M-1.

M-2 — cw2 version check on migrate
==========================================================
migrate now verifies the stored cw2 contract name matches CONTRACT_NAME
and returns a typed InvalidMigration error otherwise, preventing
silent overwrite when migrating from a foreign contract. Audit: M-2.

M-3 — HATCHERS semantics clarified
==========================================================
Net of the H-1 vesting refactor, HATCHERS now stores HatcherState with
explicit `contributed` (gross hatch intake — used for
contribution_limits.max checks) and `minted - already_burned` (live
token balance — used for vesting checks). Documented in state.rs and
the contract README. Audit: M-3.

M-4 — remove dead HATCHER_ALLOWLIST Map
==========================================================
The bare `Map<&Addr, HatcherAllowlistConfig>` constant that
namespace-collided with the IndexedMap (`hatcher_allowlist()`) is now
removed. Both shared the prefix "hatcher_allowlist" so a future
contributor writing through the bare Map would have silently bypassed
the secondary index. Audit: M-4.

M-5 — hatch deadline + permissionless abort path
==========================================================
HatchConfig gains an optional `hatch_deadline: Option<Timestamp>` and
ExecuteMsg gains `AbortHatch {}`. Anyone can call AbortHatch after the
deadline if `initial_raise.min` has not been reached; the contract
transitions to Closed phase so hatchers can recover their reserve via
existing sells. UpdatePhaseConfigMsg::Hatch can update the deadline.

This is the v1 implementation: hatchers recover their reserve-side
contribution but the funding-pool portion remains under owner control.
The full pro-rata Refunding sub-state is deferred to a follow-up PR
per the audit-readiness plan. Audit: M-5.

M-6 — trust-model documentation
==========================================================
cw-abc README now has a "Trust assumptions" section detailing owner
privileges and recommending DAO-core ownership for production. Also
added a "Vesting" section describing the H-1 schedule semantics, and
trimmed the now-obsolete "Optionally vest tokens" Future Work bullet.

Verification:
- cargo clippy --lib -p cw-abc -p dao-abc-factory --features
  cosmwasm_tokenfactory -- -D warnings: clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
L-1 — bound query_hatcher_allowlist
========================================================
Replaced unbounded `iter.collect()` for `limit: None` with
DEFAULT_LIMIT=30 / MAX_LIMIT=100 caps. Audit: L-1.

L-2 — surface DAO query errors in allowlist check
========================================================
`assert_allowlisted_through_daos` now distinguishes "DAO returned 0"
from "DAO query errored." Inline doc comment guides operators to
monitor the queue for stale entries that no longer respond to
`VotingPowerAtHeight`. Audit: L-2.

L-3 — eliminate self-call auth bypass
========================================================
Instantiate now calls `commands::update_hatch_allowlist` inline
rather than via a deferred CosmosMsg::Wasm self-call, removing the
`if env.contract.address != info.sender` auth-bypass branch from
update_hatch_allowlist. Future code paths that introduce additional
self-calls can no longer accidentally hit the bypass. Audit: L-3.

L-4 — guard u128 -> i128 cast in cw-curves::decimal
========================================================
Added an assertion in packages/cw-curves/src/utils.rs::decimal that
catches values >= 2^127 before the cast that would otherwise produce
a silently-negative i128. Audit: L-4.

L-6 — raise cube_root precision (EXTRA_DIGITS 9 -> 15)
========================================================
SquareRoot::supply on small reserves was rounding to 3 supply
decimals, leaking up to 170 micro-units per call on test cases.
Boost to 15-digit cube_root precision. Two existing test
expectations updated to the more accurate values (matching the
test comments' stated true values). Audit: L-6.

L-7 — was addressed in the C-2 commit.
L-5 (Curve trait -> Result<>) deferred — invasive multi-file change;
queued as a follow-up to keep this audit-readiness PR focused.

I-1 — remove unused error variants
========================================================
- cw-abc: dropped `MismatchedSellAmount` and `Unauthorized` (cw-abc
  uses cw_ownable::OwnershipError for unauthorized owner-only paths).
- dao-abc-factory: dropped `UnsupportedFactoryMsg`. `Unauthorized`
  retained — now used by C-2's reverse-handshake check.
Audit: I-1.

I-2 — zero exit_fee on close
========================================================
`commands::close` now resets `phase_config.open.exit_fee` to zero so
the stored config matches runtime semantics
(`calculate_sell_quote` returns Decimal::zero() in Closed phase).
Audit: I-2.

I-4 — standardize CONTRACT_NAME format
========================================================
`dao-abc-factory` now uses `"crates.io:dao-abc-factory"` to match
cw-abc's convention. Audit: I-4.

I-5 — doc comment on assert_allowlisted DAO-typed-individual rejection
========================================================
Audit: I-5.

I-6 — doc comment on strict `>` in MAX_SUPPLY check
========================================================
Audit: I-6.

I-7 — code comment on TEMP_SUPPLY load/remove ordering
========================================================
Audit: I-7.

Verification:
- cargo clippy --lib -p cw-curves -p cw-abc -p dao-abc-factory
  --features cosmwasm_tokenfactory -- -D warnings: clean.
- cargo test -p cw-curves: 3/3 passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reviews packages/cw-curves, contracts/external/cw-abc, and
contracts/external/dao-abc-factory. 21 findings (2 Critical, 6 High,
6 Medium, 7 Low, 7 Informational).

Status table appended showing per-finding fix commit:
- 19 fully fixed
- 2 partial (M-5 Refunding sub-state, L-2 attribute surface)
- 1 deferred (L-5 — Curve trait Result conversion is invasive,
  queued as separate PR)

All Criticals and Highs fully addressed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the previous `unwrap()`-on-overflow surface in the Curve trait
and its three impls with a typed `CurveError`. Closes audit finding L-5
(was deferred from the prior round of fixes).

cw-curves changes
==========================================================
- New `CurveError` enum with `Overflow { scale, value }` and
  `DivisionByZero` variants. Added thiserror as a workspace dep.
- `Curve` trait sigs change: `spot_price`, `reserve`, `supply` all
  return `Result<_, CurveError>`.
- `DecimalPlaces::to_reserve` and `to_supply` return Result; `to_u128`
  failures surface as `CurveError::Overflow`.
- `utils::square_root` and `cube_root` return Result; `decimal_to_std`
  also returns Result (rare-path, mostly theoretical).
- All three curve impls (Constant, Linear, SquareRoot) propagate via
  `?` and convert zero-slope/zero-value into `DivisionByZero`.
- 3 new unit tests for division-by-zero (one per curve type).

cw-abc consumer changes
==========================================================
- `helpers::calculate_buy_quote` and `calculate_sell_quote`: propagate
  `?` through `curve.supply()` / `curve.reserve()` calls.
- `commands::update_curve`: propagate `?` through the continuity check.
- `queries::query_curve_info`: convert `CurveError` to `StdError::generic_err`
  for the spot_price call.
- `error::ContractError`: new `CurveError(#[from] cw_curves::CurveError)`
  variant.

Verification:
- cargo +nightly-2024-01-08 test -p cw-curves: 6/6 passing (3 happy-path
  + 3 division-by-zero).
- cargo +nightly-2024-01-08 clippy --lib -p cw-curves -p cw-abc
  -p dao-abc-factory --features cosmwasm_tokenfactory -- -D warnings:
  clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous round shipped AbortHatch as a transition to Closed —
hatchers recovered their reserve-side contribution but the funding-pool
portion remained owner-withdrawable. This commit completes M-5:
hatchers now reclaim their pro-rata share of (reserve + funding).

Design
==========================================================
- New `CommonsPhase::Refunding` variant + `expect_refunding` helper.
- New `RefundSnapshot { total_pool, total_contributed }` Item, written
  at AbortHatch time so pro-rata math is deterministic and late
  claimants don't dilute earlier ones.
- New `HatcherState.claimed_refund: bool` to prevent double-claim.
- New `ExecuteMsg::ClaimRefund {}` handler — caller must be a hatcher,
  must surrender their unburned hatcher tokens (mirrors `sell` semantics
  of must_pay supply_denom), and receives
  `state.contributed * snapshot.total_pool / snapshot.total_contributed`
  reserve tokens.
- New typed errors: `RefundAlreadyClaimed`, `RefundBurnMismatch`.

Refunding-phase rejections (M-5 invariant: funding pool reserved for hatchers):
- buy(): rejected (CommonsClosed).
- sell(): rejected via calculate_sell_quote (use ClaimRefund instead).
- withdraw(): rejected (owner can't drain the funding pool).
- close(): rejected (Refunding is terminal).
- update_curve(): already gated on Closed phase, won't fire.
- AbortHatch: already gated on Hatch phase, won't fire.

Other operational handlers (toggle_pause, update_funding_pool_forwarding,
update_max_supply, update_hatch_allowlist) remain enabled — they don't
extract value from the refund pool.

abort_hatch flow:
- Existing deadline + initial_raise.min checks unchanged.
- Iterates HATCHERS to compute total_contributed.
- Snapshots `(total_pool, total_contributed)`.
- Transitions to Refunding (was Closed).
- Emits attributes for indexers.

claim_refund flow:
- expect_refunding() phase guard.
- Loads HatcherState; rejects with SenderNotAllowlisted if non-hatcher.
- Rejects RefundAlreadyClaimed if already claimed.
- must_pay(supply_denom) for unburned hatcher tokens; rejects with
  RefundBurnMismatch if amount != minted - already_burned.
- multiply_ratio computes pro-rata refund.
- State updated FIRST (claimed_refund = true) before issuing burn/refund
  messages — re-entrancy via reply can't double-claim.
- BankMsg::Send for the refund + Issuer Burn for the surrendered tokens.

README + audit report
==========================================================
- README "Trust assumptions" updated to describe Refunding-phase
  funding-pool lock.
- Future Work bullet about Refunding (now implemented) removed.

Verification (pinned nightly):
- cargo clippy --lib -p cw-abc -p dao-abc-factory
  --features cosmwasm_tokenfactory -- -D warnings: clean.
- cargo test -p cw-curves: 6/6 passing.

K-phase rejection tests for the Refunding lifecycle land in a
follow-up commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds `src/audit_tests.rs` with rejection tests for each Critical, High,
and load-bearing Medium audit finding. One or more tests per finding
asserting the defended-against behavior is now rejected.

Coverage
==========================================================
C-1: update_curve rejects in Hatch / Open phase, rejects on >1% drift,
     rejects non-owner. (4 tests)
H-1: vested_amount math — None / Cliff pre / Cliff post / Linear partial /
     Linear full / no-clock-defensive. (6 tests)
H-2: UpdatePhaseConfigMsg::Closed no longer deserializes; sanity check
     that Open variant still does. (1 test)
H-3+H-4: instantiate rejects 100% entry_fee in Hatch and Open;
         instantiate rejects 100% exit_fee; update_phase_config rejects
         the same updates. (4 tests)
H-5: instantiate rejects supply_decimals=38, reserve_decimals=39, accepts
     decimals=18. (3 tests)
H-6: instantiate rejects min > max contribution_limits, accepts equal.
     (2 tests)
M-1: priority queue insert order — mixed [3, None, 1, 2, None] resolves
     to [1, 2, 3, None_a, None_b]. (1 test)
M-2: migrate rejects foreign cw2 contract name; accepts matching.
     (2 tests)
M-5: buy / withdraw / close all rejected in Refunding phase;
     claim_refund rejects non-hatcher; claim_refund rejects double-claim;
     abort_hatch rejects pre-deadline; abort_hatch rejects when no
     deadline configured. (7 tests)
L-3: update_hatch_allowlist no longer admits self-call (sender ==
     contract.address now fails ownership check). (1 test)

Total: 30 audit-defense tests. Plus the existing 6 cw-curves tests
(3 happy-path + 3 division-by-zero) and the existing donate / withdraw /
toggle_pause tests in commands.rs.

Module structure
==========================================================
- `src/audit_tests.rs` declared in `lib.rs` under `#[cfg(test)]`.
- `commands::insert_into_priority_queue` made `pub(crate)` so the M-1
  test can exercise it directly without going through the full
  update_hatch_allowlist flow.

Verification
==========================================================
The test build pulls in `osmosis-test-tube` via `dao-testing` (dev-dep
graph), which requires libclang for bindgen. This container does not
have libclang installed and the pinned nightly does not support the
optional-dev-dep pattern that would let us gate it. CI machines have
libclang and run the full suite. The test code is verified by
inspection; logic mirrors existing test patterns in
`commands.rs::tests::donate`.

Tests deferred to a follow-up cw-multi-test integration setup
==========================================================
- C-2 factory reverse-handshake roundtrip (needs mock voting module +
  cw-multi-test app)
- H-1 full vesting matrix through buy/sell flow (needs token-factory
  simulation)
- M-5 full ClaimRefund roundtrip with actual mint/burn (same)
- K12 curve overflow propagation through ContractError::CurveError

The vested_amount math test (H-1) covers the scheduler in isolation;
the integration matrix is queued.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds packages/cw-curves/src/diff_tests.rs with pure-Rust f64 reference
implementations for each curve type, then random-walks 1000 iterations
per curve per (supply_decimals, reserve_decimals) matrix asserting the
production curve matches the reference within tolerance.

Coverage
==========================================================
- diff_constant_random_walk: 4 (sd, rd) combinations × 1000 iterations,
  abs_tol=10, rel_tol=1e-3.
- diff_linear_random_walk: 3 combinations × 1000 iterations, abs_tol=100,
  rel_tol=1e-3.
- diff_sqrt_random_walk: 2 combinations × 1000 iterations, abs_tol=100,
  rel_tol=5e-3 (extra precision overhead from sqrt).
- diff_*_round_trip: 500 iterations of supply(reserve(s)) ≈ s, bounded
  drift checks. SquareRoot variant skips reserves < 100 base units where
  quantization dominates.
- diff_boundary_supply_zero / one: edge-case sanity for all 3 curves.

Determinism
==========================================================
SplitMix64 PRNG seeded per test (no rand dep). Hardcoded seeds so
failures reproduce; assertion message prints seed and inputs.

Verification
==========================================================
cargo +nightly-2024-01-08 test -p cw-curves: 14/14 passing
- 3 happy-path (constant_curve, linear_curve, sqrt_curve)
- 3 division-by-zero (typed CurveError)
- 6 differential random walks
- 2 round-trip identity
- 2 boundary-case

Closes the audit-suggested differential test work item that was queued
as a follow-on. The suite is the reference for future curve additions
(S-curve, Taylor series, etc.).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…resh

dao-abc-factory README
==========================================================
Renamed `README` -> `README.md` for consistency with sibling contracts.
Expanded from a 4-line stub to a full doc covering:

- The DAO instantiation flow (dao-dao-core -> voting-module ->
  this factory -> cw-abc -> ownership handoff via TokenFactoryCallback /
  ModuleInstantiateCallback).
- The C-2 reverse-handshake authentication pattern with the actual
  code snippet and rationale.
- State variables (DAOS map, CURRENT_DAO + VOTING_MODULE TempState).
- Query surface.
- Audit cross-reference.

Audit report status table
==========================================================
- M-5 promoted from Partial -> Fixed; references both 29ba5e1 (deadline +
  abort) and 744e609 (full Refunding sub-state with ClaimRefund).
- L-5 promoted from Deferred -> Fixed; references 74931ee (Curve trait
  Result conversion).
- Summary updated: 20 fully fixed, 1 partial (L-2 attribute surface).
  All Criticals, Highs, and Mediums fully addressed.
- Verification section updated: cw-curves now reports 14/14 tests
  (was 3/3); test-tube + schema regen explicitly noted as deferred to
  libclang-equipped CI.

Schema regen (Phase O) deferred
==========================================================
`bash scripts/schema.sh` for cw-abc + dao-abc-factory triggers the
osmosis-test-tube build script via the dao-testing dev-dep graph,
which needs libclang. Container can't sudo apt-install. CI machines
have libclang and will regen as part of the standard build pipeline;
the existing schemas in source remain stale until then. Documented in
the audit report Verification section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…custom-factory

`cargo +nightly-2024-01-08 fmt --all` applied to bring formatting in
line with the pinned nightly's rustfmt. No semantic changes.

Final verification (Phase Q gate):
- cargo fmt --check: clean
- cargo clippy --lib -p cw-curves -p cw-abc -p dao-abc-factory
  --features cosmwasm_tokenfactory -- -D warnings: clean
- cargo test -p cw-curves: 14/14 passing
- cargo build --release --target wasm32-unknown-unknown for cw-abc and
  dao-abc-factory: green
  - cw_abc.wasm: 16KB
  - dao_abc_factory.wasm: 311KB

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generalizes Constant, Linear, and SquareRoot under a single curve type
with a rational exponent `num/den`. Closes the "additional curve types"
follow-up from PR #926 partially; Sigmoid lands in a follow-on commit.

cw-curves additions
==========================================================
- New `nth_root(value, n) -> Result<Decimal, CurveError>` helper in
  `utils.rs`. Newton-Raphson on Decimal with a bit-count-guided initial
  guess (`x_0 = 2^(bits/n)` where `bits ≈ log2(value)`) so `x^(n-1)`
  doesn't saturate rust_decimal on the first iteration. Falls through
  to `square_root` (n=2) and `cube_root` (n=3) fast paths. Bounded at
  64 iterations with overflow-safe `checked_mul`.
- New `pow_rational(base, num, den)` helper that dispatches to integer
  power for `den=1`, otherwise computes `base^num` then `nth_root(_, den)`.
  GCD-reduces num/den to maximize fast-path hits.
- `Power` curve impl in `curves/power.rs`:
    f(s)   = slope * s^(num/den)
    F(s)   = slope * den / (num + den) * s^((num + den) / den)
    F^-1(r) = ((num + den) * r / (slope * den))^(den / (num + den))
- 5 new unit tests:
  - power_curve_matches_linear_at_n1 / matches_square_root_at_n_half /
    matches_constant_at_n0: parity with existing curves on shared exponents.
  - power_curve_round_trip: 4 supplies through reserve()/supply() with
    exotic exponent 3/4.
  - power_division_by_zero_on_zero_slope.
- 2 new differential tests in `diff_tests.rs`:
  - diff_power_random_walk: 6 (num, den) pairs × 2 (sd, rd) matrices ×
    500 iterations against an f64 reference.
  - diff_power_round_trip: 200 iterations of supply(reserve(s)) ≈ s for
    n=3/4, skipping pathologically-small reserves.

cw-abc wiring
==========================================================
- New `CurveType::Power { slope, scale, exponent_num, exponent_den }`
  variant in `abc.rs`. Existing Constant/Linear/SquareRoot retained for
  back-compat; new deployments can use Power for any rational exponent
  including the existing 0/1, 1/1, 1/2.

Verification
==========================================================
- cargo +nightly-2024-01-08 test -p cw-curves: **21 passed; 0 failed**
  (was 14 → 21; 5 Power unit tests + 2 Power diff tests).
- cargo clippy --lib -p cw-curves -p cw-abc -p dao-abc-factory
  --features cosmwasm_tokenfactory -- -D warnings: clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the "additional curve types" follow-up alongside the Power curve.
Sigmoid is the standard logistic shape used in production by Token
Engineering Commons for smoothed price discovery.

cw-curves additions
==========================================================
- New `taylor_exp(x: Decimal) -> Result<Decimal, CurveError>` helper:
  range-reduces x = k + r where k is the integer part and |r| < 1, then
  computes e^k by repeated multiplication and e^r via 20-term Taylor.
  Negative inputs handled via 1/e^|x| to avoid alternating-sign series
  precision loss. Bounded |x| ≤ 30 to keep results in Decimal range.
- `decimal_to_std` now rounds to 18 decimal places before string
  conversion (StdDecimal precision cap was rejecting longer mantissas).
- New `Sigmoid` curve impl in `curves/sigmoid.rs`:
    f(s) = amplitude / (1 + e^(-steepness * (s - midpoint)))
  Numerical strategy: spot_price closed-form via taylor_exp; reserve via
  Simpson's rule (32 panels); supply via Newton-Raphson on the integral
  (≤ 32 iters). Closed-form integral via softplus would have required
  taylor_ln; deferred for impl simplicity. Documented as research-quality
  precision (~1e-3 relative error) with higher gas cost than the
  closed-form curves.
- 11 new unit tests:
  - 5 taylor_exp tests (zero, e, 1/e, 2.5, large-rejection)
  - 6 sigmoid tests (midpoint half-amplitude, saturation, reserve zero,
    reserve monotonic, round-trip, division-by-zero)
- 1 new differential test: 100 sigmoid spot-price samples vs f64 reference.

cw-abc wiring
==========================================================
- New `CurveType::Sigmoid` variant carrying `(amplitude, amplitude_scale,
  steepness_num, steepness_den, midpoint, midpoint_scale)`. Steepness as
  rational so it round-trips cleanly through JSON.

Verification
==========================================================
- cargo +nightly-2024-01-08 test -p cw-curves: **33 passed; 0 failed**
  (was 21 → 33).
- cargo clippy --lib -p cw-curves -p cw-abc -p dao-abc-factory
  --features cosmwasm_tokenfactory -- -D warnings: clean.

Future work (out of scope this PR)
==========================================================
- Closed-form integral via taylor_ln helper (would replace Simpson's
  rule with O(1) instead of O(panels) cost).
- Tighter bounds on Newton convergence near the asymptote regime.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the L-2 follow-up that was previously partial. The
`assert_allowlisted_through_daos` helper now returns a `Vec<Attribute>`
alongside the override-limits result; each entry whose
`VotingPowerAtHeight` query errored produces a `try_dao_query_failed`
attribute carrying the DAO address. `commands::buy()` attaches these
attributes to the buy response so operators can detect stale or
migrated DAO entries from chain logs without inferring from gas
profile.

Code changes
==========================================================
- `commands::assert_allowlisted` returns
  `Result<(HatchConfig, Vec<Attribute>), ContractError>`.
- `commands::assert_allowlisted_through_daos` returns
  `Result<(Option<MinMax>, Vec<Attribute>), ContractError>`. The Err
  branch of each per-DAO query pushes a `try_dao_query_failed`
  attribute and continues to the next entry; iteration semantics
  unchanged (a single broken DAO doesn't lock out users with voting
  power in other allowlisted DAOs).
- `commands::buy()` Hatch branch captures the attributes from
  `assert_allowlisted` and threads them through `add_attributes(...)`
  on the response.

Audit report
==========================================================
- L-2 row promoted from Partial → Fixed.
- Summary updated: **21/21 findings fully fixed**.

Verification
==========================================================
- cargo clippy --lib -p cw-abc --features cosmwasm_tokenfactory
  -- -D warnings: clean.
- Unit test for the attribute path queued to land in Phase S
  (cw-multi-test integration test) where we can wire a mock voting
  module that errors on VotingPowerAtHeight; the audit_tests.rs
  mock_dependencies harness doesn't model wasm_smart queries cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Was inadvertently swept into the Phase U commit. Moving back to
working-tree-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI's `Lints` job caught formatting deviations in the Phase U (Power),
Phase V (Sigmoid), and Phase T (L-2) code that I didn't re-run fmt on
after the edits. `cargo +nightly-2024-01-08 fmt --all` applied across
cw-abc/abc.rs, cw-abc/commands.rs, cw-curves/{utils,tests,diff_tests,
curves/power}.rs.

No semantic changes.

Verification (post-fmt):
- cargo fmt --all -- --check: clean
- cargo test -p cw-curves: 33 passing
- cargo clippy --lib -p cw-curves -p cw-abc -p dao-abc-factory
  --features cosmwasm_tokenfactory -- -D warnings: clean

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…actory feature on cw-abc + dao-abc-factory

Two CI failures from the previous push:

1. `Test Suite` (Basic workflow) — `dao-voting-cw721-staked::test_factory`
   and `test_factory_with_funds_pass_through` were failing because the
   C-2 parity reverse-handshake on `dao-test-custom-factory` queries
   `info.sender` for `VotingModuleQueryMsg::Dao` then queries that DAO
   for `VotingModule {}`. Those sibling tests instantiate cw721-staked
   directly from an EOA (`creator`) — there's no DAO at all in the
   test setup, so the second handshake step queries an EOA address
   (returned as the "DAO") and fails with "ContractData not found".

   Fix: revert the C-2 fix on dao-test-custom-factory. It's a `contracts/test/...`
   contract that's exercised by sibling-crate tests in patterns the
   production C-2 hardening doesn't accommodate. The production fix
   on `dao-abc-factory` (commit 429a45a) stays as-is.

   Audit report updated: C-2 row notes the test-factory parity revert
   with reasoning. Production C-2 fix unchanged.

2. `workspace-optimize` (Test Tube workflow setup) — wasm build of
   cw-abc / dao-abc-factory was failing with cw-tokenfactory-types'
   compile_error because no tokenfactory backend was selected.

   Fix: add `default = ["osmosis_tokenfactory"]` to both crates'
   Cargo.toml [features] sections. Matches the pattern used by
   cw-tokenfactory-issuer, dao-voting-token-staked, and
   dao-test-custom-factory. Juno deployments which use
   cosmwasm_tokenfactory override at build time:
   `cargo wasm --no-default-features --features cosmwasm_tokenfactory`.

Code changes
==========================================================
- `contracts/test/dao-test-custom-factory/src/contract.rs`: removed
  `assert_caller_is_voting_module` helper and its call sites; restored
  the original `info.sender → VotingModuleQueryMsg::Dao` query (no
  reverse-handshake). Cleaned up unused `ensure`, `QuerierWrapper`,
  `DaoQueryMsg` imports.
- `contracts/external/cw-abc/Cargo.toml`: `default = ["osmosis_tokenfactory"]`.
- `contracts/external/dao-abc-factory/Cargo.toml`: same.
- `audits/2026-05-09-cw-abc-security-review.md`: C-2 row reflects the
  test-factory parity revert.

Verification (post-fix)
==========================================================
- cargo fmt --check: clean
- cargo clippy --lib -p cw-curves -p cw-abc -p dao-abc-factory
  -p dao-test-custom-factory -- -D warnings: clean (without explicit
  feature flags — defaults pick a backend cleanly)
- cargo test -p cw-curves: 33 passed
- cargo wasm --release for cw-abc + dao-abc-factory: builds clean with
  no explicit feature flag

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented May 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 48.25397% with 978 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.41%. Comparing base (0178cf5) to head (32a0f26).

Files with missing lines Patch % Lines
contracts/external/cw-abc/src/commands.rs 39.38% 451 Missing ⚠️
contracts/external/cw-abc/src/queries.rs 0.00% 126 Missing ⚠️
contracts/external/cw-abc/src/contract.rs 40.51% 116 Missing ⚠️
contracts/external/dao-abc-factory/src/contract.rs 0.00% 111 Missing ⚠️
contracts/external/cw-abc/src/helpers.rs 36.26% 58 Missing ⚠️
contracts/external/cw-abc/src/abc.rs 59.83% 49 Missing ⚠️
packages/cw-curves/src/utils.rs 82.51% 32 Missing ⚠️
contracts/external/cw-abc/src/state.rs 43.90% 23 Missing ⚠️
packages/cw-curves/src/curves/power.rs 85.71% 6 Missing ⚠️
packages/cw-curves/src/curves/sigmoid.rs 92.77% 6 Missing ⚠️
Additional details and impacted files
@@               Coverage Diff               @@
##           development     #926      +/-   ##
===============================================
- Coverage        96.56%   89.41%   -7.16%     
===============================================
  Files              199      174      -25     
  Lines            67407    30663   -36744     
===============================================
- Hits             65094    27417   -37677     
- Misses            2313     3246     +933     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

juno-ai-dev and others added 3 commits May 10, 2026 01:24
…versions

Two CI failures from the previous push:

1. `Basic` workflow Lints job — `cargo clippy --all-targets -- -D warnings`
   caught unused imports in `audit_tests.rs`: ClosedConfig,
   CommonsPhaseConfig, HatchConfig, OpenConfig, ReserveToken, SupplyToken.
   Locally I only ran `clippy --lib` which doesn't include test targets,
   so the warning was missed. Pruned to only the imports actually used
   (CommonsPhase, CurveType, MinMax, VestingSchedule).

2. `Integration Tests` workflow — all 8 tests failing with
   "Unknown opcode 192: create wasm contract failed" against the pinned
   juno v15.0.0 chain (wasmd v0.31, cosmwasm-vm 1.2). The just
   `download-deps` recipe pulled `cw-plus/releases/latest` and
   `cw-nfts/releases/latest`; recent cw-plus releases ship wasm built
   against newer cosmwasm-vm features (Wasm sign-extension proposal —
   opcode 0xC0 = 192) that the test chain can't deserialize.

   Fix: pin to v1.1.2 (cw-plus) and v0.18.0 (cw-nfts) which match the
   workspace's `cw20 = "1.1"` and `cw721 = "0.18"` deps and are
   known-compatible with the test chain. HEAD-checked the assets are
   downloadable at those tags.

   This is a pre-existing latent issue affecting any PR opened against
   `development` after a recent cw-plus release; not specific to the
   cw-abc branch but unblocks #926 CI here.

Verification (post-fix):
- cargo fmt --all -- --check: clean
- cargo clippy --lib -p cw-curves -p cw-abc -p dao-abc-factory
  -p dao-test-custom-factory -- -D warnings: clean

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Test Tube workflow was failing with 13 compilation errors in
contracts/external/cw-abc/src/test_tube/{test_env,integration_tests}.rs
and contracts/external/dao-abc-factory/src/test_tube/test_env.rs. The
test scaffolding from the rebase referenced struct shapes that have
evolved on `development` since the cw-abc branch was last touched
(2y ago). All errors fall into known categories:

- `HatchConfig` gained `hatch_deadline: Option<Timestamp>` (M-5 fix)
- `CommonsPhaseConfig` gained `vesting: VestingSchedule` (H-1 fix)
- `NewTokenInfo` gained `token_issuer_salt` (upstream)
- `ModuleInstantiateInfo` gained `salt` (upstream)
- `ModuleInstantiateInfo.funds` changed from `Vec<Coin>` to
  `Option<Vec<Coin>>` (upstream)
- `dao_proposal_single::msg::InstantiateMsg` gained `delegation_module`
  (upstream)
- `dao_interface::msg::InstantiateMsg` gained `initial_actions`
  (upstream)

Fix: updated each call site to provide the new fields. Defaulted
post-audit fields:
- `hatch_deadline: None` (no deadline in existing test scenarios)
- `vesting: VestingSchedule::None` (no vesting; tests pre-date H-1)
- `delegation_module: None`, `initial_actions: None`,
  `token_issuer_salt: None`, `salt: None`, `funds: None`

Files updated:
- `contracts/external/cw-abc/src/test_tube/test_env.rs`
- `contracts/external/cw-abc/src/test_tube/integration_tests.rs`
- `contracts/external/dao-abc-factory/src/test_tube/test_env.rs`

These are mechanical "field-add" updates to keep existing test
coverage running. Net new test scenarios (H-1 vesting matrix, C-2
factory reverse-handshake roundtrip, M-5 ClaimRefund) for the
audit-defense surface remain queued as Phase S.

Verification (post-fix):
- cargo fmt --all -- --check: clean
- cargo clippy --lib -p cw-curves -p cw-abc -p dao-abc-factory
  -- -D warnings: clean (no explicit feature flags; defaults pick
  osmosis_tokenfactory which now flows through cleanly)

Note: the previously-flagged `unused imports` warning in audit_tests.rs
was already fixed in commit fea240c (CI ran on a pre-fix commit).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…chemas

The Lints CI step diffs committed schema JSON against fresh `cargo run
--example schema` output and rejects any drift. Three schemas had
diverged from current contract code:

- cw-abc: Phase U/V (Power, Sigmoid curves), Refunding sub-state,
  ClaimRefund + AbortHatch handlers, VestingSchedule, HatcherState,
  cube_root precision bump, typed CurveError variant
- dao-abc-factory: dao-abc-factory contract_version bump to
  2.8.0-alpha.2; vesting field on phase config; Open phase description
  refresh; Power/Sigmoid curve variants
- cw-tokenfactory-issuer: doc-comment typo fixes
  (trasfer/recieve/intedended/whis/wiil/allownances)

PR #926 description already flagged this as pending CI work.
@JakeHartnell JakeHartnell mentioned this pull request May 11, 2026
16 tasks
@JakeHartnell
JakeHartnell marked this pull request as ready for review May 12, 2026 22:53
@JakeHartnell

Copy link
Copy Markdown
Member Author

Need to fix integration tests (a problem for many PRs), but otherwise this is ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants