Add Apyx Protocol yield adapter#2544
Add Apyx Protocol yield adapter#2544dead-pool-aka-wilson wants to merge 3 commits intoDefiLlama:masterfrom
Conversation
📝 WalkthroughWalkthroughAdded a new adaptor at Changes
Sequence Diagram(s)sequenceDiagram
participant Adapter as apyx-protocol (index.js)
participant Vault as APYUSD_VAULT (contract)
participant RateView as RATE_VIEW (contract)
participant PriceSvc as PriceAPI (utils.getPrices)
participant Return as PoolArray
Adapter->>Vault: call totalAssets()
Adapter->>RateView: call apy()
Adapter->>PriceSvc: fetch APXUSD token price
Vault-->>Adapter: totalAssets (18-decimals)
RateView-->>Adapter: raw apy value
PriceSvc-->>Adapter: token price (USD)
Adapter->>Adapter: validate price
Adapter->>Adapter: compute tvlUsd = totalAssets * price
Adapter->>Adapter: compute apyBase = rawApy * 1e16
Adapter-->>Return: return [ { pool descriptor with tvlUsd, apyBase, metadata, url } ]
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
|
Error while running apyx-protocol adapter: Test Suites: 1 failed, 1 total |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/adaptors/apyx-protocol/index.js (2)
9-23: Parallelize independent SDK calls for better performance.The two contract calls are independent and can be executed concurrently using
Promise.all.♻️ Proposed refactor to parallelize calls
- const totalAssets = ( - await sdk.api.abi.call({ + const [totalAssetsResult, apyResultData] = await Promise.all([ + sdk.api.abi.call({ target: APYUSD_VAULT, abi: 'function totalAssets() view returns (uint256)', chain: 'ethereum', - }) - ).output; - - const apyResult = ( - await sdk.api.abi.call({ + }), + sdk.api.abi.call({ target: RATE_VIEW, abi: 'function apy() view returns (uint256)', chain: 'ethereum', - }) - ).output; + }), + ]); + + const totalAssets = totalAssetsResult.output; + const apyResult = apyResultData.output;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/adaptors/apyx-protocol/index.js` around lines 9 - 23, The two independent SDK calls to sdk.api.abi.call (targeting APYUSD_VAULT -> totalAssets and RATE_VIEW -> apyResult) should be run concurrently to improve performance; update the code to call both sdk.api.abi.call invocations inside a Promise.all and then destructure the results into totalAssets and apyResult (preserving the existing .output extraction) so behavior is unchanged but latency is reduced.
25-26: Add token price lookup for TVL calculation.The TVL calculation divides by 1e18 without multiplying by apxUSD price. While the 18-decimal assumption is correct, apxUSD is a synthetic stablecoin backed by dividend-bearing preferred shares (RWA), designed to maintain ~$1 peg but not guaranteed. A depeg would result in inaccurate TVL reporting.
Other ERC-4626 vault adapters (avon-megavault, treehouse-protocol, falcon-finance) fetch and multiply by token price regardless of stablecoin status. Consider either:
- Adding price lookup to follow the safer pattern, or
- Documenting the ~1:1 peg assumption in a code comment explaining why price is omitted
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/adaptors/apyx-protocol/index.js` around lines 25 - 26, The TVL calculation uses tvlUsd = totalAssets / 1e18 but omits multiplying by the apxUSD token price, which can misreport TVL if apxUSD depegs; update the adapter to fetch the apxUSD/token price (reuse your existing price lookup utility or add a getTokenPrice call) and compute tvlUsd = (totalAssets / 1e18) * tokenPrice; ensure you reference the totalAssets and tvlUsd variables and preserve apyBase = apyResult / 1e16, and add a brief comment explaining the price multiplication so future readers know we intentionally include token price for safety.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/adaptors/apyx-protocol/index.js`:
- Around line 9-23: The two independent SDK calls to sdk.api.abi.call (targeting
APYUSD_VAULT -> totalAssets and RATE_VIEW -> apyResult) should be run
concurrently to improve performance; update the code to call both
sdk.api.abi.call invocations inside a Promise.all and then destructure the
results into totalAssets and apyResult (preserving the existing .output
extraction) so behavior is unchanged but latency is reduced.
- Around line 25-26: The TVL calculation uses tvlUsd = totalAssets / 1e18 but
omits multiplying by the apxUSD token price, which can misreport TVL if apxUSD
depegs; update the adapter to fetch the apxUSD/token price (reuse your existing
price lookup utility or add a getTokenPrice call) and compute tvlUsd =
(totalAssets / 1e18) * tokenPrice; ensure you reference the totalAssets and
tvlUsd variables and preserve apyBase = apyResult / 1e16, and add a brief
comment explaining the price multiplication so future readers know we
intentionally include token price for safety.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 40542071-303e-4acb-adc6-c15e8d83a412
📒 Files selected for processing (1)
src/adaptors/apyx-protocol/index.js
|
Error while running apyx-protocol adapter: Test Suites: 1 failed, 1 total |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/adaptors/apyx-protocol/index.js (1)
8-21: Consider adding error handling for contract calls.The concurrent contract calls could fail due to RPC errors or network issues. Adding try-catch or validation would make the adapter more robust.
🔧 Suggested error handling pattern
const [totalAssetsRes, apyRes, { pricesByAddress }] = await Promise.all([ sdk.api.abi.call({ target: APYUSD_VAULT, abi: 'function totalAssets() view returns (uint256)', chain: 'ethereum', }), sdk.api.abi.call({ target: RATE_VIEW, abi: 'function apy() view returns (uint256)', chain: 'ethereum', }), utils.getPrices([APXUSD_TOKEN], 'ethereum'), ]); + if (!totalAssetsRes?.output || !apyRes?.output) { + throw new Error('Failed to fetch contract data'); + } + const totalAssets = totalAssetsRes.output;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/adaptors/apyx-protocol/index.js` around lines 8 - 21, Wrap the concurrent calls inside the apy function (the await Promise.all that calls sdk.api.abi.call for APYUSD_VAULT and RATE_VIEW and utils.getPrices for APXUSD_TOKEN) in a try-catch, catch RPC/network errors from sdk.api.abi.call and utils.getPrices, log or throw a clear error including the target/abi or token, and validate the returned objects (e.g., ensure totalAssetsRes, apyRes and pricesByAddress exist and have expected properties) before using them so the adapter fails gracefully or returns a safe fallback instead of crashing on undefined fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/adaptors/apyx-protocol/index.js`:
- Around line 23-28: The code computes tvlUsd using tokenPrice from
pricesByAddress which can be undefined; add a guard before computing tvlUsd:
check tokenPrice (from pricesByAddress[APXUSD_TOKEN.toLowerCase()]) and if it's
undefined or not a finite number, handle it (e.g., log a warning and set tvlUsd
= 0 or skip/mark the pool as invalid) rather than letting (totalAssets / 1e18) *
tokenPrice produce NaN; update the block around totalAssets, apyResult,
tokenPrice and tvlUsd to validate tokenPrice and take the safe fallback path.
---
Nitpick comments:
In `@src/adaptors/apyx-protocol/index.js`:
- Around line 8-21: Wrap the concurrent calls inside the apy function (the await
Promise.all that calls sdk.api.abi.call for APYUSD_VAULT and RATE_VIEW and
utils.getPrices for APXUSD_TOKEN) in a try-catch, catch RPC/network errors from
sdk.api.abi.call and utils.getPrices, log or throw a clear error including the
target/abi or token, and validate the returned objects (e.g., ensure
totalAssetsRes, apyRes and pricesByAddress exist and have expected properties)
before using them so the adapter fails gracefully or returns a safe fallback
instead of crashing on undefined fields.
🪄 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: 9cdfef5e-f7bb-40d2-bd61-3968d7ecbcae
📒 Files selected for processing (1)
src/adaptors/apyx-protocol/index.js
|
Error while running apyx-protocol adapter: Test Suites: 1 failed, 1 total |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/adaptors/apyx-protocol/index.js`:
- Around line 26-28: The adapter currently throws an Error when tokenPrice is
not finite (the block checking Number.isFinite(tokenPrice)), which hard-fails
ingestion; change this to a resilient fallback by logging a warning (e.g., using
processLogger.warn or console.warn) that price is unavailable and
returning/continuing in a way that skips processing this pool for this run (for
example return null or undefined from the function that computes pool metrics or
skip adding the pool to results) instead of throwing; ensure all callers of that
function handle the null/undefined result so a transient pricing outage does not
crash the adapter.
🪄 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: 3c9f290c-0051-4c12-b28f-63d1cf75e7a3
📒 Files selected for processing (1)
src/adaptors/apyx-protocol/index.js
| if (!Number.isFinite(tokenPrice)) { | ||
| throw new Error(`apxUSD price unavailable from coins.llama.fi`); | ||
| } |
There was a problem hiding this comment.
Avoid hard-failing the adapter when token price is temporarily missing
At Line 27, throwing here makes the whole adapter fail on transient pricing outages. Prefer a safe fallback (skip pool for this run) so ingestion remains resilient.
💡 Proposed resilient fallback
const tokenPrice = pricesByAddress[APXUSD_TOKEN.toLowerCase()];
if (!Number.isFinite(tokenPrice)) {
- throw new Error(`apxUSD price unavailable from coins.llama.fi`);
+ return [];
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/adaptors/apyx-protocol/index.js` around lines 26 - 28, The adapter
currently throws an Error when tokenPrice is not finite (the block checking
Number.isFinite(tokenPrice)), which hard-fails ingestion; change this to a
resilient fallback by logging a warning (e.g., using processLogger.warn or
console.warn) that price is unavailable and returning/continuing in a way that
skips processing this pool for this run (for example return null or undefined
from the function that computes pool metrics or skip adding the pool to results)
instead of throwing; ensure all callers of that function handle the
null/undefined result so a transient pricing outage does not crash the adapter.
Summary
Adding yield tracking for Apyx Protocol's apyUSD vault.
apyUSD is an ERC-4626 vault where users deposit apxUSD and earn yield on the underlying collateral backing apxUSD. Yield is vested linearly over a configurable period.
Pool Details
0x38EEb52F0771140d10c4E9A9a72349A329Fe8a6A(apyUSD)0x98A878b1Cd98131B271883B390f68D2c90674665(apxUSD)ApyUSDRateViewcontract at0xCABa36EDE2C08e16F3602e8688a8bE94c1B4e484Changes from prior PR #2428
tokenfield (recommended, becoming required)apyx-protocolaligns with TVL adapter PR (DefiLlama-Adapters #18617)Links
Summary by CodeRabbit