Skip to main content
KeyStone uses a commitment-based deposit scheme on the KeystoneSettlement contract to ensure atomic settlement while keeping deposit intent private. Parties deposit their assets directly to the contract using a wallet-bound deposit secret. The LAST deposit executes the settlement inline once the compliance gate passes - every leg pays out to its recipient bound at registration, with no further transaction from anyone.

How it works

1. Settlement reaches AWAITING_DEPOSITS

After compliance clears, the settlement advances to AWAITING_DEPOSITS. At this point, the API response includes a deposit_secret and deposit_key for each leg with direction: "deliver".

2. Parties deposit using their secret

Each party deposits on-chain by calling depositLeg(settlementId, legIndex, depositSecret) on the KeystoneSettlement contract. The platform’s backend uses its custody provider (such as MPC wallets or any signing solution) to construct and sign the deposit transaction. KeyStone is NOT involved in deposits. The contract handles everything:
  • Verifies keccak256(abi.encode(msg.sender, depositSecret)) == leg.depositKey - the key binds BOTH the depositor wallet and the secret
  • Validates the leg has not already been deposited (LegAlreadyDeposited)
  • Pulls amount + additive fees via transferFrom
  • Emits a LegDeposited event
The deposit key commits to the depositor wallet AND the secret. The transaction MUST be sent from the wallet the key was computed for - a leaked secret is useless from any other address. Depositor addresses are only revealed on-chain at deposit time, not at settlement creation.

3. Last deposit executes inline

If the leg just deposited was the last outstanding one AND every party hash is attested Pass in the ComplianceRegistry, the settlement executes inside the same deposit transaction:
  • Tokens from the seller’s leg go to the buyer’s wallet (recipient bound at registration)
  • Tokens from the buyer’s leg go to the seller’s wallet
  • Fees (if configured) transfer to the fee recipient
If attestations are still pending at the last deposit, the settlement stays registered; once the gate clears, execute(settlementId) can be called by the operator or any depositor - the caller only triggers the pre-committed plan, no one can change it.

4. Recovery: abort, timeout, pull refunds

If the settlement is aborted (operator-only, pre-execution) or the deadline passes (claimTimeout, callable by the operator or any depositor):
  • Deposits stay locked until each one is claimed back via claimRefund(settlementId, legIndex) - per leg, by its depositor (or the operator)
  • The refund always pays the depositor address RECORDED at deposit time, including any additive fees
  • One blocked depositor can never strand another leg’s refund
  • No partial execution is possible at any point

Commitment scheme overview

The commitment scheme replaces address-based deposit authorization with cryptographic secrets:

Deposit flow for platforms

From your platform’s perspective:
  1. You receive a webhook: settlement.state.awaiting_deposits
  2. Query the settlement via GET /v1/settlements/{id} - the response includes deposit_secret and deposit_key on each leg
  3. For each leg where your party has direction: "deliver", construct a deposit transaction:
    • Approve the KeystoneSettlement contract to spend the token (amount + any additive fees)
    • Call depositLeg(settlementId, legIndex, depositSecret) from the wallet the deposit key was computed for
  4. Your custody provider signs and broadcasts the transaction
  5. The contract verifies the wallet-bound secret and accepts the deposit
  6. The last deposit auto-executes the settlement when the compliance gate passes
  7. You receive a webhook: settlement.state.finalized
Cross-chain mode: a settlement registered with a non-zero abortDeadline does not auto-execute on the last deposit. It flips to the contract’s Prepared phase and the KeystoneRouter coordinates release across the involved chains. Your deposit flow is identical either way; the hosted platform currently registers every settlement in single-chain mode.

Integration example

Monitoring deposit status

Check deposit progress by querying the settlement:
The response includes the current state and leg statuses showing which deposits have been received.

Timeout behavior

Every settlement has a timeout_at deadline, enforced by the contract itself. If all deposits are not received strictly before it:
  1. The operator or any depositor can call claimTimeout(settlementId) - not pausable
  2. The settlement transitions to TIMED_OUT
  3. Each received deposit is reclaimed via claimRefund(settlementId, legIndex) - by its depositor or the operator, always paying the recorded depositor
  4. All platforms are notified via webhook once the events are observed
Deposits/execution and timeout claims are mutually exclusive by timestamp - there is no instant where both are live.

Fees

If the environment has fees configured, they are included in the on-chain leg registration as FeeSpec entries. The contract collects fees at execution and transfers them to the configured recipient. See KeystoneSettlement for details on how fees work at the contract level.

Token standards

See KeystoneSettlement for full contract documentation.