Skip to content

fix: arrakis-v1 adapter#2323

Merged
0xkr3p merged 3 commits intoDefiLlama:masterfrom
0xkr3p:fix/arrakis-v1-adapter
Jan 31, 2026
Merged

fix: arrakis-v1 adapter#2323
0xkr3p merged 3 commits intoDefiLlama:masterfrom
0xkr3p:fix/arrakis-v1-adapter

Conversation

@0xkr3p
Copy link
Contributor

@0xkr3p 0xkr3p commented Jan 30, 2026

Summary by CodeRabbit

  • New Features

    • Added a public URL endpoint for accessing Arrakis Finance vault information and metrics.
  • Refactor

    • Overhauled Arrakis V1 data fetching to improve multi-chain APY, token metadata, price retrieval and TVL calculations; vaults with TVL below $1,000 are filtered out for better accuracy.
    • Public interface preserved; timetravel remains disabled.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 30, 2026

📝 Walkthrough

Walkthrough

Refactored Arrakis V1 adaptor to use a FACTORIES-driven getApy pipeline: fetch APYs from an indexer, enumerate deployers and pools, fetch token metadata and balances via multicall, retrieve prices, compute TVL (filtering < $1,000), and export apy plus a public URL and timetravel flag.

Changes

Cohort / File(s) Summary
Arrakis V1 Adaptor
src/adaptors/arrakis-v1/index.js
Replaced GraphQL chain-specific fetch with a FACTORIES map and unified getApy. Added APY indexer fetch, deployer/pool enumeration, multicall for token0/token1 and balances, token metadata & price lookups, TVL calculation with a $1k floor, and exported url alongside apy and timetravel.

Sequence Diagram

sequenceDiagram
    participant Module as Arrakis Module
    participant Indexer as Arrakis Indexer
    participant Factory as Chain/Factory
    participant MultiCall as MultiCall Service
    participant PriceSvc as LLama Price Service
    participant Output as Pools Output

    Module->>Indexer: fetch APY data
    Indexer-->>Module: apyByVault map

    Module->>Factory: iterate FACTORIES -> getDeployers()
    Factory-->>Module: deployer list
    Module->>Factory: getPools(deployer)
    Factory-->>Module: vault addresses

    Module->>MultiCall: request token0/token1 & balances
    MultiCall-->>Module: token addresses & balances

    Module->>PriceSvc: fetch token prices & metadata
    PriceSvc-->>Module: prices, symbols, decimals

    Module->>Module: compute TVL per vault (filter < $1000)
    Module->>Output: emit pool objects (pool, chain, project, symbol, tvlUsd, apyBase, underlyingTokens)
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through FACTORIES, ledger in paw,
I fetched APYs, balances, and more to draw.
Pools lined up, tokens priced and true,
TVLs filtered, a tidy view — woohoo! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'fix: arrakis-v1 adapter' is vague and generic. While it identifies the component being modified, it does not describe what the actual fix is or what problem is being addressed, making it unclear to someone reviewing the PR history. Consider a more descriptive title that explains the fix, such as 'fix: replace arrakis-v1 GraphQL with indexer-based data fetch' or 'fix: refactor arrakis-v1 adapter to use factory-based pool discovery'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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 docstrings
🧪 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

The arrakis-v1 adapter exports pools:

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

Nb of pools: 34
 

