feat: add hermetica hbtc token and adapter#18479
feat: add hermetica hbtc token and adapter#18479anch09 wants to merge 7 commits intoDefiLlama:mainfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdded a new Stacks TVL adapter for Hermetica hBTC and updated token mappings; refactored the Hermetica module to remove custom Clarity parsing and to use concurrent contract calls for supply/share-price retrievals. Changes
Sequence Diagram(s)sequenceDiagram
participant Adapter as Hermetica-hBTC Adapter
participant SDK as Stacks SDK (`call`)
participant HB as hBTC Contract
participant HS as hBTC State Contract
Adapter->>SDK: call(get-total-supply) to HB
Adapter->>SDK: call(get-share-price) to HS
par Concurrent responses
SDK-->>HB: returns totalSupply (micro-units)
SDK-->>HS: returns sharePrice (micro-units)
end
Adapter->>Adapter: normalize values (/ 10**8) and compute TVL = totalSupply * sharePrice
Adapter-->>Client: return { bitcoin: <value> }
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The adapter at projects/hermetica exports TVL: |
|
The adapter at projects/hermetica-hbtc exports TVL: |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
projects/hermetica/stacks-call.js (2)
13-20: Potential precision loss when converting large integers to Number.The function converts the result to
Numberwhich can only safely represent integers up to2^53 - 1. For token supplies with 8 decimals, this limits accurate representation to ~90 million tokens. If hBTC or USDh supplies exceed this, you'll get precision errors.Consider returning the string representation or using BigInt throughout the calculation chain, or document this limitation if the expected supplies are well under this threshold.
💡 Option: Return BigInt and handle downstream
async function makeReadOnlyContractCall({ contract, function_name }) { const [contract_address, contract_name] = contract.split('.'); const response = await post( `https://api.mainnet.hiro.so/v2/contracts/call-read/${contract_address}/${contract_name}/${function_name}`, { sender: contract_address, arguments: [] } ); - return Number(parseClarityInt(response.result)); + return BigInt(parseClarityInt(response.result)); }Then handle BigInt division in the callers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@projects/hermetica/stacks-call.js` around lines 13 - 20, The makeReadOnlyContractCall function currently converts the Clarity integer result to a JavaScript Number causing precision loss for large token supplies; instead, preserve full precision by returning either the raw string from parseClarityInt or a BigInt (e.g., BigInt(parseClarityInt(...))) and update callers to handle string/BigInt arithmetic (or document the Number limitation). Locate makeReadOnlyContractCall and replace the Number(parseClarityInt(response.result)) conversion with a non-lossy return value (string or BigInt) and ensure downstream code that consumes makeReadOnlyContractCall (call sites) performs appropriate BigInt or string-based division/formatting.
3-11: Consider adding input validation for robustness.The
parseClarityIntfunction will fail with unclear errors ifresponse.resultfrom the API is undefined or malformed (e.g., when the contract call fails). This could happen if the Hiro API returns an error response structure.♻️ Proposed defensive check
function parseClarityInt(hexString) { + if (!hexString || typeof hexString !== 'string') { + throw new Error(`Invalid Clarity response: expected hex string, got ${typeof hexString}`); + } let hex = hexString.startsWith("0x") ? hexString.slice(2) : hexString; let numberHex = hex.slice(4);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@projects/hermetica/stacks-call.js` around lines 3 - 11, The parseClarityInt function lacks input validation and will throw on undefined/malformed input; update parseClarityInt to first validate that its hexString parameter is a non-empty string (and that response.result is present where it's called), then guard the "0x" check and slicing operations, and wrap the BigInt conversion in a try/catch to throw or return a descriptive error/value when parsing fails; reference the parseClarityInt function name and the BigInt conversion/overflow check branches to add these guards and clear error messages.projects/hermetica-hbtc/index.js (1)
9-9: Methodology description could be more precise.The methodology states "Counts the number of hBTC tokens" but the implementation actually returns BTC value (
hBTCSupply * sharePrice), not the raw token count. Consider updating to accurately describe the TVL calculation.📝 Suggested methodology update
- methodology: 'Counts the number of hBTC tokens on Stacks.', + methodology: 'TVL = hBTC supply on Stacks valued by hBTC share price (representing underlying BTC).',🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@projects/hermetica-hbtc/index.js` at line 9, Update the methodology string to accurately describe the TVL calculation: replace the current "Counts the number of hBTC tokens on Stacks." with a description stating that the module returns the BTC value (TVL) computed as hBTCSupply multiplied by sharePrice (i.e., hBTCSupply * sharePrice), and reference the variables/logic used to compute TVL (hBTCSupply and sharePrice) so the methodology matches the implementation in this file's methodology property.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@projects/hermetica-hbtc/index.js`:
- Line 2: Remove the unused import of the get function: delete the require
statement that brings in get (const { get } = require('../helper/http')) from
the top of the file so there are no unused imports remaining in
projects/hermetica-hbtc index.js.
---
Nitpick comments:
In `@projects/hermetica-hbtc/index.js`:
- Line 9: Update the methodology string to accurately describe the TVL
calculation: replace the current "Counts the number of hBTC tokens on Stacks."
with a description stating that the module returns the BTC value (TVL) computed
as hBTCSupply multiplied by sharePrice (i.e., hBTCSupply * sharePrice), and
reference the variables/logic used to compute TVL (hBTCSupply and sharePrice) so
the methodology matches the implementation in this file's methodology property.
In `@projects/hermetica/stacks-call.js`:
- Around line 13-20: The makeReadOnlyContractCall function currently converts
the Clarity integer result to a JavaScript Number causing precision loss for
large token supplies; instead, preserve full precision by returning either the
raw string from parseClarityInt or a BigInt (e.g., BigInt(parseClarityInt(...)))
and update callers to handle string/BigInt arithmetic (or document the Number
limitation). Locate makeReadOnlyContractCall and replace the
Number(parseClarityInt(response.result)) conversion with a non-lossy return
value (string or BigInt) and ensure downstream code that consumes
makeReadOnlyContractCall (call sites) performs appropriate BigInt or
string-based division/formatting.
- Around line 3-11: The parseClarityInt function lacks input validation and will
throw on undefined/malformed input; update parseClarityInt to first validate
that its hexString parameter is a non-empty string (and that response.result is
present where it's called), then guard the "0x" check and slicing operations,
and wrap the BigInt conversion in a try/catch to throw or return a descriptive
error/value when parsing fails; reference the parseClarityInt function name and
the BigInt conversion/overflow check branches to add these guards and clear
error messages.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7d5aef8c-7aa3-4e32-a2ca-3127100ba336
📒 Files selected for processing (4)
projects/helper/coreAssets.jsonprojects/hermetica-hbtc/index.jsprojects/hermetica/index.jsprojects/hermetica/stacks-call.js
|
The adapter at projects/hermetica exports TVL: |
|
The adapter at projects/hermetica-hbtc exports TVL: |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
projects/hermetica-hbtc/index.js (1)
5-5: Consider centralizing the state contract address in shared assets.
hBTCStateContractis hardcoded whilehBTCContractcomes fromcoreAssets.json. Putting both in one shared source reduces drift risk during contract upgrades.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@projects/hermetica-hbtc/index.js` at line 5, hBTCStateContract is hardcoded while hBTCContract is read from coreAssets.json—centralize both by moving hBTCStateContract into the shared assets file (e.g., coreAssets.json) and update the initializer that currently reads hBTCContract to also read hBTCStateContract; modify references to the constant name hBTCStateContract in projects/hermetica-hbtc/index.js to pull from the shared asset object (same key name you add) so both addresses are sourced from the single canonical asset (coreAssets) to avoid drift on upgrades.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@projects/hermetica-hbtc/index.js`:
- Line 8: Update the exported adapter's methodology string to accurately
describe the BTC-equivalent calculation instead of saying it simply "counts the
number of hBTC tokens"; specifically state that the adapter computes BTC value
by multiplying totalSupply by sharePrice (variables totalSupply and sharePrice)
to derive BTC-equivalent holdings and returns that BTC amount. Ensure the new
wording appears where the methodology property is defined so consumers see the
correct description.
---
Nitpick comments:
In `@projects/hermetica-hbtc/index.js`:
- Line 5: hBTCStateContract is hardcoded while hBTCContract is read from
coreAssets.json—centralize both by moving hBTCStateContract into the shared
assets file (e.g., coreAssets.json) and update the initializer that currently
reads hBTCContract to also read hBTCStateContract; modify references to the
constant name hBTCStateContract in projects/hermetica-hbtc/index.js to pull from
the shared asset object (same key name you add) so both addresses are sourced
from the single canonical asset (coreAssets) to avoid drift on upgrades.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cdb4c5f4-7368-4fc1-90d4-75d7f112baa0
📒 Files selected for processing (1)
projects/hermetica-hbtc/index.js
|
The adapter at projects/hermetica exports TVL: |
|
The adapter at projects/hermetica-hbtc exports TVL: |
|
projects/hermetica/stacks-call.js
Outdated
| @@ -0,0 +1,22 @@ | |||
| const { post } = require('../helper/http') | |||
|
|
|||
| function parseClarityInt(hexString) { | |||
There was a problem hiding this comment.
instead of using this new function, could you use the existing call helper, I tested it here and got the same output
There was a problem hiding this comment.
Hi,
I didn't use the call helper because when running the test it was throwing me Error loading module: Error: Cannot find module '@stacks/transactions' with MODULE_NOT_FOUND. And even after running npm install, seems that the module is not in the package.json file
There was a problem hiding this comment.
Why after the changes the bot doesn't display the TVL comments?
There was a problem hiding this comment.
hello, Im not sure why it wasnt working for you, but I tested your changes locally and it looked good to me (except the .value for microSharePrice)
projects/hermetica-hbtc/index.js
Outdated
| tvl: async () => { | ||
| const [microhBTCSupplyStacks, microSharePrice] = await Promise.all([ | ||
| makeReadOnlyContractCall({ contract: hBTCContract, function_name: 'get-total-supply' }), | ||
| makeReadOnlyContractCall({ contract: hBTCStateContract, function_name: 'get-share-price' }) |
There was a problem hiding this comment.
can you please share the bitcoin addresses where hBTC collateral is held? The docs mention using the sBTC bridge, is there a way to track the btc deposited for hBTC specifically?
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@projects/hermetica/index.js`:
- Around line 26-29: The code calls an undefined function
makeReadOnlyContractCall and passes wrong parameter names; replace that call
with the imported call function and adapt its signature to match call(target,
abi, optionalArgs) (mirror the bitcoin.tvl usage): use call(USDhContract,
'get-total-supply') (or the correct ABI shape expected by call) to fetch total
supply and assign to supplyOnStacksuUsdh; ensure you remove/replace references
to makeReadOnlyContractCall and update parameter names from
contract/function_name to the call() parameters used elsewhere.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 25da8338-218b-4960-a9d4-47da64bcaf36
📒 Files selected for processing (2)
projects/hermetica-hbtc/index.jsprojects/hermetica/index.js
✅ Files skipped from review due to trivial changes (1)
- projects/hermetica-hbtc/index.js
projects/hermetica-hbtc/index.js
Outdated
| call({ target: hBTCStateContract, abi: 'get-share-price' }) | ||
| ]); | ||
|
|
||
| const sharePrice = Number(microSharePrice.value) / (10 ** 8); |
There was a problem hiding this comment.
can you remove .value here, get-share-price returns only a number
There was a problem hiding this comment.
I just removed this. But I'm still not fully convinced that the call function will work. Looking at the main branch's package.json file doesn't contain the dependencies that the stacks call function wrapper need.
const stacks = require('@stacks/transactions')
const { STACKS_MAINNET, } = require('@stacks/network')
const { createApiKeyMiddleware, createFetchFn } = require('@stacks/common')
NOTE
Please enable "Allow edits by maintainers" while putting up the PR.
package-lock.jsonfile as part of your changes, we use lockfileVersion 2, and most use v1 and using that messes up our CIName (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):
Does this project have a referral program?
Summary by CodeRabbit
New Features
Improvements