Skip to content

Add stakeTHENA erc4626 vault on BSC#2499

Open
ftm1337 wants to merge 3 commits intoDefiLlama:masterfrom
ftm1337:master
Open

Add stakeTHENA erc4626 vault on BSC#2499
ftm1337 wants to merge 3 commits intoDefiLlama:masterfrom
ftm1337:master

Conversation

@ftm1337
Copy link
Copy Markdown
Contributor

@ftm1337 ftm1337 commented Mar 21, 2026

Summary by CodeRabbit

  • New Features
    • Added support for Guru Network Classic vaults: the app now discovers ERC-4626-based vault wrappers, displays per-vault APY and TVL (priced in USD using live token prices), lists underlying token addresses, and links to each vault's details page. Timetravel-enabled historical APY/TVL queries supported.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 21, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f7f878d1-ff7a-463d-a516-5a618f270607

📥 Commits

Reviewing files that changed from the base of the PR and between f07c1a9 and 9ed4dc9.

📒 Files selected for processing (1)
  • src/adaptors/guru-network-classic/index.js

📝 Walkthrough

Walkthrough

New adapter module guru-network-classic added; it fetches token prices, queries ERC‑4626 vault info for configured wrappers, computes USD TVL per vault using token decimals and prices, and returns standardized pool objects with apy, tvlUsd, underlyingTokens, and url.

Changes

Cohort / File(s) Summary
Guru Network Classic Adapter
src/adaptors/guru-network-classic/index.js
Added new adapter exporting timetravel: true and apy (async main). Introduces a fixed wrappers list, fetches token prices from coins.llama.fi via Axios, retrieves ERC‑4626 info via utils.getERC4626Info, computes tvlUsd = erc4626.tvl / 10^decimals * price, and returns pool objects (pool, chain, project, symbol, apyBase, underlyingTokens, url). Omits entries when price or decimals missing.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Adapter as Guru\ Adapter
    participant PriceAPI as coins.llama.fi
    participant Utils as utils.getERC4626Info
    participant Result as Results

    Client->>Adapter: call main()/apy()
    Adapter->>PriceAPI: fetch prices for underlying token list
    PriceAPI-->>Adapter: return price and decimals
    Adapter->>Utils: request ERC‑4626 info for each wrapper (concurrent)
    Utils-->>Adapter: return vault info (tvl, decimals, apyBase, etc.)
    Adapter->>Adapter: compute tvlUsd = ERC4626_TVL / 10^decimals * token_price
    Adapter->>Result: assemble pool result objects
    Result-->>Client: return array of pool results
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hop through prices, decimals, and vault,
Counting TVLs in a neat little vault,
APYs tucked in each tiny line,
One wrapper, one price — all aligns. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add stakeTHENA erc4626 vault on BSC' accurately and specifically describes the main change: adding a new ERC-4626 vault adapter for stakeTHENA on Binance Smart Chain.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@llamatester
Copy link
Copy Markdown

The guru-network-classic adapter exports pools:

Test Suites: 1 passed, 1 total
Tests: 10 passed, 10 total
Snapshots: 0 total
Time: 0.28 s
Ran all test suites.

Nb of pools: 1
 

