Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

OIF Settlers

Open Intent Framework settlers manage cross-chain intent creation, escrow, and settlement.

Overview

Shinobi Cash uses three settler contracts:

ContractChainPurpose
ShinobiInputSettlerOriginEscrows funds, handles claims/refunds
ShinobiDepositOutputSettlerPool (Arbitrum)Fills deposit intents
ShinobiWithdrawalOutputSettlerDestinationFills withdrawal intents

Intent Structure

struct ShinobiIntent {
    // Base OIF StandardOrder Fields
    address user;           // Intent creator (verified on origin)
    uint256 nonce;          // Unique identifier component
    uint256 originChainId;  // Chain where intent was created
    uint32 expires;         // Expiry timestamp for refunds
    uint32 fillDeadline;    // Deadline for filling
    address fillOracle;     // Oracle for fill proof validation
    uint256[2][] inputs;    // Input tokens [tokenId, amount][]
    MandateOutput[] outputs;// Outputs to fill on destination
 
    // Shinobi Extensions
    address intentOracle;   // Oracle for intent proof validation
    bytes refundCalldata;   // Custom refund logic
}

ShinobiInputSettler

Manages intent creation and escrow on origin chains.

State

address public immutable entrypoint;  // Only caller for open()
mapping(bytes32 => OrderStatus) public orderStatus;
 
enum OrderStatus {
    None,       // Order doesn't exist
    Deposited,  // Funds escrowed, awaiting fill or expiry
    Claimed,    // Solver filled and claimed
    Refunded    // Intent expired and refunded
}

Functions

open

Create an intent and escrow funds. Only callable by the entrypoint.

function open(ShinobiIntent calldata intent) external payable

finalise

Release escrowed funds to the solver after proving the fill.

function finalise(
    ShinobiIntent calldata intent,
    SolveParams[] calldata solveParams,
    bytes32 destination
) external
Oracle Validation:
For each output:
1. Check fill timestamp <= fillDeadline
2. Build payloadHash = keccak256(solver | orderId | timestamp | output)
3. Pack into proofSeries: [chainId, oracle, settler, payloadHash]
4. Call fillOracle.efficientRequireProven(proofSeries)

refund

Refund expired intent. Permissionless — anyone can trigger for expired intents.

function refund(ShinobiIntent calldata intent) external

State Machine

                          ┌─────────────┐
                          │    None     │
                          └──────┬──────┘
                                 │ open()
                          ┌──────▼──────┐
                          │  Deposited  │
                          └──────┬──────┘
                      ┌──────────┴──────────┐
                      │                     │
              finalise()                 refund()
                      │                     │
               ┌──────▼──────┐       ┌──────▼──────┐
               │   Claimed   │       │  Refunded   │
               └─────────────┘       └─────────────┘

ShinobiDepositOutputSettler

Handles deposit fills on the pool chain.

Key Difference: Mandatory Intent Validation

Deposits require intentOracle validation to prevent depositor address spoofing:

address public immutable intentOracle;  // MUST be used for all deposits
 
function fill(ShinobiIntent calldata intent) external payable nonReentrant {
    // 1. Validate deposits have exactly one output
    if (intent.outputs.length != 1) revert InvalidOutput();
 
    // 2. Validate correct destination chain
    if (intent.outputs[0].chainId != block.chainid) revert InvalidChain();
 
    // 3. Validate fill deadline
    if (block.timestamp > intent.fillDeadline) revert FillDeadlinePassed();
 
    // 4. CRITICAL: Validate intent uses configured oracle
    if (intent.intentOracle != intentOracle) revert IntentOracleMismatch();
 
    // 5. Compute unique order identifier
    bytes32 orderId = intent.orderIdentifier();
 
    // 6. CRITICAL: Validate intent proof via oracle
    if (!IInputOracle(intentOracle).isProven(
        intent.originChainId,
        bytes32(uint256(uint160(intentOracle))),
        bytes32(uint256(uint160(address(this)))),
        orderId
    )) revert IntentNotProven();
 
    // 7. Fill output with callback to crosschainDeposit()
    _fillOutput(orderId, intent.outputs[0], msg.sender);
}

Why intentOracle is required: Without this, an attacker could create fake intents claiming any depositor address. The oracle proves the intent originated from a legitimate user on the origin chain.

ShinobiWithdrawalOutputSettler

Handles withdrawal fills on destination chains.

Key Difference: Optimistic Settlement

Withdrawals use optimistic settlement — NO intent proof validation:

address public immutable fillOracle;  // Validated for consistency only
 
function fill(ShinobiIntent calldata intent) external payable nonReentrant {
    // 1. Validate has outputs
    if (intent.outputs.length == 0) revert InvalidOutput();
 
    // 2. Validate correct destination chain
    if (intent.outputs[0].chainId != block.chainid) revert InvalidChain();
 
    // 3. Validate fill deadline
    if (block.timestamp > intent.fillDeadline) revert FillDeadlinePassed();
 
    // 4. Validate fillOracle for consistency
    if (intent.fillOracle != fillOracle) revert FillOracleMismatch();
 
    // 5. Compute unique order identifier
    bytes32 orderId = intent.orderIdentifier();
 
    // NO intentOracle validation - ZK proof already validated on origin
 
    // 6. Fill each output with simple ETH transfer
    for (uint256 i = 0; i < intent.outputs.length; i++) {
        _fillOutput(orderId, intent.outputs[i], msg.sender);
    }
}

Why intentOracle is NOT required: The ZK proof on the origin chain already validated:

  • User owns a valid deposit (nullifier)
  • User knows the secret (commitment membership)
  • Withdrawal parameters are bound to the proof (context)

The intent was created by the trusted ShinobiCashEntrypoint after proof validation.

Oracle System

Two oracles ensure secure cross-chain settlement:

OracleDirectionPurposeRequired For
fillOracleDest → OriginProves the fill happenedAll intents (claim)
intentOracleOrigin → DestProves intent is legitimateDeposits only

Security Comparison

FeatureDepositsWithdrawals
Intent validationRequired (intentOracle)Not required
WhyDepositor address could be spoofedZK proof validates user
Fill validationfillOraclefillOracle
Refund mechanismStandard ETH refundRefund commitment in pool

Source Code

Related