From 8e8b76837defa6dac3a71d01e23ce45f12b6089b Mon Sep 17 00:00:00 2001 From: MD Date: Thu, 19 Dec 2024 07:41:12 +0100 Subject: [PATCH 01/22] fix: add risk profile to cbbtc vault (#1660) --- src/adaptors/impermax-finance/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/adaptors/impermax-finance/index.js b/src/adaptors/impermax-finance/index.js index 3fb6dceaf0..ac7d4d4c6f 100644 --- a/src/adaptors/impermax-finance/index.js +++ b/src/adaptors/impermax-finance/index.js @@ -215,6 +215,10 @@ const lendingVaultProfiles = { address: '0x683cc7cbb8b8c5b3c5fae85a4ae70e887217883b'.toLowerCase(), risk: 'Aggressive', }, // ETH (high) + { + address: '0xc68c47085D2B53A0A782c168D1b54a913A668cB5'.toLowerCase(), + risk: 'Conservative', + }, // cbBTC (low) ], }; From 6c0f1a4daed11343eacaf38947f9205e14597c9f Mon Sep 17 00:00:00 2001 From: kavsky02 <95619352+kavsky02@users.noreply.github.com> Date: Thu, 19 Dec 2024 07:43:46 +0100 Subject: [PATCH 02/22] Re-introduce deltaprime yields from saving pools (#1661) --- src/adaptors/deltaprime/index.js | 77 ++++++-------------------------- src/utils/exclude.js | 1 - 2 files changed, 13 insertions(+), 65 deletions(-) diff --git a/src/adaptors/deltaprime/index.js b/src/adaptors/deltaprime/index.js index 272391a5aa..3bce20c821 100644 --- a/src/adaptors/deltaprime/index.js +++ b/src/adaptors/deltaprime/index.js @@ -59,16 +59,11 @@ const getBoostRewardTokenAbi = { } // Avalanche -const USDC_POOL_TUP_CONTRACT = '0x2323dAC85C6Ab9bd6a8B5Fb75B0581E31232d12b'; -const USDT_POOL_TUP_CONTRACT = '0xd222e10D7Fe6B7f9608F14A8B5Cf703c74eFBcA1'; -const WAVAX_POOL_TUP_CONTRACT = '0xD26E504fc642B96751fD55D3E68AF295806542f5'; -const BTC_POOL_TUP_CONTRACT = '0x475589b0Ed87591A893Df42EC6076d2499bB63d0'; -const ETH_POOL_TUP_CONTRACT = '0xD7fEB276ba254cD9b34804A986CE9a8C3E359148'; - -const AVAX_POOL_REWARDER_CONTRACT = '0x6373122eD8Eda8ECA439415709318DCB6ddC1af3'; -const USDT_POOL_REWARDER_CONTRACT = '0xBC6Ef309f2eC71698eA310D62FF2E0543472D965'; -const USDC_POOL_REWARDER_CONTRACT = '0x596f6EFD98daF650CF98A1E62A53AB2a44e7E875'; -const BTC_POOL_REWARDER_CONTRACT = '0x3FE9BE379eD15962AFAbE01c002B8c433C6Af4ec'; +const USDC_POOL_TUP_CONTRACT = '0x8027e004d80274FB320e9b8f882C92196d779CE8'; +const USDT_POOL_TUP_CONTRACT = '0x1b6D7A6044fB68163D8E249Bce86F3eFbb12368e'; +const WAVAX_POOL_TUP_CONTRACT = '0xaa39f39802F8C44e48d4cc42E088C09EDF4daad4'; +const BTC_POOL_TUP_CONTRACT = '0x70e80001bDbeC5b9e932cEe2FEcC8F123c98F738'; +const ETH_POOL_TUP_CONTRACT = '0x2A84c101F3d45610595050a622684d5412bdf510'; const WAVAX_TOKEN_ADDRESS = '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7'; const USDC_TOKEN_ADDRESS = '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E'; @@ -80,11 +75,11 @@ const GGAVAX_TOKEN_ADDRESS = '0xA25EaF2906FA1a3a13EdAc9B9657108Af7B703e3'; const SAVAX_TOKEN_ADDRESS = '0x2b2C81e08f1Af8835a78Bb2A90AE924ACE0eA4bE'; // Arbitrum -const USDC_POOL_TUP_ARBI_CONTRACT = '0x5f3DB5899a7937c9ABF0A5Fc91718E6F813e4195'; -const ETH_POOL_TUP_ARBI_CONTRACT = '0x2E2fE9Bc7904649b65B6373bAF40F9e2E0b883c5'; -const ARB_POOL_TUP_ARBI_CONTRACT = '0x14c82CFc2c651700a66aBDd7dC375c9CeEFDDD72'; -const BTC_POOL_TUP_ARBI_CONTRACT = '0x275Caecf5542bF4a3CF64aa78a3f57dc9939675C'; -const DAI_POOL_TUP_ARBI_CONTRACT = '0x7Dcf909B1E4b280bEe72C6A69b3a7Ed8adfb63f0'; +const USDC_POOL_TUP_ARBI_CONTRACT = '0x8Ac9Dc27a6174a1CC30873B367A60AcdFAb965cc'; +const ETH_POOL_TUP_ARBI_CONTRACT = '0x788A8324943beb1a7A47B76959E6C1e6B87eD360'; +const ARB_POOL_TUP_ARBI_CONTRACT = '0xC629E8889350F1BBBf6eD1955095C2198dDC41c2'; +const BTC_POOL_TUP_ARBI_CONTRACT = '0x0ed7B42B74F039eda928E1AE6F44Eed5EF195Fb5'; +const DAI_POOL_TUP_ARBI_CONTRACT = '0xFA354E4289db87bEB81034A3ABD6D465328378f1'; const USDC_TOKEN_ARBI_ADDRESS = '0xaf88d065e77c8cc2239327c5edb3a432268e5831'; const ETH_TOKEN_ARBI_ADDRESS = '0x82af49447d8a07e3bd95bd0d56f35241523fbab1'; @@ -92,13 +87,6 @@ const ARB_TOKEN_ARBI_ADDRESS = '0x912CE59144191C1204E64559FE8253a0e49E6548'; const BTC_TOKEN_ARBI_ADDRESS = '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f'; const DAI_TOKEN_ARBI_ADDRESS = '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1'; -const POOL_ADDRESS_TO_REWARDER_CONTRACT = { - '0x2323dAC85C6Ab9bd6a8B5Fb75B0581E31232d12b': USDC_POOL_REWARDER_CONTRACT, - '0xd222e10D7Fe6B7f9608F14A8B5Cf703c74eFBcA1': USDT_POOL_REWARDER_CONTRACT, - '0xD26E504fc642B96751fD55D3E68AF295806542f5': AVAX_POOL_REWARDER_CONTRACT, - '0x475589b0Ed87591A893Df42EC6076d2499bB63d0': BTC_POOL_REWARDER_CONTRACT -} - const getPoolTVL = async (poolAddress, chain = 'avax') => { return (await sdk.api.abi.call({ abi: getPoolTotalSupplyAbi, @@ -115,33 +103,6 @@ const getTokenPrice = async (tokenAddress, chain='avax') => { return data.coins[Object.keys(data.coins)[0]].price } -const getPoolBoostRate = async (poolAddress, poolTVL, chain = 'avax') => { - if(chain === 'avax') { - let rewarderContractAddress = POOL_ADDRESS_TO_REWARDER_CONTRACT[poolAddress]; - - if(rewarderContractAddress) { - let rewardsRatePerSecond = (await sdk.api.abi.call({ - abi: getPoolBoostRateAbi, - chain: chain, - target: rewarderContractAddress, - params: [], - })).output; - - let rewardTokenAddress = (await sdk.api.abi.call({ - abi: getBoostRewardTokenAbi, - chain: chain, - target: rewarderContractAddress, - params: [], - })).output; - - let rewardTokenPrice = await getTokenPrice(rewardTokenAddress, chain); - - return rewardsRatePerSecond * rewardTokenPrice * 86400 * 365 / poolTVL / 1e16; - } - } - return 0; -} - const getPoolDepositRate = async (poolAddress, chain = 'avax') => { return (await sdk.api.abi.call({ abi: getPoolDepositRateAbi, @@ -262,7 +223,6 @@ const getUsdtPoolTVL = async() => { const getPoolsAPYs = async () => { const usdcPoolTvl = await getUsdcPoolTVL(); - const usdcRewardApy = await getPoolBoostRate(USDC_POOL_TUP_CONTRACT, usdcPoolTvl, 'avax'); const usdcPool = { pool: `dp-${USDC_TOKEN_ADDRESS}-avalanche`, chain: utils.formatChain('avalanche'), @@ -270,13 +230,10 @@ const getPoolsAPYs = async () => { symbol: utils.formatSymbol('USDC'), tvlUsd: usdcPoolTvl, apyBase: await getUsdcPoolDepositRate(), - apyReward: usdcRewardApy, - underlyingTokens: [USDC_TOKEN_ADDRESS], - rewardTokens: [GGAVAX_TOKEN_ADDRESS], + underlyingTokens: [USDC_TOKEN_ADDRESS] }; const usdtPoolTvl = await getUsdtPoolTVL(); - const usdtRewardApy = await getPoolBoostRate(USDT_POOL_TUP_CONTRACT, usdtPoolTvl, 'avax'); const usdtPool = { pool: `dp-${USDT_TOKEN_ADDRESS}-avalanche`, chain: utils.formatChain('avalanche'), @@ -284,13 +241,10 @@ const getPoolsAPYs = async () => { symbol: utils.formatSymbol('USDt'), tvlUsd: usdtPoolTvl, apyBase: await getUsdtPoolDepositRate(), - apyReward: usdtRewardApy, - underlyingTokens: [USDT_TOKEN_ADDRESS], - rewardTokens: [SAVAX_TOKEN_ADDRESS], + underlyingTokens: [USDT_TOKEN_ADDRESS] }; const wavaxPoolTvl = await getWavaxPoolTVL(); - const wavaxRewardApy = await getPoolBoostRate(WAVAX_POOL_TUP_CONTRACT, wavaxPoolTvl, 'avax'); const wavaxPool = { pool: `dp-${WAVAX_TOKEN_ADDRESS}-avalanche`, chain: utils.formatChain('avalanche'), @@ -298,13 +252,10 @@ const getPoolsAPYs = async () => { symbol: utils.formatSymbol('WAVAX'), tvlUsd: wavaxPoolTvl, apyBase: await getWavaxPoolDepositRate(), - apyReward: wavaxRewardApy, underlyingTokens: [WAVAX_TOKEN_ADDRESS], - rewardTokens: [SAVAX_TOKEN_ADDRESS], }; const btcPoolTvl = await getBtcPoolTVL(); - const btcRewardApy = await getPoolBoostRate(BTC_POOL_TUP_CONTRACT, btcPoolTvl, 'avax'); const btcPool = { pool: `dp-${BTC_TOKEN_ADDRESS}-avalanche`, chain: utils.formatChain('avalanche'), @@ -312,9 +263,7 @@ const getPoolsAPYs = async () => { symbol: utils.formatSymbol('BTC.b'), tvlUsd: btcPoolTvl, apyBase: await getBtcPoolDepositRate(), - apyReward: btcRewardApy, - underlyingTokens: [BTC_TOKEN_ADDRESS], - rewardTokens: [GGAVAX_TOKEN_ADDRESS], + underlyingTokens: [BTC_TOKEN_ADDRESS] }; const ethPoolTvl = await getEthPoolTVL(); diff --git a/src/utils/exclude.js b/src/utils/exclude.js index f74c1632c4..cb68e862da 100644 --- a/src/utils/exclude.js +++ b/src/utils/exclude.js @@ -151,7 +151,6 @@ const excludeAdaptors = [ 'maia-dao', 'hermes-protocol', 'xtoken', - 'deltaprime', 'arbitrum-exchange-v3', 'bfx-(blast-futures)', 'stack', From 01ac823c1453461a3e0e4d109994e19c717a151c Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Thu, 19 Dec 2024 08:34:33 -0600 Subject: [PATCH 03/22] Add more blend pool yields (#1662) * use unique pool ids for each blend pool and asset * simplify logic for adding pools to the return array * remove url change * fix a typo --- src/adaptors/blend-pools/index.js | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/adaptors/blend-pools/index.js b/src/adaptors/blend-pools/index.js index a5c07c395f..a326df91f9 100644 --- a/src/adaptors/blend-pools/index.js +++ b/src/adaptors/blend-pools/index.js @@ -43,7 +43,7 @@ const getApy = async (poolId, backstop) => { if (borrowEmissionsPerAsset > 0) { borrowEmissionsAPR = (borrowEmissionsPerAsset * usdcPerBlnd) / price; } - // Estimate borrow APY compoumded daily + // Estimate borrow APY compounded daily const borrowApy = (1 + reserve.borrowApr / 365) ** 365 - 1; let totalSupply = reserve.totalSupplyFloat() * price; let totalBorrow = reserve.totalLiabilitiesFloat() * price; @@ -51,7 +51,7 @@ const getApy = async (poolId, backstop) => { const url = `https://mainnet.blend.capital/dashboard/?poolId=${poolId}`; pools.push({ - pool: `${reserve.assetId}-stellar`.toLowerCase(), + pool: `${pool.id}-${reserve.assetId}-stellar`.toLowerCase(), chain: formatChain('stellar'), project: 'blend-pools', symbol: reserve.tokenMetadata.symbol, @@ -66,7 +66,7 @@ const getApy = async (poolId, backstop) => { apyBaseBorrow: borrowApy * 100, apyRewardBorrow: borrowEmissionsAPR * 100, ltv: totalBorrow / totalSupply, - poolMeta: `Pool ID: ${pool.id}`, + poolMeta: `${pool.config.name} Pool`, url, }); } @@ -80,18 +80,7 @@ const apy = async () => { for (const poolId of BLEND_POOLS) { let poolApys = await getApy(poolId, backstop); - for (const poolApy of poolApys) { - if (poolApy) { - let index = pools.findIndex((pool) => pool.pool == poolApy.pool); - if (index !== -1) { - if (poolApy.apyReward > pools[index].apyReward) { - pools[index] = poolApy; - } - } else { - pools.push(poolApy); - } - } - } + pools.push(...poolApys) } return pools; }; From 3b22a52d483b0d79185e2aef5f793b5649715357 Mon Sep 17 00:00:00 2001 From: slasher125 Date: Fri, 20 Dec 2024 12:34:27 +0400 Subject: [PATCH 04/22] aave-v3 fix --- src/adaptors/aave-v3/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adaptors/aave-v3/index.js b/src/adaptors/aave-v3/index.js index a64c2b02e2..9e62b19b8c 100755 --- a/src/adaptors/aave-v3/index.js +++ b/src/adaptors/aave-v3/index.js @@ -204,7 +204,7 @@ const stkGho = async () => { const stkghoMeritApy = ( await axios.get('https://apps.aavechan.com/api/merit/base-aprs') - ).data.actionsAPR['ethereum-stkgho']; + ).data['ethereum-stkgho']; const stkghoApy = stkghoNativeApy + stkghoMeritApy; From 485b6628100244c3bc5f2ee6e1cf86e5ff8ac528 Mon Sep 17 00:00:00 2001 From: Bao Nguyen <151540392+baonguyen1904@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:44:12 +0700 Subject: [PATCH 05/22] Adding Harmonix yield pools (#1657) * Implement Harmonix yield adaptor * Update underlying asset returns array of address --- src/adaptors/harmonix-finance/index.js | 111 +++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/adaptors/harmonix-finance/index.js diff --git a/src/adaptors/harmonix-finance/index.js b/src/adaptors/harmonix-finance/index.js new file mode 100644 index 0000000000..9359237324 --- /dev/null +++ b/src/adaptors/harmonix-finance/index.js @@ -0,0 +1,111 @@ +const axios = require('axios'); +const sdk = require('@defillama/sdk'); +const ethers = require('ethers'); +const utils = require('../utils') + +// ABI for totalValueLocked function +const totalValueLockedABI = { + "inputs": [], + "name": "totalValueLocked", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" +}; + +// Mapping of chain names to chain IDs +const chains = { + ethereum: 'ethereum', + arbitrum_one: 'arbitrum', + base: 'base', +}; + +const getTvl = async (contractAddress, chain) => { + try { + const tvl = await sdk.api.abi.call({ + target: contractAddress, + abi: totalValueLockedABI, + chain + }); + return tvl.output; + } catch (error) { + throw new Error(`Failed to fetch TVL from contract ${contractAddress} on chain ${chain} : ${error.message}`); + } +}; + +const assets = { + arbitrum: { + eth: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', + wbtc: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f', + rseth: '0x4186BFC76E2E237523CBC30FD220FE055156b41F', + link: '0xf97f4df75117a78c1A5a0DBb814Af92458539FB4', + uni: '0xfa7f8980b0f1e64a2062791cc3b0871572f1f7f0' + }, + ethereum: { + eth: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + rseth: '0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7', + }, +}; + +const getApy = async () => { + const response = await axios.get('https://api.harmonix.fi/api/v1/vaults/', { + headers: { + 'accept': 'application/json' + } + }); + + const pools = await Promise.all(response.data.map(async vault => { + return Promise.all(vault.vaults.map(async v => { + const chainId = chains[v.network_chain]; + const tvl = await getTvl(v.contract_address, chainId); + let tvlUsd = tvl; // Default to the fetched TVL + + // Convert TVL to USDC if vault_currency is not USDC + if (v.vault_currency !== 'USDC') { + const tokenKey = `${chainId}:${assets[chainId][v.vault_currency.toLowerCase()]}` + const priceData = await axios.get(`https://coins.llama.fi/prices/current/${tokenKey}`); + const tokenPrice = priceData.data.coins[`${tokenKey}`]?.price; + if (tokenPrice) { + if (v.vault_currency === 'ETH') { + tvlUsd = (tvl / 1e18) * tokenPrice; + } else if (v.vault_currency === 'WBTC') { + tvlUsd = (tvl / 1e8) * tokenPrice; + } else { + tvlUsd = (tvl / 1e6) * tokenPrice; + } + } else { + throw new Error(`Price for ${v.vault_currency} not found.`); + } + } + else { + tvlUsd /= 1e6 + } + + return { + pool: v.contract_address, // unique identifier for the pool + chain: chainId || null, // map chain name to chain ID + project: 'harmonix-finance', // project slug + symbol: utils.formatSymbol(v.vault_currency), // format the symbol + tvlUsd, // total value locked in USD + apyBase: v.apy, // APY from the vault + apyReward: 0, // hardcoded for now + rewardTokens: [], // hardcoded for now + url: `https://app.harmonix.fi/vaults/${v.slug}`, // URL to the vault + underlyingTokens: v.underlying_asset ? [assets[chainId][v.underlying_asset.toLowerCase()]] : [], // underlying asset + }; + })); + })); + + return pools.flat(); // flatten the array of pools +}; + +module.exports = { + timetravel: false, + apy: getApy, + url: 'https://app.harmonix.fi/vaults/', // Link to page with pools +}; From ecab4ec2f9d1e7e6f931b3782311c2710bc6d72e Mon Sep 17 00:00:00 2001 From: Deantoshi <141426562+Deantoshi@users.noreply.github.com> Date: Fri, 20 Dec 2024 06:48:11 -0500 Subject: [PATCH 06/22] added the ironclad base deployment (#1663) Co-authored-by: Daniel_Dean --- src/adaptors/ironclad-finance/index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/adaptors/ironclad-finance/index.js b/src/adaptors/ironclad-finance/index.js index 824a8754d8..64d63a0102 100644 --- a/src/adaptors/ironclad-finance/index.js +++ b/src/adaptors/ironclad-finance/index.js @@ -16,6 +16,14 @@ const chains = { SimplifiedProtocolDataReader: '0x78d5439da3201F44ce9A642DB95D798e9249952F', rewardTokens: ['0x3b6ea0fa8a487c90007ce120a83920fd52b06f6d'] }, + base: { + LendingPool: '0xB702cE183b4E1Faa574834715E5D4a6378D0eEd3', + ProtocolDataProvider: '0xed984A0E9c12Ee27602314191Fc4487A702bB83f', + url: 'base', + SimplifiedProtocolDataReader: '0x78d5439da3201F44ce9A642DB95D798e9249952F', + rewardTokens: ['0x3b6ea0fa8a487c90007ce120a83920fd52b06f6d'] + } + }; const getApy = async () => { From b77879905dd61f637126db1cea7558a953fe1aae Mon Sep 17 00:00:00 2001 From: slasher125 Date: Mon, 23 Dec 2024 10:40:48 +0400 Subject: [PATCH 07/22] beets rename --- src/adaptors/{beethoven-x-dex => beets-dex}/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/adaptors/{beethoven-x-dex => beets-dex}/index.js (99%) diff --git a/src/adaptors/beethoven-x-dex/index.js b/src/adaptors/beets-dex/index.js similarity index 99% rename from src/adaptors/beethoven-x-dex/index.js rename to src/adaptors/beets-dex/index.js index 6dd40310fc..afb28c9019 100644 --- a/src/adaptors/beethoven-x-dex/index.js +++ b/src/adaptors/beets-dex/index.js @@ -46,7 +46,7 @@ const apy = async () => { pool: chain === 'FANTOM' ? p.id : `${p.address}-${chain.toLowerCase()}`, chain: utils.formatChain(chain.toLowerCase()), - project: 'beethoven-x-dex', + project: 'beets-dex', symbol: p.address === '0x43da214fab3315aa6c02e0b8f2bfb7ef2e3c60a5' ? 'USDC-DAI' From 643442bb96351a599744e8b695ff452da979a5fc Mon Sep 17 00:00:00 2001 From: slasher125 Date: Mon, 23 Dec 2024 10:54:48 +0400 Subject: [PATCH 08/22] remove project --- src/utils/exclude.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/exclude.js b/src/utils/exclude.js index cb68e862da..36a31e3530 100644 --- a/src/utils/exclude.js +++ b/src/utils/exclude.js @@ -154,6 +154,7 @@ const excludeAdaptors = [ 'arbitrum-exchange-v3', 'bfx-(blast-futures)', 'stack', + 'liquid-bolt', ]; const excludePools = [ From 991cca56a8019464b99f8c1834a913f5190befea Mon Sep 17 00:00:00 2001 From: slasher125 Date: Mon, 23 Dec 2024 10:58:53 +0400 Subject: [PATCH 09/22] update exclusion list --- src/utils/exclude.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/exclude.js b/src/utils/exclude.js index 36a31e3530..e25028cd41 100644 --- a/src/utils/exclude.js +++ b/src/utils/exclude.js @@ -155,6 +155,7 @@ const excludeAdaptors = [ 'bfx-(blast-futures)', 'stack', 'liquid-bolt', + 'avault', ]; const excludePools = [ From bfe41dd2f2f7e05390aa3c680ecfbcc27a86572b Mon Sep 17 00:00:00 2001 From: Dashan McCain <91407856+DashanMcCain@users.noreply.github.com> Date: Sun, 22 Dec 2024 23:32:42 -0800 Subject: [PATCH 10/22] feat: nucleus vault yields (#1664) --- src/adaptors/nucleus/index.js | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/adaptors/nucleus/index.js diff --git a/src/adaptors/nucleus/index.js b/src/adaptors/nucleus/index.js new file mode 100644 index 0000000000..0829eacdd1 --- /dev/null +++ b/src/adaptors/nucleus/index.js @@ -0,0 +1,52 @@ +const utils = require('../utils'); +const sdk = require('@defillama/sdk'); + +const vaultData = async () => { + const vaults = await utils.getData( + 'https://backend.nucleusearn.io/v1/protocol/markets' + ); + const tokens = await utils.getData( + 'https://backend.nucleusearn.io/v1/protocol/tokens' + ); + + let pools = []; + await Promise.all( + Object.keys(vaults).map(async (vaultAddress) => { + try { + const vaultApyQuery = await utils.getData( + `https://backend.nucleusearn.io/v1/vaults/apy?token_address=${vaultAddress}&lookback_days=14` + ); + const vaultSymbol = await sdk.api2.erc20.symbol(vaultAddress); + + const ethereumApi = new sdk.ChainApi({ chain: 'ethereum' }); + const vaultBalances = await ethereumApi.sumTokens({ + owner: vaultAddress, + tokens: tokens, + }); + const usdBalance = await ethereumApi.getUSDValue(); + console.log('Vault TVL: ', usdBalance); + + console.log('Vault Symbol: ', vaultSymbol); + const pool = { + pool: `${vaultAddress}-ethereum`, + chain: 'Ethereum', + project: 'nucleus', + symbol: vaultSymbol.output, + tvlUsd: usdBalance, + apy: vaultApyQuery.apy, // 14 days apy + }; + pools.push(pool); + } catch (error) { + console.error(`Error processing vault: ${vaultAddress}`, error); + } + }) + ); + + return pools; +}; + +module.exports = { + timetravel: false, + apy: vaultData, + url: 'https://app.nucleusearn.io/dashboard', +}; From a9dc9d8c35381748c0585be7283a4300efc1f29e Mon Sep 17 00:00:00 2001 From: slasher125 Date: Tue, 24 Dec 2024 10:19:01 +0400 Subject: [PATCH 11/22] update orca --- src/adaptors/orca/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adaptors/orca/index.js b/src/adaptors/orca/index.js index 75f9532732..c1c99051a7 100644 --- a/src/adaptors/orca/index.js +++ b/src/adaptors/orca/index.js @@ -4,7 +4,7 @@ const utils = require('../utils'); const getApy = async () => { let whirlpools = ( await axios.get('https://api.mainnet.orca.so/v1/whirlpool/list') - ).data.whirlpools; + ).data.whirlpools.filter((i) => i.whitelisted === true); whirlpools = whirlpools.map((p) => { const apyReward = From c0c7d903e55d8f335a7c965a876b714677c670c8 Mon Sep 17 00:00:00 2001 From: slasher125 Date: Wed, 25 Dec 2024 12:04:40 +0400 Subject: [PATCH 12/22] rename extra-finance --- .../abis/veloPairsSugar.json | 0 .../abis/veloPairsSugarV2.json | 0 .../compute.js | 0 .../contract.js | 0 .../{extra-finance => extra-finance-leverage-farming}/index.js | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) rename src/adaptors/{extra-finance => extra-finance-leverage-farming}/abis/veloPairsSugar.json (100%) rename src/adaptors/{extra-finance => extra-finance-leverage-farming}/abis/veloPairsSugarV2.json (100%) rename src/adaptors/{extra-finance => extra-finance-leverage-farming}/compute.js (100%) rename src/adaptors/{extra-finance => extra-finance-leverage-farming}/contract.js (100%) rename src/adaptors/{extra-finance => extra-finance-leverage-farming}/index.js (98%) diff --git a/src/adaptors/extra-finance/abis/veloPairsSugar.json b/src/adaptors/extra-finance-leverage-farming/abis/veloPairsSugar.json similarity index 100% rename from src/adaptors/extra-finance/abis/veloPairsSugar.json rename to src/adaptors/extra-finance-leverage-farming/abis/veloPairsSugar.json diff --git a/src/adaptors/extra-finance/abis/veloPairsSugarV2.json b/src/adaptors/extra-finance-leverage-farming/abis/veloPairsSugarV2.json similarity index 100% rename from src/adaptors/extra-finance/abis/veloPairsSugarV2.json rename to src/adaptors/extra-finance-leverage-farming/abis/veloPairsSugarV2.json diff --git a/src/adaptors/extra-finance/compute.js b/src/adaptors/extra-finance-leverage-farming/compute.js similarity index 100% rename from src/adaptors/extra-finance/compute.js rename to src/adaptors/extra-finance-leverage-farming/compute.js diff --git a/src/adaptors/extra-finance/contract.js b/src/adaptors/extra-finance-leverage-farming/contract.js similarity index 100% rename from src/adaptors/extra-finance/contract.js rename to src/adaptors/extra-finance-leverage-farming/contract.js diff --git a/src/adaptors/extra-finance/index.js b/src/adaptors/extra-finance-leverage-farming/index.js similarity index 98% rename from src/adaptors/extra-finance/index.js rename to src/adaptors/extra-finance-leverage-farming/index.js index 185e3c0b1e..a63b52b4c8 100644 --- a/src/adaptors/extra-finance/index.js +++ b/src/adaptors/extra-finance-leverage-farming/index.js @@ -12,7 +12,7 @@ const { getAllVeloPoolInfo, } = require('./compute'); -const project = 'extra-finance'; +const project = 'extra-finance-leverage-farming'; const chains = ['optimism', 'base']; const subgraphUrls = { From 9eaa30f9b32bd1385680a0b85f016e504907279e Mon Sep 17 00:00:00 2001 From: Karman <130730603+KarmanMax@users.noreply.github.com> Date: Fri, 27 Dec 2024 14:25:29 +0800 Subject: [PATCH 13/22] update extra-finance adapter (#1666) --- .../extra-finance-leverage-farming/contract.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/adaptors/extra-finance-leverage-farming/contract.js b/src/adaptors/extra-finance-leverage-farming/contract.js index 34b2518120..621cc76c28 100644 --- a/src/adaptors/extra-finance-leverage-farming/contract.js +++ b/src/adaptors/extra-finance-leverage-farming/contract.js @@ -4,8 +4,8 @@ const pairsSugarContractAbi = require("./abis/veloPairsSugarV2.json"); const { concat } = require('lodash'); const veloPairAddress = { - optimism: '0x1381B1E6aaFa01bD28e95AdaB35bdA8191826bC8', - base: '0x82357A700f242476da8C5712C010B2D5e327C588' + optimism: '0xD11Aa38D87C6604A127431D4d3aa8C0e9763f0be', + base: '0x51f290CCCD6a54Af00b38edDd59212dE068B8A4b' } const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000" @@ -27,9 +27,9 @@ exports.getAllVeloPools = async function (chain) { const simpleRpcProvider = new ethers.providers.JsonRpcProvider(rpcUrl); const veloPairContract = new Contract(veloPairAddress[chain], pairsSugarContractAbi, simpleRpcProvider) const poolInfoLists = await Promise.all([ - veloPairContract.all(400, 0), - veloPairContract.all(400, 400), - veloPairContract.all(400, 800), + veloPairContract.all(300, 0), + veloPairContract.all(300, 300), + veloPairContract.all(300, 600), ]) const poolInfoList = concat(...poolInfoLists) return poolInfoList From 313e08231f3e6e65ad73fe297b3eb06788a4ff98 Mon Sep 17 00:00:00 2001 From: fextr <34183870+fextr@users.noreply.github.com> Date: Thu, 26 Dec 2024 22:26:38 -0800 Subject: [PATCH 14/22] update rlpPriceStorage address in rlp-resolv adapter (#1667) --- src/adaptors/resolv-rlp/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adaptors/resolv-rlp/index.js b/src/adaptors/resolv-rlp/index.js index 7226aa9e57..2372a20b09 100644 --- a/src/adaptors/resolv-rlp/index.js +++ b/src/adaptors/resolv-rlp/index.js @@ -5,7 +5,7 @@ const ethers = require('ethers'); const RLP = '0x4956b52aE2fF65D74CA2d61207523288e4528f96'; -const rlpPriceStorage = '0xAa33e5ECAE01779b26cD9dBD3c62E34c29b2D565'; +const rlpPriceStorage = '0xaE2364579D6cB4Bbd6695846C1D595cA9AF3574d'; const topic0priceSet = '0x2f0fe01aa6daff1c7bb411a324bdebe55dc2cd1e0ff2fc504b7569346e7d7d5a'; From b4410847f883392fb6e9991107824e64e688cb31 Mon Sep 17 00:00:00 2001 From: Han <79642550+nicetomeetyou1@users.noreply.github.com> Date: Fri, 27 Dec 2024 14:06:35 +0700 Subject: [PATCH 15/22] Scallop: add borrow reward apy (#1668) * feat: add scallop lend adaptor * fix: tvl and apy calculation * fix: tvl calculation and add addtional fields * feat: add borrow reward * refactor: minor * feat: add ltv --- src/adaptors/scallop-lend/index.js | 37 ++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/adaptors/scallop-lend/index.js b/src/adaptors/scallop-lend/index.js index 808516335a..e935d3cf52 100644 --- a/src/adaptors/scallop-lend/index.js +++ b/src/adaptors/scallop-lend/index.js @@ -2,24 +2,51 @@ const axios = require('axios'); const utils = require('../utils') const baseUrl = 'https://sdk.api.scallop.io/api'; -const marketEndpoint = `${baseUrl}/market`; -const spoolsEndpoint = `${baseUrl}/spools`; +const marketEndpoint = `${baseUrl}/market/migrate`; +const spoolsEndpoint = `${baseUrl}/spools/migrate`; +const borrowIncentiveEndpoint = `${baseUrl}/borrowIncentivePools`; const main = async () => { - let [market, spools] = await Promise.all([axios.get(marketEndpoint), axios.get(spoolsEndpoint)]); + let [market, spools, borrowIncentive] = await Promise.all([axios.get(marketEndpoint), axios.get(spoolsEndpoint), axios.get(borrowIncentiveEndpoint)]); const supplyRewards = {}; + const rewardTokenPool = {}; spools.data.spools.forEach((spool) => { + if(spool.rewardApr <= 0) { + return; + } supplyRewards[spool.coinType] = { rewardApr: spool.rewardApr, rewardCoinType: spool.rewardCoinType, }; + if(rewardTokenPool[spool.coinType] === undefined) { + rewardTokenPool[spool.coinType] = []; + } + rewardTokenPool[spool.coinType].push(spool.rewardCoinType); + }); + + const borrowRewards = {}; + borrowIncentive.data.forEach((borrow) => { + borrow.rewards.forEach((reward) => { + if (borrowRewards[borrow.coinType] === undefined) { + borrowRewards[borrow.coinType] = []; + } + borrowRewards[borrow.coinType].push({ + rewardApr: reward.rewardApr, + rewardCoinType: reward.coinType, + }); + if(rewardTokenPool[borrow.coinType] === undefined) { + rewardTokenPool[borrow.coinType] = []; + } + rewardTokenPool[borrow.coinType].push(reward.coinType); + }); }); const arr = []; market.data.pools.forEach((pool) => { const supplyUsd = parseFloat(pool.supplyCoin) * parseFloat(pool.coinPrice); const borrowUsd = parseFloat(pool.borrowCoin) * parseFloat(pool.coinPrice); + const collateralFactor = market.data.collaterals.find((collateral) => collateral.coinType === pool.coinType); arr.push({ chain: 'Sui', project: 'scallop-lend', @@ -28,10 +55,12 @@ const main = async () => { tvlUsd: supplyUsd - borrowUsd, apyBase: parseFloat(pool.supplyApy * 100), apyReward: supplyRewards[pool.coinType] ? parseFloat(supplyRewards[pool.coinType].rewardApr * 100) : null, - rewardTokens: supplyRewards[pool.coinType] ? [supplyRewards[pool.coinType].rewardCoinType] : [], + rewardTokens: rewardTokenPool[pool.coinType] ? Array.from(new Set(rewardTokenPool[pool.coinType])) : null, totalSupplyUsd: supplyUsd, totalBorrowUsd: borrowUsd, apyBaseBorrow: parseFloat(pool.borrowApy * 100), + apyRewardBorrow: borrowRewards[pool.coinType] ? parseFloat(borrowRewards[pool.coinType].reduce((prev, curr) => prev + curr.rewardApr, 0) * 100) : null, + ltv: Number(parseFloat(collateralFactor ? collateralFactor.collateralFactor : 0).toFixed(2)), }); }); From 49029183f240b2033c591d35916de834db845042 Mon Sep 17 00:00:00 2001 From: 0xmDreamy <124707942+0xmDreamy@users.noreply.github.com> Date: Sat, 28 Dec 2024 16:18:12 +0700 Subject: [PATCH 16/22] feat(abracadabra-spell): Add single-sided GM cauldrons (#1670) --- src/adaptors/abracadabra-spell/cauldrons.js | 22 ++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/adaptors/abracadabra-spell/cauldrons.js b/src/adaptors/abracadabra-spell/cauldrons.js index b2cf9efcef..cd4d0a14c3 100644 --- a/src/adaptors/abracadabra-spell/cauldrons.js +++ b/src/adaptors/abracadabra-spell/cauldrons.js @@ -30,31 +30,43 @@ const POOLS = { address: '0x7962acfcfc2ccebc810045391d60040f635404fb', collateralPoolId: '906b233c-8478-4b94-94e5-2d77e6c7c9e5', symbol: "SOL-USDC", - }, // gmSOL + }, // gmSOLUSDC { version: 4, address: '0x2b02bBeAb8eCAb792d3F4DDA7a76f63Aa21934FA', collateralPoolId: '61b4c35c-97f6-4c05-a5ff-aeb4426adf5b', symbol: "ETH-USDC", - }, // gmETH + }, // gmETHUSDC { version: 4, address: '0xD7659D913430945600dfe875434B6d80646d552A', collateralPoolId: '5b8c0691-b9ff-4d82-97e4-19a1247e6dbf', symbol: "WBTC.B-USDC", - }, // gmBTC + }, // gmBTCUSDC { version: 4, address: '0x4F9737E994da9811B8830775Fd73E2F1C8e40741', collateralPoolId: 'f3fa942f-1867-4028-95ff-4eb76816cd07', symbol: "ARB-USDC", - }, // gmARB + }, // gmARBUSDC { version: 4, address: '0x66805F6e719d7e67D46e8b2501C1237980996C6a', collateralPoolId: 'dffb3514-d667-4f2f-8df3-f716ebe09c93', symbol: "LINK-USDC", - }, // gmLINK + }, // gmLINKUSDC + { + version: 4, + address: '0x9fF8b4C842e4a95dAB5089781427c836DAE94831', + collateralPoolId: 'ffb4e407-6507-4615-b776-a0d99cfc1bbb', + symbol: "WBTC.B-WBTC.B", + }, // gmBTC + { + version: 4, + address: '0x625Fe79547828b1B54467E5Ed822a9A8a074bD61', + collateralPoolId: '5e2aac09-71c8-4092-ba4f-00f1ac0d04fd', + symbol: "ETH-ETH", + }, // gmETH { version: 4, address: '0x49De724D7125641F56312EBBcbf48Ef107c8FA57' }, // WBTC { version: 4, address: '0x780db9770dDc236fd659A39430A8a7cC07D0C320' }, // WETHV2 ], From a4a05f78d335aa1c7ec631ba2d7187fac1bd002c Mon Sep 17 00:00:00 2001 From: slasher125 Date: Sat, 28 Dec 2024 18:29:44 +0400 Subject: [PATCH 17/22] cetus add tvl filter cause wrong values --- src/adaptors/cetus-amm/index.js | 46 +++++++++++++++++---------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/adaptors/cetus-amm/index.js b/src/adaptors/cetus-amm/index.js index b4a5bc0987..8fad7fd911 100644 --- a/src/adaptors/cetus-amm/index.js +++ b/src/adaptors/cetus-amm/index.js @@ -8,28 +8,30 @@ const chains = { const apy = async (chain) => { const data = (await axios.get(chains[chain])).data.data.pools; - return data.map((p) => { - const apyReward = p.rewarder_apr.reduce( - (a, b) => a + Number(b.replace('%', '')), - 0 - ); - return { - chain, - project: 'cetus-amm', - pool: p.swap_account, - symbol: p.symbol, - tvlUsd: Number(p.tvl_in_usd), - apyBase: Number(p.apr_24h.replace('%', '')), - apyBase7d: Number(p.apr_7day.replace('%', '')), - volumeUsd1d: Number(p.vol_in_usd_24h), - volumeUsd7d: Number(p.vol_in_usd_7_day), - apyReward, - rewardTokens: apyReward > 0 ? ['sui', 'cetus'] : [], - poolMeta: `${Number(p.fee) * 100}%`, - underlyingTokens: [p.token_a_address, p.token_b_address], - url: `https://app.cetus.zone/liquidity/deposit?poolAddress=${p.swap_account}`, - }; - }); + return data + .map((p) => { + const apyReward = p.rewarder_apr.reduce( + (a, b) => a + Number(b.replace('%', '')), + 0 + ); + return { + chain, + project: 'cetus-amm', + pool: p.swap_account, + symbol: p.symbol, + tvlUsd: Number(p.tvl_in_usd), + apyBase: Number(p.apr_24h.replace('%', '')), + apyBase7d: Number(p.apr_7day.replace('%', '')), + volumeUsd1d: Number(p.vol_in_usd_24h), + volumeUsd7d: Number(p.vol_in_usd_7_day), + apyReward, + rewardTokens: apyReward > 0 ? ['sui', 'cetus'] : [], + poolMeta: `${Number(p.fee) * 100}%`, + underlyingTokens: [p.token_a_address, p.token_b_address], + url: `https://app.cetus.zone/liquidity/deposit?poolAddress=${p.swap_account}`, + }; + }) + .filter((i) => i.tvlUsd <= 1e8); }; const main = async () => { From 8c1abb8b004414b70af70c030c8f0a5da998b83e Mon Sep 17 00:00:00 2001 From: 0xprinc <0xprinc@gmail.com> Date: Mon, 30 Dec 2024 10:51:56 +0530 Subject: [PATCH 18/22] added fluid-vaults (#1659) * added fluid_vaults adaptor * made further changes * all except 1 test passing * updated apyBase and apyReward logic * added the changes * . * symbols are fetching * . * cleaned up * changed pooladdresses format * merged vaults into lending adaptor * added additional returned variables --------- Co-authored-by: 0xprinc Co-authored-by: bergben --- .../fluid-lending/abiVaultResolver.js | 2267 +++++++++++++++++ src/adaptors/fluid-lending/index.js | 288 ++- 2 files changed, 2489 insertions(+), 66 deletions(-) create mode 100644 src/adaptors/fluid-lending/abiVaultResolver.js diff --git a/src/adaptors/fluid-lending/abiVaultResolver.js b/src/adaptors/fluid-lending/abiVaultResolver.js new file mode 100644 index 0000000000..bf9167a961 --- /dev/null +++ b/src/adaptors/fluid-lending/abiVaultResolver.js @@ -0,0 +1,2267 @@ +module.exports = [ + { + inputs: [ + { internalType: 'address', name: 'factory_', type: 'address' }, + { internalType: 'address', name: 'liquidityResolver_', type: 'address' }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [], + name: 'FACTORY', + outputs: [ + { + internalType: 'contract IFluidVaultFactory', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'LIQUIDITY_RESOLVER', + outputs: [ + { + internalType: 'contract IFluidLiquidityResolver', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'slot_', type: 'uint256' }, + { internalType: 'int256', name: 'key1_', type: 'int256' }, + { internalType: 'uint256', name: 'key2_', type: 'uint256' }, + ], + name: 'calculateDoubleIntUintMapping', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'slot_', type: 'uint256' }, + { internalType: 'int256', name: 'key_', type: 'int256' }, + ], + name: 'calculateStorageSlotIntMapping', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: 'slot_', type: 'uint256' }, + { internalType: 'uint256', name: 'key_', type: 'uint256' }, + ], + name: 'calculateStorageSlotUintMapping', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getAbsorbedDustDebt', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getAbsorbedLiquidityRaw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getAllVaultsAddresses', + outputs: [ + { internalType: 'address[]', name: 'vaults_', type: 'address[]' }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getAllVaultsLiquidation', + outputs: [ + { + components: [ + { internalType: 'address', name: 'vault', type: 'address' }, + { internalType: 'address', name: 'token0In', type: 'address' }, + { internalType: 'address', name: 'token0Out', type: 'address' }, + { internalType: 'address', name: 'token1In', type: 'address' }, + { internalType: 'address', name: 'token1Out', type: 'address' }, + { internalType: 'uint256', name: 'inAmt', type: 'uint256' }, + { internalType: 'uint256', name: 'outAmt', type: 'uint256' }, + { internalType: 'uint256', name: 'inAmtWithAbsorb', type: 'uint256' }, + { + internalType: 'uint256', + name: 'outAmtWithAbsorb', + type: 'uint256', + }, + { internalType: 'bool', name: 'absorbAvailable', type: 'bool' }, + ], + internalType: 'struct Structs.LiquidationStruct[]', + name: 'liquidationsData_', + type: 'tuple[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'vault_', type: 'address' }, + { internalType: 'uint256', name: 'branch_', type: 'uint256' }, + ], + name: 'getBranchDataRaw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'vault_', type: 'address' }, + { internalType: 'uint256', name: 'index_', type: 'uint256' }, + ], + name: 'getContractForDeployerIndex', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getDexFromAddress', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address[]', name: 'vaults_', type: 'address[]' }, + { internalType: 'uint256[]', name: 'tokensInAmt_', type: 'uint256[]' }, + ], + name: 'getMultipleVaultsLiquidation', + outputs: [ + { + components: [ + { internalType: 'address', name: 'vault', type: 'address' }, + { internalType: 'address', name: 'token0In', type: 'address' }, + { internalType: 'address', name: 'token0Out', type: 'address' }, + { internalType: 'address', name: 'token1In', type: 'address' }, + { internalType: 'address', name: 'token1Out', type: 'address' }, + { internalType: 'uint256', name: 'inAmt', type: 'uint256' }, + { internalType: 'uint256', name: 'outAmt', type: 'uint256' }, + { internalType: 'uint256', name: 'inAmtWithAbsorb', type: 'uint256' }, + { + internalType: 'uint256', + name: 'outAmtWithAbsorb', + type: 'uint256', + }, + { internalType: 'bool', name: 'absorbAvailable', type: 'bool' }, + ], + internalType: 'struct Structs.LiquidationStruct[]', + name: 'liquidationsData_', + type: 'tuple[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'vault_', type: 'address' }, + { internalType: 'uint256', name: 'positionId_', type: 'uint256' }, + ], + name: 'getPositionDataRaw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getRateRaw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getRebalancer', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'vault_', type: 'address' }, + { internalType: 'int256', name: 'tick_', type: 'int256' }, + ], + name: 'getTickDataRaw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'vault_', type: 'address' }, + { internalType: 'int256', name: 'key_', type: 'int256' }, + ], + name: 'getTickHasDebtRaw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'vault_', type: 'address' }, + { internalType: 'int256', name: 'tick_', type: 'int256' }, + { internalType: 'uint256', name: 'id_', type: 'uint256' }, + ], + name: 'getTickIdDataRaw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'nftId_', type: 'uint256' }], + name: 'getTokenConfig', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getTotalVaults', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getVaultAbsorb', + outputs: [ + { + components: [ + { internalType: 'address', name: 'vault', type: 'address' }, + { internalType: 'bool', name: 'absorbAvailable', type: 'bool' }, + ], + internalType: 'struct Structs.AbsorbStruct', + name: 'absorbData_', + type: 'tuple', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'vaultId_', type: 'uint256' }], + name: 'getVaultAddress', + outputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getVaultEntireData', + outputs: [ + { + components: [ + { internalType: 'address', name: 'vault', type: 'address' }, + { internalType: 'bool', name: 'isSmartCol', type: 'bool' }, + { internalType: 'bool', name: 'isSmartDebt', type: 'bool' }, + { + components: [ + { internalType: 'address', name: 'liquidity', type: 'address' }, + { internalType: 'address', name: 'factory', type: 'address' }, + { + internalType: 'address', + name: 'operateImplementation', + type: 'address', + }, + { + internalType: 'address', + name: 'adminImplementation', + type: 'address', + }, + { + internalType: 'address', + name: 'secondaryImplementation', + type: 'address', + }, + { internalType: 'address', name: 'deployer', type: 'address' }, + { internalType: 'address', name: 'supply', type: 'address' }, + { internalType: 'address', name: 'borrow', type: 'address' }, + { + components: [ + { internalType: 'address', name: 'token0', type: 'address' }, + { internalType: 'address', name: 'token1', type: 'address' }, + ], + internalType: 'struct IFluidVault.Tokens', + name: 'supplyToken', + type: 'tuple', + }, + { + components: [ + { internalType: 'address', name: 'token0', type: 'address' }, + { internalType: 'address', name: 'token1', type: 'address' }, + ], + internalType: 'struct IFluidVault.Tokens', + name: 'borrowToken', + type: 'tuple', + }, + { internalType: 'uint256', name: 'vaultId', type: 'uint256' }, + { internalType: 'uint256', name: 'vaultType', type: 'uint256' }, + { + internalType: 'bytes32', + name: 'supplyExchangePriceSlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'borrowExchangePriceSlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'userSupplySlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'userBorrowSlot', + type: 'bytes32', + }, + ], + internalType: 'struct IFluidVault.ConstantViews', + name: 'constantVariables', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint16', + name: 'supplyRateMagnifier', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'borrowRateMagnifier', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'collateralFactor', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'liquidationThreshold', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'liquidationMaxLimit', + type: 'uint16', + }, + { internalType: 'uint16', name: 'withdrawalGap', type: 'uint16' }, + { + internalType: 'uint16', + name: 'liquidationPenalty', + type: 'uint16', + }, + { internalType: 'uint16', name: 'borrowFee', type: 'uint16' }, + { internalType: 'address', name: 'oracle', type: 'address' }, + { + internalType: 'uint256', + name: 'oraclePriceOperate', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'oraclePriceLiquidate', + type: 'uint256', + }, + { internalType: 'address', name: 'rebalancer', type: 'address' }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + ], + internalType: 'struct Structs.Configs', + name: 'configs', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'lastStoredLiquiditySupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredLiquidityBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredVaultSupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredVaultBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquiditySupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquidityBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'vaultSupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'vaultBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'supplyRateLiquidity', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'borrowRateLiquidity', + type: 'uint256', + }, + { + internalType: 'int256', + name: 'supplyRateVault', + type: 'int256', + }, + { + internalType: 'int256', + name: 'borrowRateVault', + type: 'int256', + }, + { + internalType: 'int256', + name: 'rewardsOrFeeRateSupply', + type: 'int256', + }, + { + internalType: 'int256', + name: 'rewardsOrFeeRateBorrow', + type: 'int256', + }, + ], + internalType: 'struct Structs.ExchangePricesAndRates', + name: 'exchangePricesAndRates', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'totalSupplyVault', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalBorrowVault', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalSupplyLiquidityOrDex', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalBorrowLiquidityOrDex', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'absorbedSupply', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'absorbedBorrow', + type: 'uint256', + }, + ], + internalType: 'struct Structs.TotalSupplyAndBorrow', + name: 'totalSupplyAndBorrow', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'withdrawLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawableUntilLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawable', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowLimit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowableUntilLimit', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowable', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowLimitUtilization', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minimumBorrowing', + type: 'uint256', + }, + ], + internalType: 'struct Structs.LimitsAndAvailability', + name: 'limitsAndAvailability', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'totalPositions', + type: 'uint256', + }, + { internalType: 'int256', name: 'topTick', type: 'int256' }, + { + internalType: 'uint256', + name: 'currentBranch', + type: 'uint256', + }, + { internalType: 'uint256', name: 'totalBranch', type: 'uint256' }, + { internalType: 'uint256', name: 'totalBorrow', type: 'uint256' }, + { internalType: 'uint256', name: 'totalSupply', type: 'uint256' }, + { + components: [ + { internalType: 'uint256', name: 'status', type: 'uint256' }, + { + internalType: 'int256', + name: 'minimaTick', + type: 'int256', + }, + { + internalType: 'uint256', + name: 'debtFactor', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'partials', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'debtLiquidity', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseBranchId', + type: 'uint256', + }, + { + internalType: 'int256', + name: 'baseBranchMinima', + type: 'int256', + }, + ], + internalType: 'struct Structs.CurrentBranchState', + name: 'currentBranchState', + type: 'tuple', + }, + ], + internalType: 'struct Structs.VaultState', + name: 'vaultState', + type: 'tuple', + }, + { + components: [ + { internalType: 'bool', name: 'modeWithInterest', type: 'bool' }, + { internalType: 'uint256', name: 'supply', type: 'uint256' }, + { + internalType: 'uint256', + name: 'withdrawalLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandPercent', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandDuration', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseWithdrawalLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawableUntilLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawable', + type: 'uint256', + }, + ], + internalType: 'struct Structs.UserSupplyData', + name: 'liquidityUserSupplyData', + type: 'tuple', + }, + { + components: [ + { internalType: 'bool', name: 'modeWithInterest', type: 'bool' }, + { internalType: 'uint256', name: 'borrow', type: 'uint256' }, + { internalType: 'uint256', name: 'borrowLimit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandPercent', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandDuration', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseBorrowLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'maxBorrowLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'borrowableUntilLimit', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowable', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowLimitUtilization', + type: 'uint256', + }, + ], + internalType: 'struct Structs.UserBorrowData', + name: 'liquidityUserBorrowData', + type: 'tuple', + }, + ], + internalType: 'struct Structs.VaultEntireData', + name: 'vaultData_', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getVaultId', + outputs: [{ internalType: 'uint256', name: 'id_', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'vault_', type: 'address' }, + { internalType: 'uint256', name: 'tokenInAmt_', type: 'uint256' }, + ], + name: 'getVaultLiquidation', + outputs: [ + { + components: [ + { internalType: 'address', name: 'vault', type: 'address' }, + { internalType: 'address', name: 'token0In', type: 'address' }, + { internalType: 'address', name: 'token0Out', type: 'address' }, + { internalType: 'address', name: 'token1In', type: 'address' }, + { internalType: 'address', name: 'token1Out', type: 'address' }, + { internalType: 'uint256', name: 'inAmt', type: 'uint256' }, + { internalType: 'uint256', name: 'outAmt', type: 'uint256' }, + { internalType: 'uint256', name: 'inAmtWithAbsorb', type: 'uint256' }, + { + internalType: 'uint256', + name: 'outAmtWithAbsorb', + type: 'uint256', + }, + { internalType: 'bool', name: 'absorbAvailable', type: 'bool' }, + ], + internalType: 'struct Structs.LiquidationStruct', + name: 'liquidationData_', + type: 'tuple', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getVaultState', + outputs: [ + { + components: [ + { internalType: 'uint256', name: 'totalPositions', type: 'uint256' }, + { internalType: 'int256', name: 'topTick', type: 'int256' }, + { internalType: 'uint256', name: 'currentBranch', type: 'uint256' }, + { internalType: 'uint256', name: 'totalBranch', type: 'uint256' }, + { internalType: 'uint256', name: 'totalBorrow', type: 'uint256' }, + { internalType: 'uint256', name: 'totalSupply', type: 'uint256' }, + { + components: [ + { internalType: 'uint256', name: 'status', type: 'uint256' }, + { internalType: 'int256', name: 'minimaTick', type: 'int256' }, + { internalType: 'uint256', name: 'debtFactor', type: 'uint256' }, + { internalType: 'uint256', name: 'partials', type: 'uint256' }, + { + internalType: 'uint256', + name: 'debtLiquidity', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseBranchId', + type: 'uint256', + }, + { + internalType: 'int256', + name: 'baseBranchMinima', + type: 'int256', + }, + ], + internalType: 'struct Structs.CurrentBranchState', + name: 'currentBranchState', + type: 'tuple', + }, + ], + internalType: 'struct Structs.VaultState', + name: 'vaultState_', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getVaultType', + outputs: [{ internalType: 'uint256', name: 'vaultType_', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getVaultVariables2Raw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + name: 'getVaultVariablesRaw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getVaultsAbsorb', + outputs: [ + { + components: [ + { internalType: 'address', name: 'vault', type: 'address' }, + { internalType: 'bool', name: 'absorbAvailable', type: 'bool' }, + ], + internalType: 'struct Structs.AbsorbStruct[]', + name: 'absorbData_', + type: 'tuple[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address[]', name: 'vaults_', type: 'address[]' }], + name: 'getVaultsAbsorb', + outputs: [ + { + components: [ + { internalType: 'address', name: 'vault', type: 'address' }, + { internalType: 'bool', name: 'absorbAvailable', type: 'bool' }, + ], + internalType: 'struct Structs.AbsorbStruct[]', + name: 'absorbData_', + type: 'tuple[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'getVaultsEntireData', + outputs: [ + { + components: [ + { internalType: 'address', name: 'vault', type: 'address' }, + { internalType: 'bool', name: 'isSmartCol', type: 'bool' }, + { internalType: 'bool', name: 'isSmartDebt', type: 'bool' }, + { + components: [ + { internalType: 'address', name: 'liquidity', type: 'address' }, + { internalType: 'address', name: 'factory', type: 'address' }, + { + internalType: 'address', + name: 'operateImplementation', + type: 'address', + }, + { + internalType: 'address', + name: 'adminImplementation', + type: 'address', + }, + { + internalType: 'address', + name: 'secondaryImplementation', + type: 'address', + }, + { internalType: 'address', name: 'deployer', type: 'address' }, + { internalType: 'address', name: 'supply', type: 'address' }, + { internalType: 'address', name: 'borrow', type: 'address' }, + { + components: [ + { internalType: 'address', name: 'token0', type: 'address' }, + { internalType: 'address', name: 'token1', type: 'address' }, + ], + internalType: 'struct IFluidVault.Tokens', + name: 'supplyToken', + type: 'tuple', + }, + { + components: [ + { internalType: 'address', name: 'token0', type: 'address' }, + { internalType: 'address', name: 'token1', type: 'address' }, + ], + internalType: 'struct IFluidVault.Tokens', + name: 'borrowToken', + type: 'tuple', + }, + { internalType: 'uint256', name: 'vaultId', type: 'uint256' }, + { internalType: 'uint256', name: 'vaultType', type: 'uint256' }, + { + internalType: 'bytes32', + name: 'supplyExchangePriceSlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'borrowExchangePriceSlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'userSupplySlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'userBorrowSlot', + type: 'bytes32', + }, + ], + internalType: 'struct IFluidVault.ConstantViews', + name: 'constantVariables', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint16', + name: 'supplyRateMagnifier', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'borrowRateMagnifier', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'collateralFactor', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'liquidationThreshold', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'liquidationMaxLimit', + type: 'uint16', + }, + { internalType: 'uint16', name: 'withdrawalGap', type: 'uint16' }, + { + internalType: 'uint16', + name: 'liquidationPenalty', + type: 'uint16', + }, + { internalType: 'uint16', name: 'borrowFee', type: 'uint16' }, + { internalType: 'address', name: 'oracle', type: 'address' }, + { + internalType: 'uint256', + name: 'oraclePriceOperate', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'oraclePriceLiquidate', + type: 'uint256', + }, + { internalType: 'address', name: 'rebalancer', type: 'address' }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + ], + internalType: 'struct Structs.Configs', + name: 'configs', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'lastStoredLiquiditySupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredLiquidityBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredVaultSupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredVaultBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquiditySupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquidityBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'vaultSupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'vaultBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'supplyRateLiquidity', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'borrowRateLiquidity', + type: 'uint256', + }, + { + internalType: 'int256', + name: 'supplyRateVault', + type: 'int256', + }, + { + internalType: 'int256', + name: 'borrowRateVault', + type: 'int256', + }, + { + internalType: 'int256', + name: 'rewardsOrFeeRateSupply', + type: 'int256', + }, + { + internalType: 'int256', + name: 'rewardsOrFeeRateBorrow', + type: 'int256', + }, + ], + internalType: 'struct Structs.ExchangePricesAndRates', + name: 'exchangePricesAndRates', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'totalSupplyVault', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalBorrowVault', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalSupplyLiquidityOrDex', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalBorrowLiquidityOrDex', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'absorbedSupply', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'absorbedBorrow', + type: 'uint256', + }, + ], + internalType: 'struct Structs.TotalSupplyAndBorrow', + name: 'totalSupplyAndBorrow', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'withdrawLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawableUntilLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawable', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowLimit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowableUntilLimit', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowable', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowLimitUtilization', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minimumBorrowing', + type: 'uint256', + }, + ], + internalType: 'struct Structs.LimitsAndAvailability', + name: 'limitsAndAvailability', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'totalPositions', + type: 'uint256', + }, + { internalType: 'int256', name: 'topTick', type: 'int256' }, + { + internalType: 'uint256', + name: 'currentBranch', + type: 'uint256', + }, + { internalType: 'uint256', name: 'totalBranch', type: 'uint256' }, + { internalType: 'uint256', name: 'totalBorrow', type: 'uint256' }, + { internalType: 'uint256', name: 'totalSupply', type: 'uint256' }, + { + components: [ + { internalType: 'uint256', name: 'status', type: 'uint256' }, + { + internalType: 'int256', + name: 'minimaTick', + type: 'int256', + }, + { + internalType: 'uint256', + name: 'debtFactor', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'partials', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'debtLiquidity', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseBranchId', + type: 'uint256', + }, + { + internalType: 'int256', + name: 'baseBranchMinima', + type: 'int256', + }, + ], + internalType: 'struct Structs.CurrentBranchState', + name: 'currentBranchState', + type: 'tuple', + }, + ], + internalType: 'struct Structs.VaultState', + name: 'vaultState', + type: 'tuple', + }, + { + components: [ + { internalType: 'bool', name: 'modeWithInterest', type: 'bool' }, + { internalType: 'uint256', name: 'supply', type: 'uint256' }, + { + internalType: 'uint256', + name: 'withdrawalLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandPercent', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandDuration', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseWithdrawalLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawableUntilLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawable', + type: 'uint256', + }, + ], + internalType: 'struct Structs.UserSupplyData', + name: 'liquidityUserSupplyData', + type: 'tuple', + }, + { + components: [ + { internalType: 'bool', name: 'modeWithInterest', type: 'bool' }, + { internalType: 'uint256', name: 'borrow', type: 'uint256' }, + { internalType: 'uint256', name: 'borrowLimit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandPercent', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandDuration', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseBorrowLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'maxBorrowLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'borrowableUntilLimit', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowable', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowLimitUtilization', + type: 'uint256', + }, + ], + internalType: 'struct Structs.UserBorrowData', + name: 'liquidityUserBorrowData', + type: 'tuple', + }, + ], + internalType: 'struct Structs.VaultEntireData[]', + name: 'vaultsData_', + type: 'tuple[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'slot_', type: 'uint256' }], + name: 'normalSlot', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'nftId_', type: 'uint256' }], + name: 'positionByNftId', + outputs: [ + { + components: [ + { internalType: 'uint256', name: 'nftId', type: 'uint256' }, + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'bool', name: 'isLiquidated', type: 'bool' }, + { internalType: 'bool', name: 'isSupplyPosition', type: 'bool' }, + { internalType: 'int256', name: 'tick', type: 'int256' }, + { internalType: 'uint256', name: 'tickId', type: 'uint256' }, + { internalType: 'uint256', name: 'beforeSupply', type: 'uint256' }, + { internalType: 'uint256', name: 'beforeBorrow', type: 'uint256' }, + { + internalType: 'uint256', + name: 'beforeDustBorrow', + type: 'uint256', + }, + { internalType: 'uint256', name: 'supply', type: 'uint256' }, + { internalType: 'uint256', name: 'borrow', type: 'uint256' }, + { internalType: 'uint256', name: 'dustBorrow', type: 'uint256' }, + ], + internalType: 'struct Structs.UserPosition', + name: 'userPosition_', + type: 'tuple', + }, + { + components: [ + { internalType: 'address', name: 'vault', type: 'address' }, + { internalType: 'bool', name: 'isSmartCol', type: 'bool' }, + { internalType: 'bool', name: 'isSmartDebt', type: 'bool' }, + { + components: [ + { internalType: 'address', name: 'liquidity', type: 'address' }, + { internalType: 'address', name: 'factory', type: 'address' }, + { + internalType: 'address', + name: 'operateImplementation', + type: 'address', + }, + { + internalType: 'address', + name: 'adminImplementation', + type: 'address', + }, + { + internalType: 'address', + name: 'secondaryImplementation', + type: 'address', + }, + { internalType: 'address', name: 'deployer', type: 'address' }, + { internalType: 'address', name: 'supply', type: 'address' }, + { internalType: 'address', name: 'borrow', type: 'address' }, + { + components: [ + { internalType: 'address', name: 'token0', type: 'address' }, + { internalType: 'address', name: 'token1', type: 'address' }, + ], + internalType: 'struct IFluidVault.Tokens', + name: 'supplyToken', + type: 'tuple', + }, + { + components: [ + { internalType: 'address', name: 'token0', type: 'address' }, + { internalType: 'address', name: 'token1', type: 'address' }, + ], + internalType: 'struct IFluidVault.Tokens', + name: 'borrowToken', + type: 'tuple', + }, + { internalType: 'uint256', name: 'vaultId', type: 'uint256' }, + { internalType: 'uint256', name: 'vaultType', type: 'uint256' }, + { + internalType: 'bytes32', + name: 'supplyExchangePriceSlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'borrowExchangePriceSlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'userSupplySlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'userBorrowSlot', + type: 'bytes32', + }, + ], + internalType: 'struct IFluidVault.ConstantViews', + name: 'constantVariables', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint16', + name: 'supplyRateMagnifier', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'borrowRateMagnifier', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'collateralFactor', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'liquidationThreshold', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'liquidationMaxLimit', + type: 'uint16', + }, + { internalType: 'uint16', name: 'withdrawalGap', type: 'uint16' }, + { + internalType: 'uint16', + name: 'liquidationPenalty', + type: 'uint16', + }, + { internalType: 'uint16', name: 'borrowFee', type: 'uint16' }, + { internalType: 'address', name: 'oracle', type: 'address' }, + { + internalType: 'uint256', + name: 'oraclePriceOperate', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'oraclePriceLiquidate', + type: 'uint256', + }, + { internalType: 'address', name: 'rebalancer', type: 'address' }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + ], + internalType: 'struct Structs.Configs', + name: 'configs', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'lastStoredLiquiditySupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredLiquidityBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredVaultSupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredVaultBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquiditySupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquidityBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'vaultSupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'vaultBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'supplyRateLiquidity', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'borrowRateLiquidity', + type: 'uint256', + }, + { + internalType: 'int256', + name: 'supplyRateVault', + type: 'int256', + }, + { + internalType: 'int256', + name: 'borrowRateVault', + type: 'int256', + }, + { + internalType: 'int256', + name: 'rewardsOrFeeRateSupply', + type: 'int256', + }, + { + internalType: 'int256', + name: 'rewardsOrFeeRateBorrow', + type: 'int256', + }, + ], + internalType: 'struct Structs.ExchangePricesAndRates', + name: 'exchangePricesAndRates', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'totalSupplyVault', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalBorrowVault', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalSupplyLiquidityOrDex', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalBorrowLiquidityOrDex', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'absorbedSupply', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'absorbedBorrow', + type: 'uint256', + }, + ], + internalType: 'struct Structs.TotalSupplyAndBorrow', + name: 'totalSupplyAndBorrow', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'withdrawLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawableUntilLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawable', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowLimit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowableUntilLimit', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowable', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowLimitUtilization', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minimumBorrowing', + type: 'uint256', + }, + ], + internalType: 'struct Structs.LimitsAndAvailability', + name: 'limitsAndAvailability', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'totalPositions', + type: 'uint256', + }, + { internalType: 'int256', name: 'topTick', type: 'int256' }, + { + internalType: 'uint256', + name: 'currentBranch', + type: 'uint256', + }, + { internalType: 'uint256', name: 'totalBranch', type: 'uint256' }, + { internalType: 'uint256', name: 'totalBorrow', type: 'uint256' }, + { internalType: 'uint256', name: 'totalSupply', type: 'uint256' }, + { + components: [ + { internalType: 'uint256', name: 'status', type: 'uint256' }, + { + internalType: 'int256', + name: 'minimaTick', + type: 'int256', + }, + { + internalType: 'uint256', + name: 'debtFactor', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'partials', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'debtLiquidity', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseBranchId', + type: 'uint256', + }, + { + internalType: 'int256', + name: 'baseBranchMinima', + type: 'int256', + }, + ], + internalType: 'struct Structs.CurrentBranchState', + name: 'currentBranchState', + type: 'tuple', + }, + ], + internalType: 'struct Structs.VaultState', + name: 'vaultState', + type: 'tuple', + }, + { + components: [ + { internalType: 'bool', name: 'modeWithInterest', type: 'bool' }, + { internalType: 'uint256', name: 'supply', type: 'uint256' }, + { + internalType: 'uint256', + name: 'withdrawalLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandPercent', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandDuration', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseWithdrawalLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawableUntilLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawable', + type: 'uint256', + }, + ], + internalType: 'struct Structs.UserSupplyData', + name: 'liquidityUserSupplyData', + type: 'tuple', + }, + { + components: [ + { internalType: 'bool', name: 'modeWithInterest', type: 'bool' }, + { internalType: 'uint256', name: 'borrow', type: 'uint256' }, + { internalType: 'uint256', name: 'borrowLimit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandPercent', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandDuration', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseBorrowLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'maxBorrowLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'borrowableUntilLimit', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowable', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowLimitUtilization', + type: 'uint256', + }, + ], + internalType: 'struct Structs.UserBorrowData', + name: 'liquidityUserBorrowData', + type: 'tuple', + }, + ], + internalType: 'struct Structs.VaultEntireData', + name: 'vaultData_', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'user_', type: 'address' }], + name: 'positionsByUser', + outputs: [ + { + components: [ + { internalType: 'uint256', name: 'nftId', type: 'uint256' }, + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'bool', name: 'isLiquidated', type: 'bool' }, + { internalType: 'bool', name: 'isSupplyPosition', type: 'bool' }, + { internalType: 'int256', name: 'tick', type: 'int256' }, + { internalType: 'uint256', name: 'tickId', type: 'uint256' }, + { internalType: 'uint256', name: 'beforeSupply', type: 'uint256' }, + { internalType: 'uint256', name: 'beforeBorrow', type: 'uint256' }, + { + internalType: 'uint256', + name: 'beforeDustBorrow', + type: 'uint256', + }, + { internalType: 'uint256', name: 'supply', type: 'uint256' }, + { internalType: 'uint256', name: 'borrow', type: 'uint256' }, + { internalType: 'uint256', name: 'dustBorrow', type: 'uint256' }, + ], + internalType: 'struct Structs.UserPosition[]', + name: 'userPositions_', + type: 'tuple[]', + }, + { + components: [ + { internalType: 'address', name: 'vault', type: 'address' }, + { internalType: 'bool', name: 'isSmartCol', type: 'bool' }, + { internalType: 'bool', name: 'isSmartDebt', type: 'bool' }, + { + components: [ + { internalType: 'address', name: 'liquidity', type: 'address' }, + { internalType: 'address', name: 'factory', type: 'address' }, + { + internalType: 'address', + name: 'operateImplementation', + type: 'address', + }, + { + internalType: 'address', + name: 'adminImplementation', + type: 'address', + }, + { + internalType: 'address', + name: 'secondaryImplementation', + type: 'address', + }, + { internalType: 'address', name: 'deployer', type: 'address' }, + { internalType: 'address', name: 'supply', type: 'address' }, + { internalType: 'address', name: 'borrow', type: 'address' }, + { + components: [ + { internalType: 'address', name: 'token0', type: 'address' }, + { internalType: 'address', name: 'token1', type: 'address' }, + ], + internalType: 'struct IFluidVault.Tokens', + name: 'supplyToken', + type: 'tuple', + }, + { + components: [ + { internalType: 'address', name: 'token0', type: 'address' }, + { internalType: 'address', name: 'token1', type: 'address' }, + ], + internalType: 'struct IFluidVault.Tokens', + name: 'borrowToken', + type: 'tuple', + }, + { internalType: 'uint256', name: 'vaultId', type: 'uint256' }, + { internalType: 'uint256', name: 'vaultType', type: 'uint256' }, + { + internalType: 'bytes32', + name: 'supplyExchangePriceSlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'borrowExchangePriceSlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'userSupplySlot', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'userBorrowSlot', + type: 'bytes32', + }, + ], + internalType: 'struct IFluidVault.ConstantViews', + name: 'constantVariables', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint16', + name: 'supplyRateMagnifier', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'borrowRateMagnifier', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'collateralFactor', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'liquidationThreshold', + type: 'uint16', + }, + { + internalType: 'uint16', + name: 'liquidationMaxLimit', + type: 'uint16', + }, + { internalType: 'uint16', name: 'withdrawalGap', type: 'uint16' }, + { + internalType: 'uint16', + name: 'liquidationPenalty', + type: 'uint16', + }, + { internalType: 'uint16', name: 'borrowFee', type: 'uint16' }, + { internalType: 'address', name: 'oracle', type: 'address' }, + { + internalType: 'uint256', + name: 'oraclePriceOperate', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'oraclePriceLiquidate', + type: 'uint256', + }, + { internalType: 'address', name: 'rebalancer', type: 'address' }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + ], + internalType: 'struct Structs.Configs', + name: 'configs', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'lastStoredLiquiditySupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredLiquidityBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredVaultSupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastStoredVaultBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquiditySupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'liquidityBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'vaultSupplyExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'vaultBorrowExchangePrice', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'supplyRateLiquidity', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'borrowRateLiquidity', + type: 'uint256', + }, + { + internalType: 'int256', + name: 'supplyRateVault', + type: 'int256', + }, + { + internalType: 'int256', + name: 'borrowRateVault', + type: 'int256', + }, + { + internalType: 'int256', + name: 'rewardsOrFeeRateSupply', + type: 'int256', + }, + { + internalType: 'int256', + name: 'rewardsOrFeeRateBorrow', + type: 'int256', + }, + ], + internalType: 'struct Structs.ExchangePricesAndRates', + name: 'exchangePricesAndRates', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'totalSupplyVault', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalBorrowVault', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalSupplyLiquidityOrDex', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'totalBorrowLiquidityOrDex', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'absorbedSupply', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'absorbedBorrow', + type: 'uint256', + }, + ], + internalType: 'struct Structs.TotalSupplyAndBorrow', + name: 'totalSupplyAndBorrow', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'withdrawLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawableUntilLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawable', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowLimit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowableUntilLimit', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowable', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowLimitUtilization', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minimumBorrowing', + type: 'uint256', + }, + ], + internalType: 'struct Structs.LimitsAndAvailability', + name: 'limitsAndAvailability', + type: 'tuple', + }, + { + components: [ + { + internalType: 'uint256', + name: 'totalPositions', + type: 'uint256', + }, + { internalType: 'int256', name: 'topTick', type: 'int256' }, + { + internalType: 'uint256', + name: 'currentBranch', + type: 'uint256', + }, + { internalType: 'uint256', name: 'totalBranch', type: 'uint256' }, + { internalType: 'uint256', name: 'totalBorrow', type: 'uint256' }, + { internalType: 'uint256', name: 'totalSupply', type: 'uint256' }, + { + components: [ + { internalType: 'uint256', name: 'status', type: 'uint256' }, + { + internalType: 'int256', + name: 'minimaTick', + type: 'int256', + }, + { + internalType: 'uint256', + name: 'debtFactor', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'partials', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'debtLiquidity', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseBranchId', + type: 'uint256', + }, + { + internalType: 'int256', + name: 'baseBranchMinima', + type: 'int256', + }, + ], + internalType: 'struct Structs.CurrentBranchState', + name: 'currentBranchState', + type: 'tuple', + }, + ], + internalType: 'struct Structs.VaultState', + name: 'vaultState', + type: 'tuple', + }, + { + components: [ + { internalType: 'bool', name: 'modeWithInterest', type: 'bool' }, + { internalType: 'uint256', name: 'supply', type: 'uint256' }, + { + internalType: 'uint256', + name: 'withdrawalLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandPercent', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandDuration', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseWithdrawalLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawableUntilLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'withdrawable', + type: 'uint256', + }, + ], + internalType: 'struct Structs.UserSupplyData', + name: 'liquidityUserSupplyData', + type: 'tuple', + }, + { + components: [ + { internalType: 'bool', name: 'modeWithInterest', type: 'bool' }, + { internalType: 'uint256', name: 'borrow', type: 'uint256' }, + { internalType: 'uint256', name: 'borrowLimit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'lastUpdateTimestamp', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandPercent', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expandDuration', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'baseBorrowLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'maxBorrowLimit', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'borrowableUntilLimit', + type: 'uint256', + }, + { internalType: 'uint256', name: 'borrowable', type: 'uint256' }, + { + internalType: 'uint256', + name: 'borrowLimitUtilization', + type: 'uint256', + }, + ], + internalType: 'struct Structs.UserBorrowData', + name: 'liquidityUserBorrowData', + type: 'tuple', + }, + ], + internalType: 'struct Structs.VaultEntireData[]', + name: 'vaultsData_', + type: 'tuple[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'user_', type: 'address' }], + name: 'positionsNftIdOfUser', + outputs: [ + { internalType: 'uint256[]', name: 'nftIds_', type: 'uint256[]' }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'tickRaw_', type: 'uint256' }], + name: 'tickHelper', + outputs: [{ internalType: 'int256', name: 'tick', type: 'int256' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [], + name: 'totalPositions', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'nftId_', type: 'uint256' }], + name: 'vaultByNftId', + outputs: [{ internalType: 'address', name: 'vault_', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, +] \ No newline at end of file diff --git a/src/adaptors/fluid-lending/index.js b/src/adaptors/fluid-lending/index.js index fcfccacc21..c1bea2302f 100644 --- a/src/adaptors/fluid-lending/index.js +++ b/src/adaptors/fluid-lending/index.js @@ -1,88 +1,244 @@ const axios = require('axios'); const sdk = require('@defillama/sdk'); - const utils = require('../utils'); -const CHAIN_ID_MAPPING = { - ethereum: 1, - arbitrum: 42161, - base: 8453, +// Constants +const CONSTANTS = { + CHAIN_ID_MAPPING: { + ethereum: 1, + arbitrum: 42161, + base: 8453, + }, + // SUPPORTED_CHAINS: ['ethereum'], + SUPPORTED_CHAINS: ['ethereum', 'arbitrum', 'base'], + RESOLVERS: { + LENDING: { + ethereum: '0xC215485C572365AE87f908ad35233EC2572A3BEC', + arbitrum: '0xdF4d3272FfAE8036d9a2E1626Df2Db5863b4b302', + base: '0x3aF6FBEc4a2FE517F56E402C65e3f4c3e18C1D86', + }, + VAULT: { + ethereum: '0x814c8C7ceb1411B364c2940c4b9380e739e06686', + arbitrum: '0xD7D455d387d7840F56C65Bb08aD639DE9244E463', + base: '0x79B3102173EB84E6BCa182C7440AfCa5A41aBcF8', + }, + }, }; +// Import ABIs const abiLendingResolver = require('./abiLendingResolver'); -const lendingResolver = { - ethereum: '0xC215485C572365AE87f908ad35233EC2572A3BEC', - arbitrum: '0xdF4d3272FfAE8036d9a2E1626Df2Db5863b4b302', - base: '0x3aF6FBEc4a2FE517F56E402C65e3f4c3e18C1D86', +const abiVaultResolver = require('./abiVaultResolver'); + +// Lending Functions +const getLendingApy = async (chain) => { + try { + const fTokensEntireData = ( + await sdk.api.abi.call({ + target: CONSTANTS.RESOLVERS.LENDING[chain], + abi: abiLendingResolver.find((m) => m.name === 'getFTokensEntireData'), + chain, + }) + ).output; + + const underlying = fTokensEntireData.map((d) => d.asset); + + const [symbol, decimals] = await Promise.all([ + sdk.api.abi.multiCall({ + calls: underlying.map((t) => ({ target: t })), + abi: 'erc20:symbol', + chain, + }), + sdk.api.abi.multiCall({ + calls: underlying.map((t) => ({ target: t })), + abi: 'erc20:decimals', + chain, + }), + ]); + + const priceKeys = underlying.map((i) => `${chain}:${i}`).join(','); + const prices = ( + await axios.get(`https://coins.llama.fi/prices/current/${priceKeys}`) + ).data.coins; + + return fTokensEntireData + .map((token, i) => ({ + project: 'fluid-lending', + pool: `${chain}_${token.tokenAddress}`, + tvlUsd: + (token.totalAssets * prices[`${chain}:${underlying[i]}`].price) / + 10 ** decimals.output[i].output, + totalSupplyUsd: + (token.totalAssets * prices[`${chain}:${underlying[i]}`].price) / + 10 ** decimals.output[i].output, + totalBorrowUsd: 0, + symbol: symbol.output[i].output, + underlyingTokens: [token.asset], + rewardTokens: [token.asset], + chain, + ltv: 0, + apyBase: Number((token.supplyRate / 1e2).toFixed(2)), + apyBaseBorrow: 0, + apyReward: Number((token.rewardsRate / 1e12).toFixed(2)), + apyRewardBorrow: 0, + })) + .filter((i) => utils.keepFinite(i)); + } catch (error) { + console.error(`Error fetching lending APY for ${chain}:`, error); + return []; + } }; -const getApy = async (chain) => { - const fTokensEntireData = ( - await sdk.api.abi.call({ - target: lendingResolver[chain], - abi: abiLendingResolver.find((m) => m.name === 'getFTokensEntireData'), - chain, - }) - ).output; +// Vault Functions +const getVaultApy = async (chain) => { + try { + const vaultsEntireData = ( + await sdk.api.abi.call({ + target: CONSTANTS.RESOLVERS.VAULT[chain], + abi: abiVaultResolver.find((m) => m.name === 'getVaultsEntireData'), + chain, + }) + ).output; - const underlying = fTokensEntireData.map((d) => d.asset); + const filteredVaults = vaultsEntireData.filter( + (vault) => vault[1] === false && vault[2] === false + ); - const symbol = ( - await sdk.api.abi.multiCall({ - calls: underlying.map((t) => ({ target: t })), - abi: 'erc20:symbol', - chain, - }) - ).output.map((o) => o.output); + const vaultDetails = { + pools: filteredVaults.map((vault) => vault[0]), + underlyingTokens: filteredVaults.map((vault) => [ + normalizeAddress(vault[3][8][0]), + normalizeAddress(vault[3][9][0]), + ]), + rewardsRates: filteredVaults.map((vault) => Math.max(0, vault[5][12])), + rewardsRatesBorrow: filteredVaults.map((vault) => + Math.max(0, vault[5][13]) + ), + supplyRates: filteredVaults.map((vault) => Math.max(0, vault[5][8])), + supplyRatesBorrow: filteredVaults.map((vault) => + Math.max(0, vault[5][9]) + ), + suppliedTokens: filteredVaults.map((vault) => vault[8][5]), + borrowedTokens: filteredVaults.map((vault) => vault[8][4]), + supplyTokens: filteredVaults.map((vault) => + normalizeAddress(vault[3][8][0]) + ), + borrowTokens: filteredVaults.map((vault) => + normalizeAddress(vault[3][9][0]) + ), + ltv: filteredVaults.map((vault) => normalizeAddress(vault[4][2])), + }; - const decimals = ( - await sdk.api.abi.multiCall({ - calls: underlying.map((t) => ({ target: t })), - abi: 'erc20:decimals', - chain, - }) - ).output.map((o) => o.output); - - const priceKeys = underlying.map((i) => `${chain}:${i}`).join(','); - const prices = ( - await axios.get(`https://coins.llama.fi/prices/current/${priceKeys}`) - ).data.coins; - - const pools = fTokensEntireData.map((token, i) => { - const tokenAddress = token.tokenAddress; - const underlyingToken = token.asset; - const underlyingSymbol = symbol[i]; - const decimals = token.decimals; - const tokenPrice = prices[`${chain}:${underlying[i]}`].price; - - const totalSupplyUsd = (token.totalAssets * tokenPrice) / 10 ** decimals; - - const apyBase = Number((token.supplyRate / 1e2).toFixed(2)); - const apyReward = Number((token.rewardsRate / 1e12).toFixed(2)); - - return { - project: 'fluid-lending', - pool: tokenAddress, - tvlUsd: totalSupplyUsd, - symbol: underlyingSymbol, - underlyingTokens: [underlyingToken], - rewardTokens: [underlyingToken], // rewards are always in underlying + const tokenData = await fetchTokenData(chain, vaultDetails); + + return calculateVaultPoolData( chain, - apyBase, - apyReward, - }; - }); + filteredVaults, + vaultDetails, + tokenData + ).filter((pool) => utils.keepFinite(pool)); + } catch (error) { + console.error(`Error fetching vault APY for ${chain}:`, error); + return []; + } +}; + +// Helper Functions +const normalizeAddress = (address) => { + const lowercaseAddress = String(address).toLowerCase(); + return lowercaseAddress === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + ? '0x0000000000000000000000000000000000000000' + : lowercaseAddress; +}; + +const fetchTokenData = async (chain, vaultDetails) => { + const priceKeys = vaultDetails.supplyTokens + .map((token) => `${chain}:${token}`) + .join(','); + const borrowPriceKeys = vaultDetails.underlyingTokens + .map((tokens) => `${chain}:${tokens[1]}`) + .join(','); + + const [prices, borrowPrices] = await Promise.all([ + axios + .get(`https://coins.llama.fi/prices/current/${priceKeys}`) + .then((r) => r.data.coins), + axios + .get(`https://coins.llama.fi/prices/current/${borrowPriceKeys}`) + .then((r) => r.data.coins), + ]); + + return { + symbol: vaultDetails.underlyingTokens.map( + (tokens) => + `${prices[`${chain}:${tokens[0]}`].symbol}/${ + borrowPrices[`${chain}:${tokens[1]}`].symbol + }` + ), + decimals: vaultDetails.supplyTokens.map( + (token) => prices[`${chain}:${token}`].decimals + ), + borrowTokenDecimals: vaultDetails.borrowTokens.map( + (token) => borrowPrices[`${chain}:${token}`].decimals + ), + prices: vaultDetails.supplyTokens.map( + (token) => prices[`${chain}:${token}`].price + ), + borrowTokenPrices: vaultDetails.borrowTokens.map( + (token) => borrowPrices[`${chain}:${token}`].price + ), + }; +}; + +const calculateVaultPoolData = ( + chain, + filteredVaults, + vaultDetails, + tokenData +) => { + const totalSupplyUsd = vaultDetails.suppliedTokens.map( + (suppliedToken, index) => + (suppliedToken * tokenData.prices[index]) / + 10 ** tokenData.decimals[index] + ); + const totalBorrowUsd = vaultDetails.borrowedTokens.map( + (borrowedToken, index) => + (borrowedToken * tokenData.borrowTokenPrices[index]) / + 10 ** tokenData.borrowTokenDecimals[index] + ); - return pools.filter((i) => utils.keepFinite(i)); + return filteredVaults.map((vault, index) => ({ + project: 'fluid-lending', + pool: `${chain}_${vaultDetails.pools[index]}`, + tvlUsd: totalSupplyUsd[index], + totalSupplyUsd: totalSupplyUsd[index], + totalBorrowUsd: totalBorrowUsd[index], + symbol: tokenData.symbol[index].replace('.base', ''), + underlyingTokens: vaultDetails.underlyingTokens[index], + rewardTokens: vaultDetails.underlyingTokens[index], + chain, + apyBase: Number((vaultDetails.supplyRates[index] / 1e2).toFixed(2)), + apyBaseBorrow: Number( + (vaultDetails.supplyRatesBorrow[index] / 1e2).toFixed(2) + ), + apyReward: Number((vaultDetails.rewardsRates[index] / 1e12).toFixed(2)), + apyRewardBorrow: Number( + (vaultDetails.rewardsRatesBorrow[index] / 1e12).toFixed(2) + ), + ltv: vaultDetails.ltv[index] / 1e4, + })); }; +// Main Function const apy = async () => { - const chains = Object.keys(CHAIN_ID_MAPPING); - const apy = await Promise.all(chains.map((chain) => getApy(chain))); - return apy.flat(); + const [lendingData, vaultData] = await Promise.all([ + Promise.all(CONSTANTS.SUPPORTED_CHAINS.map(getLendingApy)), + Promise.all(CONSTANTS.SUPPORTED_CHAINS.map(getVaultApy)), + ]); + // Combine and flatten both arrays + return [...lendingData.flat(), ...vaultData.flat()]; }; module.exports = { apy, - url: `https://fluid.instadapp.io/lending/`, + url: 'https://fluid.instadapp.io', }; From 953e9379b01e5b3eaf4113aa8ca26f3a11f40340 Mon Sep 17 00:00:00 2001 From: stark <166841586+starketh25@users.noreply.github.com> Date: Tue, 31 Dec 2024 13:32:46 +0530 Subject: [PATCH 19/22] Feat/fenix standard pools (#1672) * Feat: add fenix v3 and v2 pools * fix: add 10k tvl check * chore: remove unneccesary call in v3 pool * fix: slug name as folder * fix: remove v2 to add in seperate pr * feat: add v2 pools to yeild server * fix: build * fix: tvl values --- src/adaptors/fenix-standard-pools/index.js | 101 +++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/adaptors/fenix-standard-pools/index.js diff --git a/src/adaptors/fenix-standard-pools/index.js b/src/adaptors/fenix-standard-pools/index.js new file mode 100644 index 0000000000..b819857aa1 --- /dev/null +++ b/src/adaptors/fenix-standard-pools/index.js @@ -0,0 +1,101 @@ +const sdk = require('@defillama/sdk'); +const axios = require('axios'); +const utils = require('../utils'); +const { request, gql } = require('graphql-request'); + +const API_URL = `https://blaze.prod.fenix.aegas.it/liquidity/rewards`; + +const SUBGRAPH_URL = + 'https://api.goldsky.com/api/public/project_clxadvm41bujy01ui2qalezdn/subgraphs/fenix-v2-subgraph/latest/gn'; + +const FNX_ADDRESS = '0x52f847356b38720B55ee18Cb3e094ca11C85A192'; + +const swapPairsQuery = (skip) => { + return gql` + query MyQuery { + pairs(first: 100, skip: ${skip}, where: {reserveUSD_gt: 10000}) { + reserve0 + reserve1 + token1 { + id + symbol + } + token0 { + id + symbol + } + reserveUSD + id + } + } + `; +}; + +const getPairs = async () => { + let pairs = []; + let index = 0; + let res; + do { + res = await request(SUBGRAPH_URL, swapPairsQuery(index), {}); + if (res.pairs.length > 0) { + pairs = [...pairs, ...res.pairs]; + } + index += res.pairs.length; + } while (res.pairs.length > 0); + return pairs; +}; + +const getApy = async () => { + const pairs = await getPairs(); + const poolsRes = await axios.get( + `${API_URL}?${pairs.map((pair) => `pools=${pair.id}`).join('&')}` + ); + + // First get FNX price from DeFiLlama + const { coins: fnxPrice } = await utils.getData( + `https://coins.llama.fi/prices/current/blast:${FNX_ADDRESS}?searchWidth=4h` + ); + + const fnxPriceUsd = fnxPrice[`blast:${FNX_ADDRESS}`]?.price || 0; + + // Create apyDict by calculating (rewards/tvl) * 100 * 52 for each pool + const apyDict = {}; + for (const pool of poolsRes.data) { + const pairData = pairs.find( + (p) => p.id.toLowerCase() === pool.pool.toLowerCase() + ); + + if (pairData) { + // Convert reward to annual value (weekly * 52) and from Wei to FNX + const annualReward = (parseFloat(pool.rewardWei) * 52) / 1e18; + // Convert to USD using FNX price + const annualRewardUSD = annualReward * fnxPriceUsd; + // Get TVL + const tvl = parseFloat(pairData.reserveUSD); + // Calculate APY: (annual reward in USD / TVL) * 100 + apyDict[pool.pool.toLowerCase()] = (annualRewardUSD / tvl) * 100; + } + } + + const pools = pairs.map((pair) => { + tvl = parseFloat(pair.reserveUSD); + return { + pool: pair.id, + chain: utils.formatChain('blast'), + project: 'fenix-standard-pools', + symbol: `${pair.token0.symbol}-${pair.token1.symbol}`, + tvlUsd: tvl, + apyReward: parseFloat(apyDict[pair.id.toLowerCase()] || 0), + underlyingTokens: [pair.token0.id, pair.token1.id], + rewardTokens: [FNX_ADDRESS], + }; + }); + + return pools; +}; +getApy(); +module.exports = { + timetravel: false, + apy: getApy, + url: 'https://www.fenixfinance.io/liquidity', +}; From 411c0144e6155ade3ec9f5bc48f8579bb8b1d58a Mon Sep 17 00:00:00 2001 From: stark <166841586+starketh25@users.noreply.github.com> Date: Tue, 31 Dec 2024 13:36:53 +0530 Subject: [PATCH 20/22] Feat: add fenix v3 and v2 pools (#1671) * Feat: add fenix v3 and v2 pools * fix: add 10k tvl check * chore: remove unneccesary call in v3 pool * fix: slug name as folder * fix: remove v2 to add in seperate pr * fix: tvl values * fix:build --- .../fenix-concentrated-liquidity/index.js | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/adaptors/fenix-concentrated-liquidity/index.js diff --git a/src/adaptors/fenix-concentrated-liquidity/index.js b/src/adaptors/fenix-concentrated-liquidity/index.js new file mode 100644 index 0000000000..a0fce10477 --- /dev/null +++ b/src/adaptors/fenix-concentrated-liquidity/index.js @@ -0,0 +1,112 @@ +const sdk = require('@defillama/sdk'); +const axios = require('axios'); +const utils = require('../utils'); +const { request, gql } = require('graphql-request'); + +const API_URL = `https://blaze.prod.fenix.aegas.it/liquidity/rewards`; + +const SUBGRAPH_URL = + 'https://api.goldsky.com/api/public/project_clxadvm41bujy01ui2qalezdn/subgraphs/fenix-v3-dex/latest/gn'; + +const FNX_ADDRESS = '0x52f847356b38720B55ee18Cb3e094ca11C85A192'; + +const swapPairsQuery = (skip) => { + return gql` + query MyQuery { + pools(first: 100, skip: ${skip}, where: {totalValueLockedUSD_gt: 10000}) { + totalValueLockedToken0 + totalValueLockedToken1 + totalValueLockedUSD + token1 { + id + symbol + } + token0 { + id + symbol + } + id + } + } + `; +}; + +const getPairs = async () => { + try { + let pools = []; + let index = 0; + let res; + + do { + res = await request(SUBGRAPH_URL, swapPairsQuery(index), {}); + + if (res.pools?.length > 0) { + pools = [...pools, ...res.pools]; + } + index += res.pools?.length || 0; + } while (res.pools?.length > 0); + + return pools; + } catch (error) { + console.error('Error in getPairs:', error); + throw error; + } +}; + +const getApy = async () => { + try { + const pairs = await getPairs(); + + const poolsRes = await axios.get( + `${API_URL}?${pairs.map((pair) => `pools=${pair.id}`).join('&')}` + ); + // console.log('Pools rewards sample:', poolsRes.data); + + const { coins: fnxPrice } = await utils.getData( + `https://coins.llama.fi/prices/current/blast:${FNX_ADDRESS}?searchWidth=4h` + ); + const fnxPriceUsd = fnxPrice[`blast:${FNX_ADDRESS}`]?.price || 0; + + const apyDict = {}; + for (const pool of poolsRes.data) { + const pairData = pairs.find( + (p) => p.id.toLowerCase() === pool.pool.toLowerCase() + ); + + if (pairData) { + const weeklyRewardInFNX = parseFloat(pool.rewardWei) / 1e18; + const annualRewardInFNX = weeklyRewardInFNX * 52; + const annualRewardUSD = annualRewardInFNX * fnxPriceUsd; + const tvl = parseFloat(pairData.totalValueLockedUSD); + apyDict[pool.pool.toLowerCase()] = (annualRewardUSD / tvl) * 100; + } + } + + const pools = pairs.map((pair) => { + let tvl = parseFloat(pair.totalValueLockedUSD); + + const poolData = { + pool: pair.id, + chain: utils.formatChain('blast'), + project: 'fenix-concentrated-liquidity', + symbol: `${pair.token0.symbol}-${pair.token1.symbol}`, + tvlUsd: tvl, + apyReward: parseFloat(apyDict[pair.id.toLowerCase()] || 0), + underlyingTokens: [pair.token0.id, pair.token1.id], + rewardTokens: [FNX_ADDRESS], + }; + + return poolData; + }); + return pools; + } catch (error) { + console.error('Error in getApy:', error); + throw error; + } +}; + +module.exports = { + timetravel: false, + apy: getApy, + url: 'https://www.fenixfinance.io/liquidity', +}; From a7e8aaf106b108f578ca1616fb6d70fd534b71ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danil=20Shaymurzin=20=E2=9A=A1=EF=B8=8F?= Date: Tue, 31 Dec 2024 13:09:12 +0500 Subject: [PATCH 21/22] feat: add merkeProof oracles getPrices and rewardApy/rewardTokens for EVAA Protocol (#1665) * feat: add rewardApy for EVAA Protocol * feat: add rewardTokens * feat: merkleProof oracle getPrices system * feat: rewardApy & rewardTokens prop * fix: type capability for calculateRewardApy func * fix: tokenSymbol return for rewardTokens --- src/adaptors/evaa-protocol/getPrices.js | 376 ++++++++++++++++++++++++ src/adaptors/evaa-protocol/index.js | 69 +++-- src/adaptors/evaa-protocol/rewardApy.js | 177 +++++++++++ 3 files changed, 590 insertions(+), 32 deletions(-) create mode 100644 src/adaptors/evaa-protocol/getPrices.js create mode 100644 src/adaptors/evaa-protocol/rewardApy.js diff --git a/src/adaptors/evaa-protocol/getPrices.js b/src/adaptors/evaa-protocol/getPrices.js new file mode 100644 index 0000000000..ec5d0666a5 --- /dev/null +++ b/src/adaptors/evaa-protocol/getPrices.js @@ -0,0 +1,376 @@ +const fetch = require('node-fetch'); +const { Cell, Slice, Dictionary, beginCell } = require('@ton/core'); +const { signVerify } = require('@ton/crypto'); + +const ORACLES = [ + { + id: 0, + address: + '0xd3a8c0b9fd44fd25a49289c631e3ac45689281f2f8cf0744400b4c65bed38e5d', + pubkey: Buffer.from( + 'b404f4a2ebb62f2623b370c89189748a0276c071965b1646b996407f10d72eb9', + 'hex' + ), + }, + { + id: 1, + address: + '0x2c21cabdaa89739de16bde7bc44e86401fac334a3c7e55305fe5e7563043e191', + pubkey: Buffer.from( + '9ad115087520d91b6b45d6a8521eb4616ee6914af07fabdc2e9d1826dbb17078', + 'hex' + ), + }, + { + id: 2, + address: + '0x2eb258ce7b5d02466ab8a178ad8b0ba6ffa7b58ef21de3dc3b6dd359a1e16af0', + pubkey: Buffer.from( + 'e503e02e8a9226b34e7c9deb463cbf7f19bce589362eb448a69a8ee7b2fca631', + 'hex' + ), + }, + { + id: 3, + address: + '0xf9a0769954b4430bca95149fb3d876deb7799d8f74852e0ad4ccc5778ce68b52', + pubkey: Buffer.from( + '9cbf8374cf1f2cf17110134871d580198416e101683f4a61f54cf2a3e4e32070', + 'hex' + ), + }, +]; + +const TTL_ORACLE_DATA_SEC = 120; +const MINIMAL_ORACLES = 3; + +function verifyPricesTimestamp(priceData) { + const timestamp = Date.now() / 1000; + const pricesTime = priceData.timestamp; + return timestamp - pricesTime < TTL_ORACLE_DATA_SEC; +} + +function verifyPricesSign(priceData) { + const message = priceData.dataCell.refs[0].hash(); + const signature = priceData.signature; + const publicKey = priceData.pubkey; + + return signVerify(message, signature, publicKey); +} + +function getMedianPrice(pricesData, assetId) { + try { + const usingPrices = pricesData.filter((x) => x.dict.has(assetId)); + const sorted = usingPrices + .map((x) => x.dict.get(assetId)) + .sort((a, b) => Number(a) - Number(b)); + + if (sorted.length === 0) { + return null; + } + + const mid = Math.floor(sorted.length / 2); + if (sorted.length % 2 === 0) { + return (sorted[mid - 1] + sorted[mid]) / 2n; + } else { + return sorted[mid]; + } + } catch { + return null; + } +} + +function packAssetsData(assetsData) { + if (assetsData.length === 0) { + throw new Error('No assets data to pack'); + } + return assetsData.reduceRight( + (acc, { assetId, medianPrice }) => + beginCell() + .storeUint(assetId, 256) + .storeCoins(medianPrice) + .storeMaybeRef(acc) + .endCell(), + null + ); +} + +function packPrices(assetsDataCell, oraclesDataCell) { + return beginCell() + .storeRef(assetsDataCell) + .storeRef(oraclesDataCell) + .endCell(); +} + +function readUnaryLength(slice) { + let res = 0; + while (slice.loadBit()) { + res++; + } + return res; +} + +function doGenerateMerkleProof(prefix, slice, n, keys) { + // Reading label + const originalCell = slice.asCell(); + + if (keys.length == 0) { + // no keys to prove, prune the whole subdict + return convertToPrunedBranch(originalCell); + } + + let lb0 = slice.loadBit() ? 1 : 0; + let prefixLength = 0; + let pp = prefix; + + if (lb0 === 0) { + // Short label detected + + // Read + prefixLength = readUnaryLength(slice); + + // Read prefix + for (let i = 0; i < prefixLength; i++) { + pp += slice.loadBit() ? '1' : '0'; + } + } else { + let lb1 = slice.loadBit() ? 1 : 0; + if (lb1 === 0) { + // Long label detected + prefixLength = slice.loadUint(Math.ceil(Math.log2(n + 1))); + for (let i = 0; i < prefixLength; i++) { + pp += slice.loadBit() ? '1' : '0'; + } + } else { + // Same label detected + let bit = slice.loadBit() ? '1' : '0'; + prefixLength = slice.loadUint(Math.ceil(Math.log2(n + 1))); + for (let i = 0; i < prefixLength; i++) { + pp += bit; + } + } + } + + if (n - prefixLength === 0) { + return originalCell; + } else { + let sl = originalCell.beginParse(); + let left = sl.loadRef(); + let right = sl.loadRef(); + // NOTE: Left and right branches are implicitly contain prefixes '0' and '1' + if (!left.isExotic) { + const leftKeys = keys.filter((key) => { + return pp + '0' === key.slice(0, pp.length + 1); + }); + left = doGenerateMerkleProof( + pp + '0', + left.beginParse(), + n - prefixLength - 1, + leftKeys + ); + } + if (!right.isExotic) { + const rightKeys = keys.filter((key) => { + return pp + '1' === key.slice(0, pp.length + 1); + }); + right = doGenerateMerkleProof( + pp + '1', + right.beginParse(), + n - prefixLength - 1, + rightKeys + ); + } + + return beginCell().storeSlice(sl).storeRef(left).storeRef(right).endCell(); + } +} + +function generateMerkleProofDirect(dict, keys, keyObject) { + keys.forEach((key) => { + if (!dict.has(key)) { + throw new Error( + `Trying to generate merkle proof for a missing key "${key}"` + ); + } + }); + const s = beginCell().storeDictDirect(dict).asSlice(); + return doGenerateMerkleProof( + '', + s, + keyObject.bits, + keys.map((key) => + keyObject.serialize(key).toString(2).padStart(keyObject.bits, '0') + ) + ); +} + +function endExoticCell(b) { + let c = b.endCell(); + return new Cell({ exotic: true, bits: c.bits, refs: c.refs }); +} + +function convertToMerkleProof(c) { + return endExoticCell( + beginCell() + .storeUint(3, 8) + .storeBuffer(c.hash(0)) + .storeUint(c.depth(0), 16) + .storeRef(c) + ); +} + +function createOracleDataProof(oracle, data, signature, assets) { + let prunedDict = generateMerkleProofDirect( + data.prices, + assets, + Dictionary.Keys.BigUint(256) + ); + let prunedData = beginCell() + .storeUint(data.timestamp, 32) + .storeMaybeRef(prunedDict) + .endCell(); + let merkleProof = convertToMerkleProof(prunedData); + let oracleDataProof = beginCell() + .storeUint(oracle.id, 32) + .storeRef(merkleProof) + .storeBuffer(signature) + .asSlice(); + return oracleDataProof; +} + +function packOraclesData(oraclesData, assets) { + if (oraclesData.length == 0) { + throw new Error('no oracles data to pack'); + } + let proofs = oraclesData + .sort((d1, d2) => d1.oracle.id - d2.oracle.id) + .map(({ oracle, data, signature }) => + createOracleDataProof(oracle, data, signature, assets) + ); + return proofs.reduceRight( + (acc, val) => beginCell().storeSlice(val).storeMaybeRef(acc).endCell(), + null + ); +} + +async function getPrices(endpoint = 'api.stardust-mainnet.iotaledger.net') { + try { + const prices = await Promise.all( + ORACLES.map(async (oracle) => { + try { + const outputResponse = await fetch( + `https://${endpoint}/api/indexer/v1/outputs/nft/${oracle.address}`, + { + headers: { accept: 'application/json' }, + signal: AbortSignal.timeout(5000), + } + ); + const outputData = await outputResponse.json(); + const priceResponse = await fetch( + `https://${endpoint}/api/core/v2/outputs/${outputData.items[0]}`, + { + headers: { accept: 'application/json' }, + signal: AbortSignal.timeout(5000), + } + ); + const priceData = await priceResponse.json(); + + const data = JSON.parse( + decodeURIComponent( + priceData.output.features[0].data + .replace('0x', '') + .replace(/[0-9a-f]{2}/g, '%$&') + ) + ); + + const pricesCell = Cell.fromBoc( + Buffer.from(data.packedPrices, 'hex') + )[0]; + const signature = Buffer.from(data.signature, 'hex'); + const publicKey = Buffer.from(data.publicKey, 'hex'); + const timestamp = Number(data.timestamp); + + return { + dict: pricesCell + .beginParse() + .loadRef() + .beginParse() + .loadDictDirect( + Dictionary.Keys.BigUint(256), + Dictionary.Values.BigVarUint(4) + ), + dataCell: beginCell() + .storeRef(pricesCell) + .storeBuffer(signature) + .endCell(), + oracleId: oracle.id, + signature, + pubkey: publicKey, + timestamp, + }; + } catch (error) { + console.error( + `Error fetching prices from oracle ${oracle.id}:`, + error + ); + return null; + } + }) + ); + + const validPrices = prices.filter( + (price) => + price && verifyPricesTimestamp(price) && verifyPricesSign(price) + ); + + if (validPrices.length < MINIMAL_ORACLES) { + throw new Error('Not enough valid price data'); + } + + const sortedByTimestamp = validPrices + .slice() + .sort((a, b) => b.timestamp - a.timestamp); + const newerPrices = sortedByTimestamp + .slice(0, MINIMAL_ORACLES) + .sort((a, b) => a.oracleId - b.oracleId); + + const allAssetIds = new Set( + newerPrices.flatMap((p) => Array.from(p.dict.keys())) + ); + + const medianData = Array.from(allAssetIds) + .map((assetId) => ({ + assetId, + medianPrice: getMedianPrice(newerPrices, assetId), + })) + .filter((x) => x.medianPrice !== null); + + const packedMedianData = packAssetsData(medianData); + + const oraclesData = newerPrices.map((x) => ({ + oracle: { id: x.oracleId, pubkey: x.pubkey }, + data: { timestamp: x.timestamp, prices: x.dict }, + signature: x.signature, + })); + + const packedOracleData = packOraclesData( + oraclesData, + medianData.map((x) => x.assetId) + ); + + const dict = Dictionary.empty(); + for (const { assetId, medianPrice } of medianData) { + dict.set(assetId, medianPrice); + } + + return { + dict, + dataCell: packPrices(packedMedianData, packedOracleData), + }; + } catch (error) { + console.error('Error processing prices:', error); + return undefined; + } +} + +module.exports = getPrices; diff --git a/src/adaptors/evaa-protocol/index.js b/src/adaptors/evaa-protocol/index.js index 376234e24f..19db20432f 100644 --- a/src/adaptors/evaa-protocol/index.js +++ b/src/adaptors/evaa-protocol/index.js @@ -3,8 +3,10 @@ const utils = require('../utils'); const fetch = require('node-fetch') const { TonClient } = require("@ton/ton"); const { Address, Cell, Slice, Dictionary, beginCell } = require("@ton/core"); +const { signVerify } = require('@ton/crypto'); const crypto = require("crypto"); -const NFT_ID = '0xfb9874544d76ca49c5db9cc3e5121e4c018bc8a2fb2bfe8f2a38c5b9963492f5'; +const getPrices = require('./getPrices'); +const { getDistributions, calculateRewardApy } = require('./rewardApy'); function sha256Hash(input) { const hash = crypto.createHash("sha256"); @@ -31,6 +33,12 @@ const assets = { tsTON: { assetId: sha256Hash("tsTON"), token: 'EQC98_qAmNEptUtPc7W6xdHh_ZHrBUFpw5Ft_IzNU20QAJav' }, }; +function findAssetKeyByBigIntId(searchAssetId) { + return Object.entries(assets).find(([key, value]) => + BigInt(value.assetId) === searchAssetId + )?.[0]; +} + const MASTER_CONSTANTS = { FACTOR_SCALE: BigInt(1e12), @@ -306,37 +314,6 @@ function calculateCurrentRates(assetConfig, assetData) { }; } -async function getPrices(endpoint = "api.stardust-mainnet.iotaledger.net") { - try { - let result = await fetch(`https://${endpoint}/api/indexer/v1/outputs/nft/${NFT_ID}`, { - headers: { accept: 'application/json' }, - }); - let outputId = await result.json(); - - result = await fetch(`https://${endpoint}/api/core/v2/outputs/${outputId.items[0]}`, { - headers: { accept: 'application/json' }, - }); - - let resData = await result.json(); - - const data = JSON.parse( - decodeURIComponent(resData.output.features[0].data.replace('0x', '').replace(/[0-9a-f]{2}/g, '%$&')), - ); - - const pricesCell = Cell.fromBoc(Buffer.from(data['packedPrices'], 'hex'))[0]; - const signature = Buffer.from(data['signature'], 'hex'); - - return { - dict: pricesCell.beginParse().loadDictDirect(Dictionary.Keys.BigUint(256), Dictionary.Values.BigUint(64)), - dataCell: beginCell().storeRef(pricesCell).storeBuffer(signature).endCell(), - }; - } catch (error) { - console.error(error); - return undefined; - } -} - - // ignore pools with TVL below the threshold const MIN_TVL_USD = 100000; @@ -350,6 +327,7 @@ function calculatePresentValue(index, principalValue) { const getApy = async () => { console.log("Requesting prices") let prices = await getPrices(); + let distributions = await getDistributions(); const client = new TonClient({ endpoint: "https://toncenter.com/api/v2/jsonRPC" }); @@ -365,6 +343,9 @@ const getApy = async () => { console.log(e); } }); + + const rewardApys = calculateRewardApy(distributions, 'main', data,prices); + return Object.entries(assets).map(([tokenSymbol, asset]) => { const { assetId, token } = asset; console.log("Process symbol", tokenSymbol, asset, assetId, token) @@ -398,6 +379,27 @@ const getApy = async () => { console.log(tokenSymbol, "supplyApy", supplyApy * 100); console.log(tokenSymbol, "borrowApy", borrowApy * 100); + const apyRewardData = rewardApys.find( + (rewardApy) => + rewardApy.rewardingAssetId == assetId && + rewardApy.rewardType.toLowerCase() === 'supply' + ); + + const apyReward = apyRewardData ? apyRewardData.apy : undefined; + const rewardTokens = apyRewardData + ? [findAssetKeyByBigIntId(apyRewardData.rewardsAssetId)] + : undefined; + + const apyRewardBorrowData = rewardApys.find( + (rewardApy) => + rewardApy.rewardingAssetId == assetId && + rewardApy.rewardType.toLowerCase() === 'borrow' + ); + + const apyRewardBorrow = apyRewardBorrowData + ? apyRewardBorrowData.apy + : undefined; + return { pool: `evaa-${assetId}-ton`.toLowerCase(), chain: 'Ton', @@ -405,6 +407,9 @@ const getApy = async () => { symbol: tokenSymbol, tvlUsd: totalSupplyUsd - totalBorrowUsd, apyBase: supplyApy * 100, + apyReward, + rewardTokens, + // apyRewardBorrow, underlyingTokens: [token], url: `https://app.evaa.finance/token/${tokenSymbol}`, totalSupplyUsd: totalSupplyUsd, diff --git a/src/adaptors/evaa-protocol/rewardApy.js b/src/adaptors/evaa-protocol/rewardApy.js new file mode 100644 index 0000000000..3b1671328c --- /dev/null +++ b/src/adaptors/evaa-protocol/rewardApy.js @@ -0,0 +1,177 @@ +const fetch = require('node-fetch'); + +function isLeapYear(year) { + return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; +} + +async function getDistributions(endpoint = 'evaa.space') { + try { + let result = await fetch(`https://${endpoint}/query/distributions/list`, { + headers: { accept: 'application/json' }, + }); + let resData = await result.json(); + return resData; + } catch (error) { + console.error(error); + return undefined; + } +} +const isLeap = isLeapYear(new Date().getFullYear()); +const totalSecsInYear = (isLeap ? 366 : 365) * 24 * 60 * 60; + +function calcApy( + rewardAmount, + totalAmount, + rewardingAssetPrice, + rewardsAssetPrice, + rewardingScaleFactor, + rewardsScaleFactor, + totalSecsInCurrentSeason +) { + const rate = rewardingScaleFactor / Number(totalAmount); + const rewardForUnit = + rate * + (((Number(rewardAmount) / rewardsScaleFactor) * (rewardsAssetPrice ?? 0)) / + (rewardingAssetPrice || 1)) * + rewardingScaleFactor; + + return ( + ((rewardForUnit * totalSecsInYear) / + (totalSecsInCurrentSeason * rewardingScaleFactor)) * + 100 + ); +} + +function calculateRewardApy(distributionsResp, pool, data, prices) { + try { + if ( + !distributionsResp?.distributions || + distributionsResp.distributions.length === 0 + ) { + console.log('Invalid distributions data:', distributionsResp); + return []; + } + + const currentCampaign = distributionsResp?.distributions.find( + (campaign) => campaign.started && !campaign.expired + ); + + if (!currentCampaign) { + return []; + } + + const seasonsApy = currentCampaign.seasons + ?.filter((season) => season.started && !season.expired) + ?.filter((season) => season.pool === pool) + ?.map((season) => { + const rewardingAssetId = BigInt(season?.rewarding_asset_id ?? 0); + const rewardsAssetId = BigInt(season?.rewards_asset_id ?? 0); + + const rewardingAssetData = data.assetsData.get(rewardingAssetId); + const rewardsAssetData = data.assetsData.get(rewardsAssetId); + + if (!rewardingAssetData || !rewardsAssetData) { + return []; + } + + const rewardType = + season?.reward_type?.toLowerCase() === 'borrow' ? 'Borrow' : 'Supply'; + + let rewardAmount = Number(season?.rewards_amount) || 0; + + if (rewardType === 'Borrow' && season?.borrow_budget) { + rewardAmount = season.borrow_budget; + } else if (rewardType === 'Supply' && season?.supply_budget) { + rewardAmount = season.supply_budget; + } + + const totalAmountSupply = + rewardingAssetData.totalSupply?.original ?? + rewardingAssetData.totalSupply; + const totalAmountBorrow = + rewardingAssetData.totalBorrow?.original ?? + rewardingAssetData.totalBorrow; + + const totalAmount = + rewardType === 'Borrow' ? totalAmountBorrow : totalAmountSupply; + + if (!totalAmount || totalAmount === '0') { + return []; + } + + const rewardingAssetConfig = data.assetsConfig.get(rewardingAssetId); + const rewardsAssetConfig = data.assetsConfig.get(rewardsAssetId); + + const rewardingScaleFactor = + 10 ** Number(rewardingAssetConfig?.decimals ?? 0); + const rewardsScaleFactor = + 10 ** Number(rewardsAssetConfig?.decimals ?? 0); + + const rewardingPriceData = prices.dict.get(rewardingAssetId); + const rewardsPriceData = prices.dict.get(rewardsAssetId); + + const rewardingAssetPrice = Number(rewardingPriceData); + const rewardsAssetPrice = Number(rewardsPriceData); + + const seasonStart = new Date(season?.campaign_start ?? 0); + const seasonEnd = new Date(season?.campaign_end ?? 0); + const totalSecsInCurrentSeason = (seasonEnd - seasonStart) / 1000; + + if (totalSecsInCurrentSeason <= 0) { + return []; + } + + const baseApy = calcApy( + rewardAmount, + totalAmount, + rewardingAssetPrice, + rewardsAssetPrice, + rewardingScaleFactor, + rewardsScaleFactor, + totalSecsInCurrentSeason + ); + + const result = [ + { + apy: baseApy, + rewardType, + rewardingAssetId, + rewardsAssetId, + }, + ]; + + if ( + rewardType === 'Borrow' && + season?.supply_budget && + season.supply_budget > 0 + ) { + const supplyApy = calcApy( + season.supply_budget, + totalAmountSupply, + rewardingAssetPrice, + rewardsAssetPrice, + rewardingScaleFactor, + rewardsScaleFactor, + totalSecsInCurrentSeason + ); + result.push({ + apy: supplyApy, + rewardType: 'Supply', + rewardingAssetId, + rewardsAssetId, + }); + } + + return result; + }); + return seasonsApy.flat(); + } catch (error) { + console.error(error); + return []; + } +} + +module.exports = { + getDistributions, + calculateRewardApy, +}; From ffee1fc98b32bc238fcf5a4eb8ab45426e0df0ff Mon Sep 17 00:00:00 2001 From: Rafael Albuquerque <70333411+0xhafa@users.noreply.github.com> Date: Tue, 31 Dec 2024 05:32:14 -0300 Subject: [PATCH 22/22] fix: dinero pxeth peg rate (#1669) --- src/handlers/triggerLSDRates.js | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/handlers/triggerLSDRates.js b/src/handlers/triggerLSDRates.js index 9e65a5fe16..635c7737e6 100644 --- a/src/handlers/triggerLSDRates.js +++ b/src/handlers/triggerLSDRates.js @@ -417,14 +417,6 @@ const getExpectedRates = async () => { type: 'function', }; - const apxETHAbi = { - inputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }], - name: 'convertToAssets', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }; - // --- cbETH const cbETHRate = Number((await axios.get(cbETHRateUrl)).data.amount); @@ -577,17 +569,6 @@ const getExpectedRates = async () => { }) ).output / 1e18; - const apxEth = - ( - await sdk.api.abi.call({ - target: lsdTokens.find((lsd) => lsd.name === 'Dinero (pxETH)') - .addressExchangeRate, - chain: 'ethereum', - abi: apxETHAbi, - params: [1000000000000000000n], - }) - ).output / 1e18; - const lsETH = 10000 / ( @@ -660,8 +641,6 @@ const getExpectedRates = async () => { ? uniETH : lsd.name === 'mETH Protocol' ? mETH - : lsd.name === 'Dinero (pxETH)' - ? apxEth : lsd.name === 'Liquid Collective' ? lsETH : lsd.name === 'MEV Protocol'