Exchange invariant catalogue

An invariant is a rule that must be true after every operation, whatever order the operations arrive in. Exchange losses often come from broken invariants: money that is created, released twice or allowed to leave when it should not. This page lists twenty of them, grouped by where they live (terms are in the glossary). For each: the rule, the usual way it breaks, and where to look.

These are patterns from building and reviewing exchange systems. They are not a list of defects found at any named company.

A

Balances and locks

A1 · Conservation

Rule. for every asset, the sum of all user balances plus the exchange's own accounts equals the sum of all credits minus debits ever posted.

Breaks when. a path posts one side of an entry without the other, or a rounding remainder is dropped instead of booked.

Look at. every function that writes a balance; any write outside the posting function.

A2 · No negative available balance

Rule. a user's available balance is never below zero.

Breaks when. two requests pass the balance check before either debit is applied (check-then-act race).

Look at. whether check and debit are one atomic step.

A3 · Lock and unlock are symmetric

Rule. whatever amount is locked for an order is released in the same amount and with the same rounding.

Breaks when. lock rounds one way and unlock the other, leaving a residue per order.

Look at. the lock and unlock formulas side by side; rounding mode per asset.

A4 · Partial cancel releases the remainder, not the original

Rule. after a partial fill and a cancel, the released amount equals the unfilled portion only.

Breaks when. the cancel path reads the original locked amount.

Look at. cancel and expiry paths, including cancel-replace.

A5 · One balance, one serialisation point

Rule. withdrawals, orders, transfers and fees that debit the same balance go through one lock or one serial queue.

Breaks when. two services debit the same balance without a shared lock.

Look at. which services can write to the balance store.

B

Matching and fees

B1 · Fills never exceed the order

Rule. cumulative fill quantity never exceeds order quantity, and remaining quantity plus filled quantity equals the original.

Breaks when. remaining and locked amounts are tracked independently.

Look at. the partial-fill path.

B2 · Price and time priority hold

Rule. a better-priced order always fills before a worse one, and equal prices fill by arrival time.

Breaks when. amend or cancel-replace keeps the old timestamp, or a retried request creates a duplicate.

Look at. amend semantics; queue structure.

B3 · Order types obey their definition

Rule. post-only never takes liquidity, IOC never rests, reduce-only never increases a position, a stop triggers only on the correct side.

Breaks when. an edge case (cross at the same tick, simultaneous trigger) is not covered.

Look at. the order-type switch and tick-boundary handling.

B4 · Fees never favour the trader at the margin

Rule. fee rounding is in one declared direction, and the exchange never pays out more rebate than it collects in fees on the same trade.

Breaks when. fee floors and rebate ceilings; a rebate tier that exceeds the taker fee.

Look at. fee tiers, rounding mode, per-pair precision.

B5 · Precision and scale are consistent across pairs

Rule. quantity and price scale factors are applied in the same order for every pair.

Breaks when. base and quote scales are mixed, hitting low-decimal or very high-value assets first.

Look at. scale configuration and conversion code.

B6 · Settlement dust is accounted for

Rule. every per-trade rounding remainder is booked to a known account.

Breaks when. remainders vanish or land in a claimable balance.

Look at. settlement and netting.

C

Deposits and idempotency

C1 · A deposit credits at most once

Rule. the same on-chain deposit, however many times it is observed or replayed, credits exactly once.

Breaks when. the idempotency key is missing, too narrow, or expires before a retry.

Look at. the key, its scope (user vs global) and its lifetime.

C2 · Deposits credit only at finality

Rule. funds become spendable only after the chain's confirmation threshold, and a reorganisation reverses the credit safely.

Breaks when. N confirmations is below the chain's real reorg depth, or no handler exists.

Look at. per-chain thresholds; the reorg handler.

C3 · Retries do not duplicate intent

Rule. retrying an order, cancel, amend or withdrawal request produces the same single outcome.

Breaks when. a retry creates two live orders or two fills from one intent.

Look at. key scope per endpoint.

D

Withdrawals

D1 · What is signed equals what was approved

Rule. the destination, amount, asset and fee in the signed transaction equal those in the approved request, compared before broadcast by a component that did not build the transaction.

Breaks when. the request is changed between approval and signing, or the signer sees a reference instead of the content.

Look at. the last point where content can change; who verifies it.

D2 · Approval cannot be satisfied by one actor

Rule. no single person, device or credential set can satisfy more than one required approval.

Breaks when. one workstation or role is counted twice.

Look at. role overlaps; shared credentials.

D3 · Outflow is bounded outside the application

Rule. total outflow per period from the hot wallet is capped by a control the creating application cannot change.

Breaks when. limits live only in the same code path an attacker would alter.

Look at. where limits are enforced, and who can change them.

D4 · A failed or cancelled withdrawal releases its lock exactly once

Rule. funds locked for a withdrawal return exactly once on failure, and not at all if the broadcast succeeded.

Breaks when. a timeout after broadcast is treated as a failure, then retried.

Look at. the state machine and its unknown-outcome state.

E

Reconciliation and access

E1 · Internal ledger equals chain plus custodian

Rule. total internal liabilities per asset never exceed the sum of on-chain wallet balances and custodian balances, and any gap is explained.

Breaks when. reconciliation runs but nobody reads the exceptions.

Look at. who reads the output, and how fast.

E2 · Credentials are scoped to the account and the action

Rule. an API key or sub-account credential works only for its own account and its granted actions.

Breaks when. a key for account A is accepted for account B, or a read-only key reaches a trade or withdraw endpoint.

Look at. the authorisation check at each endpoint, not only at login.

Written down, then tested

In an invariant review we write your system's rules down like these, then build an executable test harness that you keep and run on every release. The withdrawal-path checklist covers the signing side.