Proof of reserves: what it does and doesn’t prove

proof of reserves
Table of Contents

Proof of reserves is a check that a custodian, usually a crypto exchange, controlled enough of an asset at a given moment to cover what it owed customers in that asset. It pairs a cryptographic commitment to customer balances with signed proof that the exchange controls specific on-chain addresses. It shows the money was there. It does not show the money was free.

The UK Home Office has a rule for student visa applicants: the money has to sit in your account for at least 28 days in a row. The logic is simple: a balance on one day can be borrowed from a relative and handed back the next morning. Most proof of reserves reports are a balance on one day. That is the thing to keep in mind for the rest of this page.

Quick Answer

Proof of reserves shows that an exchange controlled on-chain assets at least equal to the customer balances it committed to, for specific assets, at one moment. It does not show other liabilities, whether the assets were borrowed or pledged, whether anything changed afterwards, or whether the exchange is solvent. It is evidence, not an audit.

Last updated October 2026.

On this page

  • How proof of reserves works
  • What it proves, and what it does not
  • What 2022 showed
  • Proof of reserves on-chain
  • How to read a report
  • Where it fits for a protocol team
  • Frequently asked questions

How proof of reserves works

A proof of reserves has two halves. One is a commitment to what the exchange owes its customers. The other is evidence of what it holds. The exchange passes, for a given asset, when the second number is at least the first.

  1. The liabilities: The exchange takes a snapshot of every customer balance and builds a Merkle tree from it. In the version Vitalik Buterin described in his November 2022 post on proof of solvency, each node is a “(balance, hash)” pair, so the root commits to both the individual balances and their total. The root is published. Each customer can check that their own balance is a leaf under it.
  2. The assets: The exchange shows it controls on-chain addresses holding at least that total, usually by signing messages with the keys for those addresses. The early version was blunter. As Buterin’s post recounts, in 2011 Mt. Gox “moved 424242 BTC to a pre-announced address” to show it had the coins.
  3. The comparison: Someone, usually an accounting firm, checks that the assets cover the committed balances.

Kraken’s page is a clear example of the process. An accountant “takes an anonymized snapshot of all balances held and aggregates them into a Merkle tree”, collects signatures that prove control of the on-chain addresses, and verifies that those balances “exceed or match the client balances represented in the Merkle tree”. When we read Kraken’s proof of reserves page on 6 October 2026, it showed a snapshot dated 30 June 2026 and a bitcoin reserve ratio of 102.9%. That figure was true on 30 June. The page cannot say anything about the three months since.

What proof of reserves proves, and what it does not

A proof of reserves answers three narrow questions well and leaves the bigger ones open. The table is the short version.

QuestionAnswered?Why
Did the exchange control these addresses at the snapshot?YesSignatures from the keys, checked on-chain
Was my balance included in what it committed to?Yes, if you checkYour leaf sits under the published Merkle root
Did on-chain assets cover in-scope customer balances at that moment?Yes, for the in-scope assetsThe comparison the accountant ran
Does the exchange owe anything else, to anyone?NoOnly customer balances are in the tree
Were the assets borrowed, lent out or pledged?NoControl at one moment says nothing about claims on the coins
Is any of it still true today?NoIt is a snapshot
Are the exchange’s controls and governance any good?NoNobody looked

It counts customer balances, not everything owed

The tree holds what customers are owed. Loans the exchange has taken, money owed to lenders and other creditors are not in it. When Mazars produced a proof of reserves for Binance in December 2022, CNBC reported that it “only accounted for bitcoin” and “did not show liabilities for Binance’s lending arm”.

Even the customer half depends on customers checking. Buterin’s post walks through how an exchange could hide a hole in one branch of the tree, and notes that “the exchange would have to hope that nobody in the entire right half of the tree checks their balance proof”. A tree nobody checks proves very little.

It cannot see what the assets are pledged to

A signature proves control of a key. It does not prove the coins are unencumbered. Kraken says this about its own process: the procedure “cannot identify any hidden encumbrances or prove that funds had not been borrowed for purposes of passing the review”. Buterin makes the same point about collusion: exchanges could shuttle collateral between each other to pass, “and would allow them to pretend to be solvent when they actually are not”. That is the visa problem exactly.

It describes one moment

Kraken’s own list of shortcomings adds that “keys may have been lost or funds stolen since the latest review”. A report is a photograph, and the exchange keeps moving after it is taken. We made the same argument about code in when a smart contract audit actually expires: a check describes the thing it checked, on the day it checked it.

