Proof of Reserve

A verification mechanism that cryptographically proves on-chain token supply is backed by real off-chain or cross-chain assets.

Proof of Reserve (PoR) is a cryptographic verification method that proves the assets backing a token or protocol actually exist. In DeFi, PoR is used to verify that wrapped tokens, stablecoins, and Real World Asset tokens are fully collateralized by their claimed reserves. This prevents fractional reserve fraud where issuers mint more tokens than they have backing assets—a practice that has led to major collapses in crypto history.

Why Proof of Reserve Matters

Without PoR, users must trust issuers aren't printing unbacked tokens:

1Scenario: Wrapped Bitcoin (WBTC)
2- Claims: 1 WBTC = 1 BTC held in custody
3- Risk: Custodian mints WBTC without depositing BTC
4- Result: Token becomes partially backed, eventual collapse

PoR provides cryptographic verification that reserves match or exceed circulating supply.

How Proof of Reserve Works

On-Chain Verification

1import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
2
3contract TokenWithPoR {
4 AggregatorV3Interface public reserveFeed;
5
6 function mint(uint256 amount) external onlyMinter {
7 // Get verified reserve amount from Chainlink PoR feed
8 (, int256 reserves,,,) = reserveFeed.latestRoundData();
9
10 // Ensure supply never exceeds reserves
11 require(
12 totalSupply() + amount <= uint256(reserves),
13 "Insufficient reserves"
14 );
15
16 _mint(msg.sender, amount);
17 }
18
19 function getReserveRatio() external view returns (uint256) {
20 (, int256 reserves,,,) = reserveFeed.latestRoundData();
21 if (totalSupply() == 0) return type(uint256).max;
22 return uint256(reserves) * 1e18 / totalSupply();
23 }
24}

Chainlink Proof of Reserve

Chainlink provides PoR feeds for various asset types:

Cross-Chain Reserves: Verify BTC/ETH locked on other chains Off-Chain Reserves: Verify bank balances, custody holdings Self-Attested Reserves: Protocol-reported reserves with oracle delivery

1// Example: WBTC Reserve Feed
2AggregatorV3Interface wbtcReserves = AggregatorV3Interface(
3 0x... // Chainlink WBTC PoR feed address
4);
5
6function checkCollateralization() public view returns (bool) {
7 (, int256 btcReserves,,,) = wbtcReserves.latestRoundData();
8 return uint256(btcReserves) >= wbtcToken.totalSupply();
9}

Types of Proof of Reserve

Cross-Chain PoR

Verify assets locked on another blockchain:

1Bitcoin locked in custody → Chainlink nodes verify → On-chain feed
2
3WBTC minted on Ethereum ≤ Verified BTC amount

Off-Chain PoR

Verify traditional assets (bank accounts, commodities):

1Bank account balance → Third-party attestation → Chainlink feed
2
3Stablecoin supply ≤ Verified USD balance

Smart Contract PoR

Verify DeFi protocol collateralization:

1// Verify lending protocol solvency
2function getLendingReserves() public view returns (uint256) {
3 return totalDeposits - totalBorrows + collateralValue;
4}

PoR in Practice

Stablecoins

1contract Stablecoin {
2 AggregatorV3Interface public usdReserves;
3
4 modifier ensureBacking(uint256 mintAmount) {
5 (, int256 reserves,,,) = usdReserves.latestRoundData();
6 require(
7 totalSupply() + mintAmount <= uint256(reserves),
8 "Insufficient USD backing"
9 );
10 _;
11 }
12
13 function mint(address to, uint256 amount)
14 external
15 onlyMinter
16 ensureBacking(amount)
17 {
18 _mint(to, amount);
19 }
20}

Wrapped Tokens

1contract WrappedAsset {
2 // Circuit breaker if reserves drop
3 function checkHealth() public view returns (bool) {
4 (, int256 reserves,,,) = reserveFeed.latestRoundData();
5 uint256 ratio = uint256(reserves) * 100 / totalSupply();
6 return ratio >= MIN_RESERVE_RATIO; // e.g., 100%
7 }
8
9 modifier whenHealthy() {
10 require(checkHealth(), "Reserve ratio too low");
11 _;
12 }
13
14 function redeem(uint256 amount) external whenHealthy {
15 _burn(msg.sender, amount);
16 // Release underlying asset
17 }
18}

RWA Tokens

For tokenized Real World Assets:

1contract RWAToken {
2 // PoR verifies physical assets back the tokens
3 function verifyBacking() external view returns (bool, string memory) {
4 (, int256 assetValue,,,) = porFeed.latestRoundData();
5 uint256 tokenValue = totalSupply() * pricePerToken;
6
7 if (uint256(assetValue) >= tokenValue) {
8 return (true, "Fully backed");
9 } else {
10 return (false, "Under-collateralized");
11 }
12 }
13}

Security Considerations

Feed Staleness

PoR feeds may not update in real-time:

1function getReserves() public view returns (uint256) {
2 (
3 uint80 roundId,
4 int256 reserves,
5 uint256 startedAt,
6 uint256 updatedAt,
7 uint80 answeredInRound
8 ) = reserveFeed.latestRoundData();
9
10 // Check freshness
11 require(block.timestamp - updatedAt < MAX_STALENESS, "Stale PoR data");
12 require(reserves > 0, "Invalid reserves");
13
14 return uint256(reserves);
15}

Attestation Trust

For off-chain reserves, you trust the attestor:

  • Who performs the audit?
  • How often?
  • What's their liability?

Flash Loan Considerations

PoR checks should happen atomically with minting:

1// VULNERABLE: Separate check and mint
2function checkThenMint(uint256 amount) external {
3 require(checkReserves(amount), "Insufficient reserves");
4 // Attacker could manipulate reserves here
5 _mint(msg.sender, amount);
6}
7
8// SECURE: Atomic check
9function secureMint(uint256 amount) external {
10 (, int256 reserves,,,) = reserveFeed.latestRoundData();
11 require(totalSupply() + amount <= uint256(reserves), "Insufficient");
12 _mint(msg.sender, amount);
13}

Audit Checklist

When auditing Proof of Reserve implementations:

  • PoR checked before every mint
  • Feed staleness validated
  • Atomic check-and-mint pattern
  • Reserve ratio thresholds appropriate
  • Circuit breakers on under-collateralization
  • Feed address immutable or properly governed
  • Decimal handling correct
  • Trust assumptions documented

Notable PoR Implementations

AssetPoR ProviderReserve Type
WBTCChainlinkCross-chain BTC
USDCThird-party auditsBank accounts
PAXGChainlinkGold bars
stETHChainlinkBeacon chain ETH

Proof of Reserve brings transparency to backed assets, reducing counterparty risk and enabling trustless verification of collateralization—a critical component for stablecoins, wrapped assets, and RWA tokens.

Need expert guidance on Proof of Reserve?

Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.

Get a Quote

oog
zealynx

Subscribe to Our Newsletter

Stay updated with our latest security insights and blog posts

© 2024 Zealynx