Skip to content

Conversation

@Peyton-Spencer
Copy link
Contributor

@Peyton-Spencer Peyton-Spencer commented Oct 27, 2025

Summary

This adapter calculates the Bitcoin TVL for zrchain by querying actual Bitcoin addresses from the zrchain treasury and change addresses, then summing their Bitcoin balances using DefiLlama's Bitcoin helper.

Key Implementation Details

  • Data Source: Queries zrchain's treasury API endpoints to retrieve Bitcoin mainnet addresses
  • Address Coverage:
    • Treasury Addresses (296): Retrieved via paginated /zenbtc_wallets endpoint, filtered for WALLET_TYPE_BTC_MAINNET
    • Change Addresses (1): Retrieved from /zenbtc/params endpoint, then queried via /key_by_id API for each key ID
  • Balance Calculation: Uses DefiLlama's sumBitcoinTokens() helper from helper/chain/bitcoin.js to query actual BTC balances from Bitcoin blockchain
  • Total TVL: Combined Bitcoin balance across all 297 addresses = 74.05 BTC

Methodology

zrchain locks native Bitcoin through its decentralized MPC network. zenBTC, Zenrock's flagship product, is a yield-bearing wrapped Bitcoin issued on Solana and EVM chains. TVL represents the total Bitcoin locked in zrchain treasury addresses. All zenBTC is fully backed by native Bitcoin, with the price of zenBTC anticipated to increase as yield payments are made continuously.

References

Test Plan

  • Paginate through all zrchain treasury addresses
  • Retrieve change addresses from zenbtc params
  • Query actual Bitcoin balances for all addresses
  • Verify combined TVL calculation

🤖 Generated with Claude Code

- Tracks native Bitcoin locked by zrchain protocol across Ethereum and Solana
- Reports proportional Bitcoin distribution per chain from zrchain API
- Uses DefiLlama SDK helpers for both chains (Solana getTokenSupplies, Ethereum api.call)
- Implements promise-based caching to prevent redundant fetches with concurrent calls
- Derives Solana mint address from program ID using PDA with "wrapped_mint" seed
- Tested with live mainnet data: ~74 BTC across chains

Methodology: TVL represents total native Bitcoin locked by the protocol, with zenBTC as wrapped representations on each chain. Each zenBTC is backed by at least 1 BTC in custody, with yield mechanisms coming soon that will increase the backing ratio above 1:1.
@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

solana                    8.54 M
ethereum                  3.35 k

total                    8.54 M 

@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

solana                    8.55 M
ethereum                  3.35 k

total                    8.55 M 

@waynebruce0x
Copy link
Collaborator

Here we should count the collateral BTC held at bitcoin addresses on the bitcoin network

@waynebruce0x waynebruce0x self-assigned this Oct 27, 2025
@Peyton-Spencer
Copy link
Contributor Author

@waynebruce0x it's possible to query zrchain to get all the BTC addresses. Let me try this out and push to this PR. query all BTC addresses-> fetch balance for each. It will be a lot of addresses

@Peyton-Spencer
Copy link
Contributor Author

We can do this by paginating these addresses
https://api.diamond.zenrocklabs.io/zrchain/treasury/zenbtc_wallets?pagination.key=XXX

- Implement paginated fetching of Bitcoin mainnet addresses from zrchain treasury (297 addresses total)
- Replace custodied BTC API endpoint with actual on-chain balance queries using Bitcoin helper
- Add change address (bc1qngthd4lgz6pjkf24d2cesltlnd7nd0pjguuvqu) to treasury wallet list
- TVL now calculated from verified Bitcoin address balances (~74.05 BTC)
- Maintains proportional distribution across Ethereum and Solana zenBTC supplies

This provides transparent, on-chain verified TVL instead of relying on API-reported custodied amounts.
@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

solana                    8.52 M
ethereum                  3.34 k

total                    8.52 M 

- Replace hardcoded change address with dynamic fetching from zenbtc params API
- Implement getChangeAddresses() function that:
  - Fetches changeAddressKeyIDs from /zenbtc/params
  - Queries /zrchain/treasury/key_by_id/{keyID}/WALLET_TYPE_BTC_MAINNET/ for each key
  - Extracts addresses from wallet data
- Fetch treasury and change addresses in parallel for efficiency
- Update logging to show breakdown (296 treasury + 1 change = 297 total addresses)

This makes the adapter dynamic and resilient to future changes in the zenbtc configuration.
@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

solana                    8.52 M
ethereum                  3.34 k

total                    8.53 M 

@Peyton-Spencer
Copy link
Contributor Author

@waynebruce0x now fetching TVL via the BTC addresses. Fetching via the zrchain API.

…ation

The tvl() function now fetches both treasury and change addresses in parallel,
combining them to calculate the total Bitcoin TVL. This ensures accurate accounting
of all custodied Bitcoin across both wallet types.

Test results: 297 total addresses (296 treasury + 1 change) = 74.05 BTC TVL

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

bitcoin                   8.53 M

total                    8.53 M 

@Peyton-Spencer
Copy link
Contributor Author

@waynebruce0x I moved the TVL to bitcoin showing all of our locked BTC. We would like to open another PR soon to add Zenrock Chain (zrchain).

