Skip to main content

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

Arbiters are specialized contracts that handle settlement validation and resource unlocking for different protocols. They validate user signatures, unlock input tokens, and coordinate target operation execution.
Arbiters are called by adapters to perform the actual settlement logic after pre-funding or other preparation steps are complete.

Arbiter Architecture

ArbiterBase

All arbiters inherit from ArbiterBase, which provides protocol integration:
ArbiterBase.sol
abstract contract ArbiterBase {
    address public immutable ROUTER;
    address public immutable COMPACT;
    address public immutable EXECUTOR;
    address public immutable ADDRESS_BOOK;
    
    modifier onlyRouter() {
        require(msg.sender == ROUTER, OnlyRouter());
        _;
    }
    
    constructor(address router, address compact, address addressBook) {
        ROUTER = router;
        COMPACT = compact;
        ADDRESS_BOOK = addressBook;
        EXECUTOR = IAddressBook(addressBook).intentExecutor();
    }
}
Key Components:

Router Access Control

Only Router can call arbiter functions via onlyRouter modifier

Protocol Integration

Immutable references to Compact, Executor, and AddressBook

Signature Validation

Validates user signatures before resource movements

Resource Unlocking

Claims user tokens from protocols (Compact, Permit2)

Settlement Flow

Arbiters orchestrate the settlement process in coordination with adapters:
1

Pre-Funding (Adapter)

Adapter pre-funds recipient with output tokens before calling arbiter
2

Signature Validation (Arbiter)

Arbiter validates user signatures and order metadata
3

Pre-Claim Operations (Arbiter)

Execute any required setup operations (approvals, configurations)
4

Resource Unlock (Arbiter)

Unlock and transfer user’s input tokens to solver
5

Target Execution (Arbiter)

Execute user-specified operations (swaps, transfers)

SameChainArbiter

Handles same-chain settlements for both Compact and Permit2 protocols:

Compact Settlement

SameChainArbiter.sol
function handleCompact_NotarizedChain(
    Types.Order calldata order,
    Types.Signatures calldata sigs,
    bytes32[] calldata otherElements,
    bytes calldata allocatorData,
    address relayer
) external onlyRouter returns (address sponsor, uint256 nonce) {
    sponsor = order.sponsor;
    nonce = order.nonce;
    
    // Ensure order hasn't expired
    require(order.fillDeadline >= block.timestamp, OrderExpired());
    
    // STEP 1: Pre-claim validation and execution
    bytes32 mandateHash = _compactPreClaimOps(
        order,
        sigs,
        otherElements,
        0,
        block.chainid
    );
    
    // STEP 2: Resource unlock and deposit to relayer
    _unlockNotarizedChain({
        order: order,
        otherElements: otherElements,
        originChainSig: sigs.notarizedClaimSig,
        allocatorData: allocatorData,
        depositor: relayer,
        mandateHash: mandateHash
    });
    
    // STEP 3: Execute target operations
    if (order.targetOps.data.length != 0) {
        address recipient = order.recipient;
        SmartExecutionLib.SigMode targetOpsSigMode = order.targetOps.extractSigMode();
        bool sigModeMatch = (
            order.preClaimOps.data.length == 0 || 
            targetOpsSigMode == order.preClaimOps.extractSigMode()
        );
        
        if (
            recipient == sponsor && 
            !targetOpsSigMode.isExecutionEmissary() && 
            sigModeMatch
        ) {
            EXECUTOR.executeOpsWithoutSignature(recipient, order.targetOps);
        }
    }
}
STEP 1: Pre-Claim Validation
  • Validates order signatures and metadata
  • Executes pre-claim operations (approvals, setup)
  • Generates mandate hash for resource unlock
  • Ensures prerequisites before claiming
STEP 2: Resource Unlock
  • Validates signatures against mandate hash
  • Unlocks user’s input tokens from Compact
  • Transfers tokens directly to relayer address
  • Returns claim hash for tracking
STEP 3: Target Operations
  • Checks execution conditions (recipient == sponsor, etc.)
  • Executes user-specified operations without additional signatures
  • Uses trusted execution pattern for gas efficiency
  • Maintains atomic execution guarantees

Permit2 Settlement

Streamlined flow for Permit2-based orders:
SameChainArbiter.sol
function handlePermit2(
    Types.Order calldata order,
    Types.Signatures calldata sigs,
    address relayer
) external onlyRouter returns (address sponsor, uint256 nonce) {
    sponsor = order.sponsor;
    nonce = order.nonce;
    
    require(order.fillDeadline >= block.timestamp, OrderExpired());
    
    // STEP 1: Pre-claim validation (simplified for Permit2)
    bytes32 mandateHash = _permit2PreClaimOps(order, sigs);
    
    // STEP 2: Resource unlock via Permit2
    _unlockPermit2({
        order: order,
        sig: sigs.notarizedClaimSig,
        depositor: relayer,
        mandateHash: mandateHash
    });
    
    // STEP 3: Execute target operations
    if (order.targetOps.data.length != 0) {
        address recipient = order.recipient;
        SmartExecutionLib.SigMode targetOpsSigMode = order.targetOps.extractSigMode();
        bool sigModeMatch = (
            order.preClaimOps.data.length == 0 || 
            targetOpsSigMode == order.preClaimOps.extractSigMode()
        );
        
        if (
            recipient == sponsor && 
            !targetOpsSigMode.isExecutionEmissary() && 
            sigModeMatch
        ) {
            EXECUTOR.executeOpsWithoutSignature(recipient, order.targetOps);
        }
    }
}
Permit2 settlement is more gas-efficient than Compact due to simplified validation and unlock process, making it optimal for straightforward token operations.

