Skip to content

feat: adapter for Spectra MetaVaults#2465

Open
Ulydev wants to merge 4 commits intoDefiLlama:masterfrom
Ulydev:master
Open

feat: adapter for Spectra MetaVaults#2465
Ulydev wants to merge 4 commits intoDefiLlama:masterfrom
Ulydev:master

Conversation

@Ulydev
Copy link
Contributor

@Ulydev Ulydev commented Mar 9, 2026

This PR implements a basic yield adapter for Spectra MetaVaults, containing TVL, base & rewards APYs.

Summary by CodeRabbit

  • New Features
    • Added Spectra MetaVaults support: consolidates base+rewards APY, TVL, and standardized vault details across multiple chains; returns only visible vaults, excludes entries with invalid TVL, and presents results sorted by TVL.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 9, 2026

📝 Walkthrough

Walkthrough

Adds a new Spectra MetaVaults adapter that concurrently fetches chain-specific APY data, constructs mvId and reward entries, filters visible vaults with finite TVL, normalizes results to APY objects, sorts by TVL descending, and exports apy() and timetravel: false.

Changes

Cohort / File(s) Summary
Spectra MetaVaults Adapter
src/adaptors/spectra-metavaults/index.js
New adapter module added. Implements chain metadata, mvId and rewards extraction helpers, concurrent per-chain API requests with x-client-id header, response flattening, visibility and finite TVL filtering, normalization to APY objects, and TVL-descending sorting. Exports apy() and timetravel: false.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(200,200,255,0.5)
    participant Client
    end
    rect rgba(200,255,200,0.5)
    participant Adapter
    end
    rect rgba(255,200,200,0.5)
    participant SpectraAPI
    end
    rect rgba(255,255,200,0.5)
    participant Processor
    end

    Client->>Adapter: call apy()
    Adapter->>SpectraAPI: concurrent GET /chain-endpoint (x-client-id)
    SpectraAPI-->>Adapter: per-chain responses
    Adapter->>Processor: flatten responses, filter VISIBLE, compute mvId/rewards, normalize
    Processor-->>Adapter: APY objects
    Adapter-->>Client: sorted APY list (by TVL)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I nibble on endpoints, hop through each chain,
I stitch mvIds and rewards like a thread in the grain.
TVLs sorted, APYs aligned in a row,
I celebrate data that tidy and glow —
Hooray for MetaVaults, fetch, normalize, go! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: adapter for Spectra MetaVaults' clearly and concisely describes the main change—adding a new adapter for Spectra MetaVaults with APY data fetching and normalization.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

Error while running spectra-metavaults adapter:

Test Suites: 1 failed, 1 total
Tests: 2 failed, 42 passed, 44 total
Snapshots: 0 total
Time: 0.272 s
Ran all test suites.

Nb of pools: 5
 

