Skip to content

feat: add MetaSwap batch calldata enforcer - #201

Open
hanzel98 wants to merge 1 commit into
mainfrom
feat/metaswap-batch-calldata-enforcer
Open

feat: add MetaSwap batch calldata enforcer#201
hanzel98 wants to merge 1 commit into
mainfrom
feat/metaswap-batch-calldata-enforcer

Conversation

@hanzel98

@hanzel98 hanzel98 commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add MetaSwapBatchCalldataEnforcer for canonical DelegationManager batch redemptions.
  • Let one delegation authorize an ERC-20 approval plus MetaSwap call, an approval reset plus approval and swap, or one native-token swap.
  • Integrate deployment into the shared caveat-enforcer deployment script and document the security assumptions in the existing enforcer guide.

Behavior

Signed terms bind the MetaSwap target, input token, input amount, and approval shape. The enforcer requires BATCH_DEFAULT_MODE and accepts only:

Native:       [MetaSwap.swap{ value: amount }(...)]
ERC-20:       [token.approve(metaSwap, amount), MetaSwap.swap(...)]
ERC-20 reset: [token.approve(metaSwap, 0), token.approve(metaSwap, amount), MetaSwap.swap(...)]

The swap target, value, selector, tokenFrom, and amount must match the terms. aggregatorId and route data remain flexible.

Usage

bytes memory terms = abi.encodePacked(
    metaSwap,
    tokenIn,
    tokenInAmount,
    bytes1(resetApproval ? 1 : 0)
);

Caveat memory caveat = Caveat({
    enforcer: address(metaSwapBatchCalldataEnforcer),
    terms: terms,
    args: hex""
});

// Redeem ExecutionLib.encodeBatch(executions) with ModeLib.encodeSimpleBatch().

Add LimitedCallsEnforcer to make the delegation one-shot. Add ERC20BalanceChangeEnforcer or NativeBalanceChangeEnforcer to enforce tokenOutMin.

Security

The delegate is trusted to choose safe swap data: aggregatorId and route data are supplied by the redeemer and are not restricted by this enforcer. The enforcer binds the direct input approval and MetaSwap input fields, but it does not validate route side effects, adapter behavior, output amount, or a mutable MetaSwap implementation. A residual allowance may remain if MetaSwap spends less than the approved amount.

Deployment and verification

The enforcer is deployed through the existing shared script:

forge script script/DeployCaveatEnforcers.s.sol \
  --rpc-url <rpc_url> --private-key $PRIVATE_KEY --broadcast

The existing script/verification/verify-enforcer-contracts.sh remains the canonical verification flow after deployed addresses are recorded. No enforcer-specific script or environment variable is introduced.

Test plan

  • ERC-20 approve(amount) + swap
  • ERC-20 approve(0) + approve(amount) + swap
  • Native-token swap{ value: amount }
  • Canonical DelegationManager redemption
  • Flexible aggregatorId and route data
  • Tampered target, value, selector, token, amount, approval, mode, terms, and batch shape
  • Composition with LimitedCallsEnforcer and ERC20BalanceChangeEnforcer
  • 100% enforcer line, statement, branch, and function coverage
  • 1,058 non-fork regression tests passing

Note

Medium Risk
The enforcer authorizes ERC-20 approvals to MetaSwap within signed bounds while leaving swap route data delegate-controlled, so delegators must trust MetaSwap/adapters and may retain residual allowance; misuse is mitigated by documentation and recommended companion enforcers.

Overview
Adds MetaSwapBatchCalldataEnforcer, a new caveat that limits BATCH_DEFAULT_MODE redemptions to fixed MetaSwap swap batches while the redeemer can still pick aggregatorId and route data.

Signed terms pack MetaSwap address, input token (address(0) for native), input amount, and whether the batch must use approve(0) before approve(amount). The hook enforces batch length and pins approval/swap targets, values, selectors, spender, and swap tokenFrom/amount; it does not cap swap output or audit route side effects.

Docs describe the allowed shapes and trust assumptions (compose with LimitedCallsEnforcer and balance-change enforcers). Deploy script deploys the new singleton. Tests cover happy paths, tampering, full DelegationManager redemption, and pairing with LimitedCallsEnforcer and ERC20BalanceChangeEnforcer.

Reviewed by Cursor Bugbot for commit 6086455. Bugbot is set up for automated code reviews on this repo. Configure here.

@hanzel98
hanzel98 requested a review from a team as a code owner August 29, 2026 23:53
Bind swap inputs and approval shape while preserving redeemer-selected route data for limit orders.
@hanzel98
hanzel98 force-pushed the feat/metaswap-batch-calldata-enforcer branch from b9e7058 to 6086455 Compare August 30, 2026 00:13
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.

1 participant