feat(contracts): support signed revoke and batch buyer accounting migration - #24
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the AntseedBuyerOperator contract to improve buyer/operator lifecycle control (including an optional EIP-712 signed revoke path) and introduce a remaining-balance accounting model with one-time migration helpers, alongside interface and Foundry test updates.
Changes:
- Added signed revoke support (
REVOKE_OPERATOR_TYPEHASH,revokeOperator(buyer,timestamp,sig)) while keeping the legacy direct revoke entrypoint. - Introduced remaining/usage-aware accounting (
principalRemaining,bonusRemaining,lastAccountedBalance) plus single/batch migration helpers. - Updated
IAntseedDepositsto expose buyer balance (available/reserved) and expanded tests for non-operator funding behavior, revoke flows, usage accounting, and migration.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
contracts/src/AntseedBuyerOperator.sol |
Adds signed revoke, remaining-based accounting + migration, and adjusts funding/withdraw/revoke/transfer flows accordingly. |
contracts/src/interfaces/IAntseedDeposits.sol |
Extends deposits interface with getBuyerBalance needed for usage/remaining accounting. |
contracts/test/AntseedBuyerOperator.t.sol |
Updates mocks and adds coverage for signed revoke, non-operator funding bonus wipe, usage accounting, migrations, and transfer invariants. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
@blueogin please review |
| function transferBuyerOperator(address buyer, address newOperator) external nonReentrant onlyAdmin { | ||
| if (buyer == address(0)) revert InvalidAddress(); | ||
| _withdrawUnusedBonus(buyer); | ||
| _deposits().transferOperator(buyer, newOperator); | ||
| emit BuyerOperatorTransferred(buyer, newOperator); | ||
| } |
There was a problem hiding this comment.
_revokeOperator added CloseChannelsBeforeRevoke to stop bonus being stranded in reserved channels, but the transfer path has no equivalent check - the operator role can be handed off with bonus still locked.
There was a problem hiding this comment.
thats expected. added a description to the method
Summary
This PR updates the Base-side
AntseedBuyerOperatorand the Cloudflare Worker integration around buyer/operator lifecycle management, remaining-balance accounting, signed buyer actions, and migration tooling.The main contract changes support safer signed operations, per-buyer nonce replay protection, signed operator revocation, principal/bonus remaining-balance tracking, and one-time migration of existing buyer accounting. The Worker changes keep its API and funding behavior aligned with the updated contract surface.
What Changed
Contracts
owner/adminresponsibilities so:ownercontrols upgrades, token sweeping, and privileged fund operations.adminis the day-to-day operational caller.revokeOperator(address buyer, uint256 nonce, bytes buyerSig)revokeOperator(address buyer)remains available for direct buyer/admin revocation.usedNonces[buyer]is shared by signed withdraw, revoke, request-close, and channel-withdraw actions.nonceinstead oftimestamp.ECDSArecovery helpers for malformed/malleable signature handling.principalRemainingbonusRemainingtotalPrincipalWithdrawntotalBonusWithdrawnlastAccountedBalancemigrateBuyerAccounting(address buyer)migrateBuyerAccounting(address[] buyers)buyerAccountingMigrated[buyer]IAntseedDepositswithgetBuyerBalancefor usage-aware accounting.Backend Worker
timestampto decimal-stringnonce.POST /v1/accounts/:account/operator-revoke:{ nonce, signature }AntseedBuyerOperator.revokeOperator(buyer, nonce, buyerSig).AntSeedFundingVaultClient.revokeBuyerOperatorfor the new revoke endpoint.AntSeedFundingVaultClient.isBuyerOperator, which reads:AntseedBuyerOperator.registry()registry.deposits()deposits.getOperator(buyer)principalUsd === 0,bonusUsd > 0, and the on-chain operator check confirms this contract is not the buyer operator.depositForBuyerWithIdwhen this contract remains the buyer operator.backend/scripts/migrate-buyer-accounting.tsto discover historical funded buyers and batch-run accounting migration.Docs And Tooling
backend/README.mdendpoint list withoperator-revoke.docs/ARCHITECTURE.mdfor nonce-based auth, the revoke endpoint, and current backend/operator behavior.contracts/DEPLOY.mdfor the owner/admin naming andtransferAdminflow.yarn install --immutable.lintscript uses Yarn commands.backend/package-lock.jsonfrom the branch diff.Validation
cd contracts && forge test --match-contract AntseedBuyerOperatorTest-> 44 passedcd contracts && forge test-> 81 passedcd backend && npm test-> 76 passedcd backend && npm run check:worker-only && npm run typecheck-> passedNotes