Skip to content

feat(contracts): M002 legacy seller claims migration - #982

Open
alexanderludwig wants to merge 9 commits into
contracts-update-allfrom
codex/m002-legacy-seller-claims
Open

feat(contracts): M002 legacy seller claims migration#982
alexanderludwig wants to merge 9 commits into
contracts-update-allfrom
codex/m002-legacy-seller-claims

Conversation

@alexanderludwig

@alexanderludwig alexanderludwig commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds M002, the migration that unfreezes the deployed AntseedSellerRewardsPool after M001 activates. Follows up on Shahaf's AntseedLegacySellerClaimPolicy sketch and his ask to add a wash-trading check.

Claims from the pool are blocked twice today, and M001 deliberately leaves both alone:

Blocker Revert M002 fix (signer)
pool.sellerClaimPolicy == 0 NoSellerClaimPolicy deploy + install AntseedLegacySellerClaimPolicy (sellerRewardsPoolOwner)
pool not on ANTSToken.transferWhitelist while transfers are disabled TransfersNotEnabled setTransferWhitelist(pool, true) (deployer = token owner)

What's in it

  • policies/AntseedLegacySellerClaimPolicy.sol — stateless (the pool calls claimableSellerRewards as a view, so no claims[seller] counter is possible). Re-derives each seller's cumulative locked ANTS from EmissionsV2/V1 state mirroring claimSellerEmissions, treats cumulative − locked as already released, pays releaseBps (default 1538 ≈ 10/65) with optional linear vesting. Proven wash traders (isProvenWashTrader on the wash-trading registry, or owner flag) get 0; their ANTS stays in the pool.
  • script/migrations/M002LegacySellerClaims/Install.s.sol — keyless (vm.startBroadcast(address)), idempotent, both steps skip what's already on chain. Guards: M001 active, pool discovered via V2, lastEpoch = gate.effectiveEpoch() − 1 ≥ MIGRATION_EPOCH, wash registry required with code.
  • scripts/deployments/m002.mjs — single install phase; states ready / active / not-applicable (V1-only testnet) / invalid (incl. a claim policy this ledger didn't install). Reads V2 from legacyEmissionsEscrow.legacyEmissions(); defaults WASH_TRADING_REGISTRY to what M001 pinned into PositionInit. Records 002-legacy-seller-claims + current.json; finalize recovers a crash-after-broadcast. --fork-test rehearses M001 then applies M002 on top.
  • m001.mjs / ledger.mjs — extracted rehearseM001OnFork for reuse; canonicalRoot override; chain config only regenerates from the repo ledger (never from a temp rehearsal root).
  • Docs: README section, M002LegacySellerClaims/README.md runbook, .env.example, CHANGELOG.

Test plan

  • forge test — 796/796 (incl. 15 new M002 migration tests: frozen-before proof for both reverts, released-share payout, wash trader NothingToClaim, both half-applied resume paths, no-op rerun, guard rejections)
  • node --test scripts/deploy-contracts.test.mjs — 37/37 (6 new M002 tests)
  • node scripts/validate-contract-deployments.mjs — clean; no gas-snapshot drift
  • pnpm contracts:deploy -- M002 --network base-mainnet --fork-test (M001 → M002 on a pinned Anvil fork) — was started locally; still in progress at PR time

Usage

pnpm contracts:deploy -- M002 --network base-mainnet --fork-test
pnpm contracts:deploy -- M002 --network base-mainnet --dry-run
pnpm contracts:deploy -- M002 --network base-mainnet --broadcast \
  --signer deployer=account:antseed-owner \
  --signer sellerRewardsPoolOwner=account:antseed-ops

Unfreezes the deployed AntseedSellerRewardsPool after M001 activates.
Claims are blocked twice today: the pool has no sellerClaimPolicy, and ANTS
transfers are disabled with the pool (the transfer sender) never whitelisted.

- policies/AntseedLegacySellerClaimPolicy: stateless claim policy that
  re-derives each seller's cumulative locked ANTS from EmissionsV2/V1 state
  (epochs 0..lastEpoch, mirroring claimSellerEmissions), releases releaseBps
  (default 1538 ~ 10/65) with optional linear vesting, and returns zero for
  sellers the wash-trading registry has proven (or the owner flagged).
- script/migrations/M002LegacySellerClaims/Install.s.sol: keyless, idempotent
  install. Token owner whitelists the pool on ANTSToken (skipped when
  transfers are enabled or already whitelisted); pool owner deploys the policy
  and installs it. Guards: M001 active, pool discovered via V2,
  lastEpoch = gate.effectiveEpoch() - 1 >= MIGRATION_EPOCH, wash registry
  required with code.
- scripts/deployments/m002.mjs: single install phase, signers deployer +
  sellerRewardsPoolOwner, states ready/active/not-applicable/invalid, records
  002-legacy-seller-claims and updates current.json, finalize recovery,
  fork test that rehearses M001 then applies M002 on top.
- m001.mjs: extract rehearseM001OnFork so later migrations can layer on an
  activated M001 fork; ledger.mjs gains a canonicalRoot override and only
  regenerates chain config from the repository ledger.
- Tests: policy unit tests, M002 migration tests (frozen-before proof,
  release payout, wash trader NothingToClaim, resume paths, no-op rerun),
  runner tests for M002 classification/baseline/records.
- Docs: README section, M002 runbook, .env.example, CHANGELOG.
@alexanderludwig
alexanderludwig changed the base branch from contracts-update-all to main September 5, 2026 08:48
@alexanderludwig
alexanderludwig changed the base branch from main to contracts-update-all September 5, 2026 08:49
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