feat(liminal-basis): add remaining Liminal products#2838
Conversation
📝 WalkthroughWalkthroughThe Liminal Basis adapter now calculates 7-day APY from NAV update events, retrieves share-manager values at NAV blocks, and supports pool generation for multiple products across Hyperliquid L1, Arbitrum, and Ethereum. ChangesLiminal Basis adapter
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Adapter
participant NAVOracle
participant ShareManager
participant EventLogs
Adapter->>EventLogs: retrieve NAVUpdated records
EventLogs-->>Adapter: return normalized NAV updates
Adapter->>ShareManager: read totalSupply and decimals at NAV blocks
ShareManager-->>Adapter: return supply and decimals
Adapter->>Adapter: calculate share values and compounded APY
Adapter->>NAVOracle: use product deployment metadata for TVL
NAVOracle-->>Adapter: return product TVL
Adapter-->>Adapter: generate pools for configured chains
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
The liminal-basis adapter exports pools: Test Suites: 1 passed, 1 total |
|
The liminal-basis adapter exports pools: Test Suites: 1 passed, 1 total |
|
The liminal-basis adapter exports pools: Test Suites: 1 passed, 1 total |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/adaptors/liminal-basis/apy.js (1)
86-109: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winNo minimum-gap safeguard on the selected baseline.
findClosestNavApyBaselineonly requires the closest match to the 7-day target; it doesn't enforce a minimum distance fromendRecord. If NAV updates are sparse/irregular and the closest available baseline ends up very close in time toendRecord,computeCompoundedApy's(ratio)**(365/periodDays)will amplify tiny share-value deltas into large-but-finite APY values that pass theNumber.isFinitecheck incomputeCompoundedApy(lines 124-144) and get surfaced to users.Consider requiring
periodDaysto exceed some floor (e.g., 1-2 days) before accepting a baseline, falling back to0otherwise.🤖 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/liminal-basis/apy.js` around lines 86 - 109, Add a minimum elapsed-period safeguard to findClosestNavApyBaseline or its caller before computeCompoundedApy accepts the selected baseline. Reject baselines whose timestamp gap from endRecord is below the chosen floor (such as 1–2 days), and return the existing zero/fallback result so short periods cannot produce surfaced APY values.
🤖 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/liminal-basis/index.js`:
- Around line 138-142: Update main’s concurrent product loading to isolate
failures per product by replacing Promise.all with Promise.allSettled or
equivalent per-product error handling. Retain fulfilled pool results, discard
rejected getPools results, and preserve the existing flattening and tvlUsd > 0
filtering for successful products.
- Around line 115-136: Update getPools so the hubDeployment NAV-derived tvlUsd
and apy values are assigned only to the canonical hyperliquidL1 pool, while
wrapper deployments receive no duplicated NAV metrics (or appropriately split
values). Preserve the existing pool mapping and metadata for every deployment
without inflating aggregate TVL.
---
Nitpick comments:
In `@src/adaptors/liminal-basis/apy.js`:
- Around line 86-109: Add a minimum elapsed-period safeguard to
findClosestNavApyBaseline or its caller before computeCompoundedApy accepts the
selected baseline. Reject baselines whose timestamp gap from endRecord is below
the chosen floor (such as 1–2 days), and return the existing zero/fallback
result so short periods cannot produce surfaced APY values.
🪄 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: d22619e5-91d5-44c7-997e-e045ed12269a
📒 Files selected for processing (3)
src/adaptors/liminal-basis/abi.jssrc/adaptors/liminal-basis/apy.jssrc/adaptors/liminal-basis/index.js
| async function getPools(product) { | ||
| const hubDeployment = product.deployments.hyperliquidL1; | ||
| const tvlUsd = await getTvlUsd(hubDeployment.navOracle); | ||
| const apyBase7d = await getApy7d( | ||
| XHYPE.hyperliquidL1.navOracle, | ||
| XHYPE.hyperliquidL1.address, | ||
| HYPERLIQUID_L1_CHAIN, | ||
| hubDeployment.navOracle, | ||
| hubDeployment.address, | ||
| HYPERLIQUID_L1_CHAIN | ||
| ); | ||
|
|
||
| const pools = Object.entries(XHYPE).map(([key, config]) => ({ | ||
| return Object.entries(product.deployments).map(([key, config]) => ({ | ||
| pool: `${config.address}-${config.chain}-${key}`.toLowerCase(), | ||
| chain: utils.formatChain(config.chain), | ||
| project: 'liminal-basis', | ||
| symbol: 'xHYPE', | ||
| symbol: product.symbol, | ||
| tvlUsd, | ||
| apyBase: apyBase7d, | ||
| apyBase7d, | ||
| underlyingTokens: config.underlyingTokens, | ||
| poolMeta: 'Delta-neutral yield', | ||
| poolMeta: product.poolMeta, | ||
| url: 'https://liminal.money/app/tokenized', | ||
| })); | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the target file and nearby symbols
ast-grep outline src/adaptors/liminal-basis/index.js --view expanded || true
# Show the relevant section with line numbers
sed -n '1,220p' src/adaptors/liminal-basis/index.js
# Search for related patterns in the repo
rg -n "liminal-basis|getPools\\(|hyperliquidL1|underlyingTokens|tvlUsd" src/adaptors -SRepository: DefiLlama/yield-server
Length of output: 50379
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,240p' src/adaptors/liminal-basis/index.js
printf '\n--- related occurrences ---\n'
rg -n "hyperliquidL1|getApy7d|getTvlUsd|product\\.deployments|deployments\\." src/adaptors/liminal-basis/index.js src/adaptors -S --glob '!**/node_modules/**' | head -n 120Repository: DefiLlama/yield-server
Length of output: 8544
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show only the target adaptor file with line numbers
cat -n src/adaptors/liminal-basis/index.js | sed -n '1,260p'
printf '\n---\n'
# Search for any notes/docs on this adaptor or product model
rg -n "liminal-basis|liminal.money|hyperliquidL1|xHYPE|product" . -S \
--glob '!**/node_modules/**' \
--glob '!**/dist/**' \
--glob '!**/build/**' \
| head -n 200Repository: DefiLlama/yield-server
Length of output: 13943
Avoid reusing the same NAV for every deployment
getPools reads tvlUsd once from hyperliquidL1 and copies it onto the arbitrum/ethereum wrappers for each product. If these pools are summed, liminal-basis TVL is inflated by 3x per product; keep the NAV on one canonical pool or split it per deployment.
🤖 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/liminal-basis/index.js` around lines 115 - 136, Update getPools
so the hubDeployment NAV-derived tvlUsd and apy values are assigned only to the
canonical hyperliquidL1 pool, while wrapper deployments receive no duplicated
NAV metrics (or appropriately split values). Preserve the existing pool mapping
and metadata for every deployment without inflating aggregate TVL.
| async function main() { | ||
| const pools = await Promise.all(PRODUCTS.map(getPools)); | ||
|
|
||
| return pools.filter((p) => p.tvlUsd > 0); | ||
| return pools.flat().filter((p) => p.tvlUsd > 0); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Promise.all couples all 4 products' success together.
If any single product's getTvlUsd/getApy7d call fails (RPC error, oracle revert, etc.), Promise.all rejects and main() throws, dropping pools for all 4 products instead of just the failing one. Consider Promise.allSettled (or per-product try/catch) so one product's failure doesn't take down the other three.
♻️ Proposed fix
async function main() {
- const pools = await Promise.all(PRODUCTS.map(getPools));
+ const results = await Promise.allSettled(PRODUCTS.map(getPools));
+ const pools = results
+ .filter((r) => r.status === 'fulfilled')
+ .map((r) => r.value);
return pools.flat().filter((p) => p.tvlUsd > 0);
}📝 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.
| async function main() { | |
| const pools = await Promise.all(PRODUCTS.map(getPools)); | |
| return pools.filter((p) => p.tvlUsd > 0); | |
| return pools.flat().filter((p) => p.tvlUsd > 0); | |
| } | |
| async function main() { | |
| const results = await Promise.allSettled(PRODUCTS.map(getPools)); | |
| const pools = results | |
| .filter((r) => r.status === 'fulfilled') | |
| .map((r) => r.value); | |
| return pools.flat().filter((p) => p.tvlUsd > 0); | |
| } |
🤖 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/liminal-basis/index.js` around lines 138 - 142, Update main’s
concurrent product loading to isolate failures per product by replacing
Promise.all with Promise.allSettled or equivalent per-product error handling.
Retain fulfilled pool results, discard rejected getPools results, and preserve
the existing flattening and tvlUsd > 0 filtering for successful products.
Summary
Why
The adapter currently lists only xHYPE. This change adds the other active Liminal products using the same on-chain methodology.
Validation
Summary by CodeRabbit