Sample pools:
┌─────────┬─────────────────────────────────────────────────────┬──────────┬──────────────────────┬──────────────────────┬────────────────────┬──────────────────────┬────────────────────┬──────────────┬──────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────┐
│ (index) │ pool                                                │ chain    │ project              │ symbol               │ tvlUsd             │ apyBase              │ apyReward          │ rewardTokens │ underlyingTokens                                 │ url                                                                                                      │ token                                        │
├─────────┼─────────────────────────────────────────────────────┼──────────┼──────────────────────┼──────────────────────┼────────────────────┼──────────────────────┼────────────────────┼──────────────┼──────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────┤
│ 0       │ '0x0c4f32c53d4b91a019c7c9d8da14af140295eef6-flare'  │ 'Flare'  │ 'spectra-metavaults' │ 'FLAREXRPYIELDPRIME' │ 2417984.806068009  │ 0.056235413544425406 │ 6.042288898627763  │ []           │ [ '0xad552a648c74d49e10027ab8a618a3ad4901c5be' ] │ 'https://app.spectra.finance/metavaults/flare:0x0c4f32c53d4b91a019c7c9d8da14af140295eef6?ref=defillama'  │ '0x6420a613e936602ca3f1ad5680b3f4d47d473bf1' │
│ 1       │ '0xc2dec6328d9ef1ef2ee85901f9c1a8db8dd1c9c1-katana' │ 'Katana' │ 'spectra-metavaults' │ 'VBUSDCKATANA'       │ 1028623.6544878271 │ 3.1204638199360923   │ 0.9876869442750333 │ []           │ [ '0x203a662b0bd271a6ed5a60edfbd04bfce608fd36' ] │ 'https://app.spectra.finance/metavaults/katana:0xc2dec6328d9ef1ef2ee85901f9c1a8db8dd1c9c1?ref=defillama' │ '0x979602aaaa3453fffb76828ba08b8f4f61f3fd41' │
│ 2       │ '0x5e93e1193a5e297cba0856e9b3f22b6e05429b9a-base'   │ 'Base'   │ 'spectra-metavaults' │ 'GAMISPECTRAUSDC'    │ 429734.7776059525  │ 10.828786737747475   │ 0                  │ []           │ [ '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913' ] │ 'https://app.spectra.finance/metavaults/base:0x5e93e1193a5e297cba0856e9b3f22b6e05429b9a?ref=defillama'   │ '0x776f95321a0285f8bcde149e3264d16dc08da69a' │
│ 3       │ '0xdc1ce87f781c92dcb4789e55ba0a305f1f86f264-base'   │ 'Base'   │ 'spectra-metavaults' │ 'ULTRAYIELDWETH'     │ 109568.14783410067 │ 2.423883903292934    │ 0                  │ []           │ [ '0x4200000000000000000000000000000000000006' ] │ 'https://app.spectra.finance/metavaults/base:0xdc1ce87f781c92dcb4789e55ba0a305f1f86f264?ref=defillama'   │ '0x79de3f1cd2570ffcd741f48e2514507e77000178' │
│ 4       │ '0xfa7b643529e74adb8c44824577f09b6cbc91ee55-base'   │ 'Base'   │ 'spectra-metavaults' │ 'ULTRAYIELDUSDC'     │ 1.000004851341856  │ null                 │ 0                  │ []           │ [ '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913' ] │ 'https://app.spectra.finance/metavaults/base:0xfa7b643529e74adb8c44824577f09b6cbc91ee55?ref=defillama'   │ '0x9c68e7e8b77aeceae15b5081e9703263c0641513' │
└─────────┴─────────────────────────────────────────────────────┴──────────┴──────────────────────┴──────────────────────┴────────────────────┴──────────────────────┴────────────────────┴──────────────┴──────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────┘
This adapter contains some pools with <10k TVL, these pools won't be shown in DefiLlama

Copy link
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.

🧹 Nitpick comments (1)
src/adaptors/spectra-metavaults/index.js (1)

53-59: Add explicit timeout to axios requests to prevent indefinite waits.

These requests inherit axios defaults without a timeout. Axios v1.7.2 defaults to timeout: 0 (no timeout), so a stalled chain endpoint will block Promise.all indefinitely, preventing the adapter from returning data. Add a per-request timeout:

Suggested fix
       axios
         .get(api(chainId), {
           headers: {
             'x-client-id': 'defillama',
           },
+          timeout: 10_000,
         })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/adaptors/spectra-metavaults/index.js` around lines 53 - 59, The axios GET
calls created inside the Object.keys(chains).map(...) (the
axios.get(api(chainId), { headers: { 'x-client-id': 'defillama' } }) block)
currently have no timeout and can hang; update the per-request config to include
an explicit timeout (e.g., timeout: 5000) so each request fails after a
reasonable period, or replace the direct axios.get calls with a pre-configured
axios instance that sets a default timeout; ensure the timeout is added
alongside the existing headers in the request config for the API calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/adaptors/spectra-metavaults/index.js`:
- Around line 53-59: The axios GET calls created inside the
Object.keys(chains).map(...) (the axios.get(api(chainId), { headers: {
'x-client-id': 'defillama' } }) block) currently have no timeout and can hang;
update the per-request config to include an explicit timeout (e.g., timeout:
5000) so each request fails after a reasonable period, or replace the direct
axios.get calls with a pre-configured axios instance that sets a default
timeout; ensure the timeout is added alongside the existing headers in the
request config for the API calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5050de61-08ee-46cb-ba62-ca917f47fa37