Sample pools:
┌─────────┬──────────────────────────────────────────────┬───────┬────────────────────────┬──────────────┬───────────────────┬───────────────────┬──────────────────────────────────────────────────┬────────────────────────────────────┐
│ (index) │ pool                                         │ chain │ project                │ symbol       │ tvlUsd            │ apyBase           │ underlyingTokens                                 │ url                                │
├─────────┼──────────────────────────────────────────────┼───────┼────────────────────────┼──────────────┼───────────────────┼───────────────────┼──────────────────────────────────────────────────┼────────────────────────────────────┤
│ 0       │ '0x5b8ce6d591c914a56cb019b3decb63ede22708c8' │ 'bsc' │ 'guru-network-classic' │ 'stakeTHENA' │ 38994.39116070418 │ 49.00485385384505 │ [ '0xafbe3b8b0939a5538de32f7752a78e08c8492295' ] │ 'https://eliteness.network/ethena' │
└─────────┴──────────────────────────────────────────────┴───────┴────────────────────────┴──────────────┴───────────────────┴───────────────────┴──────────────────────────────────────────────────┴────────────────────────────────────┘

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 `@src/adaptors/guru-network-classic/index.js`:
- Around line 17-21: The axios call that builds `prices` should include a
timeout (e.g., pass `{ timeout: 10_000 }`) to avoid hanging requests, and
downstream access to price data (where `prices[token].decimals` and
`prices[token].price` are used) must be guarded with optional chaining and
existence checks (e.g., `prices[token]?.price`) or skip/handle missing entries
from `wrappers` so the adapter doesn't throw; update the axios.get invocation
that uses `wrappers.map(...)` to include the timeout option and modify the code
paths that read `prices[token]` to check for a truthy entry (or provide a safe
default/skip) using the `prices` variable and the `token` identifier.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d1fb80cc-f29f-41a3-95bf-cc4e18d2b375

📥 Commits

Reviewing files that changed from the base of the PR and between 7532320 and 7824d92.

📒 Files selected for processing (1)
  • src/adaptors/guru-network-classic/index.js

@llamatester
Copy link
Copy Markdown

The guru-network-classic adapter exports pools:

Test Suites: 1 passed, 1 total
Tests: 10 passed, 10 total
Snapshots: 0 total
Time: 0.237 s
Ran all test suites.

Nb of pools: 1
 

Sample pools:
┌─────────┬──────────────────────────────────────────────┬───────┬────────────────────────┬──────────────┬───────────────────┬───────────────────┬──────────────────────────────────────────────────┬────────────────────────────────────┐
│ (index) │ pool                                         │ chain │ project                │ symbol       │ tvlUsd            │ apyBase           │ underlyingTokens                                 │ url                                │
├─────────┼──────────────────────────────────────────────┼───────┼────────────────────────┼──────────────┼───────────────────┼───────────────────┼──────────────────────────────────────────────────┼────────────────────────────────────┤
│ 0       │ '0x5b8ce6d591c914a56cb019b3decb63ede22708c8' │ 'bsc' │ 'guru-network-classic' │ 'stakeTHENA' │ 39190.52352989266 │ 49.00485385384505 │ [ '0xafbe3b8b0939a5538de32f7752a78e08c8492295' ] │ 'https://eliteness.network/ethena' │
└─────────┴──────────────────────────────────────────────┴───────┴────────────────────────┴──────────────┴───────────────────┴───────────────────┴──────────────────────────────────────────────────┴────────────────────────────────────┘

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/adaptors/guru-network-classic/index.js (1)

17-21: ⚠️ Potential issue | 🟠 Major

Previously reported hardening gap is still present (timeout + missing price-entry guard).

Line 18 still calls an external endpoint without timeout, and Line 32 still dereferences prices[token] without existence checks. This can hang or throw when the pricing API is slow or omits a key.

#!/bin/bash
set -euo pipefail

echo "Inspect current implementation:"
nl -ba src/adaptors/guru-network-classic/index.js | sed -n '16,36p'

echo
echo "Compare common guard/timeout patterns in adaptors:"
rg -nP --type=js -C2 'axios\.get\(|timeout:\s*[0-9_]+|prices\[[^\]]+\]\?\.|if\s*\(!prices\[' src/adaptors | head -n 200

Also applies to: 32-32

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/adaptors/guru-network-classic/index.js` around lines 17 - 21, The
axios.get call that builds the prices map (using wrappers.map ->
`${w.underlyingChain}:${w.underlyingToken}`) must be hardened: call axios.get
with a timeout option (e.g. { timeout: 5000 }) and wrap the request in try/catch
to handle request errors; after receiving the response, validate that .data and
.data.coins exist before assigning to prices and when later accessing
prices[token] (i.e. guard prices[token] with an existence check or fallback
value) so dereferencing a missing price does not throw—apply these changes
around the axios.get invocation and any code that reads prices[token], and
ensure errors are logged/handled gracefully.
🤖 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/guru-network-classic/index.js`:
- Around line 16-21: The main issue is that the exported async function main
does not accept the timetravel timestamp and always calls the current prices
endpoint; update the main signature to accept timestamp = null (async function
main(timestamp = null) or equivalent) and change the axios URL from
/prices/current/... to /prices/historical/${timestamp}/... (keeping the
wrappers.map(...) join logic unchanged); ensure the function still works when
timestamp is provided by the framework and that the unique symbols main and
wrappers are the places to edit.