It covers the assets in scope, and nothing else

Each report names the assets it covers. Kraken notes that USD “is not an in-scope asset” for its review, and Buterin points out that fiat “is not cryptographically verifiable”. An exchange can pass on bitcoin and ether and say nothing at all about the rest.

The exchange often chose the procedure

Many reports are agreed-upon procedures engagements. The accountant runs the checks the client asked for and reports what it found, with no opinion on whether those checks were enough. Mazars described its own reports this way: they “do not constitute either an assurance or an audit opinion”.

What 2022 showed about proof of reserves

The collapse of FTX in November 2022 is what set off the wave of exchange proofs of reserves. The SEC’s complaint alleged “the undisclosed diversion of FTX customers’ funds to Alameda Research” and a “virtually unlimited ‘line of credit’ funded by the platform’s customers”. That is a question about where customer money had gone and who owed what to whom, which is the half of the picture a reserves snapshot is weakest on.

Exchanges rushed to publish reports. Mazars did the work behind several of them: Binance’s was published on 7 December, Crypto.com‘s on 9 December, and KuCoin’s had already been delivered. On 16 December it paused the work, saying it had stopped “due to concerns regarding the way these reports are understood by the public”. Its statement described the reports as “limited findings based on the agreed procedures performed on the subject matter at a historical point in time”. The Binance report was no longer on its website.

In March 2023 the Office of the Investor Advocate at the PCAOB (Public Company Accounting Oversight Board), the US audit regulator, issued an advisory that Accounting Today quoted at length. Its central line: “PoR engagements are not audits and, consequently, the related reports do not provide any meaningful assurance to investors or the public.” It added that the procedures “likely do not address the crypto entity’s liabilities”, and that if assets were borrowed for the engagement, “investors would not know based on the PoR Report”.

Proof of reserves on-chain: when a contract reads the number

Some wrapped tokens, stablecoins and tokenised real-world assets put their reserve figure on-chain through an oracle feed, so that a contract can act on it. The obvious use is a mint guard: refuse to issue new tokens if supply would exceed reported reserves. This is where proof of reserves stops being a report and becomes code, and code can be wrong.

Chainlink’s documentation for its Proof of Reserve feeds is candid about where the number comes from. Off-chain reserves arrive from a third party such as an auditor, from the custodian directly, or self-reported from an API the issuer hosts. For that last type it warns that “Chainlink Labs is not responsible for the accuracy of self-reported reserves data”. For cross-chain reserves, the project can use a wallet address manager and “self-reports which addresses they own”. The feed moves the number on-chain, and the number is only as true as its source.

Here is a minimal mint guard with the three checks a contract needs before it trusts the figure.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface AggregatorV3Interface {
    function decimals() external view returns (uint8);
    function latestRoundData()
        external
        view
        returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}

// Illustrative only. A wrapped token that refuses to mint past its reported reserves.
contract ReserveGuardedToken {
    uint8 public constant decimals = 18;
    AggregatorV3Interface public immutable reserveFeed;
    uint256 public immutable maxFeedAge; // seconds, set from the feed's documented update interval
    address public immutable minter;

    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;

    constructor(AggregatorV3Interface feed, uint256 maxAge, address minter_) {
        reserveFeed = feed;
        maxFeedAge = maxAge;
        minter = minter_;
    }

    function mint(address to, uint256 amount) external {
        require(msg.sender == minter, "not minter");

        (int256 reserve, uint256 updatedAt, ) = reserveFeed.latestRoundData();
        // Check 1: a reserve figure that is zero or negative is not a reserve figure.
        require(reserve > 0, "bad reserve");
        // Check 2: an old figure describes a past that may no longer hold.
        require(block.timestamp - updatedAt <= maxFeedAge, "stale reserve");
        // Check 3: compare like with like, in the token's own decimals.
        uint256 reserveScaled = _scale(uint256(reserve), reserveFeed.decimals());
        require(totalSupply + amount <= reserveScaled, "exceeds reserve");

        totalSupply += amount;
        balanceOf[to] += amount;
    }

    function _scale(uint256 value, uint8 feedDecimals) internal pure returns (uint256) {
        if (feedDecimals <= decimals) return value * 10 ** (decimals - feedDecimals);
        return value / 10 ** (feedDecimals - decimals);
    }
}

