Skip to content

Conversation

@sirmoremoney
Copy link

@sirmoremoney sirmoremoney commented Jan 14, 2026

Summary

Test output

Nb of pools: 1

Sample pools: [
  {
    pool: '0xd53b68fb4eb907c3c1e348cd7d7bede34f763805-ethereum',
    chain: 'Ethereum',
    project: 'lazyusd',
    symbol: 'USDC',
    tvlUsd: 500661.494622,
    apyBase: 19.55,
    underlyingTokens: [ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' ],
    url: 'https://getlazy.xyz'
  }
]

Test plan

  • Ran npm run test --adapter=lazyusd - all relevant tests pass
  • Pending: TVL adapter merge (PR #17673) for protocol slug validation

Summary by CodeRabbit

  • New Features
    • Added support for tracking yield metrics from the Lazy protocol. Users can now view annual percentage yield (APY) and total value locked (TVL) for available pools.

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

Onome Okajevo added 3 commits January 13, 2026 22:04
LazyUSD is a delta-neutral yield vault on Ethereum that deploys USDC
across lending protocols, DEXs, and derivatives platforms to generate
sustainable yields while maintaining full USDC backing.

The adapter calculates APY based on share price changes over a 7-day
window, falling back to accumulated yield for new vaults.
- Use vault deploy block to calculate available history
- Try 7-day window first, fall back to 1-day if vault is newer
- Remove hardcoded daysLive that would become stale
- Corrected VAULT_DEPLOY_BLOCK from 21763550 to 24181000 (Jan 7, 2026)
- Use ethers.js directly instead of SDK for more reliable ABI parsing
- Calculate APY using 7-day window (falls back to 1-day for new vaults)
@coderabbitai
Copy link

coderabbitai bot commented Jan 14, 2026

📝 Walkthrough

Walkthrough

A new adaptor module for LazyUSD is introduced that fetches on-chain vault data from Ethereum, calculates annual percentage yield (APY) using share price mechanics with historical fallback logic, and returns structured pool information including TVL, APY, and underlying tokens.

Changes

Cohort / File(s) Summary
New LazyUSD Adaptor
src/adaptors/lazyusd/index.js
Introduces adaptor that connects to a JSON-RPC provider, queries vault contract for sharePrice and totalAssets, computes APY with historical price fallback, and exports pool data with TVL metrics and URL reference.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant Adaptor as LazyUSD Adaptor
    participant Provider as JSON-RPC Provider
    participant Vault as Vault Contract

    Caller->>Adaptor: apy()
    Adaptor->>Provider: Connect to Ethereum
    Adaptor->>Vault: Read sharePrice & totalAssets
    Vault-->>Adaptor: Contract data
    Adaptor->>Adaptor: Calculate APY (with historical fallback)
    Adaptor->>Adaptor: Format pool metadata
    Adaptor-->>Caller: Return pool array [pool, tvlUsd, apyBase, ...]
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A vault of lazy fortune found,
With APY calculated 'round,
From Ethereum's chain so deep,
This adaptor counts your yield to keep! 💰

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add LazyUSD yield adapter' directly and clearly summarizes the main change: introducing a new yield adapter for LazyUSD protocol.
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

Comment @coderabbitai help to get the list of available commands and usage tips.

@llamatester
Copy link

Error while running lazyusd adapter:

Test Suites: 1 failed, 1 total
Tests: 1 failed, 9 passed, 10 total
Snapshots: 0 total
Time: 0.301 s
Ran all test suites.

Nb of pools: 1
 

Sample pools:
┌─────────┬───────────────────────────────────────────────────────┬────────────┬───────────┬────────┬───────────────┬────────────────────┬──────────────────────────────────────────────────┬───────────────────────┐
│ (index) │ pool                                                  │ chain      │ project   │ symbol │ tvlUsd        │ apyBase            │ underlyingTokens                                 │ url                   │
├─────────┼───────────────────────────────────────────────────────┼────────────┼───────────┼────────┼───────────────┼────────────────────┼──────────────────────────────────────────────────┼───────────────────────┤
│ 0       │ '0xd53b68fb4eb907c3c1e348cd7d7bede34f763805-ethereum' │ 'Ethereum' │ 'lazyusd' │ 'USDC' │ 500661.494622 │ 19.552464046207987 │ [ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' ] │ 'https://getlazy.xyz' │
└─────────┴───────────────────────────────────────────────────────┴────────────┴───────────┴────────┴───────────────┴────────────────────┴──────────────────────────────────────────────────┴───────────────────────┘
}

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

🤖 Fix all issues with AI agents
In `@src/adaptors/lazyusd/index.js`:
- Around line 33-35: The calculation for apyBase uses historicalSharePrice (from
await vault.sharePrice({ blockTag: historicalBlock })) without guarding against
zero, which can yield Infinity/NaN; before computing priceChange and apyBase,
check that historicalSharePrice is a positive non-zero number and if it's zero
or falsy either set apyBase to 0 (or skip the APY calculation) and optionally
log/mark the vault as uninitialized — update the block that assigns
historicalSharePrice, computes priceChange, and sets apyBase to perform this
validation and handle the zero-case safely.
- Around line 4-6: The VAULT_DEPLOY_BLOCK constant is incorrect (24181000 is
non-existent); locate the actual deployment block for the VAULT address
(0xd53B68fB4eb907c3c1E348CD7d7bEDE34f763805) by checking the contract creation
transaction on Etherscan or by querying the creation tx receipt via web3/ethers
to get its blockNumber, then update VAULT_DEPLOY_BLOCK to that integer value in
the file (ensure you modify the VAULT_DEPLOY_BLOCK constant alongside the
existing VAULT and USDC constants).
🧹 Nitpick comments (2)
src/adaptors/lazyusd/index.js (2)

1-1: Unused import: sdk is never used.

The @defillama/sdk import is declared but not referenced anywhere in this file. Remove it to avoid confusion.

Suggested fix
-const sdk = require('@defillama/sdk');
 const { ethers } = require('ethers');

18-18: blocksPerDay is an approximation.

The value 7200 assumes exactly 12-second block times. Post-merge Ethereum averages ~12.05s, which introduces minor drift over 7 days (~0.4%). This is acceptable for APY estimates but worth noting.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e95933c and 5156c75.

📒 Files selected for processing (1)
  • src/adaptors/lazyusd/index.js
🔇 Additional comments (3)
src/adaptors/lazyusd/index.js (3)

8-11: LGTM!

The human-readable ABI format is appropriate for ethers.js, and the function signatures match standard vault interfaces.


27-36: Edge case: vault less than 1 day old still returns apyBase = 0.

If the vault is less than 1 day old, the fallback on line 28 sets historicalBlock = latestBlock - blocksPerDay, which may still be less than VAULT_DEPLOY_BLOCK. The condition on line 32 will then be false, leaving apyBase = 0. This is likely acceptable behavior for new vaults, but worth confirming this is intentional.


50-54: LGTM!

The export structure follows the standard DefiLlama yield adapter pattern with timetravel, apy, and url properties.

Comment on lines +4 to +6
const VAULT = '0xd53B68fB4eb907c3c1E348CD7d7bEDE34f763805';
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
const VAULT_DEPLOY_BLOCK = 24181000;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Check if vault contract exists
echo "=== Checking vault contract ==="
curl -s -X POST https://eth.llamarpc.com \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_getCode","params":["0xd53B68fB4eb907c3c1E348CD7d7bEDE34f763805","latest"],"id":1}' | jq '.'

echo ""
echo "=== Checking block 24181000 ==="
curl -s -X POST https://eth.llamarpc.com \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x170f658","false"],"id":1}' | jq '.result | {number, timestamp, hash}'

Repository: DefiLlama/yield-server

Length of output: 31926


Correct the VAULT_DEPLOY_BLOCK value.

The VAULT contract at 0xd53B68fB4eb907c3c1E348CD7d7bEDE34f763805 exists on-chain, and the USDC address is correct for Ethereum mainnet. However, block 24181000 does not exist. Verify and update VAULT_DEPLOY_BLOCK to the actual deployment block of the LazyUSD vault contract.

🤖 Prompt for AI Agents
In `@src/adaptors/lazyusd/index.js` around lines 4 - 6, The VAULT_DEPLOY_BLOCK
constant is incorrect (24181000 is non-existent); locate the actual deployment
block for the VAULT address (0xd53B68fB4eb907c3c1E348CD7d7bEDE34f763805) by
checking the contract creation transaction on Etherscan or by querying the
creation tx receipt via web3/ethers to get its blockNumber, then update
VAULT_DEPLOY_BLOCK to that integer value in the file (ensure you modify the
VAULT_DEPLOY_BLOCK constant alongside the existing VAULT and USDC constants).

Comment on lines +13 to +16
const apy = async () => {
const provider = new ethers.providers.JsonRpcProvider('https://eth.llamarpc.com');
const vault = new ethers.Contract(VAULT, ABI, provider);

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add error handling for RPC and contract calls.

The function has no try-catch or error handling. If the RPC endpoint is unavailable or the contract calls revert, the adapter will throw an unhandled exception.

Suggested approach
 const apy = async () => {
+  try {
     const provider = new ethers.providers.JsonRpcProvider('https://eth.llamarpc.com');
     const vault = new ethers.Contract(VAULT, ABI, provider);
+    // ... rest of function
+  } catch (error) {
+    console.error('LazyUSD adapter error:', error.message);
+    return [];
+  }
 };

Comment on lines +33 to +35
const historicalSharePrice = (await vault.sharePrice({ blockTag: historicalBlock })) / 1e6;
const priceChange = (currentSharePrice - historicalSharePrice) / historicalSharePrice;
apyBase = (priceChange / daysForCalc) * 365 * 100;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential division by zero if historicalSharePrice is zero.

If the vault's share price was zero at the historical block (e.g., before initialization), line 34 will produce Infinity or NaN, corrupting the APY result.

Suggested fix
   if (historicalBlock >= VAULT_DEPLOY_BLOCK) {
     const historicalSharePrice = (await vault.sharePrice({ blockTag: historicalBlock })) / 1e6;
+    if (historicalSharePrice > 0) {
       const priceChange = (currentSharePrice - historicalSharePrice) / historicalSharePrice;
       apyBase = (priceChange / daysForCalc) * 365 * 100;
+    }
   }
📝 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
const historicalSharePrice = (await vault.sharePrice({ blockTag: historicalBlock })) / 1e6;
const priceChange = (currentSharePrice - historicalSharePrice) / historicalSharePrice;
apyBase = (priceChange / daysForCalc) * 365 * 100;
if (historicalBlock >= VAULT_DEPLOY_BLOCK) {
const historicalSharePrice = (await vault.sharePrice({ blockTag: historicalBlock })) / 1e6;
if (historicalSharePrice > 0) {
const priceChange = (currentSharePrice - historicalSharePrice) / historicalSharePrice;
apyBase = (priceChange / daysForCalc) * 365 * 100;
}
}
🤖 Prompt for AI Agents
In `@src/adaptors/lazyusd/index.js` around lines 33 - 35, The calculation for
apyBase uses historicalSharePrice (from await vault.sharePrice({ blockTag:
historicalBlock })) without guarding against zero, which can yield Infinity/NaN;
before computing priceChange and apyBase, check that historicalSharePrice is a
positive non-zero number and if it's zero or falsy either set apyBase to 0 (or
skip the APY calculation) and optionally log/mark the vault as uninitialized —
update the block that assigns historicalSharePrice, computes priceChange, and
sets apyBase to perform this validation and handle the zero-case safely.

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