Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.keystoneos.xyz/llms.txt

Use this file to discover all available pages before exploring further.

KeyStone uses smart contract escrow with a commitment-based deposit scheme to ensure atomic settlement while preserving pre-execution privacy. Parties deposit their assets directly to the escrow contract using a deposit secret. The contract detects when all deposits are complete, notifies the SettlementCoordinator, and the coordinator calls executeSettlement with recipient addresses (revealed only at execution time) to release deposits autonomously.

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 to the escrow contract on-chain by calling depositLeg(settlementId, legIndex, depositSecret). 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 escrow contract handles everything:
  • Verifies keccak256(depositSecret) == leg.depositKey - the caller knows the secret
  • Validates the leg has not already been deposited
  • Validates token allowance is sufficient
  • Emits a LegDeposited event
Deposit authorization is based on knowledge of the deposit secret, not on msg.sender. Any address that knows the secret and has sufficient token balance can deposit for that leg. This preserves pre-execution privacy on public chains - party addresses are only revealed on-chain at deposit time, not at settlement creation.

3. Escrow auto-notifies coordinator

When the escrow contract detects that all legs for a settlement have been deposited, it automatically notifies the SettlementCoordinator:
  • Same-chain: Direct call to notifyDepositsComplete()
  • Cross-chain: LayerZero message

4. Coordinator auto-executes with recipient reveal

The coordinator verifies the atomicity gate (allLegsDeposited == true) and calls executeSettlement(settlementId, recipients[]) on the escrow contract. Recipient addresses are revealed only at this point - they are not stored on-chain during settlement registration. This means:
  • Tokens from the seller’s leg go to the buyer’s wallet
  • Tokens from the buyer’s leg go to the seller’s wallet
  • Fees (if configured) are sent to fee recipient addresses

5. Rollback protection

If the settlement times out or fails:
  • The coordinator dispatches rollback instructions to all escrow contracts
  • All deposits are returned to their original depositors (the address that submitted the deposit transaction)
  • No partial execution is possible
  • Anyone can trigger timeout permissionlessly after the deadline

Commitment scheme overview

The commitment scheme replaces address-based deposit authorization with cryptographic secrets:
ConceptDescription
deposit_secretRandom 32-byte hex string generated by the API per leg
deposit_keykeccak256(deposit_secret) - stored on-chain at registration
Authorizationkeccak256(callerSecret) == storedDepositKey
Privacy benefitParty addresses are hidden until deposit transaction. Recipient addresses are hidden until execution.

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 escrow contract to spend the token
    • Call depositLeg(settlementId, legIndex, depositSecret) on the escrow contract
  4. Your custody provider signs and broadcasts the transaction
  5. The escrow contract verifies the secret and accepts the deposit
  6. When all deposits are complete, contracts auto-execute
  7. You receive a webhook: settlement.state.finalized

Integration example

import { KeystoneClient } from "@keystoneos/sdk";
import { ethers } from "ethers";

const client = new KeystoneClient({
  clientId: process.env.KEYSTONE_CLIENT_ID!,
  clientSecret: process.env.KEYSTONE_CLIENT_SECRET!,
});

// Get the deposit secret from the settlement response
const settlement = await client.settlements.get(settlementId);

// Find the leg for your party
const leg = settlement.legs.find(
  (l) => l.partyRole === "seller" && l.direction === "deliver"
);
const depositSecret = leg.depositSecret;

// First, approve the escrow contract to spend tokens
const tokenContract = new ethers.Contract(leg.instrumentId, ERC20_ABI, partySigner);
await (await tokenContract.approve(ESCROW_ADDRESS, leg.quantity)).wait();

// Then deposit with the secret
const escrow = new ethers.Contract(ESCROW_ADDRESS, ESCROW_ABI, partySigner);
const tx = await escrow.depositLeg(
  settlementId,   // bytes32
  leg.legIndex,   // uint256
  depositSecret   // bytes32
);
await tx.wait();

Monitoring deposit status

Check deposit progress by querying the settlement:
curl https://api.keystoneos.xyz/v1/settlements/$ID \
  -H "Authorization: Bearer $TOKEN"
The response includes the current state and leg statuses showing which deposits have been received.

Timeout behavior

Every settlement has a timeout_at deadline. If all deposits are not received by this time:
  1. Settlement transitions to TIMED_OUT
  2. Escrow contract returns any received deposits to their original depositors
  3. All platforms are notified via webhook
Timeout is permissionless on-chain: anyone can call claimTimeout() on the KeystoneEscrow after the deadline, regardless of whether KeyStone’s services are running.

Fees

If the platform has a fee agreement configured, fees are included in the on-chain leg registration as FeeSpec entries. The escrow contract deducts fees during execution and transfers them to the configured recipients. See Smart Contracts - KeystoneEscrow for details on how fees work at the contract level.

Token standards

StandardSupportRelease mechanism
ERC-20FullStandard transfer()
ERC-3643FullforcedTransfer() via transfer agent role
See KeystoneEscrow for full contract documentation.