KeystoneSettlement replaces the earlier SettlementCoordinator + KeystoneEscrow pair with one contract that owns the full on-chain lifecycle. The lifecycle is fixed in code - every settlement runs the same audited machine:
registerSettlement and (operator-only) abort. setRouter is a deploy-time admin step, not part of settlement flow.
Lifecycle
Registration
abortDeadline selects the settlement mode. 0 is single-chain: the settlement executes autonomously on the last deposit, exactly as before. A non-zero value opts into the cross-chain Prepared phase (see Remote mode below): the last deposit flips the settlement to Prepared and the KeystoneRouter drives release or abort. Registering in cross-chain mode requires a configured router; the router address is snapshotted into the settlement at registration, so re-pointing the live router later can never redirect an in-flight settlement. KeyStone currently registers every settlement with abortDeadline = 0.
Each LegInput binds everything permanently:
isAgent check for ERC-3643 legs (so agent-gated payouts cannot strand funds later). Re-registering an existing id reverts SettlementAlreadyExists.
Deposits: wallet-bound commitment keys
keccak256(abi.encode(msg.sender, depositSecret)) == leg.depositKey - the key commits to BOTH the depositor address and the secret, so a leaked secret is useless from any other wallet. The deposit pulls amount + additive fees via transferFrom and records the depositor for refunds.
Deposits are accepted strictly before timeoutAt. Duplicate deposits revert LegAlreadyDeposited; a wrong secret or wrong wallet reverts InvalidDepositKey.
Autonomous execution
If the last outstanding deposit lands while the compliance gate already passes, the settlement executes inline in the same transaction - every leg pays out to its bound recipient, fees transfer, all-or-nothing.Registered (a closed gate never reverts a deposit) and once the gate clears execute() can be called by the operator or any depositor: every recipient and fee was bound at registration, so the caller only triggers the pre-committed plan, never steers it. (Unrelated third parties are excluded - this is permissioned institutional settlement - but every party with funds at stake can always drive execution itself.)
The gate: ComplianceRegistry.areAllPartiesCleared(settlementId, partyHashes) - every party hash bound at registration must be attested Pass.
Remote mode: the Prepared phase
A settlement registered withabortDeadline > 0 never auto-executes. Instead, when every leg is funded and the compliance gate passes, it flips to Prepared - the chain’s promise to hold funds while the KeystoneRouter collects confirmations from every participating chain and lands a release or abort decision.
prepare- operator-or-participant (the same gate asexecute). Requires all legs deposited, the compliance gate passing, andblock.timestamp < timeoutAt. The lastdepositLegalso flips toPreparedinline when the gate already passes, so an explicitpreparecall is only needed when attestations land after the final deposit. EmitsSettlementPrepared.executeFromRouter- the only path that pays out a remote-mode settlement. Callable only by the settlement’s snapshotted router, strictly beforeabortDeadline, and the compliance gate is re-checked at release time - a settlement whose compliance has since failed reverts instead of paying out.abortFromRouter- router-only abort, accepted fromRegistered(another chain never funded) orPrepared(the coordinator decided abort). Not pausable, and a re-delivered abort can never touch anExecutedsettlement.
< abortDeadline) and the Prepared-phase timeout window (>= abortDeadline, claimTimeout by the operator or any depositor) are disjoint by timestamp: at no instant are both release and timeout live, so a cross-chain settlement can never both pay out and refund.
Recovery: abort, timeout, pull refunds
abort- operator-only, allowed only whileRegistered. The race-free runbook against a pending auto-execution is pause first (pause blocks deposits and execution; abort stays pause-exempt), then abort.claimTimeout- operator or any depositor. For aRegisteredsettlement it opens attimeoutAt; for aPrepared(cross-chain) settlement it opens atabortDeadline. Each window is mutually exclusive by timestamp with the corresponding execution window.claimRefund- any depositor (or the operator), per leg, afterAbortedorTimedOut. Paysamount + additive feesto the recorded depositor, never an alternate address. Per-leg pull payment means one un-receivable depositor (e.g. a USDC blacklist) can never block other legs’ refunds.refundViaTransfer- operator escape hatch for ERC-3643 legs whose agent role was revoked after deposit; identical guards, standard transfer path.
Events
KeyStone’s backend maps
SettlementExecuted / SettlementAborted / SettlementTimedOut to the settlement states SETTLED / ROLLED_BACK / TIMED_OUT by event name - see State Machine.
Reads
Roles and pause
Pause blocks registration, deposits, and execution - never abort, timeout, or refunds.
Token support
ERC-20 and ERC-3643 (T-REX security tokens). ERC-3643 payouts and refunds route through agent-gatedforcedTransfer; the contract must be an agent on the token, verified at registration. Fee-on-transfer and rebasing tokens are not supported.