📥 Commits

Reviewing files that changed from the base of the PR and between 512b347 and c469b0b.

📒 Files selected for processing (1)
  • src/adaptors/spectra-metavaults/index.js

@llamatester
Copy link

Error while running spectra-metavaults adapter:

Test Suites: 1 failed, 1 total
Tests: 2 failed, 26 passed, 28 total
Snapshots: 0 total
Time: 0.287 s
Ran all test suites.

Nb of pools: 3
 

Sample pools:
┌─────────┬─────────────────────────────────────────────────────┬──────────┬──────────────────────┬──────────────────────┬────────────────────┬─────────────────────┬───────────────────┬──────────────┬──────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────┐
│ (index) │ pool                                                │ chain    │ project              │ symbol               │ tvlUsd             │ apyBase             │ apyReward         │ rewardTokens │ underlyingTokens                                 │ url                                                                                                      │ token                                        │
├─────────┼─────────────────────────────────────────────────────┼──────────┼──────────────────────┼──────────────────────┼────────────────────┼─────────────────────┼───────────────────┼──────────────┼──────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────┤
│ 0       │ '0x0c4f32c53d4b91a019c7c9d8da14af140295eef6-flare'  │ 'Flare'  │ 'spectra-metavaults' │ 'FLAREXRPYIELDPRIME' │ 2417984.806068009  │ 0.05614176211883315 │ 6.042288898627763 │ []           │ [ '0xad552a648c74d49e10027ab8a618a3ad4901c5be' ] │ 'https://app.spectra.finance/metavaults/flare:0x0c4f32c53d4b91a019c7c9d8da14af140295eef6?ref=defillama'  │ '0x6420a613e936602ca3f1ad5680b3f4d47d473bf1' │
│ 1       │ '0xc2dec6328d9ef1ef2ee85901f9c1a8db8dd1c9c1-katana' │ 'Katana' │ 'spectra-metavaults' │ 'VBUSDCKATANA'       │ 1028631.586456495  │ 3.1151918007408685  │ 0.988553756058695 │ []           │ [ '0x203a662b0bd271a6ed5a60edfbd04bfce608fd36' ] │ 'https://app.spectra.finance/metavaults/katana:0xc2dec6328d9ef1ef2ee85901f9c1a8db8dd1c9c1?ref=defillama' │ '0x979602aaaa3453fffb76828ba08b8f4f61f3fd41' │
│ 2       │ '0x5e93e1193a5e297cba0856e9b3f22b6e05429b9a-base'   │ 'Base'   │ 'spectra-metavaults' │ 'GAMISPECTRAUSDC'    │ 429734.83027139265 │ 10.809831152681436  │ 0                 │ []           │ [ '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913' ] │ 'https://app.spectra.finance/metavaults/base:0x5e93e1193a5e297cba0856e9b3f22b6e05429b9a?ref=defillama'   │ '0x776f95321a0285f8bcde149e3264d16dc08da69a' │
└─────────┴─────────────────────────────────────────────────────┴──────────┴──────────────────────┴──────────────────────┴────────────────────┴─────────────────────┴───────────────────┴──────────────┴──────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────┘

@llamatester
Copy link

Error while running spectra-metavaults adapter:

Test Suites: 1 failed, 1 total
Tests: 2 failed, 26 passed, 28 total
Snapshots: 0 total
Time: 0.272 s
Ran all test suites.

Nb of pools: 3
 