Trusted Execution Pattern

Arbiters use a trusted execution model for target operations:
// SameChainArbiter is whitelisted in IntentExecutor
// This enables executeOpsWithoutSignature after initial validation

EXECUTOR.executeOpsWithoutSignature(
    recipient,
    order.targetOps
);
Benefits:
  • Avoids redundant signature validation (already done in pre-claim)
  • Reduces gas costs significantly
  • Maintains security through initial validation gate

Protocol-Specific Validation

Compact Pre-Claim

function _compactPreClaimOps(
    Types.Order calldata order,
    Types.Signatures calldata sigs,
    bytes32[] calldata otherElements,
    uint256 preClaimGasStipend,
    uint256 notarizedChainId
) internal returns (bytes32 mandateHash) {
    // Validate signatures and metadata
    // Execute pre-claim operations with gas stipend
    // Generate mandate hash for resource unlock
}
Features:
  • Complex signature validation
  • Pre-claim operation execution
  • Gas stipend allocation
  • Allocator data handling

Permit2 Pre-Claim

function _permit2PreClaimOps(
    Types.Order calldata order,
    Types.Signatures calldata sigs
) internal returns (bytes32 mandateHash) {
    // Simplified signature validation
    // Generate mandate hash
}
Features:
  • Simplified validation
  • No pre-claim operations
  • Lower gas overhead

Resource Unlocking

Compact Unlock

function _unlockNotarizedChain(
    Types.Order calldata order,
    bytes32[] calldata otherElements,
    bytes calldata originChainSig,
    bytes calldata allocatorData,
    address depositor,
    bytes32 mandateHash
) internal returns (bytes32 claimHash) {
    // Validate against mandate hash
    // Unlock tokens from Compact protocol
    // Transfer to depositor (relayer)
}

Permit2 Unlock

function _unlockPermit2(
    Types.Order calldata order,
    bytes calldata sig,
    address depositor,
    bytes32 mandateHash
) internal {
    // Validate Permit2 signature
    // Transfer tokens to depositor
}

Dual Protocol Support

Use Case: Complex multi-step settlementsFeatures:
  • Pre-claim operations
  • Gas stipend allocation
  • Allocator integration
  • Multi-signature support
  • Cross-chain coordination
When to Use:
  • Complex settlement flows
  • Multi-element orders
  • Cross-chain operations
  • Advanced authorization

Security Model

Critical Security Features:
  • Access Control: Only Router can call arbiter functions
  • Signature Validation: All user signatures validated before asset movements
  • Atomic Execution: Entire settlement succeeds or reverts together
  • Deadline Enforcement: Orders expire after fillDeadline
  • Trusted Execution: Whitelist-based execution without redundant signatures

Access Control

ArbiterBase.sol
modifier onlyRouter() {
    require(msg.sender == ROUTER, OnlyRouter());
    _;
}
Only the designated Router can call arbiter settlement functions.

Atomicity Guarantees

If any step fails, the entire transaction reverts:
// If signature validation fails → revert (pre-funding also reverted)
// If resource unlock fails → revert
// If target operations fail → revert

Integration Example

How adapters integrate with arbiters:
SameChainAdapter.sol
function _handleCompactFill(
    FillDataCompact calldata fillData,
    address tokenInRecipient
) internal {
    // 1. Pre-fund recipient (adapter responsibility)
    _prefundRecipient({
        from: msg.sender,
        to: fillData.order.recipient,
        tokenOut: fillData.order.tokenOut
    });
    
    // 2. Call arbiter for settlement (arbiter responsibility)
    (address sponsor, uint256 nonce) = SameChainArbiter(ARBITER)
        .handleCompact_NotarizedChain({
            order: fillData.order,
            sigs: fillData.userSigs,
            otherElements: fillData.otherElements,
            allocatorData: fillData.allocatorData,
            relayer: tokenInRecipient
        });
    
    // 3. Emit event (adapter responsibility)
    emit RouterFilled(sponsor, nonce);
}

Target Operation Execution

Arbiters coordinate with IntentExecutor for final operations:
if (order.targetOps.data.length != 0) {
    address recipient = order.recipient;
    SmartExecutionLib.SigMode targetOpsSigMode = order.targetOps.extractSigMode();
    bool sigModeMatch = (
        order.preClaimOps.data.length == 0 || 
        targetOpsSigMode == order.preClaimOps.extractSigMode()
    );
    
    // Only execute if conditions are met
    if (
        recipient == sponsor &&           // Self-execution
        !targetOpsSigMode.isExecutionEmissary() &&  // Not delegated
        sigModeMatch                      // Sig modes align
    ) {
        EXECUTOR.executeOpsWithoutSignature(recipient, order.targetOps);
    }
}
Execution Conditions:
  1. Target ops exist: targetOps.data.length != 0
  2. Self-execution: recipient == sponsor
  3. Not emissary: !isExecutionEmissary()
  4. Signature mode match: Pre-claim and target ops use same mode
If conditions aren’t met, target operations are skipped (not reverted). This allows for flexible settlement patterns.

Adapters

Learn how adapters coordinate with arbiters

Intent Execution

Understand intent executor and ERC-7579 integration