---

Duplicate comments:
In `@src/adaptors/guru-network-classic/index.js`:
- Around line 17-21: The axios.get call that builds the prices map (using
wrappers.map -> `${w.underlyingChain}:${w.underlyingToken}`) must be hardened:
call axios.get with a timeout option (e.g. { timeout: 5000 }) and wrap the
request in try/catch to handle request errors; after receiving the response,
validate that .data and .data.coins exist before assigning to prices and when
later accessing prices[token] (i.e. guard prices[token] with an existence check
or fallback value) so dereferencing a missing price does not throw—apply these
changes around the axios.get invocation and any code that reads prices[token],
and ensure errors are logged/handled gracefully.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3b348728-fa9b-40f2-9032-f74c268b114c

📥 Commits

Reviewing files that changed from the base of the PR and between 7824d92 and f07c1a9.

📒 Files selected for processing (1)
  • src/adaptors/guru-network-classic/index.js

@llamatester
Copy link
Copy Markdown

The guru-network-classic adapter exports pools:

Test Suites: 1 passed, 1 total
Tests: 10 passed, 10 total
Snapshots: 0 total
Time: 0.238 s
Ran all test suites.

Nb of pools: 1
 

Sample pools:
┌─────────┬──────────────────────────────────────────────┬───────┬────────────────────────┬──────────────┬───────────────────┬───────────────────┬──────────────────────────────────────────────────┬────────────────────────────────────┐
│ (index) │ pool                                         │ chain │ project                │ symbol       │ tvlUsd            │ apyBase           │ underlyingTokens                                 │ url                                │
├─────────┼──────────────────────────────────────────────┼───────┼────────────────────────┼──────────────┼───────────────────┼───────────────────┼──────────────────────────────────────────────────┼────────────────────────────────────┤
│ 0       │ '0x5b8ce6d591c914a56cb019b3decb63ede22708c8' │ 'bsc' │ 'guru-network-classic' │ 'stakeTHENA' │ 39190.52352989266 │ 49.00485385384505 │ [ '0xafbe3b8b0939a5538de32f7752a78e08c8492295' ] │ 'https://eliteness.network/ethena' │
└─────────┴──────────────────────────────────────────────┴───────┴────────────────────────┴──────────────┴───────────────────┴───────────────────┴──────────────────────────────────────────────────┴────────────────────────────────────┘

@ftm1337
Copy link
Copy Markdown
Contributor Author

ftm1337 commented Mar 21, 2026

alright, good to go i guess. tvl & apy numbers tally up correctly 👍

}
return {
pool: info.pool,
chain: wrappers[i].underlyingChain,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

please use the helper: utils.formatChain(wrappers[i].underlyingChain) so we can map correctly on our side e.g. bsc -> Binance

module.exports = {
timetravel: true,
apy: main,
// url: 'https://example.com/pools', // Link to page with pools (Only required if you do not provide url's for each pool),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add base url here as a fallback pls

chain: wrappers[i].underlyingChain,
project: PROJECT,
symbol: wrappers[i].symbol,
tvlUsd: (Number(info.tvl) / 10 ** priceEntry.decimals) * priceEntry.price,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

formatting

return infos
.map((info, i) => {
const token = `${wrappers[i].underlyingChain}:${wrappers[i].underlyingToken}`;
const priceEntry = prices[token];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

formatting

@0xkr3p
Copy link
Copy Markdown
Contributor

0xkr3p commented Mar 25, 2026

hey @ftm1337 - thanks for the PR! A couple of minor issues to resolve then we are good to go! Can you format the code with prettier? there are quite a few inconsistencies

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.

3 participants