Sample pools:
┌─────────┬─────────────────────────────────────────────────────┬──────────┬──────────────────────┬──────────────────────┬────────────────────┬─────────────────────┬────────────────────┬──────────────┬──────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────┐
│ (index) │ pool                                                │ chain    │ project              │ symbol               │ tvlUsd             │ apyBase             │ apyReward          │ rewardTokens │ underlyingTokens                                 │ url                                                                                                      │ token                                        │
├─────────┼─────────────────────────────────────────────────────┼──────────┼──────────────────────┼──────────────────────┼────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────┤
│ 0       │ '0x0c4f32c53d4b91a019c7c9d8da14af140295eef6-flare'  │ 'Flare'  │ 'spectra-metavaults' │ 'FLAREXRPYIELDPRIME' │ 2511733.4591721296 │ 0.05165846113790451 │ 5.990106306927658  │ []           │ [ '0xad552a648c74d49e10027ab8a618a3ad4901c5be' ] │ 'https://app.spectra.finance/metavaults/flare:0x0c4f32c53d4b91a019c7c9d8da14af140295eef6?ref=defillama'  │ '0x6420a613e936602ca3f1ad5680b3f4d47d473bf1' │
│ 1       │ '0xc2dec6328d9ef1ef2ee85901f9c1a8db8dd1c9c1-katana' │ 'Katana' │ 'spectra-metavaults' │ 'VBUSDCKATANA'       │ 1025982.7912295067 │ 2.863105157525747   │ 0.9893409371426274 │ []           │ [ '0x203a662b0bd271a6ed5a60edfbd04bfce608fd36' ] │ 'https://app.spectra.finance/metavaults/katana:0xc2dec6328d9ef1ef2ee85901f9c1a8db8dd1c9c1?ref=defillama' │ '0x979602aaaa3453fffb76828ba08b8f4f61f3fd41' │
│ 2       │ '0x5e93e1193a5e297cba0856e9b3f22b6e05429b9a-base'   │ 'Base'   │ 'spectra-metavaults' │ 'GAMISPECTRAUSDC'    │ 429115.8948196913  │ 9.90609269629723    │ 0                  │ []           │ [ '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913' ] │ 'https://app.spectra.finance/metavaults/base:0x5e93e1193a5e297cba0856e9b3f22b6e05429b9a?ref=defillama'   │ '0x776f95321a0285f8bcde149e3264d16dc08da69a' │
└─────────┴─────────────────────────────────────────────────────┴──────────┴──────────────────────┴──────────────────────┴────────────────────┴─────────────────────┴────────────────────┴──────────────┴──────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────┘

@llamatester
Copy link

The spectra-metavaults adapter exports pools:

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

Nb of pools: 3
 

