Add Cardano native SPO staking adapter#18485
Add Cardano native SPO staking adapter#18485mauriciomagaldi wants to merge 2 commits intoDefiLlama:mainfrom
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughA new Cardano SPO staking module was added that queries the Koios API for the chain tip and epoch info, reads Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 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/cardano-spo-staking exports TVL: |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/cardano-spo-staking/index.js`:
- Around line 16-18: The code assumes get(`${KOIOS_API}/tip`) returns a
non-empty array and directly destructures into tip then reads tip.epoch_no; add
a defensive check after awaiting get(...) to verify the response is an array
with at least one element and that the first element has epoch_no (e.g., ensure
response && response.length > 0 and response[0].epoch_no !== undefined), and if
not, log/throw a clear error (using existing logger or throw) so currentEpoch is
not read from undefined; update the variables where tip and currentEpoch are
assigned in index.js to use this validation.
- Around line 29-35: Validate that epochInfo is an array with at least one
element before accessing epochInfo[0], and replace Number(...) conversion with
BigInt parsing for epochInfo[0].active_stake (e.g., const activeStakeLovelace =
BigInt(epochInfo[0].active_stake)); compute ADA safely by dividing and
formatting the BigInt (use integer division and remainder to produce a decimal
string or return the ADA amount as a string) and return that string under the
cardano key instead of a Number; update references to activeStakeLovelace and
the return object accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9d37b87c-4c7c-4175-9f95-b7b6934ce21b
📒 Files selected for processing (1)
projects/cardano-spo-staking/index.js
| // active_stake is returned in lovelace (1 ADA = 1,000,000 lovelace) | ||
| const activeStakeLovelace = Number(epochInfo[0].active_stake); | ||
|
|
||
| // Return as ADA using coingecko ID; DeFi Llama SDK handles USD conversion | ||
| return { | ||
| cardano: activeStakeLovelace / 1e6, | ||
| }; |
There was a problem hiding this comment.
Precision loss: active_stake exceeds Number.MAX_SAFE_INTEGER.
The PR states ~21.82B ADA staked, which equals ~21.82 × 10¹⁵ lovelace. JavaScript's Number.MAX_SAFE_INTEGER is ~9 × 10¹⁵, so Number(epochInfo[0].active_stake) will lose precision for current Cardano staking levels.
Additionally, there's no validation that epochInfo contains data before accessing epochInfo[0].
Proposed fix using BigInt for safe conversion
- // active_stake is returned in lovelace (1 ADA = 1,000,000 lovelace)
- const activeStakeLovelace = Number(epochInfo[0].active_stake);
-
- // Return as ADA using coingecko ID; DeFi Llama SDK handles USD conversion
- return {
- cardano: activeStakeLovelace / 1e6,
- };
+ // active_stake is returned in lovelace (1 ADA = 1,000,000 lovelace)
+ // Use BigInt to avoid precision loss for values exceeding Number.MAX_SAFE_INTEGER
+ if (!epochInfo || !epochInfo.length || !epochInfo[0].active_stake) {
+ throw new Error(`No active_stake data for epoch ${epochToQuery}`);
+ }
+ const activeStakeLovelace = BigInt(epochInfo[0].active_stake);
+ const activeStakeAda = Number(activeStakeLovelace / BigInt(1e6));
+
+ // Return as ADA using coingecko ID; DeFi Llama SDK handles USD conversion
+ return {
+ cardano: activeStakeAda,
+ };📝 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.
| // active_stake is returned in lovelace (1 ADA = 1,000,000 lovelace) | |
| const activeStakeLovelace = Number(epochInfo[0].active_stake); | |
| // Return as ADA using coingecko ID; DeFi Llama SDK handles USD conversion | |
| return { | |
| cardano: activeStakeLovelace / 1e6, | |
| }; | |
| // active_stake is returned in lovelace (1 ADA = 1,000,000 lovelace) | |
| // Use BigInt to avoid precision loss for values exceeding Number.MAX_SAFE_INTEGER | |
| if (!epochInfo || !epochInfo.length || !epochInfo[0].active_stake) { | |
| throw new Error(`No active_stake data for epoch ${epochToQuery}`); | |
| } | |
| const activeStakeLovelace = BigInt(epochInfo[0].active_stake); | |
| const activeStakeAda = Number(activeStakeLovelace / BigInt(1e6)); | |
| // Return as ADA using coingecko ID; DeFi Llama SDK handles USD conversion | |
| return { | |
| cardano: activeStakeAda, | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@projects/cardano-spo-staking/index.js` around lines 29 - 35, Validate that
epochInfo is an array with at least one element before accessing epochInfo[0],
and replace Number(...) conversion with BigInt parsing for
epochInfo[0].active_stake (e.g., const activeStakeLovelace =
BigInt(epochInfo[0].active_stake)); compute ADA safely by dividing and
formatting the BigInt (use integer division and remainder to produce a decimal
string or return the ADA amount as a string) and return that string under the
cardano key instead of a Number; update references to activeStakeLovelace and
the return object accordingly.
|
The adapter at projects/cardano-spo-staking exports TVL: |
|
sorry, we are not tracking staking for chains atm |
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):
Cardano SPO Staking
Twitter Link:
https://x.com/Cardano
List of audit links if any:
N/A — This adapter queries Cardano's native Ouroboros PoS consensus layer, not a smart contract. The staking mechanism is part of the core protocol, peer-reviewed and formally verified by IOHK Research (https://iohk.io/en/research/library/).
Website Link:
https://cardano.org/stake-pool-operation
Logo (High resolution, preferably in .svg and .png, for application on both white and black backgrounds. Will be shown with rounded borders):
https://cryptologos.cc/logos/cardano-ada-logo.svg https://cryptologos.cc/logos/cardano-ada-logo.png
Current TVL:
Treasury Addresses (if the protocol has treasury):
N/A — Native protocol-level staking, not a contract with a treasury address.
Chain:
Cardano
Coingecko ID (so your TVL can appear on Coingecko, leave empty if not listed):
cardano
Coinmarketcap ID (so your TVL can appear on Coinmarketcap):
https://coinmarketcap.com/currencies/cardano/
Short Description (to be shown on DefiLlama):
Cardano's native proof-of-stake delegation to ~2,948 stake pool operators (SPOs) via the Ouroboros consensus protocol. ADA holders delegate to pools without locking — staked ADA remains liquid and spendable at all times with no unbonding period.
Token address and ticker if any:
ADA (native token, no contract address)
Category (Yield/Dexes/Lending/Minting/Assets/Insurance/Options/Indexes/Staking):
Staking
Methodology:
Counts the total ADA actively delegated to all Cardano stake pool operators (SPOs) via the Ouroboros proof-of-stake consensus mechanism. Data is sourced from the Koios decentralized API's
/epoch_infoendpoint, which reports the aggregateactive_stake(in lovelace) snapshot across all registered stake pools for each epoch (~5 days). The adapter queries the most recently completed epoch to ensure the stake snapshot is finalized.Github org/user (Optional, if your code is open source):
https://github.com/cardano-community/koios-artifacts (data source) https://github.com/IntersectMBO/cardano-node (protocol)
Additional Context
Why this adapter is needed: Over 63% of circulating ADA (~21.82B ADA, ~$6.3B) is delegated to SPOs, but this is currently invisible on DeFi Llama. The existing Cardano "Total Staked" page shows only ~$27.9M from DeFi protocol-level staking (governance token staking in protocols like SundaeSwap, Liqwid). This adapter surfaces the native chain-level PoS staking under the "Staking" toggle, not default TVL.
Data source: Koios (https://api.koios.rest) — a decentralized, community-maintained, open-source REST API for Cardano blockchain data, operated by multiple independent node providers globally. It reads directly from
cardano-db-sync, which indexes on-chain ledger state. Theactive_stakevalue comes from the Cardano ledger's epoch boundary snapshot.Cross-reference validation:
Key distinction: Cardano staking is natively liquid — delegated ADA is never locked, has no unbonding period, and can be spent/moved at any time while still earning rewards.
Summary by CodeRabbit