Skip to content

add adapter for raydium vault#18521

Merged
g1nt0ki merged 2 commits intoDefiLlama:mainfrom
yash-trufin:truyields/truVault/raydium-vault
Mar 25, 2026
Merged

add adapter for raydium vault#18521
g1nt0ki merged 2 commits intoDefiLlama:mainfrom
yash-trufin:truyields/truVault/raydium-vault

Conversation

@yash-trufin
Copy link
Copy Markdown
Contributor

@yash-trufin yash-trufin commented Mar 24, 2026

NOTE

Please enable "Allow edits by maintainers" while putting up the PR.


  1. If you would like to add a volume/fees/revenue adapter please submit the PR here.

  2. Once your adapter has been merged, it takes time to show on the UI. If more than 24 hours have passed, please let us know in Discord.

  3. Sorry, We no longer accept fetch adapter for new projects, we prefer the tvl to computed from blockchain data, if you have trouble with creating a the adapter, please hop onto our discord, we are happy to assist you.

  4. For updating listing info It is a different repo, you can find your listing in this file, you can edit it there and put up a PR

  5. Please do not add new npm dependencies, do not edit/push pnpm-lock.yaml file as part of your changes


(Needs to be filled only for new listings)

Name (to be shown on DefiLlama): TruVault
Twitter Link: https://x.com/TruYields
List of audit links if any:
Website Link: https://app.truyields.com
Logo (High resolution, will be shown with rounded borders): https://truyields.com/brand/mark-primary.png
Current TVL:
Treasury Addresses (if the protocol has treasury)
Chain: Solana
Coingecko ID (so your TVL can appear on Coingecko, leave empty if not listed): (https://api.coingecko.com/api/v3/coins/list)
Coinmarketcap ID (so your TVL can appear on Coinmarketcap, leave empty if not listed): (https://api.coinmarketcap.com/data-api/v3/map/all?listing_status=active,inactive,untracked&start=1&limit=10000)
Short Description (to be shown on DefiLlama):
Token address and ticker if any:
Category (full list at https://defillama.com/categories) *Please choose only one: Yield
Oracle Provider(s): Specify the oracle(s) used (e.g., Chainlink, Band, API3, TWAP, etc.):
Implementation Details: Briefly describe how the oracle is integrated into your project:
Documentation/Proof: Provide links to documentation or any other resources that verify the oracle's usage:
forkedFrom (Does your project originate from another project):
methodology (what is being counted as tvl, how is tvl being calculated):
Github org/user (Optional, if your code is open source, we can track activity):
Does this project have a referral program?

TruVaults is a new listing under the parent https://defillama.com/protocol/trufin-protocol
TruFin has undergone a rebrand and we are now called TruYields. I need help with updating the website url, twitter handle, and logo. I have included the new details in the PR description above.

TruYields (update logo and links, rename from TruFin Protocol to TruYields)
├── TruStake (update logo and links)
├── TruVault (this PR)
└── TruFin Legacy Vaults (update logo and links)

Summary by CodeRabbit

  • New Features
    • Added Total Value Locked (TVL) tracking for the TruFin Raydium vault on Solana. Shows aggregated vault value including SOL balance, token holdings, and estimated position liquidity with accrued fees; factors in truSOL valuation from its stake pool. Provides a single Solana TVL metric for the vault to reflect on-chain holdings and position-based assets.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 24, 2026

📝 Walkthrough

Walkthrough

Adds a new Solana TVL module that derives vault PDAs, fetches vault and pool accounts in parallel, decodes vault/position/pool/stake-pool state, computes concentrated-liquidity token amounts and truSOL price, and returns total TVL denominated in SOL.

Changes

Cohort / File(s) Summary
TruFin Raydium Vault TVL Module
projects/trufin-vaults/index.js
New module implementing TVL calculation for the TruFin Raydium vault: defines program/mint PDAs, derives vault state & position PDAs, parallel-fetches balances and accounts, decodes vault/position/pool/stake-pool data, computes token amounts via tick math, derives truSOL price, and exports methodology and solana.tvl.

Sequence Diagram

sequenceDiagram
    participant TVL as TVL Calculator
    participant RPC as Solana RPC
    participant Vault as Vault Accounts
    participant Pool as Raydium CLMM Pool
    participant StakePool as StakePool

    TVL->>TVL: Derive vault PDAs (state, ATA, position NFT)

    par Parallel Fetches
        TVL->>RPC: Fetch vault SOL balance
        TVL->>RPC: Fetch WSOL/truSOL token accounts
        TVL->>RPC: Fetch vault position account
        TVL->>RPC: Fetch Raydium pool account
        TVL->>RPC: Fetch stake pool account
    end

    RPC-->>TVL: Return account data

    TVL->>TVL: Decode vault state (tick bounds, pool address)
    TVL->>TVL: Decode position account details
    TVL->>TVL: Decode Raydium pool data

    TVL->>StakePool: Read stake pool totals/supply
    StakePool-->>TVL: Return totals for truSOL price calc

    TVL->>TVL: Calculate truSOL price
    TVL->>TVL: Compute position token amounts using tickToPrice
    TVL->>TVL: Sum vault SOL, direct token balances, position amounts, accrued fees

    TVL->>TVL: Convert to SOL (divide by 1e9)
    TVL-->>TVL: Return { solana: totalSol }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through PDAs beneath the moonlit log,

Decoded ticks and counted every tiny cog,
WSOL, truSOL, and fees—stacked neat in a row,
I crunched the numbers fast, watched the TVL grow,
A joyful vault-hop dance across Solana's bog. 🥕✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description includes the standard template with most required fields filled (Name, Twitter, Website, Logo, Chain, Category). However, critical fields like Short Description, methodology, and Token address are empty or incomplete. Complete the missing required fields: add a Short Description, specify the methodology for TVL calculation, and provide Token address/ticker if applicable.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'add adapter for raydium vault' accurately describes the main change—adding a new TVL adapter module for a Raydium vault.

✏️ 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.

@llamabutler
Copy link
Copy Markdown

The adapter at projects/trufin-vaults exports TVL:

solana                    357.00

total                    357.11 

@llamabutler
Copy link
Copy Markdown

The adapter at projects/trufin-vaults exports TVL:

solana                    357.00

total                    356.72 

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: 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/trufin-vaults/index.js`:
- Around line 121-123: The adapter exports live-only Solana TVL via
module.exports with solana.tvl set to raydiumVaultTvl but does not mark it
latest-only; add the timetravel flag to the export by setting timetravel: false
alongside tvl (i.e., update the exported solana object that references
raydiumVaultTvl to include timetravel: false) so historical runs won't replay
current RPC state.
- Around line 104-116: The code assumes pool side A is WSOL and B is truSOL when
computing positionWsol/positionTrusol; instead, inspect the pool's token
ordering (e.g., pool.tokenMintA and pool.tokenMintB) after
decodeAccount("raydiumCLMM", poolAccount) and map amount0/amount1 and
tokenFeesOwedA/tokenFeesOwedB to the correct buckets accordingly before valuing:
if tokenMintA equals WSOL_MINT then treat amount0+tokenFeesOwedA as positionWsol
and amount1+tokenFeesOwedB as positionTrusol, otherwise swap them; then compute
positionWsol/positionTrusol and totalSol using trusolPrice as before so TVL uses
the correct side mapping for getPositionAmounts outputs and tokenFeesOwedA/B.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ed7623e-c7ae-4042-885f-6a56b897f25f

📥 Commits

Reviewing files that changed from the base of the PR and between 3b369bc and b738408.

📒 Files selected for processing (1)
  • projects/trufin-vaults/index.js

Comment on lines +104 to +116
const position = decodeAccount("raydiumPositionInfo", positionAccount);
const pool = decodeAccount("raydiumCLMM", poolAccount);

const { amount0, amount1 } = getPositionAmounts(
position.tickLower, position.tickUpper, pool.tickCurrent,
Number(position.liquidity.toString()),
);

const positionWsol = amount0 + Number(position.tokenFeesOwedA.toString());
const positionTrusol = amount1 + Number(position.tokenFeesOwedB.toString());

const totalSol = solBalance + wsolBalance + positionWsol
+ (trusolBalance + positionTrusol) * trusolPrice;
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.

⚠️ Potential issue | 🟠 Major

Map CLMM side A/B to WSOL/truSOL before valuing the position.

amount0/amount1 and tokenFeesOwedA/B are pool-side values, but this code hard-codes side A as WSOL and side B as truSOL. If the Raydium pool uses the opposite mint ordering, the position portion of TVL is mispriced. Read the pool’s token ordering first, then route each side into the WSOL/truSOL buckets before applying trusolPrice.

🧭 Minimal shape of the fix
-  const positionWsol = amount0 + Number(position.tokenFeesOwedA.toString());
-  const positionTrusol = amount1 + Number(position.tokenFeesOwedB.toString());
+  const isWsolTokenA = /* compare the decoded pool token ordering against WSOL_MINT/TRUSOL_MINT */;
+
+  const positionWsol = isWsolTokenA
+    ? amount0 + Number(position.tokenFeesOwedA.toString())
+    : amount1 + Number(position.tokenFeesOwedB.toString());
+  const positionTrusol = isWsolTokenA
+    ? amount1 + Number(position.tokenFeesOwedB.toString())
+    : amount0 + Number(position.tokenFeesOwedA.toString());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/trufin-vaults/index.js` around lines 104 - 116, The code assumes
pool side A is WSOL and B is truSOL when computing positionWsol/positionTrusol;
instead, inspect the pool's token ordering (e.g., pool.tokenMintA and
pool.tokenMintB) after decodeAccount("raydiumCLMM", poolAccount) and map
amount0/amount1 and tokenFeesOwedA/tokenFeesOwedB to the correct buckets
accordingly before valuing: if tokenMintA equals WSOL_MINT then treat
amount0+tokenFeesOwedA as positionWsol and amount1+tokenFeesOwedB as
positionTrusol, otherwise swap them; then compute positionWsol/positionTrusol
and totalSol using trusolPrice as before so TVL uses the correct side mapping
for getPositionAmounts outputs and tokenFeesOwedA/B.

Comment on lines +121 to +123
module.exports = {
methodology: "Counts the TVL of the TruFin Raydium Vault.",
solana: { tvl: raydiumVaultTvl },
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.

⚠️ Potential issue | 🟠 Major

Mark this adapter as latest-only.

raydiumVaultTvl always reads live Solana RPC state and never consumes historical inputs. Without timetravel: false, historical runs can replay current TVL as if it were past data.

🗓️ Minimal export fix
 module.exports = {
+  timetravel: false,
   methodology: "Counts the TVL of the TruFin Raydium Vault.",
   solana: { tvl: raydiumVaultTvl },
 };

Based on learnings: In DefiLlama adapters, timetravel is a valid export key.

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

In `@projects/trufin-vaults/index.js` around lines 121 - 123, The adapter exports
live-only Solana TVL via module.exports with solana.tvl set to raydiumVaultTvl
but does not mark it latest-only; add the timetravel flag to the export by
setting timetravel: false alongside tvl (i.e., update the exported solana object
that references raydiumVaultTvl to include timetravel: false) so historical runs
won't replay current RPC state.

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

♻️ Duplicate comments (2)
projects/trufin-vaults/index.js (2)

119-122: ⚠️ Potential issue | 🟠 Major

Mark this adapter as latest-only.

raydiumVaultTvl only reads live Solana RPC state and never consumes historical inputs, so historical runs will replay current TVL unless timetravel: false is exported.

🗓️ Minimal export fix
 module.exports = {
+  timetravel: false,
   methodology: "Counts the TVL of the TruFin Raydium Vault.",
   solana: { tvl: raydiumVaultTvl },
 };

Based on learnings: In DefiLlama adapters, timetravel is a valid export key.

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

In `@projects/trufin-vaults/index.js` around lines 119 - 122, The adapter is
currently replaying live RPC state for historical runs; update the
module.exports object to mark this adapter as latest-only by adding timetravel:
false to the exported object (the same object that contains methodology and
solana), e.g., add the key timetravel: false alongside methodology and solana so
raydiumVaultTvl is treated as non-timetravelable.

102-111: ⚠️ Potential issue | 🟠 Major

Use the decoded pool ordering when splitting A/B balances.

You decode pool on Line 103, but Lines 110-111 still hard-code side A as WSOL and side B as truSOL. If Raydium stores the pair in the opposite order, both the position liquidity and accrued fees are assigned to the wrong asset.

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

In `@projects/trufin-vaults/index.js` around lines 102 - 111, The code assumes
amount0/amount1 and tokenFeesOwedA/tokenFeesOwedB map to WSOL/truSOL
(positionWsol/positionTrusol) regardless of pool ordering; update the logic that
sets positionWsol and positionTrusol (and any uses of position amounts) to
consult the decoded pool ordering from pool (e.g., pool.tokenA/tokenB or
pool.tokenOrder) and assign amount0 + tokenFeesOwedA to whichever asset is the
first token and amount1 + tokenFeesOwedB to the second token, swapping
assignments when the pair is stored reversed so balances and fees match the
actual asset mints returned by decodeAccount("raydiumCLMM", poolAccount).
🤖 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/trufin-vaults/index.js`:
- Around line 119-122: The module export for this project currently exposes
methodology and solana: { tvl: raydiumVaultTvl } but does not mark that the TVL
is actually counted inside Raydium CLMM pools; update the exported object
(module.exports) to include doublecounted: true so the overlap with
projects/raydium/index.js is surfaced (i.e., add doublecounted: true at the
top-level export alongside methodology and solana).
- Around line 116-121: raydiumVaultTvl is already exported under module.exports
as solana.tvl, so its return should be the native/token balance payload itself
rather than a chain-scoped wrapper; update the return in raydiumVaultTvl to
return the balances object (e.g., the mapping of token identifiers to amounts or
the native token balance) directly instead of returning { solana: ... }, leaving
module.exports = { methodology: ..., solana: { tvl: raydiumVaultTvl } }
unchanged.

---

Duplicate comments:
In `@projects/trufin-vaults/index.js`:
- Around line 119-122: The adapter is currently replaying live RPC state for
historical runs; update the module.exports object to mark this adapter as
latest-only by adding timetravel: false to the exported object (the same object
that contains methodology and solana), e.g., add the key timetravel: false
alongside methodology and solana so raydiumVaultTvl is treated as
non-timetravelable.
- Around line 102-111: The code assumes amount0/amount1 and
tokenFeesOwedA/tokenFeesOwedB map to WSOL/truSOL (positionWsol/positionTrusol)
regardless of pool ordering; update the logic that sets positionWsol and
positionTrusol (and any uses of position amounts) to consult the decoded pool
ordering from pool (e.g., pool.tokenA/tokenB or pool.tokenOrder) and assign
amount0 + tokenFeesOwedA to whichever asset is the first token and amount1 +
tokenFeesOwedB to the second token, swapping assignments when the pair is stored
reversed so balances and fees match the actual asset mints returned by
decodeAccount("raydiumCLMM", poolAccount).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9cede83c-2451-4388-96b6-8c1cad21bffb

📥 Commits

Reviewing files that changed from the base of the PR and between b738408 and cd084f4.

📒 Files selected for processing (1)
  • projects/trufin-vaults/index.js

Comment on lines +116 to +121
return { solana: totalSol / 1e9 };
}

module.exports = {
methodology: "Counts the TVL of the TruFin Raydium Vault.",
solana: { tvl: raydiumVaultTvl },
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.

⚠️ Potential issue | 🟠 Major

Match the solana.tvl return contract.

On Line 121 this function is already mounted under the Solana chain. Returning { solana: ... } again on Line 116 is what llamabutler is flagging as “exports TVL values twice”; return the native/token balance payload directly instead of another chain-scoped wrapper.

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

In `@projects/trufin-vaults/index.js` around lines 116 - 121, raydiumVaultTvl is
already exported under module.exports as solana.tvl, so its return should be the
native/token balance payload itself rather than a chain-scoped wrapper; update
the return in raydiumVaultTvl to return the balances object (e.g., the mapping
of token identifiers to amounts or the native token balance) directly instead of
returning { solana: ... }, leaving module.exports = { methodology: ..., solana:
{ tvl: raydiumVaultTvl } } unchanged.

Comment on lines +119 to +122
module.exports = {
methodology: "Counts the TVL of the TruFin Raydium Vault.",
solana: { tvl: raydiumVaultTvl },
};
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.

⚠️ Potential issue | 🟠 Major

Flag the Raydium overlap as external double counting.

This vault TVL is capital parked inside a Raydium CLMM position, and projects/raydium/index.js:1-35 already sums every CLMM pool’s vaultA/vaultB balances. Add doublecounted: true so the overlap is surfaced correctly on the protocol page.

🔁 Minimal export fix
 module.exports = {
+  doublecounted: true,
   methodology: "Counts the TVL of the TruFin Raydium Vault.",
   solana: { tvl: raydiumVaultTvl },
 };

Based on learnings: doublecounted: true remains appropriate when a vault deploys assets into an external protocol that DefiLlama tracks independently.

📝 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
module.exports = {
methodology: "Counts the TVL of the TruFin Raydium Vault.",
solana: { tvl: raydiumVaultTvl },
};
module.exports = {
doublecounted: true,
methodology: "Counts the TVL of the TruFin Raydium Vault.",
solana: { tvl: raydiumVaultTvl },
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/trufin-vaults/index.js` around lines 119 - 122, The module export
for this project currently exposes methodology and solana: { tvl:
raydiumVaultTvl } but does not mark that the TVL is actually counted inside
Raydium CLMM pools; update the exported object (module.exports) to include
doublecounted: true so the overlap with projects/raydium/index.js is surfaced
(i.e., add doublecounted: true at the top-level export alongside methodology and
solana).

@g1nt0ki g1nt0ki self-assigned this Mar 25, 2026
@g1nt0ki g1nt0ki merged commit 2236677 into DefiLlama:main Mar 25, 2026
2 checks passed
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