Skip to content

Architecture

An intent is a declarative request of the form "I have token X on chain A, and I want token Y on chain B by deadline T." TAO Intents replaces the conventional lock-and-mint bridge model with a solver network: solvers compete to front the requested output immediately, and are reimbursed later through an on-chain optimistic settlement process. The user's deposit is held by a smart contract throughout; no operator takes custody.

This page covers the V1 architecture: a single bridge currency (USDC), a single settlement chain (Base), and a single solver operated by Tensora. All contracts are ERC-7683 compliant.


Overview

A bridge transaction proceeds in three logical phases:

  • Open. The user signs a transaction on the origin chain that escrows their input funds. If the input is not USDC, FullSettler swaps it atomically before locking.
  • Fill. A solver watching for Open events pays the requested output token to the user on the destination chain using its own capital.
  • Settle. Filled intents are batched into a Merkle root (so on-chain verification is amortized across many fills) and posted to the Settlement Contract on Base. After the challenge window passes without a successful dispute, the solver claims repayment.
%%{init: {'theme':'base','themeCSS':'[id$=-sequencenumber]{fill:#8c80e5 !important;stroke:#8c80e5 !important;}.sequenceNumber{fill:#ffffff !important;font-weight:600;font-size:13px;}','themeVariables':{'primaryColor':'#1a1a1a','primaryTextColor':'#f5f5f5','primaryBorderColor':'#8c80e5','lineColor':'#8a8a8a','secondaryColor':'#8c80e5','tertiaryColor':'#0a0a0a','noteBkgColor':'#1f1d2e','noteTextColor':'#f5f5f5','noteBorderColor':'#8c80e5','actorBkg':'#1a1a1a','actorBorder':'#8c80e5','actorTextColor':'#f5f5f5','actorLineColor':'#8a8a8a','signalColor':'#c7c7c7','signalTextColor':'#f5f5f5','sequenceNumberColor':'#ffffff'}}}%%
sequenceDiagram
    autonumber
    participant User
    participant Origin as FullSettler<br/>(origin)
    participant Solver
    participant Dest as FullSettler<br/>(destination)
    participant Hub as Settlement<br/>(Base)

    Note over User,Hub: Phase 1 Open
    User->>Origin: open(order)
    Note right of Origin: escrows USDC
    Origin-->>Solver: Open(orderId) event

    Note over User,Hub: Phase 2 Fill
    Solver->>Dest: fill(order)
    Dest-->>User: outputToken delivered

    Note over User,Hub: Phase 3 Settle
    Solver->>Hub: submit Merkle root
    Note right of Hub: challenge window
    Hub-->>Solver: claim repayment

The user only signs the open transaction. Everything after that (fill, settlement, repayment, rebalancing) happens without further user involvement.


System actors

Four actors participate in the system. Two act on-chain (deterministic contract calls); two are off-chain services constrained by what the contracts will accept.

  • User (on-chain): Signs the origin-chain open transaction and deposits funds into FullSettler. No operator can move user funds on their behalf.
  • Solver (off-chain operator, on-chain executor): Watches for Open events and fronts capital to fill intents on the destination chain. Carries timing and price risk between fill and reimbursement. In V1, Tensora operates the only solver.
  • Disputer (on-chain): Posts a bond to challenge a fill claim during the settlement window. A correct challenge voids the solver's claim and triggers a user refund; an unfounded challenge forfeits the bond. The role is open to anyone.
  • Service operator (off-chain): Performs bounded V1 settlement and refund duties allowed by the contracts: (1) batches recent fills into Merkle roots and submits them to the Settlement Contract on Base, (2) supplies dispute verification during the challenge window, and (3) holds or controls REFUNDER_ROLE to call refund on expired orders. In V1, these duties are performed by Tensora-operated services.

Bounded off-chain roles

The service operator can call refund only for expired orders through REFUNDER_ROLE; it cannot force-skip a challenge window, redirect refunds to a different address, change refund amounts, or fill an order whose deadline has passed. The solver cannot pull more funds from escrow than the order specifies.

Service API T&C gate

The Service API records per-wallet, versioned Terms & Conditions acceptance with a SIWE flow. This gates the optional POST /intents/v1/intents notification endpoint for record-keeping/compliance only. It is separate from TAO Public API bearer authentication, is not an on-chain requirement, and does not grant solver or refunder permissions.


Smart contracts

All contracts were built and audited by Tensora (auditors: OpenZeppelin and Pashov).

Origin Settler — FullSettler

