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,
FullSettlerswaps it atomically before locking. - Fill. A solver watching for
Openevents 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
opentransaction and deposits funds intoFullSettler. No operator can move user funds on their behalf. - Solver (off-chain operator, on-chain executor): Watches for
Openevents 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_ROLEto callrefundon 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 viamsg.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_ROLEaccess control onrefund: 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
sendFundsToSettlementChainfor 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). TheorderIdfrom 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
- User calls
open. Submits anOnchainCrossChainOrderto the originFullSettler. TheinputOrderData.userfield must equalmsg.senderor the call reverts (FullSettler__InvalidOrderUser). - Funds enter escrow. USDC is locked in the contract. If the input is a different ERC-20 or the
NATIVE_TOKENsentinel, the DEX Swapper converts it first. From this point, Tensora cannot access, redirect, or freeze the escrowed funds. Openevent is emitted. Carries theorderId, the canonical identifier used for status queries, fill events, dispute proofs, and refunds. Order status is set toDeposited.
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
- Solver observes and decides. Evaluates whether to fill given the protocol fee, destination gas price, and expected execution costs.
- Solver fills on the destination chain. Calls the destination
FullSettler, which pulls USDC from the solver, optionally swaps to the requestedoutputToken, and transfers the result to therecipient. - 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
- Settlement data is posted. A Merkle root of recent fills is submitted to the Settlement Contract on Base, typically every ~2 hours in V1.
- 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.
- 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
FullSettlerbridges 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.
fillDeadlineis a unix timestamp in theOnchainCrossChainOrderenvelope. Until it passes, only the settlement path can transition the order toClaimed.- 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. refundtransfers the original input amount plus the previously deducted protocol fee back to the user. The order moves toRefunded.
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.
fillDeadlinepasses without a fill andrefundis 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.openfrom your contracts or frontend: struct layout, input paths, and the full error catalogue. -
Service API Reference
REST endpoints for quotes, mirrored order status, optional notify-after-broadcast, and refund verification.
-
ERC-7683 spec
The cross-chain intents standard that
FullSettlerimplements: order envelopes, theOpenevent, and theresolveview.