Sample pools:
┌─────────┬──────────────────────────────────────────────┬────────────┬──────────────┬──────────────────┬────────────────────┬─────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────┐
│ (index) │ pool                                         │ chain      │ project      │ symbol           │ tvlUsd             │ apyBase             │ underlyingTokens                                                                               │
├─────────┼──────────────────────────────────────────────┼────────────┼──────────────┼──────────────────┼────────────────────┼─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────┤
│ 0       │ '0x50379f632ca68D36E50cfBC8F78fe16bd1499d1e' │ 'Ethereum' │ 'arrakis-v1' │ 'DAI-USDC'       │ 1268041.0873915153 │ 0.580017328869378   │ [ '0x6B175474E89094C44Da98b954EedeAC495271d0F', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' ] │
│ 1       │ '0xAbDDAfB225e10B90D798bB8A886238Fb835e2053' │ 'Ethereum' │ 'arrakis-v1' │ 'DAI-USDC'       │ 325369.5931757076  │ 0.9026801279271416  │ [ '0x6B175474E89094C44Da98b954EedeAC495271d0F', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' ] │
│ 2       │ '0x77CDd9e097f34C1fa861DAEb6823dE741fAb2321' │ 'Ethereum' │ 'arrakis-v1' │ 'ETH2x-FLI-WETH' │ 266018.0586894557  │ 17.168069392381604  │ [ '0xAa6E8127831c9DE45ae56bB1b0d4D4Da6e5665BD', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' ] │
│ 3       │ '0x7c687f775A3b73BBAb0E15832F24caaB5D53bDDe' │ 'Ethereum' │ 'arrakis-v1' │ 'WETH-ENS'       │ 88635.57119633403  │ 22.96386097251694   │ [ '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', '0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72' ] │
│ 4       │ '0x4f38892c16bfbB4f4f7424EEfAa9767F4E922073' │ 'Ethereum' │ 'arrakis-v1' │ 'USDC-FLOAT'     │ 71386.16881895234  │ 0.6194261711129175  │ [ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', '0xb05097849BCA421A3f51B249BA6CCa4aF4b97cb9' ] │
│ 5       │ '0x18D53f4953AD14236602DA05eFAfc0Df4f5d064D' │ 'Ethereum' │ 'arrakis-v1' │ 'ETHMAXY-WETH'   │ 48656.72175952894  │ 0.8865923200992449  │ [ '0x0FE20E0Fa9C78278702B05c333Cc000034bb69E2', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' ] │
│ 6       │ '0xb1Cfdc7370550f5e421E1bf0BF3CADFaDF3C4141' │ 'Ethereum' │ 'arrakis-v1' │ 'DAI-FRAX'       │ 32087.701930409687 │ 0.5011851893584045  │ [ '0x6B175474E89094C44Da98b954EedeAC495271d0F', '0x853d955aCEf822Db058eb8505911ED77F175b99e' ] │
│ 7       │ '0xEDECB43233549c51CC3268b5dE840239787AD56c' │ 'Ethereum' │ 'arrakis-v1' │ 'EURA-USDC'      │ 31068.166609394088 │ 0.40154176761313093 │ [ '0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' ] │
│ 8       │ '0x0D2A2Df39436b5c5f986552869124bA29b7Df1AC' │ 'Ethereum' │ 'arrakis-v1' │ 'icETH-WETH'     │ 25825.46382606505  │ 1.9188884105467454  │ [ '0x7C07F7aBe10CE8e33DC6C5aD68FE033085256A84', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' ] │
│ 9       │ '0x590217ef04BcB96FF6Da991AB070958b8F9E77f0' │ 'Polygon'  │ 'arrakis-v1' │ 'WBTC-WETH'      │ 18962.904239192343 │ 3.096692629288771   │ [ '0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6', '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619' ] │
└─────────┴──────────────────────────────────────────────┴────────────┴──────────────┴──────────────────┴────────────────────┴─────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────┘
This adapter contains some pools with <10k TVL, these pools won't be shown in DefiLlama

Copy link

@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

🤖 Fix all issues with AI agents
In `@src/adaptors/arrakis-v1/index.js`:
- Around line 86-91: The uniqueTokens array currently builds a Set from
token0Results.output and token1Results.output directly, which can include
null/undefined and break later multicall targets; update the construction that
derives uniqueTokens (the code using token0Results, token1Results and the
variable uniqueTokens) to filter out null/undefined outputs first (e.g., map to
r.output then .filter(t => t != null) or .filter(Boolean)) before creating the
Set so only valid token addresses are included.
- Around line 136-140: Price lookups use checksummed token0/token1 so keys like
`${chain}:${token0}` don't match DefiLlama's lowercase keys; update the key
construction in the price lookup (variables price0Key and price1Key) to
lowercase the token portion (e.g., use `${chain}:${token0.toLowerCase()}` and
`${chain}:${token1.toLowerCase()}` or otherwise lowercase the full key) so the
prices lookup from the prices object returns the correct values for price0 and
price1.
🧹 Nitpick comments (2)
src/adaptors/arrakis-v1/index.js (2)

49-60: Consider parallelizing getPools calls for better performance.

The sequential await inside the for...of loop processes deployers one at a time. If there are many deployers, this could slow down the adapter significantly.

♻️ Proposed parallel implementation
-      const vaultAddresses = [];
-      for (const deployer of deployers) {
-        const vaultsResult = await sdk.api.abi.call({
-          target: factoryAddress,
-          abi: arrakisABI.getPools,
-          params: [deployer],
-          chain: chain,
-        });
-
-        if (vaultsResult.output && vaultsResult.output.length > 0) {
-          vaultAddresses.push(...vaultsResult.output);
-        }
-      }
+      const vaultsResults = await Promise.all(
+        deployers.map((deployer) =>
+          sdk.api.abi.call({
+            target: factoryAddress,
+            abi: arrakisABI.getPools,
+            params: [deployer],
+            chain: chain,
+          })
+        )
+      );
+
+      const vaultAddresses = vaultsResults
+        .filter((result) => result.output && result.output.length > 0)
+        .flatMap((result) => result.output);

148-156: Consider lowercasing the pool address for consistency.

Many DefiLlama adapters lowercase pool addresses to ensure consistent identifiers across the system. This prevents duplicate pool entries if the same address appears with different cases.

♻️ Suggested change
         allPools.push({
-          pool: vault,
+          pool: vault.toLowerCase(),
           chain: utils.formatChain(chain),
           project: 'arrakis-v1',
           symbol: `${token0Meta.symbol}-${token1Meta.symbol}`,
           tvlUsd: tvlUsd,
           apyBase: apyBase,
           underlyingTokens: [token0, token1],
         });

@llamatester
Copy link

The arrakis-v1 adapter exports pools:

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

Nb of pools: 34
 

Sample pools:
┌─────────┬──────────────────────────────────────────────┬────────────┬──────────────┬──────────────────┬────────────────────┬─────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────┐
│ (index) │ pool                                         │ chain      │ project      │ symbol           │ tvlUsd             │ apyBase             │ underlyingTokens                                                                               │
├─────────┼──────────────────────────────────────────────┼────────────┼──────────────┼──────────────────┼────────────────────┼─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────┤
│ 0       │ '0x50379f632ca68D36E50cfBC8F78fe16bd1499d1e' │ 'Ethereum' │ 'arrakis-v1' │ 'DAI-USDC'       │ 1268165.7321949434 │ 0.580017328869378   │ [ '0x6B175474E89094C44Da98b954EedeAC495271d0F', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' ] │
│ 1       │ '0xAbDDAfB225e10B90D798bB8A886238Fb835e2053' │ 'Ethereum' │ 'arrakis-v1' │ 'DAI-USDC'       │ 325413.1214547805  │ 0.9026801279271416  │ [ '0x6B175474E89094C44Da98b954EedeAC495271d0F', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' ] │
│ 2       │ '0x77CDd9e097f34C1fa861DAEb6823dE741fAb2321' │ 'Ethereum' │ 'arrakis-v1' │ 'ETH2x-FLI-WETH' │ 266615.58145158994 │ 17.168069392381604  │ [ '0xAa6E8127831c9DE45ae56bB1b0d4D4Da6e5665BD', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' ] │
│ 3       │ '0x7c687f775A3b73BBAb0E15832F24caaB5D53bDDe' │ 'Ethereum' │ 'arrakis-v1' │ 'WETH-ENS'       │ 88909.19265013449  │ 22.96386097251694   │ [ '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', '0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72' ] │
│ 4       │ '0x4f38892c16bfbB4f4f7424EEfAa9767F4E922073' │ 'Ethereum' │ 'arrakis-v1' │ 'USDC-FLOAT'     │ 71386.24029309634  │ 0.6194261711129175  │ [ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', '0xb05097849BCA421A3f51B249BA6CCa4aF4b97cb9' ] │
│ 5       │ '0x18D53f4953AD14236602DA05eFAfc0Df4f5d064D' │ 'Ethereum' │ 'arrakis-v1' │ 'ETHMAXY-WETH'   │ 48897.24337588292  │ 0.8865923200992449  │ [ '0x0FE20E0Fa9C78278702B05c333Cc000034bb69E2', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' ] │
│ 6       │ '0xb1Cfdc7370550f5e421E1bf0BF3CADFaDF3C4141' │ 'Ethereum' │ 'arrakis-v1' │ 'DAI-FRAX'       │ 32091.883227403974 │ 0.5011851893584045  │ [ '0x6B175474E89094C44Da98b954EedeAC495271d0F', '0x853d955aCEf822Db058eb8505911ED77F175b99e' ] │
│ 7       │ '0xEDECB43233549c51CC3268b5dE840239787AD56c' │ 'Ethereum' │ 'arrakis-v1' │ 'EURA-USDC'      │ 31053.644828343815 │ 0.40154176761313093 │ [ '0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' ] │
│ 8       │ '0x0D2A2Df39436b5c5f986552869124bA29b7Df1AC' │ 'Ethereum' │ 'arrakis-v1' │ 'icETH-WETH'     │ 25952.28869446932  │ 1.9188884105467454  │ [ '0x7C07F7aBe10CE8e33DC6C5aD68FE033085256A84', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' ] │
│ 9       │ '0x590217ef04BcB96FF6Da991AB070958b8F9E77f0' │ 'Polygon'  │ 'arrakis-v1' │ 'WBTC-WETH'      │ 18989.147587785686 │ 3.096692629288771   │ [ '0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6', '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619' ] │
└─────────┴──────────────────────────────────────────────┴────────────┴──────────────┴──────────────────┴────────────────────┴─────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────┘
This adapter contains some pools with <10k TVL, these pools won't be shown in DefiLlama

Copy link

@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

🤖 Fix all issues with AI agents
In `@src/adaptors/arrakis-v1/index.js`:
- Around line 114-119: The axios GET for prices (the priceKeys -> prices call)
currently has no error handling so a failed request will crash processing for
the chain; wrap the axios.get(...) that populates prices in a try-catch, catch
and log the error via the existing logger, and provide a safe fallback (e.g.,
set prices = {} or skip tokens with missing prices) so processing continues for
other chains; ensure references to priceKeys and prices remain and that
downstream code can handle empty/missing price entries gracefully.
🧹 Nitpick comments (3)
src/adaptors/arrakis-v1/index.js (3)

17-31: Consider logging when APY data is unavailable for debugging.

The error handling silently falls back to an empty apyByVault map. While this prevents the adapter from failing, it may make debugging difficult when APY values are unexpectedly 0.

Consider also logging when the API response doesn't contain the expected data structure:

     if (arrakisResponse.data.success && arrakisResponse.data.vaults) {
       arrakisResponse.data.vaults.forEach((vault) => {
         const apyBase = vault.averageApr || 0;
         apyByVault[vault.id.toLowerCase()] = apyBase;
       });
+    } else {
+      console.warn('Arrakis APY API returned unexpected response structure');
     }

47-60: Sequential deployer iteration could be parallelized for performance.

The getPools calls are made sequentially for each deployer. If there are many deployers, this could slow down the adapter. Consider parallelizing:

       // Get all vaults for each deployer
       const vaultAddresses = [];
-      for (const deployer of deployers) {
-        const vaultsResult = await sdk.api.abi.call({
+      const vaultResults = await Promise.all(
+        deployers.map((deployer) =>
+          sdk.api.abi.call({
+            target: factoryAddress,
+            abi: arrakisABI.getPools,
+            params: [deployer],
+            chain: chain,
+          })
+        )
+      );
+
+      for (const vaultsResult of vaultResults) {
+        if (vaultsResult.output && vaultsResult.output.length > 0) {
+          vaultAddresses.push(...vaultsResult.output);
+        }
+      }
-          target: factoryAddress,
-          abi: arrakisABI.getPools,
-          params: [deployer],
-          chain: chain,
-        });
-
-        if (vaultsResult.output && vaultsResult.output.length > 0) {
-          vaultAddresses.push(...vaultsResult.output);
-        }
-      }

133-134: Potential precision loss with Number() for large token balances.

Using Number() on blockchain balance values (which can be very large integers) may cause precision loss due to JavaScript's floating-point limitations. For tokens with high decimals or large supplies, consider using a BigInt-safe approach:

-        const amount0 = Number(balances[0]) / 10 ** token0Meta.decimals;
-        const amount1 = Number(balances[1]) / 10 ** token1Meta.decimals;
+        const amount0 = Number(BigInt(balances[0])) / 10 ** token0Meta.decimals;
+        const amount1 = Number(BigInt(balances[1])) / 10 ** token1Meta.decimals;

However, since the TVL calculation multiplies by price and the final result is in USD (typically < trillions), the current approach is likely acceptable in practice for most pools. Just be aware of potential edge cases with extremely large balances.

Comment on lines +114 to +119
const priceKeys = uniqueTokens.map((t) => `${chain}:${t.toLowerCase()}`);
const prices = (
await axios.get(
`https://coins.llama.fi/prices/current/${priceKeys.join(',')}`
)
).data.coins;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add error handling for the price API call.

If the price API call fails, it will throw an unhandled exception and skip processing for the entire chain. Consider wrapping this in a try-catch or providing a fallback:

-      const priceKeys = uniqueTokens.map((t) => `${chain}:${t.toLowerCase()}`);
-      const prices = (
-        await axios.get(
-          `https://coins.llama.fi/prices/current/${priceKeys.join(',')}`
-        )
-      ).data.coins;
+      const priceKeys = uniqueTokens.map((t) => `${chain}:${t.toLowerCase()}`);
+      let prices = {};
+      try {
+        prices = (
+          await axios.get(
+            `https://coins.llama.fi/prices/current/${priceKeys.join(',')}`
+          )
+        ).data.coins;
+      } catch (priceError) {
+        console.error(`Error fetching prices for ${chain}:`, priceError.message);
+        continue;
+      }
🤖 Prompt for AI Agents
In `@src/adaptors/arrakis-v1/index.js` around lines 114 - 119, The axios GET for
prices (the priceKeys -> prices call) currently has no error handling so a
failed request will crash processing for the chain; wrap the axios.get(...) that
populates prices in a try-catch, catch and log the error via the existing
logger, and provide a safe fallback (e.g., set prices = {} or skip tokens with
missing prices) so processing continues for other chains; ensure references to
priceKeys and prices remain and that downstream code can handle empty/missing
price entries gracefully.

@0xkr3p 0xkr3p merged commit c4101e3 into DefiLlama:master Jan 31, 2026
2 checks passed
@0xkr3p 0xkr3p deleted the fix/arrakis-v1-adapter branch January 31, 2026 00:43
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