Sample pools:
┌─────────┬─────────────────────────────────────────────────────┬──────────┬──────────────────────┬──────────────────────┬────────────────────┬─────────────────────┬────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────┐
│ (index) │ pool                                                │ chain    │ project              │ symbol               │ tvlUsd             │ apyBase             │ apyReward          │ rewardTokens                                                                                   │ underlyingTokens                                 │ url                                                                                                      │ token                                        │
├─────────┼─────────────────────────────────────────────────────┼──────────┼──────────────────────┼──────────────────────┼────────────────────┼─────────────────────┼────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────┤
│ 0       │ '0x0c4f32c53d4b91a019c7c9d8da14af140295eef6-flare'  │ 'Flare'  │ 'spectra-metavaults' │ 'FLAREXRPYIELDPRIME' │ 2511733.4591721296 │ 0.05165523035226549 │ 5.990106306927658  │ [ '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d' ]                                               │ [ '0xad552a648c74d49e10027ab8a618a3ad4901c5be' ] │ 'https://app.spectra.finance/metavaults/flare:0x0c4f32c53d4b91a019c7c9d8da14af140295eef6?ref=defillama'  │ '0x6420a613e936602ca3f1ad5680b3f4d47d473bf1' │
│ 1       │ '0xc2dec6328d9ef1ef2ee85901f9c1a8db8dd1c9c1-katana' │ 'Katana' │ 'spectra-metavaults' │ 'VBUSDCKATANA'       │ 1025982.7099323167 │ 2.862923706550613   │ 0.9893410155363832 │ [ '0x6E9C1F88a960fE63387eb4b71BC525a9313d8461', '0xB77f1A8CB126D8567f226f990F84e2f698Cc30F8' ] │ [ '0x203a662b0bd271a6ed5a60edfbd04bfce608fd36' ] │ 'https://app.spectra.finance/metavaults/katana:0xc2dec6328d9ef1ef2ee85901f9c1a8db8dd1c9c1?ref=defillama' │ '0x979602aaaa3453fffb76828ba08b8f4f61f3fd41' │
│ 2       │ '0x5e93e1193a5e297cba0856e9b3f22b6e05429b9a-base'   │ 'Base'   │ 'spectra-metavaults' │ 'GAMISPECTRAUSDC'    │ 429115.90690628916 │ 9.905444050218293   │ 0                  │ [ '0x4baB31D6c557F8285eccB5167095147a36D9BaFa' ]                                               │ [ '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913' ] │ 'https://app.spectra.finance/metavaults/base:0x5e93e1193a5e297cba0856e9b3f22b6e05429b9a?ref=defillama'   │ '0x776f95321a0285f8bcde149e3264d16dc08da69a' │
└─────────┴─────────────────────────────────────────────────────┴──────────┴──────────────────────┴──────────────────────┴────────────────────┴─────────────────────┴────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────┘

@llamatester
Copy link

The spectra-metavaults adapter exports pools:

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

Nb of pools: 3
 

Sample pools:
┌─────────┬─────────────────────────────────────────────────────┬──────────┬──────────────────────┬───────────────────────┬────────────────────┬─────────────────────┬────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────┐
│ (index) │ pool                                                │ chain    │ project              │ symbol                │ tvlUsd             │ apyBase             │ apyReward          │ rewardTokens                                                                                   │ underlyingTokens                                 │ url                                                                                                      │ token                                        │
├─────────┼─────────────────────────────────────────────────────┼──────────┼──────────────────────┼───────────────────────┼────────────────────┼─────────────────────┼────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────┤
│ 0       │ '0x0c4f32c53d4b91a019c7c9d8da14af140295eef6-flare'  │ 'Flare'  │ 'spectra-metavaults' │ 'FLARE-XRPYIELDPRIME' │ 2501003.001674963  │ 0.05143754874910034 │ 5.995946687632537  │ [ '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d' ]                                               │ [ '0xad552a648c74d49e10027ab8a618a3ad4901c5be' ] │ 'https://app.spectra.finance/metavaults/flare:0x0c4f32c53d4b91a019c7c9d8da14af140295eef6?ref=defillama'  │ '0x6420a613e936602ca3f1ad5680b3f4d47d473bf1' │
│ 1       │ '0xc2dec6328d9ef1ef2ee85901f9c1a8db8dd1c9c1-katana' │ 'Katana' │ 'spectra-metavaults' │ 'VBUSDC-KATANA'       │ 1026422.4508135519 │ 2.850698724362455   │ 0.9892093337981871 │ [ '0x6E9C1F88a960fE63387eb4b71BC525a9313d8461', '0xB77f1A8CB126D8567f226f990F84e2f698Cc30F8' ] │ [ '0x203a662b0bd271a6ed5a60edfbd04bfce608fd36' ] │ 'https://app.spectra.finance/metavaults/katana:0xc2dec6328d9ef1ef2ee85901f9c1a8db8dd1c9c1?ref=defillama' │ '0x979602aaaa3453fffb76828ba08b8f4f61f3fd41' │
│ 2       │ '0x5e93e1193a5e297cba0856e9b3f22b6e05429b9a-base'   │ 'Base'   │ 'spectra-metavaults' │ 'GAMI-SPECTRAUSDC'    │ 430074.6821058778  │ 9.861748672059312   │ 0                  │ [ '0x4baB31D6c557F8285eccB5167095147a36D9BaFa' ]                                               │ [ '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913' ] │ 'https://app.spectra.finance/metavaults/base:0x5e93e1193a5e297cba0856e9b3f22b6e05429b9a?ref=defillama'   │ '0x776f95321a0285f8bcde149e3264d16dc08da69a' │
└─────────┴─────────────────────────────────────────────────────┴──────────┴──────────────────────┴───────────────────────┴────────────────────┴─────────────────────┴────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────┘