Deployed on every supported origin chain. The user interacts with this contract to open an intent.

  • Pulls the user's input token via transferFrom (or accepts native value via msg.value).
  • Optionally swaps the input to USDC via the configured Uniswap V3 router.
  • Escrows the resulting USDC and emits Open(bytes32 orderId, ResolvedCrossChainOrder).
  • Enforces REFUNDER_ROLE access control on refund: only an account granted this role can return funds for expired orders. In V1 the role is granted to a Tensora-operated refunder service.
  • Exposes sendFundsToSettlementChain for V1 contract-authorized transfers of accumulated USDC to the Base Hub (see Sending funds to the settlement chain below).

FullSettler is ERC-7683 compliant:

Function Status
open(OnchainCrossChainOrder) Supported. Entry point used by integrators and the frontend.
openFor(GaslessCrossChainOrder, signature, fillerData) Not supported. Reverts with FullSettler__NotSupported. Gasless flows are out of scope for V1.
resolve(OnchainCrossChainOrder) Supported (view). Returns the resolved order envelope for pre-flight simulation.

Destination Settler — FullSettler

Deployed on every supported destination chain. Solvers call this to deliver output tokens to the user.

  • Validates the fill against the order envelope supplied by the solver.
  • Pulls output token (USDC) from the solver and transfers it to the recipient encoded in the intent.
  • Optionally routes USDC through the DEX Swapper if the user requested a non-USDC output token.
  • Emits IntentFilled(address solver, OrderData order). The orderId from this event is aggregated into settlement Merkle roots.

Settlement Contract on Base (the Hub)

Single source of truth for optimistic verification. Deployed on Base.

  • Accepts Merkle roots submitted by the V1 settlement operator, each representing a batch of solver-claimed fills.
  • Opens a challenge window after each root is posted.
  • Verifies disputes using verification data/proofs supplied by the V1 settlement operator.
  • Holds the solver's liquidity pool and releases repayment once a fill's challenge window closes cleanly.

What the service operator cannot do

The service operator can submit settlement data, but the contract enforces timing and distribution. The service operator cannot shorten the challenge window, redirect repayment, or release funds before verification completes.

DEX Swapper

Helper contract used by both settlers when the input or requested output is not USDC. It wraps a Uniswap V3 router call:

  • Origin-side: converts the user's ERC-20 (or wrapped native token) to USDC before escrow.
  • Destination-side: converts USDC to the user's requested output token before delivery.

Only tokens with adequate Uniswap V3 liquidity on the relevant chain are supported.


End-to-end fund flow

The bridge proceeds in three phases. The user is involved only in Phase 1; Phases 2 and 3 run without further user action.

Phase 1: Open and escrow

%%{init: {'theme':'base','themeCSS':'[id$=-sequencenumber]{fill:#8c80e5 !important;stroke:#8c80e5 !important;}.sequenceNumber{fill:#ffffff !important;font-weight:600;font-size:13px;}','themeVariables':{'primaryColor':'#1a1a1a','primaryTextColor':'#f5f5f5','primaryBorderColor':'#8c80e5','lineColor':'#8a8a8a','secondaryColor':'#8c80e5','tertiaryColor':'#0a0a0a','noteBkgColor':'#1f1d2e','noteTextColor':'#f5f5f5','noteBorderColor':'#8c80e5','actorBkg':'#1a1a1a','actorBorder':'#8c80e5','actorTextColor':'#f5f5f5','actorLineColor':'#8a8a8a','signalColor':'#c7c7c7','signalTextColor':'#f5f5f5','sequenceNumberColor':'#ffffff'}}}%%
sequenceDiagram
    autonumber
    participant User
    participant Origin as FullSettler<br/>(origin)
    participant Solver

    User->>Origin: open(order)
    Note right of Origin: swap inputToken to USDC if needed
    Note right of Origin: escrow USDC
    Note right of Origin: revert if user is not msg sender
    Origin-->>Solver: Open(orderId) event
    Note over Origin: orderStatus set to Deposited
  1. User calls open. Submits an OnchainCrossChainOrder to the origin FullSettler. The inputOrderData.user field must equal msg.sender or the call reverts (FullSettler__InvalidOrderUser).
  2. Funds enter escrow. USDC is locked in the contract. If the input is a different ERC-20 or the NATIVE_TOKEN sentinel, the DEX Swapper converts it first. From this point, Tensora cannot access, redirect, or freeze the escrowed funds.
  3. Open event is emitted. Carries the orderId, the canonical identifier used for status queries, fill events, dispute proofs, and refunds. Order status is set to Deposited.

Phase 2: Fill

