✨ Add DeFindex protocol adaptor#2479
Conversation
Add yield adaptor for DeFindex protocol to retrieve APY and TVL data.
|
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:
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)
📝 WalkthroughWalkthroughNew Defindex Stellar adaptor exporting apy(timestamp), timetravel, start timestamp, and url; it fetches Defindex strategies, prefetches Stellar coin metadata from coins.llama.fi, computes per-strategy tvlUsd, filters tiny pools, and returns normalized strategy objects. ChangesDefindex Stellar Adaptor
Sequence Diagram(s)sequenceDiagram
actor Caller
participant Adaptor as Defindex Adaptor
participant DefindexAPI as defindex API
participant PricingAPI as coins.llama.fi
Caller->>Adaptor: apy(timestamp?)
Adaptor->>DefindexAPI: GET /strategies/apy?timestamp=<ts>&network=mainnet
DefindexAPI-->>Adaptor: strategies list
Adaptor->>Adaptor: extract unique assets
Adaptor->>PricingAPI: GET /coins/markets?keys=stellar:<asset>,...
PricingAPI-->>Adaptor: prices, symbols, decimals
Adaptor->>Adaptor: compute tvlUsd (strategy.tvl / 10^decimals * price)
Adaptor->>Adaptor: filter tvlUsd >= 1, build result objects
Adaptor-->>Caller: array of strategy objects (pool, chain, project, symbol, tvlUsd, apyBase, underlyingTokens, url)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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 |
There was a problem hiding this comment.
Pull request overview
This PR adds a new yield adapter for the DeFindex protocol on Stellar, fetching vault discovery data from DeFindex’s API and enriching it with USD TVL from DefiLlama coin prices.
Changes:
- Added a new
defindexadapter that pulls vaults from/vault/discover?network=mainnet. - Added DefiLlama coin-price lookup for Stellar assets and computes
tvlUsd. - Returns per-vault pool objects including
apyBase,tvlUsd,underlyingTokens, and metadata.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/adaptors/defindex/index.js (1)
32-36: Hardcoded decimals assumption for all Stellar assets.Using
STELLAR_DECIMALS = 7for all assets is standard for native Stellar assets (stroops), but custom tokens could potentially have different precision. The DefiLlama price API returns adecimalsfield per coin that's currently being discarded infetchCoinData.If all DeFindex vaults only hold standard Stellar assets, this is fine. Otherwise, consider capturing and using the decimals from the price API response.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/adaptors/defindex/index.js` around lines 32 - 36, The TVL calculation currently assumes a fixed STELLAR_DECIMALS when converting fund.total_amount to human units; update the logic in the tvlUsd calculation to read a per-asset decimals value from coinData (the decimals field returned by fetchCoinData) and use that for the divisor (i.e., divide by 10 ** decimals), falling back to STELLAR_DECIMALS if decimals is missing; also ensure fetchCoinData stores the decimals for each coin so tvlUsd (and any other uses) can look up coinData[asset].decimals instead of always using STELLAR_DECIMALS; reference tvlUsd, vault.totalManagedFunds, coinData, and fetchCoinData when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/adaptors/defindex/index.js`:
- Line 50: The generated URL has a double slash because API_BASE_URL already
ends with '/' and the request builds `${API_BASE_URL}/vault/${vault.address}`;
fix by removing the extra slash when composing the URL (e.g., build it as
`${API_BASE_URL}vault/${vault.address}`) or normalize API_BASE_URL by trimming
its trailing slash before use so that the call that uses API_BASE_URL and
vault.address produces a single slash.
- Around line 55-59: The module currently exports url: API_BASE_URL which is a
URL object; change the export to a plain string so consumers can perform string
operations—replace the exported value in module.exports (the url property) with
a string version of API_BASE_URL (e.g., API_BASE_URL.toString() or
API_BASE_URL.href or the literal URL string) while leaving apy and timetravel
unchanged.
---
Nitpick comments:
In `@src/adaptors/defindex/index.js`:
- Around line 32-36: The TVL calculation currently assumes a fixed
STELLAR_DECIMALS when converting fund.total_amount to human units; update the
logic in the tvlUsd calculation to read a per-asset decimals value from coinData
(the decimals field returned by fetchCoinData) and use that for the divisor
(i.e., divide by 10 ** decimals), falling back to STELLAR_DECIMALS if decimals
is missing; also ensure fetchCoinData stores the decimals for each coin so
tvlUsd (and any other uses) can look up coinData[asset].decimals instead of
always using STELLAR_DECIMALS; reference tvlUsd, vault.totalManagedFunds,
coinData, and fetchCoinData when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3c3760ba-8b70-4ee8-897c-a8e351277c19
📒 Files selected for processing (1)
src/adaptors/defindex/index.js
- Convert API_BASE_URL from URL object to plain string to fix double-slash in vault URLs and ensure module.exports.url is a string - Store per-asset decimals from coins API response and use them in TVL calculation instead of always assuming STELLAR_DECIMALS=7
|
The defindex adapter exports pools: Test Suites: 1 passed, 1 total |
0xkr3p
left a comment
There was a problem hiding this comment.
hey @MattPoblete, thanks for the PR just a couple of minor changes. Additionally, can you use the keepFinite filter on the pools?
Replace vault/discover with strategies/apy endpoint, add timetravel support with start timestamp, and filter pools with tvlUsd < 1.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/adaptors/defindex/index.js (1)
7-19: Minor: consider reusingutils.getPricesand guarding empty input.Other adaptors use the shared
exports.getPriceshelper insrc/adaptors/utils.jsforcoins.llama.filookups, which already handles thechain:addresskeying and response parsing. Reusing it would reduce duplication. Also, ifassetsis ever empty, the request URL becomeshttps://coins.llama.fi/prices/current/(trailing slash, empty keys) and may 404; a short-circuitif (!assets.length) return {};would make this robust independent of the caller's guard on line 28.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/adaptors/defindex/index.js` around lines 7 - 19, The fetchCoinData function should short-circuit when given no assets and reuse the shared getPrices helper to avoid duplication: add an early guard in fetchCoinData (e.g., if (!assets || !assets.length) return {}) and replace the manual axios call/response parsing with a call to the shared exports.getPrices (from src/adaptors/utils.js) so keys are constructed as chain:address and the response is parsed consistently; update fetchCoinData to map assets -> keys, call getPrices('stellar', keys) (or equivalent exported function name), and return the normalized address -> {price,symbol,decimals} result expected by callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/adaptors/defindex/index.js`:
- Around line 24-28: Replace the broken GET to
`${API_BASE_URL}/strategies/apy?timestamp=${ts}&network=mainnet` with a request
to `${API_BASE_URL}/vault/discover?network=mainnet`, remove the `ts`/timestamp
param, and then map the returned payload's `vaults` array to the code paths that
previously used `strategies`; specifically, replace uses of `strategies` with
`vaults`, use each vault's top-level numeric `apy` instead of `strategy.apy7d`,
and compute TVL by aggregating `vault.totalManagedFunds[].total_amount` (or
picking the appropriate total_amount entry) in place of `strategy.tvl`; also
update the existence check from `if (!strategies.length)` to check
`vaults.length` so the function returns [] when no vaults are returned.
- Line 48: The adapter assigns apyBase from strategy.apy7d but other adaptors
convert 7-day APY to percentage by multiplying by 100, so confirm whether
strategy.apy7d from DeFindex is already a percent; if it's a fraction (e.g.,
0.05) change the assignment to multiply by 100 (replace apyBase: strategy.apy7d
with apyBase: strategy.apy7d * 100) and ensure any negative strategy.apy7d
values are accepted only if they represent real losses (add validation or a
comment in the code near apyBase/strategy.apy7d to document the expected unit
and handle/normalize unexpected values).
- Line 50: The current per-strategy frontend URL uses Stellar Expert (`url:
\`https://stellar.expert/explorer/public/contract/${strategy.address}\``) but
the reviewer flagged this as incorrect for DeFindex and also noted line 59
should point to `https://www.defindex.io/vaults` (not `/strategies`); confirm
the correct DeFindex frontend pattern with the DeFindex team and then update the
URL assignment where `url` is set (using `strategy.address`) to the validated
per-strategy DeFindex route (e.g., change to
`https://www.defindex.io/vaults/${strategy.address}` only if confirmed), and
similarly replace any `/strategies` endpoint occurrences with `/vaults` if that
is the agreed route.
---
Nitpick comments:
In `@src/adaptors/defindex/index.js`:
- Around line 7-19: The fetchCoinData function should short-circuit when given
no assets and reuse the shared getPrices helper to avoid duplication: add an
early guard in fetchCoinData (e.g., if (!assets || !assets.length) return {})
and replace the manual axios call/response parsing with a call to the shared
exports.getPrices (from src/adaptors/utils.js) so keys are constructed as
chain:address and the response is parsed consistently; update fetchCoinData to
map assets -> keys, call getPrices('stellar', keys) (or equivalent exported
function name), and return the normalized address -> {price,symbol,decimals}
result expected by callers.
🪄 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: 74cb4374-54d6-4e58-b8c0-286355ef14e6
📒 Files selected for processing (1)
src/adaptors/defindex/index.js
| project: 'defindex', | ||
| symbol, | ||
| tvlUsd, | ||
| apyBase: strategy.apy7d, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect a sample payload to see the magnitude/shape of apy7d.
TS=$(date +%s)
curl -s "https://api.defindex.io/strategies/apy?timestamp=${TS}&network=mainnet" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d[:3] if isinstance(d,list) else d, indent=2))"Repository: DefiLlama/yield-server
Length of output: 193
🏁 Script executed:
cat -n src/adaptors/defindex/index.js | head -80Repository: DefiLlama/yield-server
Length of output: 2376
🏁 Script executed:
# Search for apy7d usage and related context
rg "apy7d" -B 3 -A 3Repository: DefiLlama/yield-server
Length of output: 34306
🏁 Script executed:
# Check if there are any transformations or calculations on apy values
rg "apyBase" -B 2 -A 2 | head -50Repository: DefiLlama/yield-server
Length of output: 2367
🏁 Script executed:
# Look for test files or sample data
fd -e "test\|spec\|json" | grep -i defindexRepository: DefiLlama/yield-server
Length of output: 48
🏁 Script executed:
# Look for DeFindex documentation or tests
find . -path ./node_modules -prune -o -type f \( -name "*defindex*" -o -name "*test*" -o -name "*spec*" \) -print | grep -i defindexRepository: DefiLlama/yield-server
Length of output: 48
🏁 Script executed:
# Check for any comments or documentation about defindex apy format
rg "defindex|DeFindex" -i -B 2 -A 2 --type md --type txtRepository: DefiLlama/yield-server
Length of output: 48
🏁 Script executed:
# Search for negative APY mentions
rg "negative|apy.*-|negative.*apy" -i | grep -i defindexRepository: DefiLlama/yield-server
Length of output: 48
🏁 Script executed:
# Check if there are any GitHub issues or comments about the defindex format
find . -name "*.md" -o -name "*.txt" | xargs grep -l -i "defindex" 2>/dev/nullRepository: DefiLlama/yield-server
Length of output: 50
🏁 Script executed:
# Search for any PR comments, commit messages, or issues mentioning defindex format
git log --all --oneline --grep="defindex" -i 2>/dev/null | head -20Repository: DefiLlama/yield-server
Length of output: 138
🏁 Script executed:
# Check if there's a changelog or updates file
find . -type f \( -name "CHANGELOG*" -o -name "CHANGES*" -o -name "NEWS*" \) | xargs grep -i defindex 2>/dev/nullRepository: DefiLlama/yield-server
Length of output: 50
🏁 Script executed:
# Look at git history of the defindex file itself
git log --oneline src/adaptors/defindex/index.js 2>/dev/null | head -10Repository: DefiLlama/yield-server
Length of output: 138
🏁 Script executed:
# Check if robo-vault provides clues (it multiplies by 100)
cat -n src/adaptors/robo-vault/index.js | grep -B 10 -A 5 "apy7d \* 100"Repository: DefiLlama/yield-server
Length of output: 607
🏁 Script executed:
# Check the actual commit to see what changed
git show 1a2aff49 --stat 2>/dev/null | head -30Repository: DefiLlama/yield-server
Length of output: 1740
🏁 Script executed:
# Get the diff for that commit to understand the strategy API change
git show 1a2aff49 -- src/adaptors/defindex/index.js 2>/dev/null | head -100Repository: DefiLlama/yield-server
Length of output: 2580
🏁 Script executed:
# Check if there are any comments in the PR or related issues
git log -p 1a2aff49 -- src/adaptors/defindex/index.js 2>/dev/null | grep -A 20 -B 5 "apy7d\|apy\|strategy" | head -80Repository: DefiLlama/yield-server
Length of output: 48
Confirm that apy7d units match DefiLlama's percentage format (not fraction).
The codebase pattern shows that other adaptors explicitly multiply by 100 (e.g., robo-vault: item.apy7d * 100, nest-credit: Number(apy7dSrc) * 100, hydro-inflow: result.avg_7_days * 100). If the DeFindex API returns apy7d as a decimal fraction (e.g., 0.05 for 5%), the current code will record it as 0.05 instead of 5, resulting in APY values 100× too small. Either verify that the API already returns percentages, or apply the * 100 transformation to match the codebase pattern. Also confirm whether negative apy7d values reflect genuine realized losses or indicate a data format issue.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/adaptors/defindex/index.js` at line 48, The adapter assigns apyBase from
strategy.apy7d but other adaptors convert 7-day APY to percentage by multiplying
by 100, so confirm whether strategy.apy7d from DeFindex is already a percent; if
it's a fraction (e.g., 0.05) change the assignment to multiply by 100 (replace
apyBase: strategy.apy7d with apyBase: strategy.apy7d * 100) and ensure any
negative strategy.apy7d values are accepted only if they represent real losses
(add validation or a comment in the code near apyBase/strategy.apy7d to document
the expected unit and handle/normalize unexpected values).
|
The defindex adapter exports pools: Test Suites: 1 passed, 1 total |
|
hi @MattPoblete, thanks for the changes. How can users deploy into the pools? I can't seem to find anywhere to deposit on https://www.defindex.io/strategies |
Summary
/strategies/apy?timestamp=<ts>&network=mainnet)starttimestamp (2025-05-15)tvlUsd < 1Test plan
npm run test --adapter=defindexand verify strategy data is returnedtvlUsdandapyBaseare non-zero for active strategieschainis"Stellar"andpoolIDs are uniqueSummary by CodeRabbit