chainflip-lending: fix tvlUsd (was Supplied, should be available liquidity) and migrate to on-chain RPC#2762
Conversation
…idity) and migrate to on-chain RPC
📝 WalkthroughWalkthroughThe Chainflip lending adapter is rewritten to query the Chainflip Substrate RPC ( Chainflip Lending Adapter Rewrite
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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 chainflip-lending adapter exports pools: Test Suites: 1 passed, 1 total |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/adaptors/chainflip-lending/index.ts (1)
104-106: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winRoute price lookups through the shared price helper.
This direct
coins.llama.ficall bypassesutils.getPriceApiData, so deployments withDL_API_KEYwon’t use the configured pro-api path fromsrc/adaptors/utils.js.Proposed refactor
- const { data: priceData } = await axios.get( - `https://coins.llama.fi/prices/current/${cgIds}` - ); + const priceData = await utils.getPriceApiData(`/prices/current/${cgIds}`);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/adaptors/chainflip-lending/index.ts` around lines 104 - 106, The Chainflip lending price fetch currently calls coins.llama.fi directly, bypassing the shared pricing flow. Update the price lookup in the Chainflip adaptor to use utils.getPriceApiData instead of axios.get so deployments with DL_API_KEY follow the configured pro-api path. Keep the logic localized around the price retrieval in the index.ts adaptor and preserve the existing cgIds-based lookup behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/adaptors/chainflip-lending/index.ts`:
- Around line 88-90: The cfRpc helper currently returns data.result
unconditionally, so JSON-RPC responses containing an error object but no result
will flow downstream as undefined and break onchainPools.map. Update cfRpc to
inspect the parsed axios response payload before returning, check for a JSON-RPC
error field, and throw or otherwise surface that error with its details instead
of returning result. Keep the fix localized to cfRpc in the chainflip-lending
adaptor so callers only receive valid RPC results.
---
Nitpick comments:
In `@src/adaptors/chainflip-lending/index.ts`:
- Around line 104-106: The Chainflip lending price fetch currently calls
coins.llama.fi directly, bypassing the shared pricing flow. Update the price
lookup in the Chainflip adaptor to use utils.getPriceApiData instead of
axios.get so deployments with DL_API_KEY follow the configured pro-api path.
Keep the logic localized around the price retrieval in the index.ts adaptor and
preserve the existing cgIds-based lookup behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c99cc3db-c3ec-4d0b-a1a7-6094a8e2f722
📒 Files selected for processing (1)
src/adaptors/chainflip-lending/index.ts
| async function cfRpc(method: string, params: unknown[] = []): Promise<any> { | ||
| const { data } = await axios.post(RPC_ENDPOINT, { jsonrpc: '2.0', method, params, id: 1 }); | ||
| return data.result; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Handle JSON-RPC error payloads before returning result.
A JSON-RPC call can fail with an error object while still returning HTTP 200; returning data.result unconditionally makes the downstream onchainPools.map(...) crash as undefined.
Proposed fix
async function cfRpc(method: string, params: unknown[] = []): Promise<any> {
const { data } = await axios.post(RPC_ENDPOINT, { jsonrpc: '2.0', method, params, id: 1 });
+ if (data?.error) {
+ const message = data.error.message ?? JSON.stringify(data.error);
+ throw new Error(`Chainflip RPC ${method} failed: ${message}`);
+ }
+ if (!data || !('result' in data)) {
+ throw new Error(`Chainflip RPC ${method} returned no result`);
+ }
return data.result;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async function cfRpc(method: string, params: unknown[] = []): Promise<any> { | |
| const { data } = await axios.post(RPC_ENDPOINT, { jsonrpc: '2.0', method, params, id: 1 }); | |
| return data.result; | |
| async function cfRpc(method: string, params: unknown[] = []): Promise<any> { | |
| const { data } = await axios.post(RPC_ENDPOINT, { jsonrpc: '2.0', method, params, id: 1 }); | |
| if (data?.error) { | |
| const message = data.error.message ?? JSON.stringify(data.error); | |
| throw new Error(`Chainflip RPC ${method} failed: ${message}`); | |
| } | |
| if (!data || !('result' in data)) { | |
| throw new Error(`Chainflip RPC ${method} returned no result`); | |
| } | |
| return data.result; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/adaptors/chainflip-lending/index.ts` around lines 88 - 90, The cfRpc
helper currently returns data.result unconditionally, so JSON-RPC responses
containing an error object but no result will flow downstream as undefined and
break onchainPools.map. Update cfRpc to inspect the parsed axios response
payload before returning, check for a JSON-RPC error field, and throw or
otherwise surface that error with its details instead of returning result. Keep
the fix localized to cfRpc in the chainflip-lending adaptor so callers only
receive valid RPC results.
chainflip-lending: fix tvlUsd (was Supplied, should be available liquidity) and migrate to on-chain RPC
What this PR does
Fixes a methodology error in
tvlUsdand migrates all data to the ChainflipSubstrate node RPC, removing the dependency on an external indexer API. APY is
now also computed from on-chain fields instead of being forwarded from a
third-party endpoint.
The bug — tvlUsd was reporting Supplied, not TVL
The previous adapter fetched
pool.tvlfromhttps://explorer-service-processor.chainflip.io/defi-llama/yield.That field maps to
total_amounton-chain — the total amount supplied bylenders, including the portion already lent out to borrowers. In DefiLlama's
taxonomy that figure is Supplied (= TVL + Borrowed), not TVL.
For a pool with near-full utilisation the error is dramatic:
Total overstatement: ~$814 K across the five pools.
The correct value for
tvlUsdis the idle liquidity in each pool —available_amountfrom the on-chain RPC — which is exactly what yieldaggregators display as "available to borrow" or "pool liquidity".
Methodology alignment with Aave v3 and Compound v3
In Aave v3's yield-server adapter,
tvlUsdfor each reserve is theunderlying token balance held by the Pool contract (i.e. liquidity not yet
lent out). In Compound v3 it is
totalSupply - totalBorrowper Comet market.Both represent idle capital, not total deposits.
Chainflip's equivalent is
pool.available_amountfromcf_lending_pools:APY methodology
Supply APY is derived from two Permill fields (parts per million, 1 000 000 = 100 %)
returned by
cf_lending_pools:Per
cf_lending_config,extra_interest = 0: the network takes no continuousshare of borrow interest. The 100 % of
current_interest_rateaccrues tolenders. The formula is therefore the direct on-chain equivalent of Aave's
liquidityRate / RAY × 100.The previous adapter forwarded the
apyfield from the external indexer API,which includes one-shot origination fees (1 % per loan, 80 % to lenders)
accumulated over historical loan origination volume. That component cannot be
derived from a single chain snapshot — the same limitation that prevents Aave
adapters from including flash-loan fee revenue in
apyBase. The on-chainformula is conservative and will understate yield for pools with high
origination turnover (most visibly BTC at current low utilisation), but it is
the correct and auditable approach.
Data source
All data comes from a single RPC call to the Chainflip mainnet Substrate node:
Returns per-asset:
available_amount,total_amount,current_interest_rate,utilisation_rate— everything needed for bothtvlUsdandapyBase.Asset prices are fetched from
coins.llama.fiusing standard coingecko IDs(bitcoin, ethereum, solana, tether, usd-coin). No external indexer is used.
Files changed
src/adaptors/chainflip-lending/index.ts— full rewriteTest output (live chain data)
Note: BTC
apyBase(0.22 %) reflects the instantaneous interest rate only.Actual lender yield is higher due to origination fees on short-term loans, but
those require historical chain indexing to quantify — out of scope for a
snapshot adapter.
Summary by CodeRabbit