Skip to content

Update surf-liquid TVL adapter with V2/V3 vault support and staking#18401

Open
rohansingh4 wants to merge 4 commits intoDefiLlama:mainfrom
rohansingh4:update-surf-liquid-tvl
Open

Update surf-liquid TVL adapter with V2/V3 vault support and staking#18401
rohansingh4 wants to merge 4 commits intoDefiLlama:mainfrom
rohansingh4:update-surf-liquid-tvl

Conversation

@rohansingh4
Copy link

@rohansingh4 rohansingh4 commented Mar 11, 2026

Summary

  • Update TVL adapter to dynamically enumerate V2 vaults via factory (getTotalVaults/getVaultInfo) and V3 vaults via VaultDeployed event logs
  • Count Morpho ERC-4626 vault share positions held by each vault as TVL
  • Add staking section: SURF staked in SURFStakingV5 + CreatorBid SURF subscriptions (SURF locked in the token contract)

Test results

  • TVL: ~$239k (Morpho vault deposits across V2 + V3 vaults)
  • Staking: ~$31k (SURF staked + CreatorBid subscriptions)

Contracts

  • V2 Factory: 0x1D283b668F947E03E8ac8ce8DA5505020434ea0E (Base)
  • V3 Factory: 0xf1d64dee9f8e109362309a4bfbb523c8e54fa1aa (Base)
  • SURF Staking: 0xB0fDFc081310A5914c2d2c97e7582F4De12FA9d6 (Base)
  • SURF Token: 0xcdca2eaae4a8a6b83d7a3589946c2301040dafbf (Base)

Summary by CodeRabbit

  • New Features

    • Enhanced TVL tracking that discovers and aggregates positions across V2 and V3 vaults (replaces previous target-based approach).
    • SURF staking and subscription balances are now included in TVL reporting.
    • Expanded asset support including USDC, WETH and CBBTC.
  • Documentation

    • Methodology updated for multi-source TVL and staking; metadata now includes double-counting, misrepresented-token notes and hallmarks.

- Enumerate V2 vaults via factory getTotalVaults/getVaultInfo
- Discover V3 vaults via VaultDeployed event logs
- Count Morpho ERC-4626 vault share positions as TVL
- Add staking: SURF staked + CreatorBid subscriptions
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 11, 2026

📝 Walkthrough

Walkthrough

Replaces single-target TVL with tvl(api) that discovers Morpho ERC‑4626 positions from V2 (factory) and V3 (VaultDeployed logs) vaults, aggregates token/owner pairs, and adds staking(api) to include SURF staking and subscriptions; exports and metadata updated.

Changes

Cohort / File(s) Summary
Surf Liquid TVL & staking
projects/surf-liquid/index.js
Replaces inline TVL with tvl(api) that enumerates V2 vaults via V2_FACTORY and discovers V3 vaults from VaultDeployed logs, builds tokensAndOwners and calls api.sumTokens. Adds staking(api) (reads SURF_STAKING.totalStaked and SURF subscription balance), declares constants (V2_FACTORY, V3_FACTORY, SURF_STAKING, SURF_TOKEN, USDC, WETH, CBBTC, ASSETS, ZERO_ADDR), and updates module.exports (base.tvl, base.staking) plus methodology, doublecounted, misrepresentedTokens, and hallmarks metadata.

Sequence Diagram(s)

sequenceDiagram
    participant Client as API Handler
    participant V2F as V2 Factory
    participant V3Logs as V3 Event Logs
    participant Vault as Vault Contract
    participant Sum as api.sumTokens

    Client->>V2F: call getTotalVaults / getVaultInfo
    V2F-->>Client: return V2 vault addresses & currentVault data
    Client->>V3Logs: query VaultDeployed logs from V3 factory
    V3Logs-->>Client: return V3 vault addresses (asset → vault)
    Client->>Vault: read token() and owner() for each discovered vault
    Vault-->>Client: token/owner pairs
    Client->>Sum: submit tokensAndOwners list
    Sum-->>Client: aggregated TVL per token
Loading
sequenceDiagram
    participant Client as API Handler
    participant STK as SURF_STAKING Contract
    participant SURF as SURF_TOKEN Contract
    participant Acc as Aggregator

    Client->>STK: call totalStaked()
    STK-->>Client: staked SURF amount
    Client->>SURF: call balanceOf(SURF_TOKEN) for subscriptions
    SURF-->>Client: subscription SURF amount
    Client->>Acc: add SURF balances to tokensAndOwners
    Acc-->>Client: SURF included in final TVL
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I'm a rabbit in code with nimble little paws,
I sniffed V2 and V3 vaults and counted their cause,
I hopped up SURF stakes and subscriptions in tow,
Collected tokens and owners — carrots in a row. 🥕🐇

