Proof of Reserves

Our commitment to transparency

Accountability, regular reviews

At Kraken, we don’t just offer you the ability to trade cutting-edge digital assets, we’re working to leverage the transparency of the open-source blockchains on which they operate.

Our regular Proof of Reserves reviews make it easy for clients to verify the in-scope balances they hold are backed by real assets, all with just a few easy clicks in their account.

An advanced cryptographic accounting procedure conducted regularly by trusted accountants, Proof of Reserves lets you verify that Kraken is meeting rigorous standards for accountability and exceeding the transparency offered by legacy financial firms.

What is Proof of Reserves?

A Proof of Reserves (PoR) review is a procedure performed by an independent 3rd party accountant. This is intended to confirm that a custodian holds the assets it claims to on behalf of its clients. This accountant takes an anonymized snapshot of all balances held and aggregates them into a Merkle tree — a privacy-friendly data structure that encapsulates all client balances.

Merkle Root Hash

From there, the accountant obtains a Merkle root: a cryptographic fingerprint that uniquely identifies the combination of these balances at the time when the snapshot was created.

The accountant then collects digital signatures produced by Kraken, which prove ownership over the on-chain addresses with publicly verifiable balances. Lastly, the accountant compares and verifies that these balances exceed or match the client balances represented in the Merkle tree, and therefore that the client assets are in Kraken’s control.

Any client can independently verify whether their balance was included in the Proof of Reserves procedure by comparing select pieces of data with the Merkle root. Any changes made to the rest of the data, however small, will affect the root – making tampering obvious.

What does Proof of Reserves cover?

Spot balances

The review will contain all of your balances in the in-scope assets, held at the time that the snapshot was taken. The following assets are in scope as of the most recent review: Bitcoin (BTC), Ether (ETH), Cardano (ADA), Polkadot (DOT), USD Coin (USDC), Tether (USDT), and Ripple (XRP).

Staking balances

If your balances were allocated to on-chain staking at the time of the snapshot, you will see a separate entry for these, following the naming convention with a '.S' suffix (e.g. DOT.S)

Margin trading

If you had margin positions at the time, then you would see your total balance adjusted by the positive position values.

Example 1

If you bought 1 BTC/USD @ 30,000 USD on margin, and your position is open, your Proof of Reserves balance will reflect a positive +1 BTC adjustment to your BTC balance. There will be no negative adjustment to your USD balance. Your BTC asset balance held under Kraken custody will include your BTC balance at the time, adjusted by the positive + 1 BTC adjustment for your margin position. Your USD asset balance will remain the same.

Example 2

If you sold 1 BTC/ETH @ 15 ETH on margin, and your position is open, your Proof of Reserves balance will reflect a positive +15 ETH adjustment to your ETH balance. There will be no negative adjustment for your BTC balance. Your ETH asset balance held under Kraken custody will include your ETH balance at the time, adjusted by the positive + 15 ETH adjustment for your margin positions. Your BTC asset balance held under Kraken custody will remain the same.

Note: The futures methodology described above is effective starting with the May 2023 Proof of Reserves reviews.

Futures balances

If you had balances in your Futures wallet at the time of the review, a separate Proof of Reserves record will exist for your futures collateral balances. Your balances are adjusted by unrealized Profit and Loss for Single Collateral futures trades. This will include the same in-scope assets as for spot and margin, and will be part of the same Merkle Tree (with its own Merkle Leaf ID). 

Example 1

If you had 1 BTC in your futures wallet, and you open a position in BTC Perp Single Collateral, which has a -0.1 BTC unrealised Profit and Loss, then your BTC balance held under Kraken custody will be 0.9 BTC (your 1 BTC, adjusted by -0.1 BTC for unrealised P&L).

Example 2

If you had 1 BTC in your futures wallet, and you open a position in BTC Perp Multi-Collateral, which has a -100.0 USD unrealised Profit and Loss, then your BTC balance held under Kraken custody will be 1 BTC (your 1 BTC is not adjusted by the unrealised P&L, as that is tracked in USD, and USD is not an in-scope asset for this review).

Note: The futures methodology described above is effective starting with the May 2023 Proof of Reserves reviews. 

Verifying that your account was included in the Proof of Reserves review

Simple verification

Follow the steps below to cryptographically verify the inclusion of your Kraken account balance in the most recent Proof of Reserves review.

Note: This verification will only reflect your account's balances in the in-scope assets at the time of the review. It will not reflect any subsequent trades or transactions, nor will it reflect balances held in assets that are not in-scope.

1. Log in to your Kraken account on and navigate to the Proof of Reserves page in the Kraken Pro interface (pro.kraken.com) (Account icon > Proof of Reserves). 

Kraken Proof of Reserves review list

