Documentation Index Fetch the complete documentation index at: https://mintlify.com/rhinestonewtf/warp-router/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Router supports two fundamental operation types: Fill and Claim . These operations enable different settlement patterns with distinct security models and use cases.
Fill operations require atomic signature authorization, while claim operations rely on protocol-level authorization already validated by the underlying protocol.
Operation Types
Fill Operations Settlement operations that fulfill user orders by transferring assets and executing target operations. Require atomic signature from authorized signer.
Claim Operations Resource unlock operations that claim user assets from protocols. Execute without atomic signatures as they rely on protocol-level authorization.
Fill Operations
Fill operations represent settlement transactions where a solver fulfills a user’s order:
Architecture
function optimized_routeFill921336808 (
bytes [] calldata relayerContexts ,
bytes calldata encodedAdapterCalldatas ,
bytes calldata atomicFillSignature
) public payable virtual nonReentrant {
// Compute hash of encoded calldata
bytes32 hash = encodedAdapterCalldatas. hashCalldata ();
// Validate atomic signature
require ( _isAtomic (hash, atomicFillSignature), IRouter. InvalidAtomicity ());
// Process each operation with adapter caching
for ( uint256 i; i < length;) {
bytes calldata adapterCalldata = adapterCalldatas[i];
bytes4 selector = bytes4 (adapterCalldata[ : 4 ]);
// Route to adapter or handle special selectors
if ( ! _processDirectFillRoute (selector, adapterCalldata)) {
// Regular adapter call with relayer context
require (
selector == adapter. callAdapterWithRelayerContext (
relayerContexts[relayerContextIndex],
adapterCalldata
),
IRouter. AdapterCallFailed ()
);
unchecked { ++ relayerContextIndex; }
}
unchecked { ++ i; }
}
}
Atomic Signature Security
The atomic fill signer prevents unauthorized operation execution:
function _isAtomic ( bytes32 hash , bytes calldata atomicSig )
internal virtual returns ( bool atomic )
{
address signer = $atomicFillSigner;
require (signer != address ( 0 ), IRouter. AtomicSignerNotSet ());
// Verify signature came from authorized signer
atomic = (signer == ECDSA. recoverCalldata (hash, atomicSig));
}
Security Model:
Only the designated atomicFillSigner can authorize fill batches
Each signature is bound to specific calldata via hash
Prevents unauthorized solvers from executing user operations
Setting signer to address(0) pauses all fill operations
Fill Flow Example
Same-chain Compact fill operation:
Solver Submits Fill
router. optimized_routeFill921336808 (
relayerContexts, // [tokenInRecipient]
encodedAdapterCalldatas, // [samechain_compact_handleFill calldata]
atomicFillSignature // Signature from atomicFillSigner
);
Router Validates Signature
bytes32 hash = encodedAdapterCalldatas. hashCalldata ();
require ( _isAtomic (hash, atomicFillSignature));
Router Delegates to Adapter
adapter. callAdapterWithRelayerContext (
relayerContext,
adapterCalldata
);
Adapter Pre-Funds Recipient
_prefundRecipient ({
from : msg.sender , // Solver
to : order.recipient,
tokenOut : order.tokenOut
});
Arbiter Validates & Unlocks
SameChainArbiter. handleCompact_NotarizedChain ({
order : order,
sigs : userSigs,
relayer : tokenInRecipient // From relayer context
});
Execute Target Operations
EXECUTOR. executeOpsWithoutSignature (
order.recipient,
order.targetOps
);
Fill Operation Security
Authorization Layers
Replay Protection
Atomicity Guarantees
1 . Atomic Fill Signature
↓
Validates entire batch from Router perspective
2 . User Signatures (in arbiter)
↓
Validates individual orders from user perspective
3 . Protocol Authorization
↓
Compact / Permit2 validates token movements
// Atomic signature bound to specific calldata
bytes32 hash = keccak256 (encodedAdapterCalldatas);
// User nonces prevent replay of orders
order.nonce // Unique per user per order
// Deadline enforcement
require (order.fillDeadline >= block .timestamp);
// All operations succeed or entire batch reverts:
✅ Pre - funding succeeds
✅ Signature validation passes
✅ Resource unlock succeeds
✅ Target operations execute
// If ANY step fails:
❌ Entire transaction reverts
❌ No partial state changes persist
Claim Operations
Claim operations unlock user resources from protocols without requiring atomic signatures:
Architecture
function routeClaim (
bytes [] calldata relayerContexts ,
bytes [] calldata adapterCalldatas
) external payable nonReentrant {
// No atomic signature validation required
uint256 length = adapterCalldatas.length;
uint256 relayerContextIndex;
bytes4 prevSelector;
address adapter;
for ( uint256 i; i < length;) {
bytes calldata adapterCalldata = adapterCalldatas[i];
bytes4 selector = bytes4 (adapterCalldata[ : 4 ]);
// Handle special selectors or route to adapter
if ( ! _processDirectClaimRoute (selector, adapterCalldata)) {
if (selector != prevSelector) {
adapter = selector. withClaimAdapter (). adapterAddress ();
prevSelector = selector;
}
require (
selector == adapter. callAdapterWithRelayerContext (
relayerContexts[relayerContextIndex],
adapterCalldata
),
IRouter. AdapterCallFailed ()
);
unchecked { ++ relayerContextIndex; }
}
unchecked { ++ i; }
}
}
Claim vs Fill
Security Model
Entry Points
Authorization
Aspect Fill Claim Atomic Signature Required ✅ Not required ❌ Protocol Auth Compact/Permit2 sigs Compact/Permit2 sigs Use Case Settlement fulfillment Resource unlocking Initiator Solver User or solver
// Fill operations - require atomic signature
router. optimized_routeFill921336808 (
relayerContexts,
encodedAdapterCalldatas,
atomicFillSignature // ✅ Required
);
// Claim operations - no atomic signature
router. routeClaim (
relayerContexts,
adapterCalldatas // ❌ No signature
);
// Fill: Dual authorization
1 . Atomic signer authorizes batch
2 . User authorizes specific order
// Claim: Single authorization
1 . User authorizes claim via protocol signature
Single Claim Operation
For individual claim operations:
function routeClaim (
bytes calldata relayerContext ,
bytes calldata adapterCalldata
) public payable nonReentrant {
bytes4 selector = bytes4 (adapterCalldata[ : 4 ]);
// Handle special selectors or route to adapter
if ( ! _processDirectClaimRoute (selector, adapterCalldata)) {
address adapter = selector. withClaimAdapter (). adapterAddress ();
require (
selector == adapter. callAdapterWithRelayerContext (
relayerContext,
adapterCalldata
),
IRouter. AdapterCallFailed ()
);
}
}
Single claim operations are optimized for gas efficiency when only one claim is needed.
Batch Processing
Both fill and claim operations support atomic batch execution:
Batch Atomicity
// All operations in batch must succeed
for ( uint256 i; i < length;) {
// Execute operation i
require (success, AdapterCallFailed ());
unchecked { ++ i; }
}
// If any operation fails:
// - Entire batch reverts
// - No partial state changes
// - All gas consumed up to failure point
Relayer Context Consumption
// Each regular adapter call consumes one relayer context
uint256 relayerContextIndex;
for ( uint256 i; i < length;) {
if ( ! isSpecialSelector) {
// Regular adapter call - consume context
adapter. callAdapterWithRelayerContext (
relayerContexts[relayerContextIndex],
adapterCalldata
);
unchecked { ++ relayerContextIndex; }
}
// Special selectors don't consume contexts
unchecked { ++ i; }
}
// Validate all contexts were consumed
require (relayerContextsLength == relayerContextIndex, LengthMismatch ());
Context Validation: The Router validates that the number of relayer contexts matches the number of regular adapter calls. Special selectors (singleCall, multiCall, fee collection) don’t consume contexts.
Special Selectors
Both fill and claim operations support special selectors that bypass adapter lookup:
function _processDirectFillRoute (
bytes4 selector ,
bytes calldata data
) internal returns ( bool processed ) {
if (selector == this .singleCall.selector) {
// Handle single call directly
processed = true ;
} else if (selector == this .multiCall.selector) {
// Handle multi call directly
processed = true ;
} else if (selector == this .collectFees.selector) {
// Handle fee collection directly
processed = true ;
}
// Returns false for regular adapters
}
Benefits:
Gas Savings Saves ~2,600+ gas by avoiding SLOAD and DELEGATECALL overhead
No Context Special selectors don’t consume relayer contexts
Built-in Common operations handled natively by Router
Gas Optimizations
Adapter Caching
bytes4 prevSelector;
address adapter;
for ( uint256 i; i < length;) {
bytes4 selector = bytes4 (adapterCalldata[ : 4 ]);
if (selector != prevSelector) {
// Cache miss - load adapter from storage
adapter = selector. withFillAdapter (). adapterAddress ();
prevSelector = selector;
}
// Cache hit - reuse adapter (saves ~2,100 gas)
adapter. callAdapter (adapterCalldata);
}
Encoded Calldata (Fill Only)
// Traditional approach:
function routeFill ( bytes [] calldata calldatas ) {
// Decodes array immediately (~200-500 gas per element)
}
// Optimized approach:
function optimized_routeFill921336808 (
bytes calldata encodedAdapterCalldatas
) {
// Decode using assembly - operates on calldata directly
assembly {
let o := add (encodedAdapterCalldatas.offset, calldataload (...))
adapterCalldatas.offset := add (o, 0x20 )
length := calldataload (o)
}
}
Context Tracking
// Efficient context consumption tracking
uint256 relayerContextIndex;
if ( ! isSpecialSelector) {
// Regular adapter - consume context
unchecked { ++ relayerContextIndex; }
}
// No increment for special selectors
Use Cases
Fill Use Cases
Claim Use Cases
Cross-Chain Settlement
User swaps ETH on Ethereum for USDC on Arbitrum
Solver fills order by providing USDC on Arbitrum
Solver claims ETH on Ethereum after settlement
Same-Chain Settlement
User swaps USDC for DAI on same chain
Solver pre-funds DAI to recipient
Solver claims USDC after arbiter validation
Intent Execution
User authorizes multi-step operations
Solver executes operations via IntentExecutor
Solver receives compensation after execution
Resource Unlocking
User claims locked tokens from Compact
User withdraws from time-locked contract
User collects yield from protocol
Post-Settlement Claims
Solver claims input tokens after filling order
User claims refunds from failed operations
Protocol claims fees from settlements
Independent Claims
Claims not tied to active settlements
User-initiated resource unlocking
Automated claim processing
Error Handling
Fill Errors
error InvalidAtomicity (); // Atomic signature invalid
error AtomicSignerNotSet (); // Signer is address(0)
error AdapterCallFailed (); // Adapter execution failed
error LengthMismatch (); // Context/calldata length mismatch
Claim Errors
error AdapterCallFailed (); // Adapter execution failed
error LengthMismatch (); // Context/calldata length mismatch
Best Practices
Use Fill for Settlements When solvers are fulfilling user orders, always use fill operations with atomic signatures for security.
Use Claim for Unlocks When users or solvers are unlocking resources without settlement context, use claim operations.
Batch Operations Combine multiple operations into atomic batches to ensure all-or-nothing execution.
Context Management Ensure relayer context array length matches number of regular adapter calls (excluding special selectors).
Router System Learn about Router architecture and operation routing
Adapters Understand adapter architecture and delegatecall pattern
Arbiters Learn about arbiter layer and settlement validation