feat: add one-shot MetaSwap limit order enforcer - #203
Closed
hanzel98 wants to merge 1 commit into
Closed
Conversation
Combine exact swap authorization, signed approval flexibility, minimum output, and one-shot consumption to remove redundant caveat calls and storage writes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
MetaSwapOneShotLimitOrderEnforcer, a purpose-specific caveat that combines MetaSwap batch validation, one-shot consumption, and minimum-output enforcement.approve(amount), and/orapprove(0) + approve(amount)fills.This is stacked on #201 so that PR and its branch remain unchanged.
Behavior
One signed delegation authorizes exactly one successful direct
BATCH_DEFAULT_MODEorder:Terms bind the MetaSwap target, input token and amount, signed approval policy, output token, recipient, and minimum net balance increase:
The batch length chooses one of the signed policy bits; unsigned caveat args are not used. Native input uses policy
0.One-slot lifecycle
A single mapping slot keyed by
(DelegationManager, delegationHash)stores:This replaces the independent call-count, lock, and balance-cache mappings used by
LimitedCallsEnforcer(1)plus a balance-change enforcer. A successful order is permanently consumed. Any revert, including insufficient output, atomically restores the unused state and permits retry.A prototype benchmark measured approximately 29-36% lower gross estimated redemption gas than composing
MetaSwapBatchCalldataEnforcer + LimitedCallsEnforcer(1) + ERC20BalanceChangeEnforcer; the finalOrderConsumedevent adds normal event cost in exchange for indexable successful fills.Security
aggregatorIdand routedataremain redeemer-controlled. The delegator trusts the configured MetaSwap contract, its adapters, and the delegate-provided route. The enforcer fixes the direct input approval and MetaSwap input fields and guarantees the signed minimum output balance increase, but it cannot prevent arbitrary route side effects or protect unrelated assets already approved to MetaSwap or its adapters.A residual input allowance may remain if MetaSwap spends less than the approved amount. Unrelated transfers or token rebases during execution may satisfy the balance increase, and malicious/non-standard output tokens may report misleading balances. Input and output tokens must differ.
Deployment and verification
Deploy through the existing shared script:
After recording deployed addresses, use the existing
script/verification/verify-enforcer-contracts.shflow. No dedicated script or environment variable is introduced.Test plan
aggregatorIdand route dataDelegationManagerredemptionLINEA_RPC_URLandARBITRUM_RPC_URLNote
Medium Risk
New on-chain swap/limit-order enforcement handles approvals and balance deltas; delegators still trust MetaSwap routes and face known balance-enforcer caveats (unrelated transfers, non-standard tokens, residual allowance).
Overview
Adds
MetaSwapOneShotLimitOrderEnforcer, a single caveat that replaces composingMetaSwapBatchCalldataEnforcer,LimitedCallsEnforcer(1), and a balance-change enforcer for one-shot MetaSwap limit orders.Signed 145-byte packed terms bind MetaSwap, exact input, an ERC-20 approval-policy bitmask (skip allowance /
approve(amount)/ reset-then-approve), output token, recipient, andtokenOutMin. Redemptions must be batch default mode with 1–3 executions matching the signed policy; routeaggregatorIdanddatastay unconstrained.Lifecycle uses one
orderStatesslot per(DelegationManager, delegationHash): cache pre-output balance and lock inbeforeHook, enforce minimum net increase and mark consumed inafterHook(withOrderConsumed). Failed fills revert the tx so the order stays retryable; success is permanent.Also wires deployment in
DeployCaveatEnforcers.s.sol, documents behavior and trust assumptions inCaveatEnforcers.md, and adds broad Foundry tests (shapes, validation, redemption, retry, double-spend).Reviewed by Cursor Bugbot for commit f6c0bb3. Bugbot is set up for automated code reviews on this repo. Configure here.