CryptoCMD CryptoCMD

Proof of Reserves: What Exchange Audits Prove and What They Hide

A Merkle tree can show your balance was counted and a wallet list can show coins exist, but neither tells you whether an exchange can pay everyone back.

Daniel Okoro · · 10 min read
Proof of Reserves: What Exchange Audits Prove and What They Hide
Photo: Nataliya Vaitkevich / Pexels

Key takeaways

  • →A Merkle tree proves your balance was included in a total. It says nothing about debts the exchange left out of that total.
  • →Showing wallets full of coins proves control at one moment, not ownership, and not that those coins aren't owed to someone else.
  • →Solvency means assets cover all liabilities, including loans and off-chain debts, not just customer balances in the tree.
  • →Check per-asset coverage, snapshot frequency, how negative balances are handled, and who actually did the verification.
  • →An attestation is not a full financial audit. Read the scope section before you trust the headline ratio.

Proof of reserves shows that an exchange held certain coins at a certain moment. It doesn't show that the exchange can repay everyone it owes. That gap is where people get hurt.

The term gets thrown around loosely. An exchange posts a page with a big green percentage, maybe an accounting firm's logo, and a tool for checking your own balance. It looks like an audit. Usually it isn't one. To judge any of these properly, you need to know the two halves of the proof, what each half can establish, and what neither one touches.

The two halves: assets and liabilities

An exchange is solvent if what it owns is worth more than what it owes. Simple. So an honest solvency proof needs two numbers:

  • Assets: the coins and cash the exchange actually controls.
  • Liabilities: everything the exchange owes, to customers and to anyone else.

Most proof-of-reserves reports handle assets by listing wallet addresses and showing the exchange controls them. Customer liabilities get a Merkle tree. Each half has blind spots, and even together they leave a big one.

How the Merkle tree works

A Merkle tree commits to a huge list of data with one short fingerprint, called the root. Change any entry and the root changes completely.

Here's the process in plain terms. The exchange snapshots every customer balance. For each account it builds a leaf: a hash of something like your account ID (or a scrambled version of it), a random salt, and your balance. A hash is a one-way fingerprint. You can't run it backward to see the inputs.

Next, it pairs leaves up and hashes each pair together. Then it pairs those results and hashes again. It repeats until a single hash remains. That's the root, and the exchange publishes it.

Here's the neat part. You don't need the whole tree to check your own entry. The exchange hands you the sibling hashes along the path from your leaf up to the root. You recompute upward. If you land on the published root, your balance was in the tree. Even with millions of accounts, that path is only a couple of dozen hashes long.

A plain Merkle tree only proves inclusion. Better versions use a Merkle sum tree, where each node also carries the sum of the balances beneath it. The root then commits to the total of all customer balances. If the exchange tried to shave your balance or quietly drop a chunk of the total, the sums along your path wouldn't add up.

What the Merkle tree proves

  • Your balance, as of the snapshot, was included in the published commitment.
  • In a sum tree, your balance contributed to the stated total.
  • The exchange can't show different users different totals without someone eventually noticing, provided the root is public and plenty of users check.

What it doesn't prove

  • That every account is in the tree. You can only check yours.
  • That there are no fake accounts with negative balances dragging the total down.
  • Anything about debts that aren't customer balances: loans, credit lines, amounts owed to market makers, legal claims.
  • Anything about the assets side at all.

That third point is what the green percentage hides. The tree is a list of what the exchange chose to put in it.

How the asset side works

Proof of Reserves: What Exchange Audits Do and Don't Prove
Photo: Rafael Minguet Delgado / Pexels

To prove reserves, an exchange publishes wallet addresses and signs a message with each address's private key. The signature shows that whoever produced the report controlled those keys. Anyone can then look up the balances on a block explorer at the snapshot block height.

This has gaps too:

  • Control isn't ownership. Coins can be borrowed for a day, shown in a wallet, and returned after the snapshot.
  • Coins can be pledged. A wallet might hold coins that already back a loan. They're there, but someone else has first claim.
  • Point in time. A monthly snapshot says nothing about the other 29 days.
  • Self-issued tokens. If a large share of reserves is the exchange's own token, its value is only as real as the market for it, and that can vanish in an afternoon.
  • Fiat and off-chain assets usually can't be proven this way. They need bank confirmations and an actual accountant.

Worked example: a 105% ratio that's actually 81%

Every number here is hypothetical, for an imaginary venue I'll call Exchange X.

Exchange X publishes a Merkle sum tree showing customer BTC balances total 10,000 BTC. It also signs messages from wallets holding 10,500 BTC. Its reserves page says 105% backed. Customers check their leaves. Everyone's included. Looks fine.

Now the parts that aren't on the page. Exchange X borrowed 3,000 BTC from a lending desk to fund its own trading. That loan is a liability, but it isn't a customer balance, so it's not in the tree. And inside the tree, an internal account carries a balance of minus 500 BTC. The sum tree adds it without complaint, which makes the customer total look 500 BTC smaller than it really is.

