On-Chain Settlement
The Web3 rail is built from five contracts, two release paths, and a nine-state lifecycle. The kernel writes signed dispatch artifacts; the chain locks funds against the receipt root; a release transaction either takes the fast path (both parties sign) or the trustless fallback (provider proves inclusion of the receipt against a published checkpoint root).
Use this page when
Where this fits
economy view of on-chain settlement. The chain-by-chain integration reference (which networks, which assets, gas profiles) lives in Integrations / Settlement. The chio-side rail abstraction lives in Settlement Rails.The Five Contracts
Every chio Web3 deployment ships the same five interfaces, addressed as Web3ContractKind in chio-web3. Concrete addresses live in the per-chain Web3ChainDeployment, but the ABI and the role of each contract are stable.
| Contract | Role |
|---|---|
ChioRootRegistry | Anchors checkpoint roots published by the kernel. Every merkle release verifies a leaf against a root that has already been registered here. |
ChioEscrow | Locks funds against a capability commitment. Holds the dispatch reference, the agreed amount, and the lifecycle state. Settles via dual signature or merkle proof. |
ChioBondVault | Holds bonds (operator collateral, agent collateral) that back high-trust capabilities. Bonds can be released, expired, or impaired against a slashing event. |
ChioIdentityRegistry | Binds chio public keys to on-chain settlement addresses. The contract checks that the binding the operator presents has the correct purpose (“settle”, “publish”) and chain scope. |
ChioPriceResolver | Returns FX prices from the configured oracle when a receipt is denominated in a non-native asset. Used by escrow on release to compute the settlement amount in the chain's settlement token. |
Bindings ship as Rust types in chio-web3-bindings, with Solidity ABIs versioned alongside the kernel. chio-settle/src/evm.rs drives these contracts and projects on-chain state back into the canonical receipt family.
Two Settlement Paths
Once an escrow is locked, releasing it is a choice between two paths. The kernel encodes the choice in Web3SettlementPath:
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Web3SettlementPath {
DualSignature,
MerkleProof,
}DualSignature (Fast Path)
Both parties sign the release. The provider signs an EIP-712 digest binding the receipt hash, the observed amount, and the escrow id; the contract recovers the signature and credits the beneficiary. Latency is a single block confirmation; gas matches a normal token transfer plus a digest verification.
Use when the buyer remains online and cooperative. This is the common path: agent calls tool, tool returns, buyer counter-signs the release, funds settle, total wall-clock is one block.
MerkleProof (Trustless Fallback)
The provider produces an inclusion proof: this receipt is a leaf in a published merkle tree, the root of which has been registered in ChioRootRegistry. The escrow contract verifies the proof against the root and releases without ever needing the buyer's signature.
Use when the buyer has gone offline, is uncooperative, or simply cannot sign within the dispute window. The trade is a heavier transaction (one merkle verification plus a root lookup) and a longer wall-clock (the receipt has to be in a checkpoint that has already been published, which is bounded by the operator's checkpoint cadence).
The roots themselves are anchored by the chio-anchor crate, which publishes signed checkpoint statements containing checkpoint_seq, batch_start_seq, batch_end_seq, tree_size, and the merkle root. A merkle release proof is verifiable end to end without trusting the operator: the chain already knows the root, and the leaf hash is recoverable from the receipt alone.
Path is per-dispatch, not per-deployment
Escrow Lifecycle States
The kernel's view of an escrow's state is Web3SettlementLifecycleState in chio-web3. Nine variants:
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Web3SettlementLifecycleState {
PendingDispatch,
EscrowLocked,
PartiallySettled,
Settled,
Reversed,
ChargedBack,
TimedOut,
Failed,
Reorged,
}| State | Meaning |
|---|---|
pending_dispatch | Dispatch artifact signed; on-chain tx not yet observed. |
escrow_locked | Funds locked in ChioEscrow; awaiting release. |
partially_settled | A partial release has paid out; remainder still locked. |
settled | Release executed; funds delivered to beneficiary; finality confirmed. |
reversed | Refund executed before release; funds returned to depositor. |
charged_back | Post-settlement reversal; an off-chain dispute clawback has been recorded. |
timed_out | Dispute window expired without release; refund recovery is the next action. |
failed | On-chain submission reverted; the dispatch needs to be retried or escalated. |
reorged | A previously confirmed settlement has been undone by a chain reorg; resubmission required. |
Lifecycle Diagram
EVM Support
EVM coverage lives in chio-settle/src/evm.rs. Dispatch and release calls are constructed as PreparedEvmCall values (from_address, to_address, data, optional gas limit) ready for an external signer to sign and broadcast.
The supported entry points cover the full lifecycle:
prepare_web3_escrow_dispatch: build aPreparedEscrowCreatefrom a signed capital-execution instruction.prepare_dual_sign_release: build aPreparedDualSignReleasewith the EIP-712 digest pre-signed by the operator key.prepare_merkle_release: build aPreparedMerkleReleasecarrying the receipt leaf hash, the root, and the proof path.prepare_escrow_refund: build the refund call once the dispute window expires.prepare_bond_lock/prepare_bond_release/prepare_bond_impair: drive theChioBondVaultover its lifecycle.prepare_erc20_approval: emit the ERC-20approve()call needed before the escrow can pull tokens.
Everything that mutates state is shaped to be signed by an external wallet or signer service; the chio kernel never holds private keys for dispatching transactions. The exception is the operator's signing key for dual-signature digests, which is presented as a hex-encoded private key only at the call site that produces the digest.
Production EVM coverage today: Base, Ethereum mainnet, Arbitrum, and Optimism. The integration page lists per-chain details. Finality is captured as Web3FinalityMode (OptimisticL2, L1Finalized, SolanaConfirmed) per deployment, with a minimum-confirmation count attached.
Solana Support
Solana support is bounded and intentional: the kernel uses the Ed25519 program (program id Ed25519SigVerify111111111111111111111111111) to verify a chio receipt signature on-chain, paired with a USDC transfer in the same transaction. Code lives in chio-settle/src/solana.rs.
The Solana dispatch model is narrower than EVM: there is no escrow contract holding funds during execution. Instead the settlement is atomic in a single transaction that contains both the Ed25519 signature verification and the SPL token transfer. The receipt and binding signed by the operator are the basis for proof; the chain verifies the signature and moves funds in the same atomic unit.
pub struct PreparedSolanaSettlement {
pub dispatch_id: String,
pub chain_id: String,
pub cluster: String,
pub program_id: String,
pub payer_address: String,
pub beneficiary_address: String,
pub settlement_mint: String,
pub capability_commitment: String,
pub receipt_hash: String,
pub settlement_amount_minor_units: u64,
pub recent_blockhash: String,
pub ed25519_program_id: String,
pub ed25519_signature: String,
pub chio_public_key: String,
pub instruction_data_hex: String,
pub note: Option<String>,
}The kernel-side helper verify_solana_binding_and_receipt confirms the binding has the settle purpose, the chain scope covers the target chain, and the settlement address decodes as a valid base58 Solana address before allowing the dispatch to be prepared.
Cross-Chain via Chainlink CCIP
For settlements that span chains (settle on Base, but the depositor funded escrow from Arbitrum, say) the kernel ships a CCIP message envelope in chio-settle/src/ccip.rs. It is not a bridge; it is a typed coordination layer over Chainlink's Cross-Chain Interoperability Protocol that lets a settlement event on one chain be reconciled with state on another.
pub struct CcipLaneConfig {
pub source_chain_id: String,
pub destination_chain_id: String,
pub router_address: String,
pub max_payload_bytes: usize,
pub max_execution_gas: u64,
pub expected_latency_secs: u64,
}
pub enum CcipMessageStatus {
Prepared,
Reconciled,
DuplicateSuppressed,
Delayed,
Unsupported,
}prepare_ccip_settlement_message validates the lane (source != destination, payload bounds non-zero, validity window at least twice the expected latency), then assembles a payload containing the dispatch id, execution receipt id, settlement reference, lifecycle state, settled amount, and beneficiary address. reconcile_ccip_delivery cross-checks the SHA-256 digest of the delivered payload against the digest the kernel originally signed.
Use CCIP when:
- The escrow chain and the bond vault chain are different (operator on Ethereum, escrow on Base).
- A multi-chain operator wants a single canonical settlement event delivered to several treasury locations.
- The integration partner already speaks CCIP and won't accept a bespoke bridge.
For typical single-chain flows, plain EVM dispatch on the same chain is simpler and cheaper. The full Chainlink integration view lives at Integrations / Chainlink.
Worked Example
An agent calls a tool that costs 1.50 USDC. The capability is bound to the Web3 rail on Base with aDualSignature path.
Happy Path: DualSignature
- Kernel signs a capital-execution instruction for 1.50 USDC.
prepare_web3_escrow_dispatchbuilds aPreparedEscrowCreate. - Operator's signer broadcasts the dispatch tx. The escrow contract locks 1.50 USDC. State:
EscrowLocked. - Tool runs. Observed cost matches the quoted 1.50 USDC.
- Operator presents
prepare_dual_sign_releaseto the buyer. Buyer counter-signs the EIP-712 digest. - Combined signatures broadcast to the contract; release executes; funds credited to beneficiary. State:
Settledafter the configured confirmation count is reached.
Total wall-clock from tool completion to settled status: a single block confirmation on Base, typically two seconds.
Fallback: MerkleProof
Same scenario, but the buyer goes offline before counter-signing.
- State remains
EscrowLockeduntil the dispute window opens for an alternate release. - The kernel publishes a checkpoint covering the receipt; the merkle root is registered in
ChioRootRegistryby the anchor pipeline. - Operator calls
prepare_merkle_releasewith the receipt leaf hash, the registered root, and the proof path computed against the checkpoint tree. - Contract verifies the proof against the registered root, confirms inclusion, and releases funds. State:
Settled. - If the dispute window expires without either path succeeding, the watchdog flips the state to
TimedOutand the next recovery action isExecuteRefund(the depositor gets their funds back).
Fallback latency is bounded by checkpoint cadence
Checkpoint Anchoring
Merkle release proofs are only as trustless as the root they verify against. Roots come from chio-anchor: the kernel publishes batched checkpoints as Web3CheckpointStatement artifacts containing batch bounds, tree size, root, kernel public key, and signature. The anchor publishes those statements to theChioRootRegistry on each target chain so that any verifier (regulator, auditor, dispute resolver) can independently verify the inclusion proof.
The receipt-side proof artifact is Web3ReceiptInclusion with checkpoint_seq, merkle_root, and the proof path. verify_anchor_inclusion_proof in chio-core::web3 is the authoritative verifier.
Finality and Recovery
Finality is observed via SettlementFinalityAssessment in chio-settle/src/observe.rs. Each chain configures a required confirmation count and a dispute window in seconds. Status is one of:
awaiting_confirmations: tx mined but not yet at the required depth.awaiting_dispute_window: confirmed, but the optimistic challenge window is open.finalized: confirmation count and dispute window both satisfied.reorged: a previously confirmed tx is no longer in the canonical chain.
Recovery actions (SettlementRecoveryAction) map onto the lifecycle state: Failed suggests RetrySubmission; TimedOut suggests ExecuteRefund; Reorged suggests ResubmitAfterReorg. The watchdog (next page) drives this automation.
See Also
- Settlement Rails for the full rail enum and the off-chain alternatives.
- Reconciliation & Watchdog for the cycle that closes out partially-settled and timed-out escrows.
- Receipts for the receipt fields that participate in merkle inclusion.
- Chainlink for the CCIP integration in depth.
- Integrations / Settlement for chain-by-chain configuration and finality details.