Copy link
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: 2

🧹 Nitpick comments (2)
src/adaptors/spectra-metavaults/index.js (2)

54-65: Consider handling individual chain API failures gracefully.

If one chain's API request fails, Promise.all will reject entirely and no pools will be returned. Using Promise.allSettled would allow partial results when some chains are unavailable.

♻️ Proposed resilient fetch pattern
   const mvs = await Promise.all(
     Object.keys(chains).map((chainId) =>
       axios
         .get(api(chainId), {
           headers: {
             'x-client-id': 'defillama',
           },
           timeout: 10_000,
         })
         .then((res) => res.data.flat())
+        .catch((err) => {
+          console.error(`Failed to fetch chain ${chainId}:`, err.message);
+          return [];
+        })
     )
   ).then((res) => res.flat());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/adaptors/spectra-metavaults/index.js` around lines 54 - 65, The current
Promise.all call that builds mvs will reject if any chain request fails; replace
it with Promise.allSettled over Object.keys(chains).map(...) so you can collect
fulfilled responses only, flatten them and ignore or log rejected ones (include
chainId and error). Update references around mvs and the axios/api call to
process only entries with status === 'fulfilled', flatten their .value results,
and optionally console.error or processLogger.warn rejected results to aid
debugging while returning partial pool data.

67-72: Unnecessary .flat() call on line 70.

mvApy returns a single object per MetaVault, not an array. The .flat() call after .map(mvApy) has no effect and can be removed for clarity.

♻️ Proposed cleanup
   const apys = mvs
     .filter((mv) => mv.status === 'VISIBLE') // only include live MetaVaults
     .map(mvApy)
-    .flat()
     .filter((i) => utils.keepFinite(i)) // skip MetaVaults with no TVL (e.g. missing price)
     .sort((a, b) => b.tvlUsd - a.tvlUsd);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/adaptors/spectra-metavaults/index.js` around lines 67 - 72, The chain
