Skip to content

Add Quiver Protocol adapter (Robinhood Chain)#2835

Open
mitchelvanamstel wants to merge 1 commit into
DefiLlama:masterfrom
mitchelvanamstel:quiver-protocol
Open

Add Quiver Protocol adapter (Robinhood Chain)#2835
mitchelvanamstel wants to merge 1 commit into
DefiLlama:masterfrom
mitchelvanamstel:quiver-protocol

Conversation

@mitchelvanamstel

@mitchelvanamstel mitchelvanamstel commented Jul 19, 2026

Copy link
Copy Markdown

Adds a yields adapter for Quiver Protocol (protocolId 8239, Liquidity Manager on Robinhood Chain — TVL adapter and fees adapter already merged: DefiLlama/DefiLlama-Adapters#20112, DefiLlama/dimension-adapters#8247).

Methodology

  • One pool entry per vault, enumerated live from both factories (Uniswap V3 + V4, incl. tokenized-stock pairs like NVDA/USDG).
  • tvlUsd: strategy position (liquidity between tick bounds at current pool tick; V4 via StateView) + idle strategy balances, priced via the DefiLlama price API.
  • apyBase: depositor share (90%; perf-fee bps read live from FeeConfig) of gross LP fees from on-chain Harvest events over the trailing 7d (clamped to protocol age), annualized against current TVL.
  • Chain notes: coins.llama.fi/block has no Robinhood support yet, so the adapter binary-searches the block at the window start on-chain; sdk provider key is robinhoodchain.

Test

npm run test --adapter=quiver-protocol: 65 passed, 65 total. 10 pools returned; current TVLs are small (young protocol, factories deployed 2026-07-16) so pools surface in the UI as they cross the $10k floor.

Summary by CodeRabbit

  • New Features
    • Added Quiver Protocol vault coverage on the Robinhood chain.
    • Displays vault TVL, underlying tokens, and base APY.
    • Supports both Uniswap v3 and v4 concentrated-liquidity strategies.
    • Calculates recent harvest-based fees and annualized returns for each vault.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a DefiLlama adapter for Quiver Protocol vaults on Robinhood chain. It enumerates v3/v4 vaults, calculates concentrated and idle token balances, values harvest fees, annualizes net fees into APY, and exports adapter metadata.

Changes

Quiver Protocol adapter

Layer / File(s) Summary
Contracts and concentrated-liquidity calculations
src/adaptors/quiver-protocol/index.js
Defines chain configuration, contract ABIs, call helpers, and token amount calculations across concentrated-liquidity tick regions.
Vault discovery and historical window
src/adaptors/quiver-protocol/index.js
Enumerates factory vaults and binary-searches on-chain timestamps to determine the trailing fee-calculation block range.
TVL, APY, and adapter exports
src/adaptors/quiver-protocol/index.js
Reads vault state, prices balances and harvest fees, applies fee splits, computes annualized APY, returns v3/v4 pool metadata, and exports adapter configuration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DefiLlama
  participant QuiverVaults
  participant HarvestEvents
  participant PriceOracle
  DefiLlama->>QuiverVaults: Enumerate vaults and read strategy state
  DefiLlama->>QuiverVaults: Read idle and concentrated token balances
  DefiLlama->>HarvestEvents: Fetch trailing Harvest events
  DefiLlama->>PriceOracle: Get token USD prices
  HarvestEvents-->>DefiLlama: Return harvested fees
  PriceOracle-->>DefiLlama: Return token valuations
  DefiLlama-->>DefiLlama: Apply fee split and annualize APY
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a new Quiver Protocol adapter for Robinhood Chain.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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.

@github-actions

Copy link
Copy Markdown

The quiver-protocol adapter exports pools:

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

Nb of pools: 10
 

Sample pools:
┌─────────┬────────────────────────────────────────────────────────┬───────────────────┬───────────────────┬────────────────┬────────────────────┬────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────┬───────────────────────────────────────────────────────────────────────────────────┐
│ (index) │ pool                                                   │ chain             │ project           │ symbol         │ tvlUsd             │ apyBase            │ underlyingTokens                                                                               │ poolMeta         │ url                                                                               │
├─────────┼────────────────────────────────────────────────────────┼───────────────────┼───────────────────┼────────────────┼────────────────────┼────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────┼───────────────────────────────────────────────────────────────────────────────────┤
│ 0       │ '0x388388456efe3bd4aabc60f865621cc71da86abe-robinhood' │ 'Robinhood Chain' │ 'quiver-protocol' │ 'CASHCAT-WETH' │ 351.8877589347734  │ 1542.2768279916597 │ [ '0x020bfC650A365f8BB26819deAAbF3E21291018b4', '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73' ] │ 'Uniswap V3 CLM' │ 'https://quiverprotocol.finance/vault/0x388388456efe3bd4aabc60f865621cc71da86abe' │
│ 1       │ '0x50bdbdc7dc4d502e314cca6ff933d129444a3fb0-robinhood' │ 'Robinhood Chain' │ 'quiver-protocol' │ 'WETH-VIRTUAL' │ 209.73694999562906 │ 301.89182393855526 │ [ '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73', '0xc6911796042b15d7Fa4F6CDe69e245DdCd3d9c31' ] │ 'Uniswap V3 CLM' │ 'https://quiverprotocol.finance/vault/0x50bdbdc7dc4d502e314cca6ff933d129444a3fb0' │
│ 2       │ '0x622344a28deeae553a56e6e87f368a9575e23b68-robinhood' │ 'Robinhood Chain' │ 'quiver-protocol' │ 'WETH-USDG'    │ 142.4257569164734  │ 153.3025431616235  │ [ '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73', '0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168' ] │ 'Uniswap V3 CLM' │ 'https://quiverprotocol.finance/vault/0x622344a28deeae553a56e6e87f368a9575e23b68' │
│ 3       │ '0xf53bdf6078d115d2c6aeb0bd357ff2656267da8c-robinhood' │ 'Robinhood Chain' │ 'quiver-protocol' │ 'USDG-NVDA'    │ 25.955935650853963 │ 40.10369465115746  │ [ '0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168', '0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC' ] │ 'Uniswap V4 CLM' │ 'https://quiverprotocol.finance/vault/0xf53bdf6078d115d2c6aeb0bd357ff2656267da8c' │
│ 4       │ '0x3c6035da6f347b05c5d56a93ae0e1b2a38c934c0-robinhood' │ 'Robinhood Chain' │ 'quiver-protocol' │ 'WETH-TENDIES' │ 16.781794114210765 │ 1686.2933501313428 │ [ '0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73', '0x45242320DBB855EeA8Fd36804C6487E10E97FCF9' ] │ 'Uniswap V3 CLM' │ 'https://quiverprotocol.finance/vault/0x3c6035da6f347b05c5d56a93ae0e1b2a38c934c0' │
│ 5       │ '0x63d9a0bc98b9dc4702a828f9917826e0b086a084-robinhood' │ 'Robinhood Chain' │ 'quiver-protocol' │ 'USDG-AAPL'    │ 5.149143147637185  │ 0                  │ [ '0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168', '0xaF3D76f1834A1d425780943C99Ea8A608f8a93f9' ] │ 'Uniswap V4 CLM' │ 'https://quiverprotocol.finance/vault/0x63d9a0bc98b9dc4702a828f9917826e0b086a084' │
│ 6       │ '0xebd9f38ccae58ac4fa1407bae19dca65fc85a47a-robinhood' │ 'Robinhood Chain' │ 'quiver-protocol' │ 'GOOGL-USDG'   │ 5.1475888959350815 │ 0                  │ [ '0x2e0847E8910a9732eB3fb1bb4b70a580ADAD4FE3', '0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168' ] │ 'Uniswap V4 CLM' │ 'https://quiverprotocol.finance/vault/0xebd9f38ccae58ac4fa1407bae19dca65fc85a47a' │
│ 7       │ '0x8152fc43e963a3ce2af1273886cbb9b9a7ea992a-robinhood' │ 'Robinhood Chain' │ 'quiver-protocol' │ 'CASHCAT-USDG' │ 5.139568074988233  │ 959.7317834376147  │ [ '0x020bfC650A365f8BB26819deAAbF3E21291018b4', '0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168' ] │ 'Uniswap V4 CLM' │ 'https://quiverprotocol.finance/vault/0x8152fc43e963a3ce2af1273886cbb9b9a7ea992a' │
│ 8       │ '0xe4bfd3cdfacfe598d88bfbbd8b36f40a23b43ac4-robinhood' │ 'Robinhood Chain' │ 'quiver-protocol' │ 'USDG-VIRTUAL' │ 4.848458150666288  │ 0                  │ [ '0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168', '0xc6911796042b15d7Fa4F6CDe69e245DdCd3d9c31' ] │ 'Uniswap V4 CLM' │ 'https://quiverprotocol.finance/vault/0xe4bfd3cdfacfe598d88bfbbd8b36f40a23b43ac4' │
│ 9       │ '0x3a1bac450c2a89e6d316b064d46d05b0652893a0-robinhood' │ 'Robinhood Chain' │ 'quiver-protocol' │ 'SPCX-USDG'    │ 4.746682816957601  │ 0                  │ [ '0x4a0E65A3EcceC6dBe60AE065F2e7bb85Fae35eEa', '0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168' ] │ 'Uniswap V4 CLM' │ 'https://quiverprotocol.finance/vault/0x3a1bac450c2a89e6d316b064d46d05b0652893a0' │
└─────────┴────────────────────────────────────────────────────────┴───────────────────┴───────────────────┴────────────────┴────────────────────┴────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────┴───────────────────────────────────────────────────────────────────────────────────┘
This adapter contains some pools with <10k TVL, these pools won't be shown in DefiLlama

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/adaptors/quiver-protocol/index.js (2)

169-172: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Redundant binary search to resolve toBlock.

blockAtTimestamp(now) starts its search from hi = await provider.getBlockNumber(), and since block timestamps are always ≤ wall-clock time, the loop will simply converge back to that same hi — spending O(log n) sequential getBlock round-trips to re-derive a number already known. toBlock can just be the latest block number directly (e.g. have blockAtTimestamp optionally short-circuit, or hoist a single provider.getBlockNumber() call and reuse it), avoiding the extra RPC round trips on every adapter run.

♻️ Possible fix
+const latestBlockNumber = async () => sdk.getProvider(SDK_CHAIN).getBlockNumber();
+
 const [fromBlock, toBlock] = await Promise.all([
     blockAtTimestamp(windowStart).then((b) => Math.max(b, FACTORY_DEPLOY_BLOCK)),
-    blockAtTimestamp(now),
+    latestBlockNumber(),
   ]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adaptors/quiver-protocol/index.js` around lines 169 - 172, Update the
block-range construction around blockAtTimestamp and toBlock to avoid
binary-searching the current time: fetch the latest block number once with
provider.getBlockNumber() and reuse it as toBlock, while retaining the timestamp
lookup and FACTORY_DEPLOY_BLOCK clamping for fromBlock.

208-215: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Hardcoded epoch duplicates FACTORY_DEPLOY_BLOCK's date and is recomputed per vault for no reason.

1784198950 is an undocumented magic number that corresponds to roughly the same 2026-07-16 date already captured in the FACTORY_DEPLOY_BLOCK comment (line 14) — two independent sources of truth for the same fact. If this literal ever drifts from the real deploy timestamp, every vault's apyBase during the ramp-up window is skewed with no obvious signal why. It's also identical for every vault yet recomputed inside the per-vault .map() callback (lines 186-228).

Consider deriving it once (e.g. (await provider.getBlock(FACTORY_DEPLOY_BLOCK)).timestamp) and hoisting the constant/computation outside the loop.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adaptors/quiver-protocol/index.js` around lines 208 - 215, Replace the
hardcoded epoch in the per-vault APY calculation with the timestamp derived from
FACTORY_DEPLOY_BLOCK, obtaining it once before the vault .map() callback and
reusing it for every vault. Update the windowDaysEffective calculation to
reference this shared deploy timestamp while preserving the existing clamping
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/adaptors/quiver-protocol/index.js`:
- Around line 44-52: Update the multiCall helper to use permitFailure: true and
filter failed or missing outputs before mapping results; also revise the
Promise.all wrapping sdk.getEventLogs calls to use Promise.allSettled and retain
only fulfilled results. Preserve successful vault/strategy data so a single RPC
or pool failure does not abort the adapter feed.

---

Nitpick comments:
In `@src/adaptors/quiver-protocol/index.js`:
- Around line 169-172: Update the block-range construction around
blockAtTimestamp and toBlock to avoid binary-searching the current time: fetch
the latest block number once with provider.getBlockNumber() and reuse it as
toBlock, while retaining the timestamp lookup and FACTORY_DEPLOY_BLOCK clamping
for fromBlock.
- Around line 208-215: Replace the hardcoded epoch in the per-vault APY
calculation with the timestamp derived from FACTORY_DEPLOY_BLOCK, obtaining it
once before the vault .map() callback and reusing it for every vault. Update the
windowDaysEffective calculation to reference this shared deploy timestamp while
preserving the existing clamping behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f32d2c1d-43b9-486f-ad2f-1f50bf8066a0

📥 Commits

Reviewing files that changed from the base of the PR and between 58e4768 and bc2e129.

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

Comment on lines +44 to +52
const call = (target, abi, params = []) =>
sdk.api.abi
.call({ target, abi, params, chain: SDK_CHAIN })
.then((r) => r.output);

const multiCall = (calls, abi) =>
sdk.api.abi
.multiCall({ calls, abi, chain: SDK_CHAIN, permitFailure: false })
.then((r) => r.output.map((o) => o.output));

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='src/adaptors/quiver-protocol/index.js'

echo '--- FILE OUTLINE ---'
ast-grep outline "$file" --view expanded || true

echo
echo '--- LINES 1-260 ---'
nl -ba "$file" | sed -n '1,260p'

echo
echo '--- SEARCH permitFailure / getEventLogs / Promise.all ---'
rg -n "permitFailure|getEventLogs|Promise\.all|multiCall\(" "$file" .

Repository: DefiLlama/yield-server

Length of output: 1021


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='src/adaptors/quiver-protocol/index.js'

echo '--- FILE SIZE ---'
wc -l "$file"

echo
echo '--- LINES 35-240 WITH NUMBERS ---'
awk 'NR>=35 && NR<=240 { printf "%4d  %s\n", NR, $0 }' "$file"

echo
echo '--- SEARCH IN FILE ---'
rg -n "permitFailure|getEventLogs|Promise\.all|multiCall\(|call\(" "$file"

Repository: DefiLlama/yield-server

Length of output: 9335


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- permitFailure true patterns ---'
rg -n "permitFailure:\s*true" src

echo
echo '--- multiCall failure handling patterns ---'
rg -n "r\.output|\.filter\(.+output|permitFailure" src | sed -n '1,220p'

Repository: DefiLlama/yield-server

Length of output: 50378


🌐 Web query:

@defillama/sdk abi multiCall permitFailure false rejects failed calls documentation

💡 Result:

In the @defillama/sdk, the permitFailure: false configuration (which is typically the default behavior) ensures that if any individual call within a multiCall operation fails, the entire multiCall execution throws an error [1][2]. This approach is used when data integrity is critical, as it prevents the adapter from processing partial or potentially incorrect data [2]. By setting permitFailure: false (or omitting the property), you enforce "strict" behavior: - If a single RPC request or contract call within the batch fails, the SDK will halt and return an error for the entire operation [1][3]. - This is preferred in scenarios where missing or failed data would lead to inaccurate results, such as incorrect TVL calculations or flawed de-duplication logic [2][4]. Conversely, setting permitFailure: true allows the multiCall to succeed even if some individual calls fail [1][4]. In this case: - The SDK returns the results for the successful calls and typically returns null or an indication of failure for the unsuccessful ones [1][5]. - Developers often use this when dealing with unreliable contracts or volatile infrastructure, but it requires implementing proper null guards or validation logic to ensure that failed calls are handled correctly downstream [1][5]. When using permitFailure: true, you are responsible for filtering out or handling these failed entries to avoid propagating errors or publishing inflated/deflated data [1][5][4]. As indicated by recent development discussions, maintainers often prefer explicit blacklisting or pre-filtering of problematic contracts over relying solely on permitFailure: true, as the latter can sometimes mask underlying issues and lead to silent errors [4][3].

Citations:


Make the fan-out calls partial-failure tolerant
multiCall(..., permitFailure: false) and the Promise.all around sdk.getEventLogs both fail the whole adapter on a single bad vault/strategy or RPC hiccup. Use permitFailure: true plus filtering, or Promise.allSettled, so one broken pool doesn’t drop the entire feed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adaptors/quiver-protocol/index.js` around lines 44 - 52, Update the
multiCall helper to use permitFailure: true and filter failed or missing outputs
before mapping results; also revise the Promise.all wrapping sdk.getEventLogs
calls to use Promise.allSettled and retain only fulfilled results. Preserve
successful vault/strategy data so a single RPC or pool failure does not abort
the adapter feed.

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.

1 participant