Skip to main content

Overview

MultiCallAdapter enables solvers to execute multiple calls on behalf of users while ensuring proper token transfers and fee collection. It supports various fill operations including standard fills, fills with fees, and fills with both fees and refunds. Source: src/arbiters/multicall/MultiCallAdapter.sol Inherits: AdapterBasePrefund, Caller

Features

  • Batched arbitrary call execution
  • Solver compensation validation
  • Token prefunding for users
  • Support for native ETH and ERC20 tokens
  • Just-In-Time (JIT) claim operations
  • Payable multicalls with ETH value forwarding

Data Structures

FillData

Data structure for multicall fill operations.
uint256[2][]
Array of [token_address, amount] pairs representing solver payment. What the solver is being paid back in after executing the multicalls.
uint256[2][]
Array of [token_address, amount] pairs the solver transfers to user. What the solver pays the account before execution.
Execution[]
Batch of execution calls to perform. Each execution contains target, value, and calldata.
address
Target smart contract account for the operations.
uint256
ETH value to send with the multicall execution.

JITClaimData

Data structure for Just-In-Time claim operations.
uint256[2][]
Array of [token_address, amount] pairs for solver compensation.
Execution[]
Batch of execution calls for the JIT claim.

Errors

TokenNotPaidInMulticall

Thrown if the solver does not receive the expected amount of input tokens after the multicall execution.

InvalidRelayerContext

Thrown when relayer context data is malformed or has incorrect length.

Constructor

Initializes the MultiCallAdapter with router address.
address
Address of the Warp Router contract that will delegatecall this adapter
The arbiter is set to address(0) since multicall operations use a different validation pattern than traditional arbiters.

Fill Functions

multicall_handleFill

Executes a standard multicall fill operation. This is the main entry point for multicall-based settlements.
FillData
Contains token transfers and multicall executions to perform
Returns:
bytes4
The function selector for verification (this.multicall_handleFill.selector)
Execution Flow:
  1. Extracts tokenIn recipient from relayer context
  2. Pre-funds user account with tokenOut
  3. Executes multicalls through arbiter
  4. Validates solver received expected tokenIn amounts
  5. Returns function selector
Function Selector: this.multicall_handleFill.selector

multicall_handleJITClaim

Handles Just-In-Time claim operations with multicall execution. Executes multicalls and ensures solver receives specified tokenIn amounts.
JITClaimData
Contains tokenIn compensation and multicall executions
Returns:
bytes4
The function selector for verification (this.multicall_handleJITClaim.selector)
Execution Flow:
  1. Extracts tokenIn recipient from relayer context
  2. Executes multicalls through arbiter
  3. Validates solver received expected tokenIn amounts
  4. Returns function selector
Function Selector: this.multicall_handleJITClaim.selector

multicall_handlePayable

Handles payable multicall operations with ETH value forwarding.
uint256
Amount of ETH to send with the multicall
Execution[]
Array of calls to execute
Returns:
bytes4
The function selector for verification (this.multicall_handlePayable.selector)
Execution Flow:
  1. Forwards ETH value and executions to arbiter’s multiCall function
  2. Returns function selector
Function Selector: this.multicall_handlePayable.selector

Internal Functions

_tokenInRecipient

Extracts the tokenIn recipient address from relayer context. Relayer Context Format: abi.encodePacked(address(tokenInRecipient)) (20 bytes) Returns:
address
The address designated to receive input tokens from the multicall

_handleMulticall

Internal handler for multicall fill operations. Prefunds user account with tokenOut before executing multicalls.
FillData
Contains all data for the fill operation
address
Address to receive tokenIn payments
Execution Steps:
  1. Prefunds user account: _prefundRecipient(msg.sender, fillData.account, fillData.tokenOut)
  2. Executes multicalls and validates tokenIn: _multicallAssertTokenIn(...)

_multicallAssertTokenIn

Core multicall execution with token validation. Executes multicalls through arbiter and ensures tokenIn is properly transferred to solver.
Execution[]
Array of calls to execute
uint256[2][]
Expected token payments to solver
address
Address to receive the tokens
uint256
ETH value to send with the multicall
Implementation:

Helper Functions

__encodeRelayerData

Helper function for off-chain components to construct relayerContext data.
address
Address to receive input tokens from the multicall
Returns:
bytes
Packed bytes containing the recipient address: abi.encodePacked(tokenInRecipient)

Interface Support

supportsInterface

Checks if adapter supports a given function selector.
bytes4
Function selector to check
Returns:
bool
True if the selector is supported. Supports:
  • this.multicall_handleFill.selector
  • this.multicall_handleJITClaim.selector
  • this.multicall_handlePayable.selector
  • Any selectors from AdapterBase
  • Any selectors from Caller
  • type(IAdapter).interfaceId

Relayer Context

The relayer context must be exactly 20 bytes containing the tokenIn recipient address:
This address receives the solver’s compensation tokens after multicall execution.

Token Format

Tokens are represented as uint256[2] arrays:
Where:
  • tokenAddress is encoded as uint256 (use IdLib.toAddress() to convert)
  • amount is the token amount in wei
For native ETH, use Constants.NATIVE_TOKEN as the token address.

Execution Flow Example

Security Considerations

  • Only callable via Router delegatecall (enforced by onlyViaRouter)
  • Executes in Router’s context with access to Router’s storage and balance
  • Validates solver compensation after multicall execution
  • Pre-funding ensures user receives tokens before multicall execution
  • Atomic execution: if any step fails, entire transaction reverts

Token Validation

The adapter validates that the solver receives expected tokenIn amounts by calling multiCallWithDrainToken on the arbiter, which:
  1. Executes the multicalls
  2. Transfers tokenIn amounts to solver
  3. Reverts if expected tokens are not available

Gas Optimization

  • Uses uint256[2][] for efficient token encoding
  • Minimal data copying with calldata parameters
  • Direct arbiter calls without intermediate proxying
  • Optimized prefunding with AdapterBasePrefund helpers