%%{init: {'theme':'base','themeCSS':'[id$=-sequencenumber]{fill:#8c80e5 !important;stroke:#8c80e5 !important;}.sequenceNumber{fill:#ffffff !important;font-weight:600;font-size:13px;}','themeVariables':{'primaryColor':'#1a1a1a','primaryTextColor':'#f5f5f5','primaryBorderColor':'#8c80e5','lineColor':'#8a8a8a','secondaryColor':'#8c80e5','tertiaryColor':'#0a0a0a','noteBkgColor':'#1f1d2e','noteTextColor':'#f5f5f5','noteBorderColor':'#8c80e5','actorBkg':'#1a1a1a','actorBorder':'#8c80e5','actorTextColor':'#f5f5f5','actorLineColor':'#8a8a8a','signalColor':'#c7c7c7','signalTextColor':'#f5f5f5','sequenceNumberColor':'#ffffff'}}}%%
sequenceDiagram
    autonumber
    participant Solver
    participant Dest as FullSettler<br/>(destination)
    participant User
    participant Operator as Service Operator

    Note right of Solver: evaluate profitability
    Solver->>Dest: fill(order)
    Note right of Dest: validate order envelope
    Note right of Dest: pull USDC from solver
    Note right of Dest: swap to outputToken if needed
    Dest->>User: outputToken delivered to recipient
    Dest-->>Operator: IntentFilled event
  1. Solver observes and decides. Evaluates whether to fill given the protocol fee, destination gas price, and expected execution costs.
  2. Solver fills on the destination chain. Calls the destination FullSettler, which pulls USDC from the solver, optionally swaps to the requested outputToken, and transfers the result to the recipient.
  3. User receives outputToken. The bridge is complete from the user's perspective.

Phase 3: Settle and repay

%%{init: {'theme':'base','themeCSS':'[id$=-sequencenumber]{fill:#8c80e5 !important;stroke:#8c80e5 !important;}.sequenceNumber{fill:#ffffff !important;font-weight:600;font-size:13px;}','themeVariables':{'primaryColor':'#1a1a1a','primaryTextColor':'#f5f5f5','primaryBorderColor':'#8c80e5','lineColor':'#8a8a8a','secondaryColor':'#8c80e5','tertiaryColor':'#0a0a0a','noteBkgColor':'#1f1d2e','noteTextColor':'#f5f5f5','noteBorderColor':'#8c80e5','actorBkg':'#1a1a1a','actorBorder':'#8c80e5','actorTextColor':'#f5f5f5','actorLineColor':'#8a8a8a','signalColor':'#c7c7c7','signalTextColor':'#f5f5f5','sequenceNumberColor':'#ffffff'}}}%%
sequenceDiagram
    autonumber
    participant Operator as Service Operator
    participant Hub as Settlement<br/>(Base)
    participant Solver
    participant Origin as FullSettler<br/>(origin)

    Operator->>Hub: submitMerkleRoot(root)
    Note over Hub: contains a batch of recent fills
    Note over Hub: challenge window opens (~2 hours)
    Note over Hub: anyone may bond and dispute
    Solver->>Hub: claim(merkleProof)
    Note over Hub: solver withdraws USDC repayment
  1. Settlement data is posted. A Merkle root of recent fills is submitted to the Settlement Contract on Base, typically every ~2 hours in V1.
  2. Challenge window opens. Any party can bond and challenge a fill. A successful challenge voids the solver's claim and refunds the user; an unfounded challenge forfeits the disputer's bond.
  3. Solver claims repayment. Presents a Merkle inclusion proof after the window closes cleanly.

Origin status in V1

In V1, the origin FullSettler does not receive a cross-chain confirmation when a solver claims repayment on Base. The origin-side orderStatus therefore reflects the deposit, not the eventual claim.

Steps 7-9 are invisible to the user

The user's funds arrive at step 6. The settlement process reimburses the solver from escrowed funds and does not affect the user's received output.


Optimistic settlement

The settlement layer is optimistic: fills are assumed honest and rejected only if challenged within the window. This amortizes gas by batching many fills into a single Merkle root instead of verifying each on-chain individually.

  • Root submission. The V1 settlement operator builds a Merkle tree of recent fills and posts its root to the Settlement Contract approximately every ~2 hours. The root supports proofs of non-membership, so affected users can prove a fill did not happen and reclaim funds.
  • Challenge window. A ~2-hour window opens per root. Anyone may post a bond and challenge a leaf. If a challenge succeeds, the solver's claim for that leaf is voided and the user is refunded. If it fails, the disputer forfeits its bond.
  • Finalization. Once the window closes, every uncontested leaf is treated as valid.
  • Solver repayment. The solver presents a Merkle inclusion proof and withdraws USDC from the settlement pool on Base.

Batching many fills into one Merkle root means a single on-chain verification can cover a batch instead of one fill at a time, which keeps protocol fees low.

In V1, Tensora submits roots and supplies dispute verification, a trusted but bounded role. The contract enforces the window, payment distribution, and non-membership proofs. V1 settlement is operationally centralized but financially constrained.