Copy link
Member

@g1nt0ki g1nt0ki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move treasury and change address fetching logic into the centralized
bitcoin-book/fetchers.js module. This allows code reuse across Bitcoin
adapters and better follows DefiLlama's organization patterns.

The zenrock fetcher uses getConfig for caching and returns all 297 addresses
(296 treasury + 1 change) for the adapter to use with the Bitcoin sumTokens helper.

Changes:
- Added zenrock fetcher to bitcoin-book/fetchers.js with getConfig caching
- Updated zenrock/index.js to use the new zenrock fetcher
- Simplified adapter to single tvl function that calls the fetcher
@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

bitcoin                   8.36 M

total                    8.36 M 

@Peyton-Spencer
Copy link
Contributor Author

@g1nt0ki I moved the address fetching logic, thanks for your review

@Peyton-Spencer Peyton-Spencer marked this pull request as draft October 31, 2025 15:01
@Peyton-Spencer
Copy link
Contributor Author

converting to draft due to adding zcash TVL, then will reopen

@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

bitcoin                   8.12 M
zcash                     168.99 k

total                    8.29 M 

@Peyton-Spencer Peyton-Spencer marked this pull request as ready for review October 31, 2025 22:11
@Peyton-Spencer
Copy link
Contributor Author

I updated the PR to include our zcash TVL for our new zenZEC token. I used the supply-based approach by querying zrchain for the custodied ZEC amount:
https://api.diamond.zenrocklabs.io/dct/supply

We plan to export TVL using the address-based approach. Monday I will look into our wallet list for zcash, but for now the supply based approach is exporting accurate ZEC TVL.

Address PR review feedback:

1. Removed all try-catch blocks that swallow errors - allow hard failures for monitoring
2. Removed console.log/console.error statements, rely on sdk.log
3. Cleaned up zcash.js:
   - Removed unused address-based balance functions
   - Removed fallback API endpoints (zcha.in, zcashnetwork.io)
   - Removed getBalanceNow and getBalance functions
   - Kept only cache API call functions
   - Changed cache delay from 3 hours to 1 hour
4. Removed zenrockDCT import from zenrock adapter (not currently used)
5. Removed commented-out address-based zcash TVL function
6. Simplified adapter code

Test results: Adapter exports 303 total addresses (bitcoin + zcash):
- Bitcoin: 8.00 M from 296 treasury + 1 change address
- Zcash: 188.07k (supply-based approach)
@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

bitcoin                   8.00 M
zcash                     188.07 k

total                    8.19 M 

@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

bitcoin                   7.92 M
zcash                     201.99 k

total                    8.12 M 

@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

bitcoin                   7.92 M
zcash                     202.37 k

total                    8.12 M 

@llamabutler
Copy link

The adapter at projects/zenrock exports TVL:

bitcoin                   7.86 M
zcash                     200.90 k

total                    8.06 M 

@Peyton-Spencer
Copy link
Contributor Author

Hi @waynebruce0x I have removed all try/catch and removed the getEnv('ZCASH_CACHE_API').

I went with the "supply method" for zcash TVL.

We have this API endpoint for returning all the zcash addresses custodied by our protocol:
https://api.diamond.zenrocklabs.io/zrchain/treasury/dct_wallets?asset_type=ASSET_ZENZEC

However, I was timing out when I tried to sum up all the balances in these addresses. So, this PR is using our endpoint for total ZEC custodied:
https://api.diamond.zenrocklabs.io/dct/supply

This allows for a single making the TVL return quicker. So, for BTC we are summing the balances in all addresses while ZEC we are multiplying custodied assets * price of ZEC.

Let me know if you need any changes, thanks!

@waynebruce0x waynebruce0x merged commit f6bfdf4 into DefiLlama:main Nov 4, 2025
1 check passed
@realdealshaman
Copy link
Contributor

Hey @Peyton-Spencer thanks for the PR! Please also fill out the listing_template details:

Name (to be shown on DefiLlama):
Twitter Link:
List of audit links if any:
Website Link:
Logo (High resolution, will be shown with rounded borders):
Current TVL:
Treasury Addresses (if the protocol has treasury)
Chain:
Coingecko ID (so your TVL can appear on Coingecko, leave empty if not listed): (https://api.coingecko.com/api/v3/coins/list)
Coinmarketcap ID (so your TVL can appear on Coinmarketcap, leave empty if not listed): (https://api.coinmarketcap.com/data-api/v3/map/all?listing_status=active,inactive,untracked&start=1&limit=10000)
Short Description (to be shown on DefiLlama):
Token address and ticker if any:
Category (full list at https://defillama.com/categories) *Please choose only one:
Oracle Provider(s): Specify the oracle(s) used (e.g., Chainlink, Band, API3, TWAP, etc.):
Implementation Details: Briefly describe how the oracle is integrated into your project:
Documentation/Proof: Provide links to documentation or any other resources that verify the oracle's usage:
forkedFrom (Does your project originate from another project):
methodology (what is being counted as tvl, how is tvl being calculated):
Github org/user (Optional, if your code is open source, we can track activity):

@Peyton-Spencer
Copy link
Contributor Author

Hey @realdealshaman should I open up a new PR with these additions since this one has been merged?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants