Settlement and cancellation
What the settlement contract checks for itself before any token moves, and the two ways to cancel an order.
- Marketenabled, epoch MATCHED, not settled, oracle fresh, price inside the band
- Ordertokens, epoch, validity window, receiver
- Replaynonce unused, then spent
- SignatureECDSA, else ERC-1271 with bounded gas
- Commitmentleaf under the root anchored before decryption
- Fillsize, minimum fill, partial-fill flag
- Pricelimit price and the order's own oracle bound
- Balancebase in equals base out, balances grew by exactly what was pulled
- Resultcomputed hash equals the hash published before settling
7. Settlement#
KasumiSettlement.settleMarket(epochId, marketId, clearingPrice, fills) settles one market of one epoch.
The matcher supplies the price and, per order, the signed order, its signature, the base fill, and the
Merkle proof of its leaf. The contract computes every token amount itself.
It reverts unless all of the following hold:
- caller is the matcher, the market is enabled, this market of this epoch is not settled yet
- the epoch is
MATCHED - the oracle price is non-zero and no older than the market's
maxOracleAge |clearingPrice - oracle| * 10000 <= oracle * market.maxOracleDeviationBps- fills are strictly ascending by order commitment (canonical order, and no duplicates)
- for each order:
- tokens match the market,
epochIdmatches,sideis 0 or 1 receiveris neither the zero address nor the settlement contractsequenceis below the committedorderCountvalidAfter <= now <= validUntil- the nonce bit is clear; it is then set
- the signature is valid for
ownerunder this contract's domain. A 65-byte signature is checked with ECDSA first (lows,vof 27 or 28), so an EOA that has delegated its code under EIP-7702 still signs as an EOA. Otherwise, ifownerhas code, ERC-1271 is used with a gas cap of 200,000 and exactly one word of return data read. - the leaf
(epochId, sequence, commitment, ciphertextHash)is under the epoch root 0 < baseFilled <= baseAmount, equalsbaseAmountif partial fills are not allowed, and is at leastminFillBase- BUY:
clearingPrice <= limitPrice; SELL:clearingPrice >= limitPrice - if the order set
maxOracleDeviationBps: a BUY does not pay more thanoracle * (1 + d), a SELL does not receive less thanoracle * (1 - d)
- tokens match the market,
- base pulled from sellers equals base owed to buyers
- the result hash computed from the transfers actually performed equals the hash the matcher published for
this market (
ResultHashMismatchotherwise). The matcher cannot publish one result and settle another, and cannot settle a market it did not publish. - after pulling, the contract's balance of each token rose by exactly the amount pulled. This rejects fee-on-transfer and rebasing behaviour.
Buyers pay ceil(fill * price / 1e18), sellers receive floor(fill * price / 1e18). The difference is
recorded in dust[quoteToken].
Settlement is all-or-nothing per market. One market's failure cannot block another market of the same epoch. Inside a market, one failing transfer reverts the segment; see THREAT_MODEL.md.
The contract stores the hash of what it settled for each market in marketResult and reports it to the
epoch manager, which compares it with the published hash and counts the market as settled. The epoch is
SETTLED once every published market has settled. Hash formats are in MATCHING.md §9.
If a market's settlement reverts after the match, for example because a filled user cancelled their nonce
onchain, revoked an allowance or cannot receive the token, the matcher re-matches that market without the
order and calls amendMarket with the new hash, or withdraws the market. Other markets are unaffected.
The operator that does this is in packages/operator; see packages/operator/README.md.
Funding is by ERC-20 allowance to the settlement contract. Kasumi never holds user keys. Permit-based approval is not implemented in v1.
8. Cancellation#
Private cancellation. While the epoch is open, the client sends { epochId, orderCommitment, cancelSecret } to the relay. The relay cannot check the secret, because cancelHash is inside the
ciphertext, so it only records it. When the epoch is opened, the order is rejected as CANCELLED if
keccak256(cancelSecret) equals the sealed cancelHash. This reveals nothing about which wallet placed
the order. It depends on the relay and matcher honouring it.
Emergency onchain cancellation. KasumiSettlement.invalidateNonce(nonce) or
invalidateNonces(word, mask). Works at any time and needs no cooperation from Kasumi. It reveals that the
wallet uses Kasumi. Security takes priority over privacy here.