The second check is the easy one to leave out. Chainlink’s own minimal example for reading a reserve feed discards the timestamp. That is fine in a documentation snippet. In a mint function it means a figure from last month can authorise a mint today, which is the point-in-time problem from the exchange world, rebuilt in Solidity.

Notice what the guard still trusts. It trusts the reporter behind the feed and the list of addresses the reserves are counted from. It trusts that maxFeedAge was set from the feed’s real update interval. It trusts the minter key, and it says nothing about the redeem path, where reserves leave. A wrapped asset is a reserve claim with a bridge attached, and chain bridges covers the other half of that risk.

How to read a proof of reserves report

Six questions get most of the value out of any report, whether it comes from an exchange or an issuer.

  • The snapshot date: How old is it, and how often is it repeated?
  • The assets in scope: Which coins are covered, and are fiat and stablecoins in or out?
  • The liabilities: Do they include every customer product, such as margin, lending and earn balances, or only spot?
  • The standard: Is it an agreed-upon procedures report or an examination with an opinion, and who chose the procedures?
  • Your own leaf: Have you checked your balance against the published root?
  • The on-chain source: If a contract reads the figure, is the feed third-party, custodian or self-reported, and what is its update interval?

A report that answers all six clearly is worth having. It is still not an audit.

Where proof of reserves fits for a protocol team

For a protocol that issues or holds backed assets, proof of reserves is evidence for users, and the security controls sit elsewhere: the code that acts on the reserve figure, the keys that can mint and redeem, and someone watching both after launch.

That makes the contract the place to spend audit time. A manual audit at Fidesium starts at $5,000, covers logic and economic risk line by line, and includes two rounds of fix verification. Our published reports are in the audit portfolio, and every audit is minted as an on-chain record so the result can be checked rather than claimed. After launch, post-deployment monitoring uses detection bots tuned to a protocol’s own logic rather than generic threshold alerts. This worked example shows what that looks like in practice.

If an enterprise customer is asking for evidence, a reserves report will not satisfy a security review on its own, because the review is about controls. SOC 2 for Web3 covers what that evidence actually looks like for a protocol.

If your contracts mint, redeem or lend against a reserve figure, talk to the audit team before that figure is trusted with real money.

Frequently asked questions

Is proof of reserves an audit?

No. Many proof of reserves reports are agreed-upon procedures engagements, where the accountant runs the checks the client chose and reports what it found without giving an opinion. The PCAOB’s Office of the Investor Advocate said in March 2023 that these engagements are not audits and do not provide meaningful assurance to investors or the public.

What is the difference between proof of reserves and proof of solvency?

Proof of reserves shows that on-chain assets covered the customer balances an exchange committed to, for specific assets, at one moment. Proof of solvency would need every liability, including loans and other creditors, and every asset, including fiat. Proof of reserves covers part of the first and part of the second, so it proves assets, not solvency.

Can proof of reserves be faked?

The signatures are hard to fake, but the result can still mislead. An exchange can borrow assets for the snapshot and return them afterwards, pledge the same coins elsewhere, leave liabilities out of scope, or hide a shortfall in a part of the Merkle tree that no customer checks. An on-chain reserve feed is only as reliable as whoever reports the number.

How do I check that my balance is in a proof of reserves?

Exchanges that publish a Merkle tree give each customer a record identifier and the hashes needed to rebuild the path from their balance to the published Merkle root. If your computed root matches the published one, your balance was included in the snapshot. Kraken publishes the steps and a script for doing this.

Does proof of reserves show an exchange’s liabilities?

Only part of them. The Merkle tree holds customer balances in the assets in scope. It does not include loans the exchange has taken, money owed to other creditors, or assets outside the scope of the report. The Mazars report for Binance in December 2022 covered bitcoin only and did not show the liabilities of its lending arm.

What is on-chain proof of reserve?

On-chain proof of reserve is a reserve figure published to a blockchain through an oracle feed, so that a smart contract can act on it, for example by refusing to mint a wrapped token or stablecoin past its reported reserves. The data can come from a third-party auditor, from a custodian, or from the issuer itself, and the contract reading it still has to check that the figure is fresh and in the right units.

Why did Mazars stop producing proof of reserves reports?

In December 2022 Mazars paused its proof of reserves work for crypto clients, including Binance, KuCoin and Crypto.com, citing concerns about the way these reports are understood by the public. It said the reports were agreed-upon procedures that did not constitute an assurance or an audit opinion, and described them as limited findings at a historical point in time.

Share:

More Posts

Tell us your security needs