2. Select the Proof of Reserves tab. This will include our most recent verified reserve ratios, as well as information specific to your account. Your account will display recent Proof of Reserves reports in which your account balance was verified, including the date of the report, the provider and the assessment scope. 

Kraken Proof of Reserves review list

3. Select the date and click Verify yourself. Here, you will find confirmation of the balances held at the time of the review, as well as a guide on how to verify your details.

Kraken audit details

Verify with the 3rd party accountant

  • Use your Merkle Leaf ID - copy the first 16 characters and input them into the 3rd party accountant's tools to retrieve your balances and review your ID in the Merkle Tree path. The 3rd party accountant's tool will open in a separate window. 

Note: This has been made available from 2023 reviews onwards. For previous review, please refer to our partner’s web page to find the verification tools.

Kraken audit details

Verify with Kraken

  • Verify your Record ID - follow the steps to recreate your record ID, which uniquely identifies your account details and the Review ID (unique for each report date)
  • Verify your Merkle Leaf ID - follow the steps to recreate your Merkle Leaf ID, which uniquely identifies your account together with the balances held at the time of the review snapshot 
  • Confirm your Merkle Leaf ID in the Merkle Tree - confirm that your ID belongs to the Merkle tree and validate the path to the Merkle Tree root, which is verified by our 3rd party accountant and shared by all clients

Note: This has been made available from 2023 reviews onwards. For previous review, please refer to our partner’s web page to find the verification tools.

Kraken audit details
Kraken audit details
Kraken audit details

Advanced verification

Tech-savvy clients may wish to independently reconstruct their particular Merkle Tree leaf node hash and look up their balances in the Merkle Tree programmatically, rather than in the Kraken or 3rd party accountant provided visual tools. 

You can perform the following verifications steps in code:

  1. You can verify the generation of your Merkle Tree Leaf ID for your account, with the steps outlined below.  

  2. You can then verify your Merkle Tree Path for the leaf ID, and reconstruct the path from your position to the root node. We provide full transparency and also include your sibling leaf IDs. 

The requisite steps, in pseudocode, to reconstruct the Record ID and Merkle Leaf from your Account Code, Kraken IIBAN, Review ID and Balances are outlined below. Note that the results are sensitive to the particular string formatting of balances, and the order of assets reviewed, as displayed on the Proof of Reserves page.

  • Record ID = SHA256(concatenate(Account Code, Kraken IIBAN, Review ID))
  • Balances = ""
  • ForEach Asset:
    • Balances = concatenate(Asset, ":", AssetBalances[asset])
  • Merkle Hash = concatenate(Record ID, “,”, Balances)
  • Merkle Leaf = substring(SHA256(Merkle Hash), 0, 16)

After your Merkle Leaf is identified, you can use a SHA256 verification with HEX values to reconstruct the Merkle Tree Path.

Specific examples are also demonstrated in the code snippets below. The resulting Merkle Leaf is also visible on the review details to help confirm you’ve reconstructed this correctly.

python

Python

import hashlib

# Merkle Leaf ID calculation
account_code = "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
iiban = "AB12C34DEFG5KSQI"
review_id = "PR30NOV23"
record_id = hashlib.sha256((account_code + iiban + review_id).encode('utf-8')).hexdigest()

balances = "ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,DOT:50.0,DOT.S:20.5,DOT.P:0.0,DOT28.S:30.1,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002"

print("Record ID: {}".format(record_id))
print("Merkle Hash: {}".format((record_id + "," + balances)))
hash_result = hashlib.sha256((record_id + "," + balances).encode('utf-8')).hexdigest()
print("SHA Result: {}".format(hash_result))
print("Merkle Leaf: {}".format(hash_result[0:16]))

#Merkle Tree Path function 
def mix(x, y):
    a = bytes.fromhex(x)
    b = bytes.fromhex(y)

    d = hashlib.sha256()
    d.update(a)
    d.update(b)
    return d.hexdigest()
rust

Rust

use sha2::{Digest, Sha256};

//Merkle Leaf ID calculation
const ACCOUNT_CODE: &str = "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1";
const IIBAN: &str = "AB12C34DEFG5KSQI";
const REVIEW_ID: &str = "PR30NOV23";
const BALANCES: &str = "ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,DOT:50.0,DOT.S:20.5,DOT.P:0.0,DOT28.S:30.1,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002";

fn main() {
    let mut record_hasher: Sha256 = Default::default();

    record_hasher.update(ACCOUNT_CODE);
    record_hasher.update(IIBAN);
    record_hasher.update(REVIEW_ID);

    let record_id = format!("{:x}", record_hasher.finalize());
    let merkle_hash = format!("{},{}", record_id, BALANCES);

    let mut merkle_hasher: Sha256 = Default::default();
    merkle_hasher.update(&merkle_hash);
    let merkle_result = format!("{:x}", merkle_hasher.finalize());

    println!("Record ID: {}", record_id);
    println!("Merkle Hash: {}", merkle_hash);
    println!("SHA Result: {}", merkle_result);
    println!("Merkle Leaf: {}", &merkle_result[..16]);
}

