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.
Warp Router implements multiple gas optimization techniques that can reduce operational costs by 20-40% compared to standard routing implementations.
Adapter Caching
One of the most effective optimizations is adapter caching in batch operations. When processing multiple operations with the same adapter, the Router caches the adapter address to avoid repeated storage reads.
How It Works
In RouterLogic.sol:188-280, the optimized routing function implements:
bytes4 prevSelector;
address adapter;
for ( uint256 i; i < length;) {
bytes4 selector = bytes4 (adapterCalldata[ : 4 ]);
if (selector != prevSelector) {
// Selector changed - load adapter from storage (2100 gas)
adapter = selector. withFillAdapter (). adapterAddress ();
prevSelector = selector;
}
// If selector == prevSelector, reuse cached adapter (saves ~2100 gas)
}
Gas Savings
Cold SLOAD : ~2,100 gas per adapter lookup
Cache hit : Skips SLOAD entirely
Typical savings : 20-40% for batches with repeated adapters
When batching operations, group calls to the same adapter together to maximize cache hits.
Special Selectors
Special selectors bypass the adapter lookup mechanism entirely for common operations, providing even greater gas savings.
Available Special Selectors
singleCall
ISingleCaller.singleCall.selector
Executes a single external call directly without adapter overhead. Defined in DirectRoutes.sol:121-127.
Gas savings : ~2,600+ gas per call (SLOAD + DELEGATECALL overhead)
multiCall
MultiCaller.multiCall.selector
Batches multiple external calls in a single transaction. Defined in DirectRoutes.sol:128-134.
Gas savings : Similar to singleCall, with additional batching efficiency
Fee Collection
In-router fee collection functions process fees without delegatecall:
IDirectRoute.onFill_inRouter_collectFee.selector
IDirectRoute.onFill_inRouter_collectFees.selector
Defined in DirectRoutes.sol:160-171.
Gas savings : ~2,600+ gas + eliminates adapter call overhead
How Special Selectors Work
From DirectRoutes.sol:146-179:
function _processDirectFillRoute ( bytes4 selector , bytes calldata adapterCalldata )
internal returns ( bool used )
{
if (selector == ISingleCaller.singleCall.selector) {
( bool success,) = address (CALLER). call (adapterCalldata[ 4 : ]);
require (success, CallFailed ());
return true ;
} else if (selector == MultiCaller.multiCall.selector) {
( bool success,) = address (CALLER). call (adapterCalldata);
require (success, CallFailed ());
return true ;
} else if (selector == IDirectRoute.onFill_inRouter_collectFee.selector) {
_onFill_inRouter_collectFee (adapterCalldata[ 4 : ]);
return true ;
}
// ... more special selectors
}
Batch Operations
Optimized Encoding
The optimized_routeFill921336808 function uses encoded calldata to reduce costs:
function optimized_routeFill921336808 (
bytes [] calldata relayerContexts ,
bytes calldata encodedAdapterCalldatas , // Encoded instead of bytes[]
bytes calldata atomicFillSignature
)
Benefits :
Reduces calldata costs by avoiding array decoding overhead
Saves ~200-500 gas per element
Assembly-based decoding operates directly on calldata pointers
Assembly Decoding
From RouterLogic.sol:206-221:
bytes [] calldata adapterCalldatas;
uint256 length;
assembly ( "memory-safe" ) {
let o := add (encodedAdapterCalldatas.offset, calldataload (encodedAdapterCalldatas.offset))
adapterCalldatas.offset := add (o, 0x20 )
length := calldataload (o)
adapterCalldatas.length := length
}
This avoids memory copying and operates directly on calldata, saving memory expansion costs.
Solver Context Management
Skip Relayer Context
Adapters can declare they don’t need relayer context using adapter tags:
function ADAPTER_TAG () external pure override returns ( bytes12 ) {
return Constants.DEFAULT_ADAPTER_TAG. setSkipRelayerContext ();
}
From IntentExecutorAdapter.sol:227-229.
Benefits :
Skips array access and bounds checking
Prevents unnecessary context consumption tracking
Example: IntentExecutorAdapter doesn’t consume relayer context
Context Consumption Tracking
From RouterLogic.sol:261-280:
if (adapterTag. isSkipRelayerContext ()) {
// No context consumption - more gas efficient
require (selector == adapter. callAdapter (adapterCalldata));
} else {
// Consume relayer context
require (relayerContextIndex < relayerContextsLength);
require (
selector == adapter. callAdapterWithRelayerContext (
relayerContexts[relayerContextIndex],
adapterCalldata
)
);
++ relayerContextIndex;
}
Packed Calldata Encoding
For approval operations, DirectRoutes uses packed encoding to save calldata costs.
Single Approval
From DirectRoutes.sol:332-368:
// Packed: abi.encodePacked(address token, address spender, uint256 amount, uint64 chainId, uint32 expires)
// Layout: [20 bytes][20 bytes][32 bytes][8 bytes][4 bytes] = 84 bytes total
// vs ABI encoding: ~160 bytes
Savings : ~76 bytes per approval (~1,200 gas at 16 gas/byte)
Batch Approvals
From DirectRoutes.sol:386-415:
// Packed prefix + ABI array:
// abi.encodePacked(uint64 chainId, uint32 expires) + abi.encode(uint256[3][])
// Saves 12 bytes of calldata overhead per batch
Based on DirectGasComparison.t.sol test results:
Adapter Caching 20-30% savings for 3+ identical adapter calls
Special Selectors ~2,600 gas saved per direct route
Encoded Calldata 200-500 gas saved per batch element
Packed Encoding ~1,200 gas saved per approval
Best Practices
Group by Adapter
Batch operations that use the same adapter together to maximize cache hits
Use Special Selectors
For simple calls and fee collection, use special selectors instead of custom adapters
Skip Unnecessary Context
If your adapter doesn’t need relayer context, use setSkipRelayerContext() in your adapter tag
Use Packed Encoding
For approvals and simple data, prefer packed encoding over ABI encoding
Always benchmark your specific use case. Gas savings vary based on:
Number of operations in batch
Adapter diversity
Storage slot warmth (cold vs warm)
Network gas pricing