Sending funds to the settlement chain (V1)

Users deposit on origin chains (see the Service API for the current list of supported origins), but the solver is repaid on Base. Accumulated USDC in origin FullSettler contracts must be moved to the Base Hub to keep the Settlement Contract solvent.

This is a contract-mediated transfer, distinct from any solver-side liquidity management (solvers may end up with all repayments on Base and rebalance their own working capital across chains using their own tooling; that is outside the protocol).

  • In V1, Tensora periodically triggers contract-authorized transfers of accumulated USDC from origin settlers to the Base Hub.
  • Only a protocol-authorized role can trigger this transfer. The role controls the trigger, not the funds.
  • The origin FullSettler bridges USDC to the Settlement Contract on Base via LayerZero/Stargate. No EOA or operator wallet holds funds in transit.

Why this step exists only in V1

This contract-to-contract bridge is a consequence of V1's single-settlement-chain design.


Order lifecycle

The origin FullSettler tracks each order through four mutually exclusive statuses, queryable via FullSettler.orderStatus(orderId):

Status Set by Meaning
None (default) The orderId has never been opened. Sentinel for unknown orders.
Deposited open Funds escrowed. Awaiting a fill or expiry.
Claimed Hub settlement (V1: Hub only, not propagated to origin) Fill validated; solver reimbursed. Terminal.
Refunded refund Deadline passed without a fill; user refunded input plus protocol fee. Terminal.

On the origin contract in V1, the lifecycle is None → Deposited, then either remains Deposited (after a successful Base-side claim) or transitions to Deposited → Refunded (if the order expires unfilled). The Claimed state is reached only on the Hub's bookkeeping in V1.

The Open event fires on entry to Deposited. The destination IntentFilled event fires when the solver delivers output. The origin status does not change from IntentFilled directly. The solver's repayment is recorded in the Hub via the Settle and claim flow.


Refunds

If an order is not filled by fillDeadline, the user's escrowed funds are returned.

  • fillDeadline is a unix timestamp in the OnchainCrossChainOrder envelope. Until it passes, only the settlement path can transition the order to Claimed.
  • After expiry, a protocol-authorized refund role on the origin settler calls refund(orderId). In V1, a Tensora-operated service holds or controls this authorized refund role.
  • refund transfers the original input amount plus the previously deducted protocol fee back to the user. The order moves to Refunded.

The refund logic is on-chain. The V1 refund service chooses when to call refund after expiry, but cannot redirect funds to a different address, change the refund amount, withhold the protocol-fee portion, or refuse a refund on an unfilled, expired order once a valid refund transaction is submitted.

If refunds are delayed

If the assigned refund role does not call refund, expired orders remain in Deposited until REFUNDER_ROLE is reassigned to a new operator.


Trust model

Two questions frame the V1 trust model.

Who can move user funds? No operator can. After deposit, funds leave FullSettler only through two contract-enforced paths:

  • The settlement process confirms a valid fill via a verified Merkle proof and releases repayment to the solver from the Base pool.
  • fillDeadline passes without a fill and refund is invoked, returning the input amount plus protocol fee to the original depositor.

The solver uses its own capital to fill intents. There is no point at which Tensora or any operator has discretionary control over user-deposited funds.

Who can delay a user from getting their money back? Tensora operates the V1 solver, and the solver can choose not to fill a particular intent. That can delay completion, but it cannot cause user fund loss: an unfilled intent expires at fillDeadline, after which refund is the only valid contract path. The delay is bounded by the deadline.

Tensora's V1 roles are coordination duties, not custodial ones:

  • Solver: Tensora-operated in V1; fills intents with its own capital. If it does not fill, user exposure is delay bounded by fillDeadline, not loss of escrowed funds.
  • Settlement service: submits Merkle roots and verifies disputes. Bounded by contract-enforced windows and payout rules.
  • Operational process: triggers settlement-chain funding and refunds through protocol-authorized roles. In V1, Tensora-operated services perform these duties. They are bounded by what those roles permit; they cannot redirect funds or change refund amounts.

Bounded trust

The settlement contract enforces challenge windows; refund deterministically returns user input plus protocol fee to the original depositor; settlement-chain funding moves funds only between authorized contracts.


Next steps

  • Contract Integration


    Call FullSettler.open from your contracts or frontend: struct layout, input paths, and the full error catalogue.

    Integrate

  • Service API Reference


    REST endpoints for quotes, mirrored order status, optional notify-after-broadcast, and refund verification.

    Explore the API

  • ERC-7683 spec


    The cross-chain intents standard that FullSettler implements: order envelopes, the Open event, and the resolve view.

    Read the spec