//Merkle Tree Path function
fn mix(x: &str, y: &str) -> Result<String, hex::FromHexError> {
    let mut leaves_hasher: Sha256 = Default::default();
    let a = hex::decode(x)?;
    let b = hex::decode(y)?;
    leaves_hasher.update(&a);
    leaves_hasher.update(&b);
    Ok(hex::encode(leaves_hasher.finalize()))
}

fn main() {
    println!("{}", mix("f42372aeb1be7296", "dfcced6ec3235f5e").unwrap());
    assert_eq!(
        mix("f42372aeb1be7296", "dfcced6ec3235f5e").unwrap(),
        "ad86a5ee2f21347403ce07e365530604690454fa76787e76be9d2f6efdceeabf"
    );
}
go

Go

package main

import (
	"crypto/sha256"
	"fmt"
)

//Merkle Leaf ID Calculation
func main() {

	accountCode := "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
	iiban := "AB12C34DEFG5KSQI"
	reviewId := "PR30NOV23"

	secret := accountCode + iiban + reviewId

	data := []byte(secret)
	hash := sha256.Sum256(data)
	recordId := string(hash[:])
	fmt.Printf("Record ID: %x\n", recordId)

	balances := "ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,DOT:50.0,DOT.S:20.5,DOT.P:0.0,DOT28.S:30.1,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002"

	merkleHash := fmt.Sprintf("%x%s%s", recordId, ",", balances)
	fmt.Printf("Merkle Hash: %s\n", merkleHash)

	hashResult := sha256.Sum256([]byte(merkleHash))
	hashResultStr := string(hashResult[:])
	fmt.Printf("SHA Result: %x\n", hashResultStr)
	fmt.Printf("Merkle Leaf: %x\n", hashResultStr[0:8])

}

//Merkle Tree path hashing
func mix(x, y string) (string, error) {
        // Convert the hex strings to bytes
        a, err := hex.DecodeString(x)
        if err != nil {
                return "", err
        }

        b, err := hex.DecodeString(y)
        if err != nil {
                return "", err
        }

        h := sha256.New()

        h.Write(a)
        h.Write(b)

        // Get the final hash value as a byte slice
        hashed := h.Sum(nil)

        // Convert the hash to a hex string and return it
        return hex.EncodeToString(hashed), nil
}

func main() {
        result, _ := mix("f42372aeb1be7296", "dfcced6ec3235f5e")
        fmt.Println(result)
}
bash

Bash

#!/bin/bash

#Merkle Leaf ID calculation
ACCOUNT_CODE="8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
IIBAN="AB12C34DEFG5KSQI"
REVIEW_ID="PR30NOV23"
RECORD_ID=$(echo -n "${ACCOUNT_CODE}${IIBAN}${REVIEW_ID}" | sha256sum | head -c 64)
BALANCES="ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,DOT:50.0,DOT.S:20.5,DOT.P:0.0,DOT28.S:30.1,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002"
MERKLE_HASH="${RECORD_ID},${BALANCES}"
HASH_RESULT=$(echo -n ${MERKLE_HASH} | sha256sum | head -c 64)

echo "Record ID: ${RECORD_ID}"
echo "Merkle Hash: ${MERKLE_HASH}"
echo "SHA Result: ${HASH_RESULT}"
echo "Merkle Leaf: $(echo -n ${HASH_RESULT} | head -c 16)"

#Merkle Tree Path function
hex_string1="f42372aeb1be7296"
hex_string2="dfcced6ec3235f5e"

# convert hex strings to binary, concatenate them and then hash
hash_result=$(echo -n "$(echo -n $hex_string1 | xxd -r -p)$(echo -n $hex_string2 | xxd -r -p)" | sha256sum | awk '{ print $1 }')

echo $hash_result

Shortcomings and future improvements

In the interest of championing transparency, we would like to share some of the shortcomings in the Proof of Reserves process that we’ve identified.

  • A Proof of Reserves involves proving control over on-chain funds at the point in time of the review, but cannot prove exclusive possession of private keys that may have theoretically been duplicated by an attacker.
  • The procedure cannot identify any hidden encumbrances or prove that funds had not been borrowed for purposes of passing the review. However, the movement of funds is visible on the blockchain, as we provide transparency over the addresses where our assets are located. Similarly, keys may have been lost or funds stolen since the latest review.
  • The accountant must be competent and independent to minimize the risk of duplicity on the part of the examinee or collusion amongst the parties.
  • We seek to mitigate some of these shortcomings by engaging with a respected, independent third party firm for our Proof of Reserves, and conducting these reviews at a regular cadence. We also provide transparency over this data directly in our client platform.