🚥 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
Title check ✅ Passed The title clearly summarizes the main changes: updating the surf-liquid TVL adapter to support both V2 and V3 vaults and adding staking functionality.
Description check ✅ Passed The PR description provides a clear summary of changes, test results with specific metrics, and contract addresses. However, it does not follow the provided repository template structure, which requires new listings to include metadata fields like methodology, token address, and category.

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

The adapter at projects/surf-liquid exports TVL:

base                      239.21 k
base-staking              31.42 k
staking                   31.42 k

total                    239.21 k 

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

🤖 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/surf-liquid/index.js`:
- Around line 71-76: The exported adapter object (module.exports) currently
exposes base: { tvl, staking } where base.tvl reports Morpho ERC‑4626 share
balances held by Surf vaults; mark this as a wrapped/downstream TVL by adding
doublecounted: true and misrepresentedTokens: true to the exported object (next
to methodology and base) so consumers know it’s vault‑in‑vault/wrapped-share
TVL; alternatively, if you prefer to represent underlying assets instead, modify
the tvl implementation referenced by the tvl symbol to unwrap ERC‑4626 shares to
their underlying before summing, but the quick fix is to add the two flags to
module.exports alongside base and methodology.
- Around line 25-27: The V2 loop pushes [v2MorphoVaults[i], v2Owners[i]] even
when one of those values is falsy; mirror the V3 guard by checking both the
vault address and owner are truthy and not ZERO_ADDR before pushing to
tokensAndOwners. Update the loop that iterates v2Owners / v2MorphoVaults to skip
iterations where v2MorphoVaults[i] is ZERO_ADDR or where v2MorphoVaults[i] or
v2Owners[i] are falsy (e.g., result of getVaultInfo()/currentVault()), so
sumTokens only receives valid [token, owner] pairs. Ensure you reference the
same variables (v2MorphoVaults, v2Owners, ZERO_ADDR, tokensAndOwners, sumTokens)
when making the check.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b9bb8de9-d9d4-4001-8461-aff70cf9d3e1

📥 Commits

Reviewing files that changed from the base of the PR and between 231d331 and f124e99.

📒 Files selected for processing (1)
  • projects/surf-liquid/index.js

@rohansingh4
Copy link
Author

Revenue is 70,000 Surf tokens, you can convert them to USD. Please refer- https://dune.com/surfliquid/stats, tvl, volume, surf buyback (is our revenue) here should't divert much from dune numbers. Dune also tracks historical prices, so I am aware there will be slight variation though most of the volume/tvl is in usdc.

Include SURF staking and CreatorBid subscriptions directly in
the tvl function instead of a separate staking category.
@llamabutler
Copy link

The adapter at projects/surf-liquid exports TVL:

base                      270.91 k

total                    270.91 k 

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)
projects/surf-liquid/index.js (1)

56-67: Consider separating staking into its own export.

SURF staking and CreatorBid subscriptions are currently merged into the tvl function. DefiLlama convention typically separates protocol token staking into a dedicated staking export. This provides clearer metrics and matches the test output showing distinct base ($239k) and base-staking ($31k) values.

♻️ Suggested refactor to separate staking
 async function tvl(api) {
   const tokensAndOwners = [];
   // ... V2 and V3 vault logic ...
   await api.sumTokens({ tokensAndOwners });
-
-  // SURF staking contract
-  const totalStaked = await api.call({ abi: "uint256:totalStaked", target: SURF_STAKING });
-  api.add(SURF_TOKEN, totalStaked);
-
-  // CreatorBid SURF subscriptions (SURF locked in the token contract)
-  const subscribed = await api.call({
-    abi: "function balanceOf(address) view returns (uint256)",
-    target: SURF_TOKEN,
-    params: [SURF_TOKEN],
-  });
-  api.add(SURF_TOKEN, subscribed);
 }

+async function staking(api) {
+  // SURF staking contract
+  const totalStaked = await api.call({ abi: "uint256:totalStaked", target: SURF_STAKING });
+  api.add(SURF_TOKEN, totalStaked);
+
+  // CreatorBid SURF subscriptions (SURF locked in the token contract)
+  const subscribed = await api.call({
+    abi: "function balanceOf(address) view returns (uint256)",
+    target: SURF_TOKEN,
+    params: [SURF_TOKEN],
+  });
+  api.add(SURF_TOKEN, subscribed);
+}

 module.exports = {
   // ...
   base: {
     tvl,
+    staking,
   },
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/surf-liquid/index.js` around lines 56 - 67, Split the SURF staking
logic out of the tvl function into a dedicated staking export: move the call
that reads totalStaked (the api.call with abi "uint256:totalStaked" targeting
SURF_STAKING) and the corresponding api.add(SURF_TOKEN, totalStaked) into a new
exported async function named staking (or export const staking = { tvl: ... }
per repo convention) that returns the staking balances; keep the existing
CreatorBid subscription code (the balanceOf call using SURF_TOKEN as target and
params [SURF_TOKEN] and its api.add) inside tvl. Ensure the new staking export
uses the same api instance pattern and is exported alongside tvl so
tests/reporting show separate base and base-staking values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@projects/surf-liquid/index.js`:
- Around line 56-67: Split the SURF staking logic out of the tvl function into a
dedicated staking export: move the call that reads totalStaked (the api.call
with abi "uint256:totalStaked" targeting SURF_STAKING) and the corresponding
api.add(SURF_TOKEN, totalStaked) into a new exported async function named
staking (or export const staking = { tvl: ... } per repo convention) that
returns the staking balances; keep the existing CreatorBid subscription code
(the balanceOf call using SURF_TOKEN as target and params [SURF_TOKEN] and its
api.add) inside tvl. Ensure the new staking export uses the same api instance
pattern and is exported alongside tvl so tests/reporting show separate base and
base-staking values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 84b8abd6-d866-4fd3-a80c-e0bf4684b494

📥 Commits

Reviewing files that changed from the base of the PR and between f124e99 and e90db2a.

📒 Files selected for processing (1)
  • projects/surf-liquid/index.js

@RohanNero RohanNero self-assigned this Mar 12, 2026

module.exports = {
methodology: "Counts the morpho deposits of each Surf Liquid vault.",
methodology: "TVL counts Morpho vault deposits across V2 and V3 Surf Liquid vaults, SURF staked, and CreatorBid SURF subscriptions.",
Copy link
Contributor

Choose a reason for hiding this comment

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

can you add a hallmarks entry for the v3 factory deployment date so the spike in tvl is explained

target: SURF_TOKEN,
params: [SURF_TOKEN],
});
api.add(SURF_TOKEN, subscribed);
Copy link
Contributor

Choose a reason for hiding this comment

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

please move the SURF token tracking back under the staking export

Copy link
Author

Choose a reason for hiding this comment

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

Done, also when will numbers be updated and depreciation tag removed?

Per reviewer feedback:
- Move SURF staking + CreatorBid subscriptions back under staking export
- Add hallmarks entry for V3 factory launch (2025-11-30) to explain TVL spike
@llamabutler
Copy link

The adapter at projects/surf-liquid exports TVL:

base                      239.11 k
base-staking              36.80 k
staking                   36.80 k

total                    239.11 k 

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.

♻️ Duplicate comments (2)
projects/surf-liquid/index.js (2)

71-77: ⚠️ Potential issue | 🟠 Major

Mark wrapped/downstream TVL explicitly in adapter metadata.

base.tvl sums Morpho ERC-4626 share balances held by Surf vaults, which is wrapped/downstream exposure and can overlap with underlying protocol TVL. Add doublecounted: true and misrepresentedTokens: true (or unwrap to underlying instead).

🏷️ Proposed metadata update
 module.exports = {
   methodology: "TVL counts Morpho vault deposits across V2 and V3 Surf Liquid vaults. Staking includes SURF staked and SURF subscriptions.",
+  doublecounted: true,
+  misrepresentedTokens: true,
   hallmarks: [["2025-11-30", "V3 factory launched"]],
   base: {
     tvl,
     staking,
   },
 };

Based on learnings, the Royco v2 adapter marks vault-in-vault accounting as doublecounted: true, and AFI marks raw vault-share reporting as misrepresentedTokens: true.

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

In `@projects/surf-liquid/index.js` around lines 71 - 77, The adapter metadata
currently exports module.exports with base: { tvl, staking } but does not mark
that base.tvl reports wrapped/downstream Morpho ERC-4626 share balances; update
the exported metadata to explicitly flag this by adding doublecounted: true and
misrepresentedTokens: true (or alternatively unwrap the vault shares to
underlying assets) so consumers know the TVL may overlap with underlying
protocols; locate the module.exports block (symbols: module.exports, base, tvl,
staking) and add those two boolean flags to the metadata object.

25-27: ⚠️ Potential issue | 🟡 Minor

Harden V2 pair validation before sumTokens.

At Line 26, the guard still only checks v2MorphoVaults[i] !== ZERO_ADDR. If v2Owners[i] or v2MorphoVaults[i] is falsy, an invalid [token, owner] pair can still be pushed.

🛡️ Proposed fix
   for (let i = 0; i < v2Owners.length; i++) {
-    if (v2MorphoVaults[i] !== ZERO_ADDR) {
+    if (v2Owners[i] && v2Owners[i] !== ZERO_ADDR && v2MorphoVaults[i] && v2MorphoVaults[i] !== ZERO_ADDR) {
       tokensAndOwners.push([v2MorphoVaults[i], v2Owners[i]]);
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/surf-liquid/index.js` around lines 25 - 27, The loop that builds
tokensAndOwners currently only checks v2MorphoVaults[i] !== ZERO_ADDR and can
push invalid pairs when v2Owners[i] or v2MorphoVaults[i] is falsy; update the
guard in the loop that iterates over v2Owners to ensure both v2MorphoVaults[i]
is truthy and not ZERO_ADDR and v2Owners[i] is truthy before pushing into
tokensAndOwners so sumTokens receives only valid [token, owner] tuples (refer to
v2Owners, v2MorphoVaults, ZERO_ADDR, tokensAndOwners and the code path that
calls sumTokens).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@projects/surf-liquid/index.js`:
- Around line 71-77: The adapter metadata currently exports module.exports with
base: { tvl, staking } but does not mark that base.tvl reports
wrapped/downstream Morpho ERC-4626 share balances; update the exported metadata
to explicitly flag this by adding doublecounted: true and misrepresentedTokens:
true (or alternatively unwrap the vault shares to underlying assets) so
consumers know the TVL may overlap with underlying protocols; locate the
module.exports block (symbols: module.exports, base, tvl, staking) and add those
two boolean flags to the metadata object.
- Around line 25-27: The loop that builds tokensAndOwners currently only checks
v2MorphoVaults[i] !== ZERO_ADDR and can push invalid pairs when v2Owners[i] or
v2MorphoVaults[i] is falsy; update the guard in the loop that iterates over
v2Owners to ensure both v2MorphoVaults[i] is truthy and not ZERO_ADDR and
v2Owners[i] is truthy before pushing into tokensAndOwners so sumTokens receives
only valid [token, owner] tuples (refer to v2Owners, v2MorphoVaults, ZERO_ADDR,
tokensAndOwners and the code path that calls sumTokens).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 736dc5ba-3ccc-4d6a-91fd-fbfec4ee2caa

📥 Commits

Reviewing files that changed from the base of the PR and between e90db2a and ccfb280.

📒 Files selected for processing (1)
  • projects/surf-liquid/index.js

- Mark adapter as doublecounted and misrepresentedTokens since TVL counts
  Morpho ERC-4626 vault shares (vault-in-vault)
- Harden V2 loop to check both owner and vault are truthy before pushing
@llamabutler
Copy link

The adapter at projects/surf-liquid exports TVL:

base                      195.86 k
base-staking              37.10 k
staking                   37.10 k

total                    195.86 k 

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)
projects/surf-liquid/index.js (1)

37-37: Consider documenting the hardcoded fromBlock.

The magic number 38856207 should have a brief inline comment explaining it's the V3 factory deployment block, improving maintainability for future developers.

-    fromBlock: 38856207,
+    fromBlock: 38856207, // V3 factory deployment block
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/surf-liquid/index.js` at line 37, The literal 38856207 assigned to
fromBlock is a magic number; add a brief inline comment next to the fromBlock
assignment (the "fromBlock" property containing 38856207) stating that this is
the V3 factory deployment block (include network and approximate date if known)
so future maintainers understand why it is hardcoded and can update it safely.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@projects/surf-liquid/index.js`:
- Line 37: The literal 38856207 assigned to fromBlock is a magic number; add a
brief inline comment next to the fromBlock assignment (the "fromBlock" property
containing 38856207) stating that this is the V3 factory deployment block
(include network and approximate date if known) so future maintainers understand
why it is hardcoded and can update it safely.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7cd87ec0-142d-4205-a8cd-adaf1c88b72a

📥 Commits

Reviewing files that changed from the base of the PR and between ccfb280 and 241a0d7.

📒 Files selected for processing (1)
  • projects/surf-liquid/index.js

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