ItemAs disclosedReality
BTC in wallets10,50010,500
Customer balances10,00010,500 (negative account removed)
Loan from lending desknot shown3,000
Total liabilities10,00013,500
Coverage ratio105%about 78%

Even setting the negative-balance trick aside, 10,500 against 13,000 of liabilities is about 81%. Every individual check passed. Every customer verified their leaf. The exchange is still short thousands of coins. If customers ran for the exit, the last fifth wouldn't get paid.

That's the core lesson. A Merkle proof isn't a lie. It's an incomplete answer to a different question.

Verify your own inclusion, step by step

Checking your leaf is still worth doing. It's the one piece you can confirm yourself. Here's how:

  1. Find the exchange's proof-of-reserves page and note the snapshot date and time, plus the published Merkle root.
  2. Check your own records for your balance at that snapshot. Use a statement or export, not today's balance.
  3. Download your inclusion proof. This is usually a file or string containing your leaf data and the sibling hashes on your path.
  4. Confirm the balance inside the leaf matches your records for every asset listed.
  5. Run the proof through an open-source verifier you can inspect, ideally one not hosted only on the exchange's own site. Some exchanges publish verifier code you can run locally.
  6. Compare the root the verifier produces with the published root. They must match exactly, character for character.
  7. Check that the root was published somewhere hard to edit later, such as an archived page, a public repository, or an on-chain transaction, and that it's the same root other users report.
  8. Look up the listed reserve wallets on a block explorer at the snapshot block and confirm the balances roughly match the claimed reserves.
  9. Repeat at the next snapshot. A habit catches a lot more than a one-off check.

If any step fails, or the exchange won't give you the proof data, treat that as information.

Checklist: is this disclosure meaningful?

These questions help separate a real disclosure from a marketing page.

  • Per-asset ratios. Is coverage shown for each coin separately? A 110% overall figure can hide 60% coverage on one asset propped up by surplus in another.
  • Negative balances. Does the method prevent negative leaves? Look for a sum tree with explicit non-negativity rules, or zero-knowledge proofs that each balance is zero or more without revealing it.
  • Full liabilities. Does the report cover anything beyond customer balances, like loans, credit facilities, and payables? If it only says customer liabilities, the debts that sink exchanges are probably outside the frame.
  • Encumbrance. Does it say whether reserve assets are pledged, lent out, or rehypothecated?
  • Asset quality. What share of reserves is the exchange's own token or illiquid assets? Strip them out mentally and recompute.
  • Frequency. Monthly is a start. More often is better. A single report from a long time ago is close to worthless.
  • Archive. Can you see past reports and roots? Gaps or quiet deletions are a warning.
  • Who verified it. Was there an independent firm, and what kind of engagement? Read the scope and limitations section. Firms often say plainly what they didn't check.
  • Open tooling. Is the verifier code public, so you're not trusting the exchange's own checker?
  • Financial statements. Does the exchange publish audited accounts at all? That's the only thing that comes close to a full liabilities picture.

Common mistakes

  • Reading the headline ratio as solvency. It's reserves divided by the liabilities the exchange chose to include. Nothing more.
  • Treating an attestation as an audit. Agreed-upon procedures check specific things on a specific date. A financial statement audit tests the whole balance sheet. The level of assurance is very different.
  • Checking today's balance instead of the snapshot balance. Your leaf reflects the snapshot. Compare it to your current balance and you'll either confuse yourself or hide a real mismatch.
  • Using only the exchange's verifier. If the exchange wrote the checker and hosts it, it can tell you whatever it wants.
  • Assuming everyone else checks. The Merkle model only works if lots of users verify. Most don't. Your check is the one you can count on.
  • Ignoring the asset mix. Full coverage in the exchange's own token isn't the same as full coverage in the coins you deposited.
  • Trusting one report forever. A good snapshot from last quarter tells you nothing about this week.

FAQ

If an exchange has proof of reserves, are my funds safe?

Safer than at an exchange that publishes nothing, perhaps. Safe, no. The proof shows certain coins existed and your balance was counted at one moment. It can't rule out hidden loans, pledged collateral, or problems that start after the snapshot. Keep only what you're actively using on any exchange.

Why don't exchanges just publish everything?

Partly privacy: full customer data can't be public. Partly competition: wallet layouts and trading positions are sensitive. And partly because a full liabilities picture is exactly what a struggling exchange doesn't want seen. Zero-knowledge techniques can answer the privacy objection. If an exchange still won't disclose liabilities after that, the other reasons deserve some thought.

What's the difference between an attestation and an audit?

An attestation is a firm checking specific claims under agreed procedures, often limited to one snapshot and one side of the ledger. A financial audit examines the whole set of accounts, including debts and controls, over a period. A firm's name on the page tells you very little until you read which one it was and what was excluded.

Which leaves the real question for any venue you use: if every customer asked for their coins back tomorrow, what in the disclosure actually proves they'd get them?

Keep learning