From c7e98069a9b96f7eb3133d98084b94b2cf1cd004 Mon Sep 17 00:00:00 2001 From: Josh Levine Date: Tue, 6 May 2025 16:14:45 -0700 Subject: [PATCH 1/3] feat: init rumpel yield adaptor --- src/adaptors/rumpel/index.js | 135 +++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 src/adaptors/rumpel/index.js diff --git a/src/adaptors/rumpel/index.js b/src/adaptors/rumpel/index.js new file mode 100644 index 0000000000..1b024a04a4 --- /dev/null +++ b/src/adaptors/rumpel/index.js @@ -0,0 +1,135 @@ +const utils = require('../utils'); + +const RUMPEL_API_URL = 'https://www.app.rumpel.xyz/api/apys'; +const RUMPEL_TVL_API_URL = + 'https://point-tokenization-app.vercel.app/api/tvl-by-strategy'; +const PROJECT_SLUG = 'rumpel'; + +const MIN_TVL_USD = 10_000; + +// interface Pool { +// pool: string; +// chain: string; +// project: string; +// symbol: string; +// tvlUsd: number; // for lending protocols: tvlUsd = totalSupplyUsd - totalBorrowUsd +// apyBase?: number; +// apyReward?: number; +// rewardTokens?: Array; +// underlyingTokens?: Array; +// poolMeta?: string; +// url?: string; +// // optional lending protocol specific fields: +// apyBaseBorrow?: number; +// apyRewardBorrow?: number; +// totalSupplyUsd?: number; +// totalBorrowUsd?: number; +// ltv?: number; // btw [0, 1] +// } + +const getPools = async () => { + let apyResponse; + try { + apyResponse = await utils.getData(RUMPEL_API_URL); + } catch (e) { + console.error('[Rumpel] Failed to fetch APY data from API', e); + return []; + } + + if ( + !apyResponse || + !apyResponse.strategies || + !Array.isArray(apyResponse.strategies) + ) { + console.error( + '[Rumpel] APY API response is missing strategies array or is malformed' + ); + return []; + } + + let tvlResponse; + try { + tvlResponse = await utils.getData(RUMPEL_TVL_API_URL); + } catch (e) { + console.warn( + '[Rumpel] Failed to fetch TVL data from API, TVL will be 0 for all pools', + e + ); + return []; + } + + const tvlMap = new Map(); + if (tvlResponse && tvlResponse.tvlByStrategy) { + for (const [strategyName, tvl] of Object.entries( + tvlResponse.tvlByStrategy + )) { + if (tvl !== null && tvl !== undefined) { + tvlMap.set(strategyName, Number(tvl)); + } + } + } + + const pools = apyResponse.strategies.map((strategy) => { + const tvlUsd = tvlMap.get(strategy.name) || 0; + + const poolData = { + pool: strategy.name, + chain: 'Ethereum', + project: PROJECT_SLUG, + symbol: strategy.underlyingSymbol, + tvlUsd: tvlUsd, + apyBase: + strategy.totalApy !== undefined && strategy.totalApy !== null + ? Number(strategy.totalApy) + : 0, + apyReward: 0, + rewardTokens: [], + underlyingTokens: strategy.underlyingTokens.map((s) => s.address), + poolMeta: `${strategy.name}${ + strategy.isLendingPosition ? ' (Lending)' : '' + }`, + url: 'https://app.rumpel.xyz/?tab=earn', + }; + + if (strategy.isLendingPosition) { + poolData.ltv = + strategy.maxLtv !== undefined && strategy.maxLtv !== null + ? 1 - 1 / Number(strategy.maxLtv) + : 0; + + let baseBorrowApy = 0; + if ( + strategy.additionalComponents && + Array.isArray(strategy.additionalComponents) + ) { + const borrowComponent = strategy.additionalComponents.find( + (comp) => comp.name === 'Borrow' && comp.negative === true + ); + if ( + borrowComponent && + borrowComponent.apy !== undefined && + borrowComponent.apy !== null + ) { + baseBorrowApy = Number(borrowComponent.apy); + } + } + poolData.apyBaseBorrow = baseBorrowApy; + poolData.apyRewardBorrow = 0; + poolData.totalSupplyUsd = 0; + poolData.totalBorrowUsd = 0; + } + + return poolData; + }); + + // Filter pools by minimum TVL + const filteredPools = pools.filter((pool) => pool.tvlUsd >= MIN_TVL_USD); + + return filteredPools; +}; + +module.exports = { + timetravel: false, + apy: getPools, + url: 'https://app.rumpel.xyz/', +}; From b0463b2b82a9c053cd7abd3a1f26816d846fa531 Mon Sep 17 00:00:00 2001 From: Josh Levine Date: Tue, 6 May 2025 16:26:20 -0700 Subject: [PATCH 2/3] fix: rename adaptor to match defillama slug --- src/adaptors/{rumpel => rumpel-labs}/index.js | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) rename src/adaptors/{rumpel => rumpel-labs}/index.js (82%) diff --git a/src/adaptors/rumpel/index.js b/src/adaptors/rumpel-labs/index.js similarity index 82% rename from src/adaptors/rumpel/index.js rename to src/adaptors/rumpel-labs/index.js index 1b024a04a4..8cdda7da0d 100644 --- a/src/adaptors/rumpel/index.js +++ b/src/adaptors/rumpel-labs/index.js @@ -3,30 +3,10 @@ const utils = require('../utils'); const RUMPEL_API_URL = 'https://www.app.rumpel.xyz/api/apys'; const RUMPEL_TVL_API_URL = 'https://point-tokenization-app.vercel.app/api/tvl-by-strategy'; -const PROJECT_SLUG = 'rumpel'; +const PROJECT_SLUG = 'rumpel-labs'; const MIN_TVL_USD = 10_000; -// interface Pool { -// pool: string; -// chain: string; -// project: string; -// symbol: string; -// tvlUsd: number; // for lending protocols: tvlUsd = totalSupplyUsd - totalBorrowUsd -// apyBase?: number; -// apyReward?: number; -// rewardTokens?: Array; -// underlyingTokens?: Array; -// poolMeta?: string; -// url?: string; -// // optional lending protocol specific fields: -// apyBaseBorrow?: number; -// apyRewardBorrow?: number; -// totalSupplyUsd?: number; -// totalBorrowUsd?: number; -// ltv?: number; // btw [0, 1] -// } - const getPools = async () => { let apyResponse; try { @@ -55,6 +35,7 @@ const getPools = async () => { '[Rumpel] Failed to fetch TVL data from API, TVL will be 0 for all pools', e ); + return []; } From 8109b3b9c52f9b8dc6fa9080a1a644be63d58cd9 Mon Sep 17 00:00:00 2001 From: Josh Levine Date: Tue, 6 May 2025 19:07:53 -0700 Subject: [PATCH 3/3] chore(rumpel): format strat symbols from names --- src/adaptors/rumpel-labs/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/adaptors/rumpel-labs/index.js b/src/adaptors/rumpel-labs/index.js index 8cdda7da0d..27a40ee8eb 100644 --- a/src/adaptors/rumpel-labs/index.js +++ b/src/adaptors/rumpel-labs/index.js @@ -35,7 +35,6 @@ const getPools = async () => { '[Rumpel] Failed to fetch TVL data from API, TVL will be 0 for all pools', e ); - return []; } @@ -57,7 +56,7 @@ const getPools = async () => { pool: strategy.name, chain: 'Ethereum', project: PROJECT_SLUG, - symbol: strategy.underlyingSymbol, + symbol: utils.formatSymbol(strategy.name), tvlUsd: tvlUsd, apyBase: strategy.totalApy !== undefined && strategy.totalApy !== null