building the apys array uses .map(mvApy).flat() even though mvApy returns a
single object per MetaVault; remove the unnecessary .flat() to avoid a no-op and
clarify intent. Update the expression that defines apys (which filters mvs by
mv.status === 'VISIBLE', maps with mvApy, filters with utils.keepFinite, and
sorts by tvlUsd) to drop the .flat() call so the pipeline becomes filter ->
map(mvApy) -> filter(utils.keepFinite) -> sort.
🤖 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/spectra-metavaults/index.js`:
- Line 40: The call to mv.metadata.title.replace(' ', '-') only replaces the
first space so symbol generation can leave spaces; update the expression used
inside utils.formatSymbol to replace all spaces — e.g., use
mv.metadata.title.replaceAll(' ', '-') (if Node target supports it) or
mv.metadata.title.replace(/ /g, '-') (or mv.metadata.title.split(' ').join('-'))
so multi-word titles like "Meta Vault USDC" become "Meta-Vault-USDC"; update the
symbol: utils.formatSymbol(...) spot accordingly.
- Line 47: The code accesses mv.underlying.address without null-safety which can
throw if mv.underlying is undefined; update the construction of underlyingTokens
(the array assigned to underlyingTokens) to use optional chaining on
mv.underlying (e.g., mv.underlying?.address) and ensure downstream consumers can
handle undefined values (filter out falsy entries or provide a default) so
malformed API responses don't cause a TypeError.

---

Nitpick comments:
In `@src/adaptors/spectra-metavaults/index.js`:
- Around line 54-65: The current Promise.all call that builds mvs will reject if
any chain request fails; replace it with Promise.allSettled over
Object.keys(chains).map(...) so you can collect fulfilled responses only,
flatten them and ignore or log rejected ones (include chainId and error). Update
references around mvs and the axios/api call to process only entries with status
=== 'fulfilled', flatten their .value results, and optionally console.error or
processLogger.warn rejected results to aid debugging while returning partial
pool data.
- Around line 67-72: The chain building the apys array uses .map(mvApy).flat()
even though mvApy returns a single object per MetaVault; remove the unnecessary
.flat() to avoid a no-op and clarify intent. Update the expression that defines
apys (which filters mvs by mv.status === 'VISIBLE', maps with mvApy, filters
with utils.keepFinite, and sorts by tvlUsd) to drop the .flat() call so the
pipeline becomes filter -> map(mvApy) -> filter(utils.keepFinite) -> sort.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8b833141-61cb-4ee0-97f6-4c9ba04766ad

📥 Commits

Reviewing files that changed from the base of the PR and between 42c7f4f and a2d4c12.

📒 Files selected for processing (1)
  • src/adaptors/spectra-metavaults/index.js

pool: mvId(mv.address, mv.chainId),
chain: utils.formatChain(chain.name),
project: 'spectra-metavaults',
symbol: utils.formatSymbol(`${mv.metadata.title.replace(' ', '-')}`),
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

replace() only replaces the first space.

String.prototype.replace() with a string argument replaces only the first occurrence. If the title contains multiple spaces (e.g., "Meta Vault USDC"), the result would be "Meta-Vault USDC" instead of "Meta-Vault-USDC".

🐛 Proposed fix to replace all spaces
-    symbol: utils.formatSymbol(`${mv.metadata.title.replace(' ', '-')}`),
+    symbol: utils.formatSymbol(`${mv.metadata.title.replace(/ /g, '-')}`),

Alternatively, use replaceAll(' ', '-') if targeting Node.js 15+.

📝 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.

Suggested change
symbol: utils.formatSymbol(`${mv.metadata.title.replace(' ', '-')}`),
symbol: utils.formatSymbol(`${mv.metadata.title.replace(/ /g, '-')}`),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/adaptors/spectra-metavaults/index.js` at line 40, The call to
mv.metadata.title.replace(' ', '-') only replaces the first space so symbol
generation can leave spaces; update the expression used inside
utils.formatSymbol to replace all spaces — e.g., use
mv.metadata.title.replaceAll(' ', '-') (if Node target supports it) or
mv.metadata.title.replace(/ /g, '-') (or mv.metadata.title.split(' ').join('-'))
so multi-word titles like "Meta Vault USDC" become "Meta-Vault-USDC"; update the
symbol: utils.formatSymbol(...) spot accordingly.

rewardTokens: Object.values(mv.liveApy?.details?.rewardTokens || {}).map(
(t) => t.address
),
underlyingTokens: [mv.underlying.address],
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing null safety on mv.underlying.

If mv.underlying is undefined (e.g., malformed API response), accessing .address will throw a TypeError. Add optional chaining for defensive handling.

🛡️ Proposed fix
-    underlyingTokens: [mv.underlying.address],
+    underlyingTokens: mv.underlying?.address ? [mv.underlying.address] : [],
📝 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.

Suggested change
underlyingTokens: [mv.underlying.address],
underlyingTokens: mv.underlying?.address ? [mv.underlying.address] : [],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/adaptors/spectra-metavaults/index.js` at line 47, The code accesses
mv.underlying.address without null-safety which can throw if mv.underlying is
undefined; update the construction of underlyingTokens (the array assigned to
underlyingTokens) to use optional chaining on mv.underlying (e.g.,
mv.underlying?.address) and ensure downstream consumers can handle undefined
values (filter out falsy entries or provide a default) so malformed API
responses don't cause a TypeError.

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.

2 participants