Settlement
Pin one EVM settlement chain, choose how escrows release, and reconcile each on-chain execution against the receipts that authorized it.
On this page
The chio-settle module pays for admitted calls on a pinned EVM chain. It turns the kernel's signed capital execution instruction into an escrow dispatch, watches it to finality, and records what the chain did as a signed execution receipt, while the signed Chio receipt stays the authority.
Settlement rails are optional modules, off in default builds. The grant's holds and caps prevent spend before dispatch; on-chain outcomes are observed and recorded. The Settlement guide wires payment adapters, escrow, and reconciliation into one deployment.
StartThe kernel authorizes; the settle module submits and observes
The kernel never talks to a chain. It admits the call under the grant and signs the instruction; chio-settle composes the transaction, a wallet signs and submits it, and the observed result folds back into signed records.
Rail outcomes are observed and recorded
The rail reports RailSettlementStatus, which folds into the receipt’s SettlementStatus: NotApplicable, Pending, Settled, or Failed. The kernel records the outcome and the payment_reference on the signed receipt; it does not decide what the rail did. What each receipt records.
PaymentAdapter lifecycle. Holds and caps prevent spend before dispatch; what the rail does is observed and recorded. The modules are off in default builds; custody and the facilitator service are left out.Settlement railsEvery settlement starts as a chio.web3-settlement-dispatch.v2 artifact, composed from the signed capital execution instruction, the pinned chain configuration, and a signed identity binding. The module derives the escrow id from the contract itself and validates the dispatch before anything is submitted. At finality it produces a chio.web3-settlement-execution-receipt.v2.
Both artifacts travel inside a SignedExportEnvelope whose signature covers the canonical JSON of the body, so any client that canonicalizes the same way verifies the same bytes. The escrow terms hash the capability id, so an on-chain escrow is reachable from the capability that authorized it. Chain data corroborates a claim only when the signed Chio verifier report also accepts it; it never overrides a signed receipt.
1. Pin one settlement chain
An operator pins exactly one chain configuration: the contract addresses, the operator address, the settlement token, and a tiered confirmation and dispute policy. The escrow and bond contracts are EVM-generic, so any EVM chain where they are deployed can be the pinned target. Base is the reference deployment.
| Chain | Assets | Finality modes | Support |
|---|---|---|---|
| Base (EVM, L2) | USDC, ETH | OptimisticL2, L1Finalized | Reference deployment |
| Other EVM chains | Per pinned configuration | OptimisticL2, L1Finalized | One active configuration |
| Solana | Ed25519 receipts | SolanaConfirmed | Local verification and instruction preparation |
On Solana, the module verifies Chio Ed25519 receipts and key bindings locally and emits a canonical chio.settle.solana-release.v1 payload for commitment-parity checks; an external submitter broadcasts it. The escrow and bond path is EVM only.
2. Pin the escrow and bond contracts
Pin each deployed address in the chain configuration and check it against the trusted contract profile. The Alloy-generated Rust bindings ship in chio-web3-bindings.
IChioEscrow. Opens a fixed-amount, time-bounded escrow that a signature release or a Merkle-proof release unlocks. The escrow id derives from its terms, and opening one that already exists reverts withEscrowAlreadyExists, so a settled escrow is never reopened. A full release pays the remaining amount; partial releases on the proof path accumulate inreleasedand emitEscrowPartialReleaseuntil the deposit is drawn down.IChioBondVault. Holds the operator bonds that back dispute outcomes. On a slash verdict the bond goes to the disputing party minus a protocol fee; on a timeout refund it returns to the operator.
3. Choose how an escrow releases
The deployment selects one release path by policy, and both produce settlement receipts. Each path carries different evidence to the same contract.
An operator signature authorizes the release
The beneficiary submits a release with the operator’s signature over the bound release message. ChioEscrow checks the signer, the beneficiary, the receipt, and an amount capped at the deposit before it transfers tokens. Release a funded EVM escrow.
Under a signature release, the operator's settlement key signs the release digest and the beneficiary submits it: two signatures per escrow, suited to low-volume, high-value transfers. Under a Merkle-proof release, the beneficiary presents a proof that the receipt sits under a checkpoint root already anchored in ChioRootRegistry. One anchor transaction is amortized across every receipt in the batch, which suits high-volume settlement; trust rests on that root and the inclusion check.
4. Set finality and dispute policy for the value at risk
A low-value call and a disputed bond release can need different confirmation and dispute windows. The chain-level mode comes from Web3FinalityMode in chio-web3:
OptimisticL2. Inclusion on the L2 sequencer; track the configured confirmations and any reorg observations.L1Finalized. Inclusion in an L1-finalized block; wait for the accepted L1-finality evidence.SolanaConfirmed. Confirmation by a supermajority of stake; local preparation produces no broadcast-finality result.
What settlement observation reports is chain-agnostic: inspect_finality returns a SettlementFinalityStatus of AwaitingConfirmations, AwaitingDisputeWindow, Finalized, or Reorged. A Reorged observation drives recovery through ResubmitAfterReorg and the rest of the SettlementRecoveryAction set.
The dispatch envelope also declares the dispute policy that applies if either party raises a claim before the release window closes. Off-chain arbitration lets a designated arbiter address sign a resolution either party can execute on chain: the lowest cost and the highest trust assumption. A timeout refund returns the escrow to the depositor when no counterparty signature arrives in time, with no arbiter. A bond slash lets the disputing party slash IChioBondVault when the operator breaches the agreement, less the protocol fee.
5. Reconcile against the kernel's receipts
The kernel receipts carry the cost metadata a reconciliation joins on. Read them over GET /v1/receipts/query with a bearer token that has receipt-read access, in whatever language your finance systems use; the receipt query cookbook covers installing the query SDK. The examples filter an illustrative capability id.
import { ReceiptQueryClient } from "@chio-protocol/sdk";
const receipts = new ReceiptQueryClient(
process.env.CHIO_CONTROL_URL!,
process.env.CHIO_AUTH_TOKEN!,
);
const page = await receipts.query({
capabilityId: "cap-expense-line-item-019",
costCurrency: "USDC",
limit: 10,
});
console.log(page.totalCount, page.receipts.length);import os
from chio import ReceiptQueryClient
receipts = ReceiptQueryClient(
os.environ["CHIO_CONTROL_URL"],
os.environ["CHIO_AUTH_TOKEN"],
)
page = receipts.query(
{
"capabilityId": "cap-expense-line-item-019",
"costCurrency": "USDC",
"limit": 10,
}
)
print(page["totalCount"], len(page["receipts"]))You should see the total count and the number of receipts in the first page. ReceiptQueryClient takes the same optional filters in both SDKs: capabilityId, toolServer, toolName, outcome, since, until, minCost, maxCost, costCurrency, agentSubject, cursor, and limit. The response carries totalCount, receipts, and a nextCursor when more remain.
For a full run, use paginate instead of query. It yields one page at a time and raises on a nextCursor that fails to advance, so it never replays a page forever. The TypeScript form is an async generator; the Python form is an iterator.
6. Read the execution receipt for the settled escrow
The query above returns kernel receipts. The settlement execution receipt is a separate artifact, Web3SettlementExecutionReceiptArtifact in chio-web3, and it embeds the whole dispatch it settles, so an auditor can reconstruct the transaction from the receipt alone.
pub struct Web3SettlementExecutionReceiptArtifact {
pub schema: String,
pub execution_receipt_id: String,
pub issued_at: u64,
pub dispatch: Web3SettlementDispatchArtifact,
pub observed_execution: crate::credit::CapitalExecutionObservation,
pub lifecycle_state: Web3SettlementLifecycleState,
pub settlement_reference: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reconciled_anchor_proof: Option<AnchorInclusionProof>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub identity_registry_evidence: Option<Web3SettlementIdentityRegistryEvidence>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub identity_registry_evidence_binding: Option<Web3SettlementIdentityRegistryEvidenceBinding>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub oracle_evidence: Option<OracleConversionEvidence>,
pub settled_amount: MonetaryAmount,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reversal_of: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub failure_reason: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
}Generate a settled one from the public-settlement proof fixture:
chio proof fixture generate public-settlement-offline-finality --out ./settlementRead its own fields, with the embedded dispatch held back:
$ jq '.settlement_receipt | {schema, execution_receipt_id, issued_at, lifecycle_state,
$ settlement_reference, settled_amount, observed_execution}' \
./settlement/settlement-proof-bundle.json{
"schema": "chio.web3-settlement-execution-receipt.v2",
"execution_receipt_id": "receipt-web3-1",
"issued_at": 1743292860,
"lifecycle_state": "settled",
"settlement_reference": "settlement-web3-1",
"settled_amount": {
"currency": "USD",
"units": 150
},
"observed_execution": {
"amount": {
"currency": "USD",
"units": 150
},
"externalReferenceId": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"observedAt": 1743292860
}
}You should see lifecycle_state set to settled and a settled_amount of 150 USD minor units that matches the observed execution. The chain, the escrow, the token, and the release path live on the embedded dispatch, listed in the reference below.
Settlement artifacts and anchoring
Search for lifecycle_state, execution_receipt_id, solana-release, or OpenTimestamps.
Execution receipt fields
The type carries #[serde(deny_unknown_fields)], so a key it does not declare is a parse error. Eight fields are required by spec/schemas/chio-web3/v2/settlement-execution-receipt.schema.json: schema, execution_receipt_id, issued_at, dispatch, observed_execution, lifecycle_state, settlement_reference, and settled_amount. The rest are optional and omitted when absent.
lifecycle_state takes one of nine values: pending_dispatch, escrow_locked, partially_settled, settled, reversed, charged_back, timed_out, failed, and reorged.
Embedded dispatch
The fixture receipt's dispatch, with capital_instruction (the signed authority chain) removed for length, then every key on the fixture receipt:
$ jq '.settlement_receipt.dispatch | del(.capital_instruction)' \
./settlement/settlement-proof-bundle.json{
"beneficiary_address": "0x2222222222222222222222222222222222222222",
"bond_vault_contract": "0x1000000000000000000000000000000000000003",
"chain_id": "eip155:8453",
"contract_package_id": "chio.official-web3-contracts",
"dispatch_id": "dispatch-web3-1",
"escrow_contract": "0x1000000000000000000000000000000000000002",
"escrow_id": "escrow-web3-1",
"issued_at": 1743292800,
"note": "Dispatches one governed escrow release over the official Base-first contract stack.",
"operator_key_hash": "0x0791868d8f29ea735f26a17a9aea038cd4255baac26eac5a74e58a07ed2f1975",
"schema": "chio.web3-settlement-dispatch.v2",
"settlement_amount": {
"currency": "USD",
"units": 150
},
"settlement_path": "merkle_proof",
"settlement_token_address": "0x735F1Ba389D9D350501dB8FBbB5b52477DcaddA8",
"support_boundary": {
"anchor_proof_required": true,
"custody_boundary_explicit": true,
"oracle_evidence_required_for_fx": true,
"real_dispatch_supported": true,
"reversal_supported": true
},
"trust_profile_id": "chio.official-web3-stack"
}$ jq '.settlement_receipt | keys' \
./settlement/settlement-proof-bundle.json[
"dispatch",
"execution_receipt_id",
"issued_at",
"lifecycle_state",
"note",
"observed_execution",
"oracle_evidence",
"reconciled_anchor_proof",
"schema",
"settled_amount",
"settlement_reference"
]Settlement and receipt identifiers
execution_receipt_id is a settlement identifier chosen by the settle runtime. A Chio receipt id is the 64-hex content address of the receipt body. The two never interchange.
Solana release payload
prepare_solana_settlement returns a PreparedSolanaSettlement instead of an execution receipt. It carries the program and mint addresses, the Ed25519 program id, the signature and Chio public key, and the hex-encoded chio.settle.solana-release.v1 instruction payload. The payload commits to the Chio receipt through receiptHash, the SHA-256 of the canonical receipt body, and commitment() derives a SettlementCommitment from it for parity checks. With no broadcast, there is no transaction hash, block number, or inclusion proof to record.
Checkpoint anchoring
Chio publishes a super-root of its receipt Merkle tree to Bitcoin through OpenTimestamps and mirrors the same root to the EVM ChioRootRegistry. The chio-anchor crate fails closed for each configured anchor: a checkpoint counts as anchored only when EVM publication, Bitcoin attestation, and, where configured, a Solana memo record all succeed. EVM anchoring is fast enough to check during a dispute; Bitcoin anchoring is slow and far harder to rewrite. Publishing to both lets a verifier choose latency or durability when it checks.
Source
- Dispatch composition and validation:
crates/economy/chio-settle/src/evm/prepare.rs:150-240. - Finality and the execution receipt:
chio-settle/src/evm/finalize.rs,observe.rs:213. - Export envelope signature:
crates/core/chio-core-types/src/receipt/lineage.rs:410-431. - Escrow reopening guard:
contracts/src/ChioEscrow.sol:309; partial release:ChioEscrow.sol:452-467. - Receipt id content address:
crates/core/chio-core-types/src/receipt/body.rs:240-243. - Solana preparation:
crates/economy/chio-settle/src/solana.rs:45-63; receipt hash:solana.rs:177-191.