From e6a65b38ebe18f7276c4793abf3765008ac9b9b2 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem de Liz Date: Fri, 30 Jun 2023 02:01:01 -0300 Subject: [PATCH 01/42] Created a service to fetch yield tokens APR and push into DB --- .../pool/lib/apr-data-sources/apr-types.ts | 7 + .../non-reaper-yield-tokens-apr.service.ts | 200 ++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 modules/pool/lib/apr-data-sources/non-reaper-yield-tokens-apr.service.ts diff --git a/modules/pool/lib/apr-data-sources/apr-types.ts b/modules/pool/lib/apr-data-sources/apr-types.ts index b51e5b268..de8463151 100644 --- a/modules/pool/lib/apr-data-sources/apr-types.ts +++ b/modules/pool/lib/apr-data-sources/apr-types.ts @@ -1,3 +1,5 @@ +import { Dictionary } from 'lodash' + export interface YearnVault { inception: number; address: string; @@ -69,3 +71,8 @@ interface YearnVaultTvl { } type YearnVaultType = 'v2'; + +export type AprBreakdown = { + total: number; + breakdown: Dictionary | undefined +} diff --git a/modules/pool/lib/apr-data-sources/non-reaper-yield-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/non-reaper-yield-tokens-apr.service.ts new file mode 100644 index 000000000..227600a3a --- /dev/null +++ b/modules/pool/lib/apr-data-sources/non-reaper-yield-tokens-apr.service.ts @@ -0,0 +1,200 @@ +import { PoolAprService } from "../../pool-types"; +import axios from "axios"; +import { PrismaPoolTokenWithExpandedNesting, PrismaPoolWithExpandedNesting } from "../../../../prisma/prisma-types"; +import { identity, pickBy, zipObject } from "lodash"; +import { AprBreakdown } from "./apr-types"; +import { prisma } from "../../../../prisma/prisma-client"; +import { networkContext } from "../../../network/network-context.service"; +import { prismaBulkExecuteOperations } from "../../../../prisma/prisma-util"; + +export class NonReaperYieldTokensAprService implements PoolAprService { + + constructor(private readonly swapProtocolFeePercentage: number) { + } + + getAprServiceName(): string { + return "NonReaperYieldTokensAprService"; + } + + public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { + const operations: any[] = []; + const aprs = await this.fetchYieldTokensApr(); + + const leafTokensPools = pools.filter((pool) => pool.tokens.find((token) => { + return Array.from(aprs.keys()).includes(token.address); + })); + + const nonReaperBoostedPools = pools.filter((pool) => pool.tokens.find((token) => { + //Checking if the pool has nested pools that contains the fetched tokens + return token.nestedPool && leafTokensPools.map(({address}) => address).includes(token.address); + })); + + const leafTokensPoolsApr = new Map(); + + for (const pool of leafTokensPools) { + const poolAprBreakdown = this.calculateLeafTokensPoolApr(pool, aprs) + if (poolAprBreakdown?.total) { + leafTokensPoolsApr.set(pool.address, poolAprBreakdown); + const itemId = `${pool.id}-tokens-yield-apr` + operations.push(prisma.prismaPoolAprItem.upsert({ + where: {id_chain: {id: itemId, chain: networkContext.chain}}, create: { + id: itemId, + chain: networkContext.chain, + poolId: pool.id, + title: `Yield Tokens APR`, + apr: poolAprBreakdown.total, + group: null, + type: 'IB_YIELD', + }, update: {title: `Yield Tokens APR`, apr: poolAprBreakdown.total}, + })); + } + } + + for (const pool of nonReaperBoostedPools) { + const poolAprBreakdown = this.calculateNonReaperBoostedPoolsApr(pool, leafTokensPoolsApr, leafTokensPools) + console.log(poolAprBreakdown); + if (poolAprBreakdown?.total) { + const itemId = `${pool.id}-apr` + operations.push(prisma.prismaPoolAprItem.upsert({ + where: {id_chain: {id: itemId, chain: networkContext.chain}}, create: { + id: itemId, + chain: networkContext.chain, + poolId: pool.id, + title: `Non Reaper Boosted Yield Tokens APR`, + apr: poolAprBreakdown.total, + group: null, + type: 'IB_YIELD', + }, update: {title: `Non Reaper Boosted Yield Tokens APR`, apr: poolAprBreakdown.total}, + })); + } + } + await prismaBulkExecuteOperations(operations); + } + + private async fetchYieldTokensApr(): Promise> { + const res = await axios.get("https://yield-tokens.balancer.workers.dev/"); + const aprs = new Map(Object.entries(res.data as { [key: string]: number })); + return aprs; + } + + private calculateLeafTokensPoolApr(pool: PrismaPoolWithExpandedNesting, yieldTokensApr: Map): AprBreakdown | undefined { + if (!pool.tokens) { + return { + total: 0, breakdown: {} + }; + } + + const totalLiquidity: number = pool.dynamicData?.totalLiquidity ?? 0; + if (!totalLiquidity) { + console.error(`Could not calculate Yield Tokens Apr for pool: ${pool.id}, reason: Missing pool liquidity`); + return; + } + + // Filter out BPT: token with the same address as the pool + const bptFreeTokens = pool.tokens.filter((token) => { + return token.address !== pool.address; + }); + + // Get each token APRs + const aprs = bptFreeTokens.map((token) => { + let apr = 0; + const yieldTokenApr = yieldTokensApr.get(token.address); + if (yieldTokenApr) { + // metastable pools incorrectly apply the swap fee to the yield earned. + // they don't have the concept of a yield fee like the newer pools do. + if (pool.type === 'META_STABLE') { + apr = yieldTokenApr * (1 - parseFloat(this.swapProtocolFeePercentage.toString() || '0.5')); + } else if (pool.type === 'PHANTOM_STABLE' || (pool.type === 'WEIGHTED' && pool.version >= 2)) { + // TODO: Add "isExemptFromYieldProtocolFee" support for each token + apr = yieldTokenApr * (1 - parseFloat(pool.dynamicData?.protocolYieldFee?.toString() || '0.5')); + } else { + apr = yieldTokenApr; + } + } + //APR from yield-tokens are multiplied by 10000: 900 -> 9% -> 0.09 + return apr * 0.0001; + }); + // Normalise tokenAPRs according to weights + const weightedAprs = bptFreeTokens.map((token, idx) => { + if (aprs[idx] === 0) { + return 0; + } + // Handle missing token weights, usually due to missing token prices + const weight = this.getTokenWeightNormalisedByUsd(token, totalLiquidity); + return aprs[idx] * weight; + }); + + // sum them up to get pool APRs + const apr = weightedAprs.reduce((sum, apr) => sum + apr, 0); + const breakdown = pickBy(zipObject(bptFreeTokens.map((t) => t.address), weightedAprs), identity); + + return { + total: apr, breakdown, + }; + } + + private calculateNonReaperBoostedPoolsApr(pool: PrismaPoolWithExpandedNesting, leafTokensPoolsApr: Map, leafTokensPools: PrismaPoolWithExpandedNesting[]) { + if (!pool.tokens) { + return { + total: 0, breakdown: {} + }; + } + + const totalLiquidity: number = pool.dynamicData?.totalLiquidity ?? 0; + if (!totalLiquidity) { + console.error(`Could not calculate Apr for pool: ${pool.id}, reason: Missing pool liquidity`); + return undefined; + } + + // Filter out BPT: token with the same address as the pool + const bptFreeTokens = pool.tokens.filter((token) => { + return token.address !== pool.address; + }); + + const aprs = bptFreeTokens.map((token) => { + let apr = 0; + const nestedPoolYieldTokensApr = leafTokensPoolsApr.get(token.address)?.total + if (nestedPoolYieldTokensApr) { + // INFO: Liquidity mining APR can't cascade to other pools + const nestedPoolSwapFee = parseFloat(leafTokensPools.find((pool) => pool.address === token.address)?.dynamicData?.swapFee || '0'); + let subApr = nestedPoolYieldTokensApr + if (pool.type === 'PHANTOM_STABLE' || (pool.type === 'WEIGHTED' && pool.version === 2)) { + subApr = subApr * (1 - parseFloat(pool.dynamicData?.protocolYieldFee || '0.5')); + } + apr = nestedPoolSwapFee + subApr; + } + return apr; + }) + + const weightedAprs = bptFreeTokens.map((token, idx) => { + if (aprs[idx] === 0) { + return 0; + } + // Handle missing token weights, usually due to missing token prices + const weight = this.getTokenWeightNormalisedByUsd(token, totalLiquidity); + return aprs[idx] * weight; + }); + + // sum them up to get pool APRs + const apr = weightedAprs.reduce((sum, apr) => sum + apr, 0); + const breakdown = pickBy(zipObject(bptFreeTokens.map((t) => t.address), weightedAprs), identity); + + return { + total: apr, breakdown, + }; + } + + // Get token weights normalised by usd price + getTokenWeightNormalisedByUsd = (token: PrismaPoolTokenWithExpandedNesting, poolTotalLiquidity: number): number => { + if (token.dynamicData?.weight) { + return parseFloat(token.dynamicData.weight); + } else if (token.dynamicData?.balanceUSD) { + // using floats assuming frontend purposes with low precision needs + return token.dynamicData?.balanceUSD / poolTotalLiquidity; + } else { + throw `No price for ${token.address}`; + } + return 0; + }; + +} \ No newline at end of file From 27ca26d88290951421aaea51f14187c3140a4c64 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem de Liz Date: Mon, 3 Jul 2023 10:00:12 -0300 Subject: [PATCH 02/42] Adding Apr Service to Mainnet network --- modules/network/mainnet.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 165fd8612..fc6c0aaf2 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -17,6 +17,8 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; +import { NonReaperYieldTokensAprService } from "../pool/lib/apr-data-sources/non-reaper-yield-tokens-apr.service"; +import { networkContext } from "./network-context.service"; const mainnetNetworkData: NetworkData = { chain: { @@ -171,6 +173,7 @@ export const mainnetNetworkConfig: NetworkConfig = { mainnetNetworkData.beets.address, mainnetNetworkData.bal.address, ]), + new NonReaperYieldTokensAprService(mainnetNetworkData.balancer.swapProtocolFeePercentage) ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService)], tokenPriceHandlers: [ From 3d84c4b4e4a6899104d0dd147c6af0723fcb1cdc Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Thu, 6 Jul 2023 23:47:51 -0300 Subject: [PATCH 03/42] Added yield tokens fetch funcionality directly on beethovenx-backend, instead of use the yield-tokens cloudflare service; Removed the boosted pools apr, and let only the yield tokens APR update, boosted pools are updated in another service; --- modules/network/mainnet.ts | 4 +- .../pool/lib/apr-data-sources/apr-types.ts | 5 - .../apr-data-sources/ib-tokens-apr.service.ts | 52 +++ .../non-reaper-yield-tokens-apr.service.ts | 200 ------------ .../token/lib/token-apr-handler/fetch-all.ts | 8 + .../lib/token-apr-handler/sources/aave.ts | 307 ++++++++++++++++++ .../token-apr-handler/sources/abis/oErc20.ts | 15 + .../sources/abis/reaperStrategy.ts | 21 ++ .../sources/abis/tesseraPool.ts | 154 +++++++++ .../lib/token-apr-handler/sources/ankr.ts | 16 + .../lib/token-apr-handler/sources/default.ts | 23 ++ .../lib/token-apr-handler/sources/euler.ts | 60 ++++ .../lib/token-apr-handler/sources/gearbox.ts | 26 ++ .../lib/token-apr-handler/sources/idle.ts | 22 ++ .../lib/token-apr-handler/sources/index.ts | 14 + .../token-apr-handler/sources/overnight.ts | 17 + .../lib/token-apr-handler/sources/ovix.ts | 57 ++++ .../lib/token-apr-handler/sources/reaper.ts | 54 +++ .../lib/token-apr-handler/sources/tessera.ts | 41 +++ .../lib/token-apr-handler/sources/tetu.ts | 9 + .../token-apr-handler/sources/tranchess.ts | 11 + modules/token/lib/token-apr-handler/tokens.ts | 35 ++ package.json | 1 + yarn.lock | 79 +++++ 24 files changed, 1024 insertions(+), 207 deletions(-) create mode 100644 modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts delete mode 100644 modules/pool/lib/apr-data-sources/non-reaper-yield-tokens-apr.service.ts create mode 100644 modules/token/lib/token-apr-handler/fetch-all.ts create mode 100644 modules/token/lib/token-apr-handler/sources/aave.ts create mode 100644 modules/token/lib/token-apr-handler/sources/abis/oErc20.ts create mode 100644 modules/token/lib/token-apr-handler/sources/abis/reaperStrategy.ts create mode 100644 modules/token/lib/token-apr-handler/sources/abis/tesseraPool.ts create mode 100644 modules/token/lib/token-apr-handler/sources/ankr.ts create mode 100644 modules/token/lib/token-apr-handler/sources/default.ts create mode 100644 modules/token/lib/token-apr-handler/sources/euler.ts create mode 100644 modules/token/lib/token-apr-handler/sources/gearbox.ts create mode 100644 modules/token/lib/token-apr-handler/sources/idle.ts create mode 100644 modules/token/lib/token-apr-handler/sources/index.ts create mode 100644 modules/token/lib/token-apr-handler/sources/overnight.ts create mode 100644 modules/token/lib/token-apr-handler/sources/ovix.ts create mode 100644 modules/token/lib/token-apr-handler/sources/reaper.ts create mode 100644 modules/token/lib/token-apr-handler/sources/tessera.ts create mode 100644 modules/token/lib/token-apr-handler/sources/tetu.ts create mode 100644 modules/token/lib/token-apr-handler/sources/tranchess.ts create mode 100644 modules/token/lib/token-apr-handler/tokens.ts diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index fc6c0aaf2..839914431 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -17,7 +17,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; -import { NonReaperYieldTokensAprService } from "../pool/lib/apr-data-sources/non-reaper-yield-tokens-apr.service"; +import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; import { networkContext } from "./network-context.service"; const mainnetNetworkData: NetworkData = { @@ -159,6 +159,7 @@ export const mainnetNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(mainnetNetworkData.rpcUrl), poolAprServices: [ + new IbTokensAprService(), new WstethAprService(tokenService, mainnetNetworkData.lido!.wstEthContract), new ReaperCryptAprService( mainnetNetworkData.reaper.linearPoolFactories, @@ -173,7 +174,6 @@ export const mainnetNetworkConfig: NetworkConfig = { mainnetNetworkData.beets.address, mainnetNetworkData.bal.address, ]), - new NonReaperYieldTokensAprService(mainnetNetworkData.balancer.swapProtocolFeePercentage) ], poolStakingServices: [new GaugeStakingService(gaugeSubgraphService)], tokenPriceHandlers: [ diff --git a/modules/pool/lib/apr-data-sources/apr-types.ts b/modules/pool/lib/apr-data-sources/apr-types.ts index de8463151..7c5b8ba31 100644 --- a/modules/pool/lib/apr-data-sources/apr-types.ts +++ b/modules/pool/lib/apr-data-sources/apr-types.ts @@ -71,8 +71,3 @@ interface YearnVaultTvl { } type YearnVaultType = 'v2'; - -export type AprBreakdown = { - total: number; - breakdown: Dictionary | undefined -} diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts new file mode 100644 index 000000000..717ab3465 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -0,0 +1,52 @@ +import { PoolAprService } from "../../pool-types"; +import axios from "axios"; +import { PrismaPoolWithExpandedNesting } from "../../../../prisma/prisma-types"; +import { zipObject } from "lodash"; +import { prisma } from "../../../../prisma/prisma-client"; +import { networkContext } from "../../../network/network-context.service"; +import { prismaBulkExecuteOperations } from "../../../../prisma/prisma-util"; + +export class IbTokensAprService implements PoolAprService { + + getAprServiceName(): string { + return "IbTokensAprService"; + } + + public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { + const operations: any[] = []; + const aprs = await this.fetchYieldTokensApr(); + const tokenYieldPools = pools.filter((pool) => pool.tokens.find((token) => { + return Array.from(aprs.keys()).includes(token.address); + })); + + for (const pool of tokenYieldPools) { + for (const token of pool.tokens) { + if (Array.from(aprs.keys()).includes(token.address)) { + const itemId = `${ pool.id }-tokens-yield-apr` + operations.push(prisma.prismaPoolAprItem.upsert({ + where: { id_chain: { id: itemId, chain: networkContext.chain } }, create: { + id: itemId, + chain: networkContext.chain, + poolId: pool.id, + title: `${ token.token.symbol || token.address } APR`, + apr: aprs.get(token.address) ?? 0, + group: null, + type: 'IB_YIELD', + }, update: { title: `${ token.token.symbol || token.address } APR`, apr: aprs.get(token.address) }, + })); + } + } + } + + await prismaBulkExecuteOperations(operations); + } + + private async fetchYieldTokensApr(): Promise> { + const res = await axios.get("https://yield-tokens.balancer.workers.dev/"); + const aprs = new Map(Object.entries(res.data as { + [key: string]: number + }).map(([key, apr]) => [key, apr * 0.0001])); + return aprs; + } + +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/non-reaper-yield-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/non-reaper-yield-tokens-apr.service.ts deleted file mode 100644 index 227600a3a..000000000 --- a/modules/pool/lib/apr-data-sources/non-reaper-yield-tokens-apr.service.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { PoolAprService } from "../../pool-types"; -import axios from "axios"; -import { PrismaPoolTokenWithExpandedNesting, PrismaPoolWithExpandedNesting } from "../../../../prisma/prisma-types"; -import { identity, pickBy, zipObject } from "lodash"; -import { AprBreakdown } from "./apr-types"; -import { prisma } from "../../../../prisma/prisma-client"; -import { networkContext } from "../../../network/network-context.service"; -import { prismaBulkExecuteOperations } from "../../../../prisma/prisma-util"; - -export class NonReaperYieldTokensAprService implements PoolAprService { - - constructor(private readonly swapProtocolFeePercentage: number) { - } - - getAprServiceName(): string { - return "NonReaperYieldTokensAprService"; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const operations: any[] = []; - const aprs = await this.fetchYieldTokensApr(); - - const leafTokensPools = pools.filter((pool) => pool.tokens.find((token) => { - return Array.from(aprs.keys()).includes(token.address); - })); - - const nonReaperBoostedPools = pools.filter((pool) => pool.tokens.find((token) => { - //Checking if the pool has nested pools that contains the fetched tokens - return token.nestedPool && leafTokensPools.map(({address}) => address).includes(token.address); - })); - - const leafTokensPoolsApr = new Map(); - - for (const pool of leafTokensPools) { - const poolAprBreakdown = this.calculateLeafTokensPoolApr(pool, aprs) - if (poolAprBreakdown?.total) { - leafTokensPoolsApr.set(pool.address, poolAprBreakdown); - const itemId = `${pool.id}-tokens-yield-apr` - operations.push(prisma.prismaPoolAprItem.upsert({ - where: {id_chain: {id: itemId, chain: networkContext.chain}}, create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `Yield Tokens APR`, - apr: poolAprBreakdown.total, - group: null, - type: 'IB_YIELD', - }, update: {title: `Yield Tokens APR`, apr: poolAprBreakdown.total}, - })); - } - } - - for (const pool of nonReaperBoostedPools) { - const poolAprBreakdown = this.calculateNonReaperBoostedPoolsApr(pool, leafTokensPoolsApr, leafTokensPools) - console.log(poolAprBreakdown); - if (poolAprBreakdown?.total) { - const itemId = `${pool.id}-apr` - operations.push(prisma.prismaPoolAprItem.upsert({ - where: {id_chain: {id: itemId, chain: networkContext.chain}}, create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `Non Reaper Boosted Yield Tokens APR`, - apr: poolAprBreakdown.total, - group: null, - type: 'IB_YIELD', - }, update: {title: `Non Reaper Boosted Yield Tokens APR`, apr: poolAprBreakdown.total}, - })); - } - } - await prismaBulkExecuteOperations(operations); - } - - private async fetchYieldTokensApr(): Promise> { - const res = await axios.get("https://yield-tokens.balancer.workers.dev/"); - const aprs = new Map(Object.entries(res.data as { [key: string]: number })); - return aprs; - } - - private calculateLeafTokensPoolApr(pool: PrismaPoolWithExpandedNesting, yieldTokensApr: Map): AprBreakdown | undefined { - if (!pool.tokens) { - return { - total: 0, breakdown: {} - }; - } - - const totalLiquidity: number = pool.dynamicData?.totalLiquidity ?? 0; - if (!totalLiquidity) { - console.error(`Could not calculate Yield Tokens Apr for pool: ${pool.id}, reason: Missing pool liquidity`); - return; - } - - // Filter out BPT: token with the same address as the pool - const bptFreeTokens = pool.tokens.filter((token) => { - return token.address !== pool.address; - }); - - // Get each token APRs - const aprs = bptFreeTokens.map((token) => { - let apr = 0; - const yieldTokenApr = yieldTokensApr.get(token.address); - if (yieldTokenApr) { - // metastable pools incorrectly apply the swap fee to the yield earned. - // they don't have the concept of a yield fee like the newer pools do. - if (pool.type === 'META_STABLE') { - apr = yieldTokenApr * (1 - parseFloat(this.swapProtocolFeePercentage.toString() || '0.5')); - } else if (pool.type === 'PHANTOM_STABLE' || (pool.type === 'WEIGHTED' && pool.version >= 2)) { - // TODO: Add "isExemptFromYieldProtocolFee" support for each token - apr = yieldTokenApr * (1 - parseFloat(pool.dynamicData?.protocolYieldFee?.toString() || '0.5')); - } else { - apr = yieldTokenApr; - } - } - //APR from yield-tokens are multiplied by 10000: 900 -> 9% -> 0.09 - return apr * 0.0001; - }); - // Normalise tokenAPRs according to weights - const weightedAprs = bptFreeTokens.map((token, idx) => { - if (aprs[idx] === 0) { - return 0; - } - // Handle missing token weights, usually due to missing token prices - const weight = this.getTokenWeightNormalisedByUsd(token, totalLiquidity); - return aprs[idx] * weight; - }); - - // sum them up to get pool APRs - const apr = weightedAprs.reduce((sum, apr) => sum + apr, 0); - const breakdown = pickBy(zipObject(bptFreeTokens.map((t) => t.address), weightedAprs), identity); - - return { - total: apr, breakdown, - }; - } - - private calculateNonReaperBoostedPoolsApr(pool: PrismaPoolWithExpandedNesting, leafTokensPoolsApr: Map, leafTokensPools: PrismaPoolWithExpandedNesting[]) { - if (!pool.tokens) { - return { - total: 0, breakdown: {} - }; - } - - const totalLiquidity: number = pool.dynamicData?.totalLiquidity ?? 0; - if (!totalLiquidity) { - console.error(`Could not calculate Apr for pool: ${pool.id}, reason: Missing pool liquidity`); - return undefined; - } - - // Filter out BPT: token with the same address as the pool - const bptFreeTokens = pool.tokens.filter((token) => { - return token.address !== pool.address; - }); - - const aprs = bptFreeTokens.map((token) => { - let apr = 0; - const nestedPoolYieldTokensApr = leafTokensPoolsApr.get(token.address)?.total - if (nestedPoolYieldTokensApr) { - // INFO: Liquidity mining APR can't cascade to other pools - const nestedPoolSwapFee = parseFloat(leafTokensPools.find((pool) => pool.address === token.address)?.dynamicData?.swapFee || '0'); - let subApr = nestedPoolYieldTokensApr - if (pool.type === 'PHANTOM_STABLE' || (pool.type === 'WEIGHTED' && pool.version === 2)) { - subApr = subApr * (1 - parseFloat(pool.dynamicData?.protocolYieldFee || '0.5')); - } - apr = nestedPoolSwapFee + subApr; - } - return apr; - }) - - const weightedAprs = bptFreeTokens.map((token, idx) => { - if (aprs[idx] === 0) { - return 0; - } - // Handle missing token weights, usually due to missing token prices - const weight = this.getTokenWeightNormalisedByUsd(token, totalLiquidity); - return aprs[idx] * weight; - }); - - // sum them up to get pool APRs - const apr = weightedAprs.reduce((sum, apr) => sum + apr, 0); - const breakdown = pickBy(zipObject(bptFreeTokens.map((t) => t.address), weightedAprs), identity); - - return { - total: apr, breakdown, - }; - } - - // Get token weights normalised by usd price - getTokenWeightNormalisedByUsd = (token: PrismaPoolTokenWithExpandedNesting, poolTotalLiquidity: number): number => { - if (token.dynamicData?.weight) { - return parseFloat(token.dynamicData.weight); - } else if (token.dynamicData?.balanceUSD) { - // using floats assuming frontend purposes with low precision needs - return token.dynamicData?.balanceUSD / poolTotalLiquidity; - } else { - throw `No price for ${token.address}`; - } - return 0; - }; - -} \ No newline at end of file diff --git a/modules/token/lib/token-apr-handler/fetch-all.ts b/modules/token/lib/token-apr-handler/fetch-all.ts new file mode 100644 index 000000000..7fdd559fb --- /dev/null +++ b/modules/token/lib/token-apr-handler/fetch-all.ts @@ -0,0 +1,8 @@ +import { tokens } from "./tokens"; + +export const fetchAllAprs = async() => { + const responses = await Promise.all( + tokens.map(({ fetchFn }) => fetchFn()) + ) + return responses.reduce((acc, val) => ({ ...acc, ...val }), {}) +} \ No newline at end of file diff --git a/modules/token/lib/token-apr-handler/sources/aave.ts b/modules/token/lib/token-apr-handler/sources/aave.ts new file mode 100644 index 000000000..91744e0d9 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/aave.ts @@ -0,0 +1,307 @@ +// can be fetched from subgraph +// aave-js: supplyAPR = graph.liquidityRate = core.getReserveCurrentLiquidityRate(_reserve) +// or directly from RPC: +// wrappedAaveToken.LENDING_POOL.getReserveCurrentLiquidityRate(mainTokenAddress) + +import axios from "axios"; + +const wrappedTokensMap = { + v2: { + [1]: { + // USDT + '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58': { + aToken: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', + underlying: '0xdac17f958d2ee523a2206206994597c13d831ec7', + }, + // USDC + '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de': { + aToken: '0xbcca60bb61934080951369a648fb03df4f96263c', + underlying: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + }, + // DAI + '0x02d60b84491589974263d922d9cc7a3152618ef6': { + aToken: '0x028171bca77440897b824ca71d1c56cac55b68a3', + underlying: '0x6b175474e89094c44da98b954eedeac495271d0f', + }, + }, + [137]: { + // USDT + '0x19c60a251e525fa88cd6f3768416a8024e98fc19': { + aToken: '0x60d55f02a771d515e077c9c2403a1ef324885cec', + underlying: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + }, + // USDC + '0x221836a597948dce8f3568e044ff123108acc42a': { + aToken: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', + underlying: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + }, + // DAI + '0xee029120c72b0607344f35b17cdd90025e647b00': { + aToken: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + underlying: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + }, + }, + }, + v3: { + [1]: { + // USDT + '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455': { + aToken: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', + underlying: '0xdac17f958d2ee523a2206206994597c13d831ec7', + }, + // USDC + '0x57d20c946a7a3812a7225b881cdcd8431d23431c': { + aToken: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', + underlying: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + }, + // DAI + '0x098256c06ab24f5655c5506a6488781bd711c14b': { + aToken: '0x018008bfb33d285247a21d44e50697654f754e63', + underlying: '0x6b175474e89094c44da98b954eedeac495271d0f', + }, + // WETH + '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6': { + aToken: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8', + underlying: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + }, + }, + [137]: { + // Matic + '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1': { + aToken: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', + underlying: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', + }, + // USDT + '0x715d73a88f2f0115d87cfe5e0f25d756b2f9679f': { + aToken: '0x6ab707aca953edaefbc4fd23ba73294241490620', + underlying: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + }, + // USDC + '0xac69e38ed4298490906a3f8d84aefe883f3e86b5': { + aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', + underlying: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + }, + // DAI + '0xdb6df721a6e7fdb97363079b01f107860ac156f9': { + aToken: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', + underlying: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + }, + // WETH + '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5': { + aToken: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', + underlying: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619', + }, + }, + [42161]: { + // USDT + '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db': { + aToken: '0x6ab707aca953edaefbc4fd23ba73294241490620', + underlying: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + }, + // USDC + '0xe719aef17468c7e10c0c205be62c990754dff7e5': { + aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', + underlying: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', + }, + // DAI + '0x345a864ac644c82c2d649491c905c71f240700b2': { + aToken: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', + underlying: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + }, + // WETH + '0x18c100415988bef4354effad1188d1c22041b046': { + aToken: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', + underlying: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', + } + }, + } +} + +const aTokens = { + v2: { + [1]: Object.values(wrappedTokensMap.v2[1]).map( + (t) => t.aToken + ), + [137]: Object.values(wrappedTokensMap.v2[137]).map( + (t) => t.aToken + ), + [42161]: {}, + }, + v3: { + [1]: Object.values(wrappedTokensMap.v3[1]).map( + (t) => t.aToken + ), + [137]: Object.values(wrappedTokensMap.v3[137]).map( + (t) => t.aToken + ), + [42161]: Object.values(wrappedTokensMap.v3[42161]).map( + (t) => t.aToken + ), + } +} + +const underlyingAssets = { + v2: { + [1]: Object.values(wrappedTokensMap.v2[1]).map( + (t) => t.underlying + ), + [137]: Object.values(wrappedTokensMap.v2[137]).map( + (t) => t.underlying + ), + [42161]: {}, + }, + v3: { + [1]: Object.values(wrappedTokensMap.v3[1]).map( + (t) => t.underlying + ), + [137]: Object.values(wrappedTokensMap.v3[137]).map( + (t) => t.underlying + ), + [42161]: Object.values(wrappedTokensMap.v3[42161]).map( + (t) => t.underlying + ), + } +} + +const underlyingsToWrapped = [ + { version: 'v2', network: 1, tokens: Object.fromEntries( + Object.keys(wrappedTokensMap.v2[1]).map((wrapped) => [ + wrappedTokensMap.v2[1][wrapped as keyof (typeof wrappedTokensMap)['v2'][1]].underlying, + wrapped, + ]) + ) }, + { version: 'v2', network: 137, tokens: Object.fromEntries( + Object.keys(wrappedTokensMap.v2[137]).map((wrapped) => [ + wrappedTokensMap.v2[137][ + wrapped as keyof (typeof wrappedTokensMap)['v2'][137] + ].underlying, + wrapped, + ]) + ) }, + { version: 'v3', network: 1, tokens: Object.fromEntries( + Object.keys(wrappedTokensMap.v3[1]).map((wrapped) => [ + wrappedTokensMap.v3[1][wrapped as keyof (typeof wrappedTokensMap)['v3'][1]].underlying, + wrapped, + ]) + ) }, + { version: 'v3', network: 137, tokens: Object.fromEntries( + Object.keys(wrappedTokensMap.v3[137]).map((wrapped) => [ + wrappedTokensMap.v3[137][ + wrapped as keyof (typeof wrappedTokensMap)['v3'][137] + ].underlying, + wrapped, + ]) + ) }, + { version: 'v3', network: 42161, tokens: Object.fromEntries( + Object.keys(wrappedTokensMap.v3[42161]).map((wrapped) => [ + wrappedTokensMap.v3[42161][ + wrapped as keyof (typeof wrappedTokensMap)['v3'][42161] + ].underlying, + wrapped, + ]) + ) }, +] + +// Subgraph +// liquidityRate, depositors APR (in rays - 27 digits) +const endpoints = [ + { version: 'v2', network: 1, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2' }, + { version: 'v2', network: 137, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic' }, + { version: 'v3', network: 1, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3' }, + { version: 'v3', network: 137, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon' }, + { version: 'v3', network: 42161, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum' }, +] + +const query = ` + query getReserves($aTokens: [String!], $underlyingAssets: [Bytes!]) { + reserves( + where: { + aToken_in: $aTokens + underlyingAsset_in: $underlyingAssets + isActive: true + } + ) { + underlyingAsset + liquidityRate + } + } +` + +interface ReserveResponse { + data: { + reserves: [ + { + underlyingAsset: string + liquidityRate: string + } + ] + } +} + +/** + * Fetching and parsing aave APRs from a subgraph + * + * @returns APRs for aave tokens + */ +export const aave = async (network: number, version: keyof (typeof wrappedTokensMap) = 'v2') => { + const noRates = Object.fromEntries( + Object.keys(wrappedTokensMap[version]).map((key) => [key, 0]) + ) + + if (!network || (network != 1 && network != 137 && network != 42161)) { + return noRates + } + + if (network == 42161 && version != 'v3') { + return noRates + } + + try { + const requestQuery = { + operationName: 'getReserves', + query, + variables: { + aTokens: aTokens[version][network], + underlyingAssets: underlyingAssets[version][network], + }, + } + + const endpoint = endpoints.find((e) => e.version == version && e.network == network)?.subgraph + const underlyingToWrapped = underlyingsToWrapped.find((e) => e.version == version && e.network == network)?.tokens + + if (!endpoint) { + throw 'no endpoint found' + } + + if (!underlyingToWrapped) { + throw 'no underlyingToWrapped found' + } + + const { data } = await axios.post(endpoint, { + body: JSON.stringify(requestQuery) + }) + + const { + data: { reserves }, + } = data as ReserveResponse + + const aprEntries = reserves.map((r) => [ + underlyingToWrapped[r.underlyingAsset], + // Note: our assumption is frontend usage, this service is not a good source where more accuracy is needed. + // Converting from aave ray number (27 digits) to bsp + // essentially same as here: + // https://github.com/aave/aave-utilities/blob/master/packages/math-utils/src/formatters/reserve/index.ts#L231 + Math.round(Number(r.liquidityRate.slice(0, -20)) / 1e3), + ]) + + return Object.fromEntries(aprEntries) + } catch (error) { + console.log(error) + + return noRates + } +} + +// TODO: RPC multicall +// always upto date +// const lendingPoolAddress = '0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9'; diff --git a/modules/token/lib/token-apr-handler/sources/abis/oErc20.ts b/modules/token/lib/token-apr-handler/sources/abis/oErc20.ts new file mode 100644 index 000000000..6dde7bf68 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/abis/oErc20.ts @@ -0,0 +1,15 @@ +export const abi = [ + { + inputs: [], + name: "borrowRatePerTimestamp", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + } +] as const diff --git a/modules/token/lib/token-apr-handler/sources/abis/reaperStrategy.ts b/modules/token/lib/token-apr-handler/sources/abis/reaperStrategy.ts new file mode 100644 index 000000000..1a89f3754 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/abis/reaperStrategy.ts @@ -0,0 +1,21 @@ +export const abi = [ + { + inputs: [ + { + internalType: 'int256', + name: '_n', + type: 'int256', + }, + ], + name: 'averageAPRAcrossLastNHarvests', + outputs: [ + { + internalType: 'int256', + name: '', + type: 'int256', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const diff --git a/modules/token/lib/token-apr-handler/sources/abis/tesseraPool.ts b/modules/token/lib/token-apr-handler/sources/abis/tesseraPool.ts new file mode 100644 index 000000000..a3fd8bb01 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/abis/tesseraPool.ts @@ -0,0 +1,154 @@ +export const abi = [ + { + inputs: [], + name: 'getPoolsUI', + outputs: [ + { + components: [ + { internalType: 'uint256', name: 'poolId', type: 'uint256' }, + { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, + { + components: [ + { + internalType: 'uint48', + name: 'startTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'endTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint96', + name: 'rewardsPerHour', + type: 'uint96', + }, + { + internalType: 'uint96', + name: 'capPerPosition', + type: 'uint96', + }, + ], + internalType: 'struct ApeCoinStaking.TimeRange', + name: 'currentTimeRange', + type: 'tuple', + }, + ], + internalType: 'struct ApeCoinStaking.PoolUI', + name: '', + type: 'tuple', + }, + { + components: [ + { internalType: 'uint256', name: 'poolId', type: 'uint256' }, + { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, + { + components: [ + { + internalType: 'uint48', + name: 'startTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'endTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint96', + name: 'rewardsPerHour', + type: 'uint96', + }, + { + internalType: 'uint96', + name: 'capPerPosition', + type: 'uint96', + }, + ], + internalType: 'struct ApeCoinStaking.TimeRange', + name: 'currentTimeRange', + type: 'tuple', + }, + ], + internalType: 'struct ApeCoinStaking.PoolUI', + name: '', + type: 'tuple', + }, + { + components: [ + { internalType: 'uint256', name: 'poolId', type: 'uint256' }, + { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, + { + components: [ + { + internalType: 'uint48', + name: 'startTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'endTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint96', + name: 'rewardsPerHour', + type: 'uint96', + }, + { + internalType: 'uint96', + name: 'capPerPosition', + type: 'uint96', + }, + ], + internalType: 'struct ApeCoinStaking.TimeRange', + name: 'currentTimeRange', + type: 'tuple', + }, + ], + internalType: 'struct ApeCoinStaking.PoolUI', + name: '', + type: 'tuple', + }, + { + components: [ + { internalType: 'uint256', name: 'poolId', type: 'uint256' }, + { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, + { + components: [ + { + internalType: 'uint48', + name: 'startTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'endTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint96', + name: 'rewardsPerHour', + type: 'uint96', + }, + { + internalType: 'uint96', + name: 'capPerPosition', + type: 'uint96', + }, + ], + internalType: 'struct ApeCoinStaking.TimeRange', + name: 'currentTimeRange', + type: 'tuple', + }, + ], + internalType: 'struct ApeCoinStaking.PoolUI', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const diff --git a/modules/token/lib/token-apr-handler/sources/ankr.ts b/modules/token/lib/token-apr-handler/sources/ankr.ts new file mode 100644 index 000000000..bd29e78d1 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/ankr.ts @@ -0,0 +1,16 @@ +import axios from "axios"; + +const ankrEth = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb' + +export const ankr = async () => { + const { data } = await axios.get('https://api.staking.ankr.com/v1alpha/metrics') + const json = data as { services: { serviceName: string; apy: string }[] } + const service = json.services.find((service) => service.serviceName === 'eth') + if (!service) { + return null + } + const scaledValue = Math.round(parseFloat(service.apy) * 100) + return { + [ankrEth]: scaledValue + } +} diff --git a/modules/token/lib/token-apr-handler/sources/default.ts b/modules/token/lib/token-apr-handler/sources/default.ts new file mode 100644 index 000000000..11213fb53 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/default.ts @@ -0,0 +1,23 @@ +import axios from "axios"; + +export const defaultFetch = async (options: { tokens: string[]; url: string; path: string; scale?: number }) => { + const { tokens, url, path, scale = 100 } = options + const { data } = await axios.get(url, { headers: { 'User-Agent': 'cf' } }) + const value = (path === '') ? data : getValueFromPath(data, path) + const scaledValue = Math.round(parseFloat(value) * scale) + + return tokens.reduce((acc, token) => { + acc[token] = scaledValue + return acc + }, {} as { [key: string]: number }) +} + +// Get a specific value from a JSON object based on a path +export const getValueFromPath = (obj: any, path: string) => { + const parts = path.split('.') + let value = obj + for (const part of parts) { + value = value[part] + } + return value +} diff --git a/modules/token/lib/token-apr-handler/sources/euler.ts b/modules/token/lib/token-apr-handler/sources/euler.ts new file mode 100644 index 000000000..9c9cce379 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/euler.ts @@ -0,0 +1,60 @@ +import axios from "axios"; + +const yieldTokens = { + eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', + eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', + eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', + eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', +} + +const query = ` + query getAssetsAPY($eTokenAddress_in: [String!]) { + assets( + where: { + eTokenAddress_in: $eTokenAddress_in + } + ) { + eTokenAddress + supplyAPY + } + } +` + +const requestQuery = { + operationName: 'getAssetsAPY', + query, + variables: { + eTokenAddress_in: Object.values(yieldTokens), + }, +} + +const url = 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet' + +interface EulerResponse { + data: { + assets: [ + { + eTokenAddress: string + supplyAPY: string + } + ] + } +} + +export const euler = async () => { + const {data} = await axios.post(url, { + body: JSON.stringify(requestQuery) + }) + + const { + data: { assets }, + } = data as EulerResponse + + const aprEntries = assets.map(({ eTokenAddress, supplyAPY }) => [ + eTokenAddress, + // supplyAPY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 + Math.round(Number(supplyAPY.slice(0, -20)) / 1e3) + ]) + + return Object.fromEntries(aprEntries) +} diff --git a/modules/token/lib/token-apr-handler/sources/gearbox.ts b/modules/token/lib/token-apr-handler/sources/gearbox.ts new file mode 100644 index 000000000..4575806b4 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/gearbox.ts @@ -0,0 +1,26 @@ +import axios from "axios"; + +const ddai = '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba' +const dusdc = '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3' + +export const gearbox = async () => { + const {data} = await axios.get('https://mainnet.gearbox.foundation/api/pools') + const json = data as { data: { dieselToken: string; depositAPY_RAY: string }[] } + const dai = json.data.find((t) => t.dieselToken.toLowerCase() == ddai) + const usdc = json.data.find((t) => t.dieselToken.toLowerCase() == dusdc) + if (!dai || !usdc) { + return null + } + + const scaleDai = Math.round( + // depositAPY_RAY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 + Number(dai.depositAPY_RAY.slice(0, -20)) / 1e3 + ) + const scaleUsdc = Math.round( + Number(usdc.depositAPY_RAY.slice(0, -20)) / 1e3 + ) + return { + [ddai]: scaleDai, + [dusdc]: scaleUsdc + } +} \ No newline at end of file diff --git a/modules/token/lib/token-apr-handler/sources/idle.ts b/modules/token/lib/token-apr-handler/sources/idle.ts new file mode 100644 index 000000000..0321de2c7 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/idle.ts @@ -0,0 +1,22 @@ +import axios from "axios"; + +const contracts = { + '0x0c80f31b840c6564e6c5e18f386fad96b63514ca': '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', // DAI + '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133': '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', // USDC + '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1': '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', // USDT +} as { [key: string]: string } + +export const idle = async (token: string) => { + const { data } = await axios.get(`https://api.idle.finance/junior-rates/${contracts[token]}?isRisk=false&order=desc&limit=1`, { + headers: { + Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M' + } + }) + const [json] = data as { idleRate: string }[] + const value = json.idleRate + const scaledValue = Math.round(Number(value) / 1e16) + + return { + [token]: scaledValue + } +} diff --git a/modules/token/lib/token-apr-handler/sources/index.ts b/modules/token/lib/token-apr-handler/sources/index.ts new file mode 100644 index 000000000..4b205dbc8 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/index.ts @@ -0,0 +1,14 @@ +import { aave } from './aave'; +import { ankr } from './ankr'; +import { defaultFetch } from './default'; +import { euler } from './euler'; +import { gearbox } from "./gearbox"; +import { idle } from './idle'; +import { overnight } from "./overnight"; +import { ovix } from "./ovix"; +import { reaper } from "./reaper"; +import { tessera } from "./tessera"; +import { tetu } from "./tetu"; +import { tranchess } from "./tranchess"; + +export { aave, ankr, defaultFetch, euler, gearbox, idle, overnight, ovix, reaper, tessera, tetu, tranchess } \ No newline at end of file diff --git a/modules/token/lib/token-apr-handler/sources/overnight.ts b/modules/token/lib/token-apr-handler/sources/overnight.ts new file mode 100644 index 000000000..a73967d82 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/overnight.ts @@ -0,0 +1,17 @@ +import axios from "axios"; + +const tokens = [ + '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', + '0x6933ec1ca55c06a894107860c92acdfd2dd8512f' +] + +export const overnight = async () => { + const {data} = await axios.get('https://app.overnight.fi/api/balancer/week/apr') + const rate = data as string + const scaledValue = Math.round(Number(rate) * 10000) + + return tokens.reduce((acc, token) => { + acc[token] = scaledValue + return acc + }, {} as { [key: string]: number }) +} diff --git a/modules/token/lib/token-apr-handler/sources/ovix.ts b/modules/token/lib/token-apr-handler/sources/ovix.ts new file mode 100644 index 000000000..3c79b7619 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/ovix.ts @@ -0,0 +1,57 @@ +import { abi } from './abis/oErc20' +import { ContractFunctionConfig, createPublicClient, http } from 'viem' +import { polygonZkEvm } from 'viem/chains' + +const client = createPublicClient({ + chain: { + ...polygonZkEvm, + contracts: { + multicall3: { + address: '0xca11bde05977b3631167028862be2a173976ca11', + blockCreated: 57_746, + }, + } + }, + transport: http('https://zkevm-rpc.com'), +}) + +export const yieldTokens = { + USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', + USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', +} as { [key: string]: `0x${string}` } + +export const wrappedTokens = { + USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', + USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', +} as { [key: string]: `0x${string}` } + +const noRates = Object.fromEntries( + Object.values(yieldTokens).map((v) => [v, 0]) +) + +const getBorrowRates = () => { + const contracts: ContractFunctionConfig[] = Object.keys(yieldTokens).map((coin) => ({ + address: yieldTokens[coin], + abi, + functionName: 'borrowRatePerTimestamp', + args: [] + })) + + return client.multicall({ contracts }) +} + +export const ovix = async () => { + try { + const borrowRates = await getBorrowRates() + + const aprs = Object.keys(wrappedTokens).map((coin, i) => [ + wrappedTokens[coin], + Math.round(10000 * (Math.pow(1 + Number(borrowRates[i].result) / 1e18, 365 * 24 * 60 * 60) - 1)) + ]) + + return Object.fromEntries(aprs) + } catch (error) { + console.log(error) + return noRates + } +} diff --git a/modules/token/lib/token-apr-handler/sources/reaper.ts b/modules/token/lib/token-apr-handler/sources/reaper.ts new file mode 100644 index 000000000..e29f7da66 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/reaper.ts @@ -0,0 +1,54 @@ +import { abi } from './abis/reaperStrategy' +import { ContractFunctionConfig, createPublicClient, http, Narrow } from 'viem' +import { arbitrum } from 'viem/chains' +import { MulticallContracts } from "viem/src/types/multicall"; +import { Contract } from "ethers"; + +const client = createPublicClient({ + chain: arbitrum, + transport: http('https://arb1.arbitrum.io/rpc'), +}) + +export const yieldTokens = { + DAI: '0x12f256109e744081f633a827be80e06d97ff7447', + USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', + USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', +} as { [key: string]: `0x${ string }` } + +export const strategiesMap = { + DAI: '0xd4d5321b04e4832772a4d70e1eed6bcb7402d7ac', + USDT: '0x8a674ebbe33d6b03825626fa432e9ece888e13b5', + USDC: '0x6f6c0c5b7af2a326111ba6a9fa4926f7ca3adf44', +} as { [key: string]: `0x${ string }` } + +const noRates = Object.fromEntries( + Object.values(yieldTokens).map((v) => [v, 0]) +) + +const getAprs = () => { + + const contracts: ContractFunctionConfig[] = Object.keys(strategiesMap).map((coin) => ({ + address: strategiesMap[coin], + abi, + functionName: 'averageAPRAcrossLastNHarvests', + args: [3] as never, + })) + + return client.multicall({ contracts }) +} + +export const reaper = async () => { + try { + const results = await getAprs() + + const aprs = Object.keys(strategiesMap).map((coin, i) => [ + yieldTokens[coin], + Math.round(Number(results[i].result)), + ]) + + return Object.fromEntries(aprs) + } catch (error) { + console.log(error) + return noRates + } +} diff --git a/modules/token/lib/token-apr-handler/sources/tessera.ts b/modules/token/lib/token-apr-handler/sources/tessera.ts new file mode 100644 index 000000000..18f146732 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/tessera.ts @@ -0,0 +1,41 @@ +import { abi } from './abis/tesseraPool' +import { createPublicClient, http } from 'viem' +import { mainnet } from 'viem/chains' + +const client = createPublicClient({ + chain: mainnet, + transport: http('https://rpc.ankr.com/eth'), +}) + +const yieldTokens = { + sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', +} + +/** + * Staked ApeCoin APR fetching + * + * @returns apr in bsp + */ +export const tessera = async () => { + let apr = 0 + + try { + const poolsUI = await client.readContract({ + address: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9', + abi, + functionName: 'getPoolsUI', + }) as unknown as { stakedAmount: bigint; currentTimeRange: { rewardsPerHour: bigint } }[] + + const apePool = poolsUI[0] + const staked = apePool.stakedAmount + const reward = apePool.currentTimeRange.rewardsPerHour * BigInt(24 * 365) + + apr = Number(reward * BigInt(1e4) / staked) + } catch (error) { + console.error('Failed to fetch Tessera Ape Coin APR:', error) + } + + return { + [yieldTokens.sApe]: apr, + } +} diff --git a/modules/token/lib/token-apr-handler/sources/tetu.ts b/modules/token/lib/token-apr-handler/sources/tetu.ts new file mode 100644 index 000000000..72bccfe5c --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/tetu.ts @@ -0,0 +1,9 @@ +import axios from "axios"; + +export const tetu = async () => { + const { data } = await axios.get('https://api.tetu.io/api/v1/reader/compoundAPRs?network=MATIC') + const json = data as { vault: string, apr: number }[] + const aprs = json.map((t) => [t.vault, Math.round(t.apr * 100)]) + + return Object.fromEntries(aprs) +} diff --git a/modules/token/lib/token-apr-handler/sources/tranchess.ts b/modules/token/lib/token-apr-handler/sources/tranchess.ts new file mode 100644 index 000000000..398b24309 --- /dev/null +++ b/modules/token/lib/token-apr-handler/sources/tranchess.ts @@ -0,0 +1,11 @@ +import axios from "axios"; + +export const tranchess = async () => { + const { data } = await axios.get('https://tranchess.com/eth/api/v3/funds'); + const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[] + // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. + const scaledValue = Math.round(365 * Number(weeklyAveragePnlPercentage) / 1e14) + return { + '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d': scaledValue + } +} diff --git a/modules/token/lib/token-apr-handler/tokens.ts b/modules/token/lib/token-apr-handler/tokens.ts new file mode 100644 index 000000000..06f68ad65 --- /dev/null +++ b/modules/token/lib/token-apr-handler/tokens.ts @@ -0,0 +1,35 @@ +import { aave, ankr, defaultFetch, gearbox, idle, overnight, ovix, reaper, tessera, tetu, tranchess } from "./sources"; + +export const tokens = [ + { name: 'idleDai', fetchFn: () => idle('0x0c80f31b840c6564e6c5e18f386fad96b63514ca') }, + { name: 'idleUsdc', fetchFn: () => idle('0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133') }, + { name: 'idleUsdt', fetchFn: () => idle('0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1') }, + { name: 'qETH', fetchFn: tranchess }, + { name: 'gearbox', fetchFn: gearbox }, + { name: 'overnight', fetchFn: overnight }, + { name: 'aaveV2Mainnet', fetchFn: () => aave(1) }, + { name: 'aaveV2Polygon', fetchFn: () => aave(137) }, + { name: 'aaveV3Mainnet', fetchFn: () => aave(1, 'v3') }, + { name: 'aaveV3Polygon', fetchFn: () => aave(137, 'v3') }, + { name: 'aaveV3Arbitrum', fetchFn: () => aave(42161, 'v3') }, + { name: 'ankr', fetchFn: ankr }, + { name: 'reaper', fetchFn: reaper }, + { name: 'tessera', fetchFn: tessera }, + { name: 'tetu', fetchFn: tetu }, + { name: 'ovix', fetchFn: ovix }, + { name: 'vEth', fetchFn: () => defaultFetch({ tokens: ['0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f'], url: 'https://apy.liebi.com/veth', path: 'veth' }) }, + { name: 'stEth', fetchFn: () => defaultFetch({ tokens: ['0x6c76971f98945ae98dd7d4dfca8711ebea946ea6', '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9', '0xae7ab96520de3a18e5e111b5eaab095312d7fe84', '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd', '0x5979d7b546e38e414f7e9822514be443a4800529'], url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr' }) }, + { name: 'stMatic', fetchFn: () => defaultFetch({ tokens: ['0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'], url: 'https://polygon.lido.fi/api/stats', path: 'apr' }) }, + { name: 'cbEth', fetchFn: () => defaultFetch({ tokens: ['0xbe9895146f7af43049ca1c1ae358b0541ea49704'], url: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', path: 'apy', scale: 10000 }) }, + { name: 'rETH', fetchFn: () => defaultFetch({ tokens: ['0xb23c20efce6e24acca0cef9b7b7aa196b84ec942', '0xae78736cd615f374d3085123a210448e74fc6393', '0xec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8'], url: 'https://api.rocketpool.net/api/apr', path: 'yearlyAPR' }) }, + { name: 'sfrxETH', fetchFn: () => defaultFetch({ tokens: ['0xac3e018457b222d93114458476f3e3416abbe38f'], url: 'https://api.frax.finance/v2/frxeth/summary/latest', path: 'sfrxethApr' }) }, + { name: 'stafi', fetchFn: () => defaultFetch({ tokens: ['0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'], url: 'https://drop-api.stafi.io/reth/v1/poolData', path: 'data.stakeApr' }) }, + { name: 'usdr', fetchFn: () => defaultFetch({ tokens: ['0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'], url: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', path: 'usdr' }) }, + { name: 'maticX', fetchFn: () => defaultFetch({ tokens: ['0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'], url: 'https://universe.staderlabs.com/polygon/apy', path: 'value' }) }, + // Had to proxy this one because Binance API was blocking requests from Cloudflare, original URL: https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH + // { name: 'wbETH', fetchFn: () => defaultFetch({ tokens: ['0xa2e3356610840701bdf5611a53974510ae27e2e1'], url: 'https://faas-ams3-2a2df116.doserverless.co/api/v1/web/fn-683e4669-de62-4f89-9609-2e24ba8acfa7/default/binance', path: 'data.0.rewardRate', scale: 10000 }) }, + { name: 'wbETH', fetchFn: () => defaultFetch({ tokens: ['0xa2e3356610840701bdf5611a53974510ae27e2e1'], url: 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', path: 'data.0.rewardRate', scale: 10000 }) }, + { name: 'swETH', fetchFn: () => defaultFetch({ tokens: ['0xf951e335afb289353dc249e82926178eac7ded78'], url: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', path: '', scale: 100 }) }, + { name: 'wjAURA', fetchFn: () => defaultFetch({ tokens: ['0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'], url: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', path: 'wjauraApy', scale: 200 }) }, + // { name: 'euler', fetchFn: euler }, +] diff --git a/package.json b/package.json index a36603005..9eee14d2a 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "stellate": "^1.15.2", "ts-dotenv": "^0.8.1", "uuid": "^8.3.2", + "viem": "^1.2.9", "yarn": "^1.22.19" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 430177feb..0f664734a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz#223572538f6bea336750039bb43a4016dcc8182d" + integrity sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ== + "@ampproject/remapping@^2.1.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" @@ -3716,6 +3721,23 @@ resolved "https://registry.yarnpkg.com/@n1ru4l/graphql-live-query/-/graphql-live-query-0.9.0.tgz#defaebdd31f625bee49e6745934f36312532b2bc" integrity sha512-BTpWy1e+FxN82RnLz4x1+JcEewVdfmUhV1C6/XYD5AjS7PQp9QFF7K8bCD6gzPTr2l+prvqOyVueQhFJxB1vfg== +"@noble/curves@1.0.0", "@noble/curves@~1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.0.0.tgz#e40be8c7daf088aaf291887cbc73f43464a92932" + integrity sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw== + dependencies: + "@noble/hashes" "1.3.0" + +"@noble/hashes@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1" + integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg== + +"@noble/hashes@~1.3.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" + integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -3863,6 +3885,28 @@ resolved "https://registry.yarnpkg.com/@sanity/timed-out/-/timed-out-4.0.2.tgz#c9f61f9a1609baa1eb3e4235a24ea2a775022cdf" integrity sha512-NBDKGj14g9Z+bopIvZcQKWCzJq5JSrdmzRR1CS+iyA3Gm8SnIWBfZa7I3mTg2X6Nu8LQXG0EPKXdOGozLS4i3w== +"@scure/base@~1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" + integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== + +"@scure/bip32@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.0.tgz#6c8d980ef3f290987736acd0ee2e0f0d50068d87" + integrity sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q== + dependencies: + "@noble/curves" "~1.0.0" + "@noble/hashes" "~1.3.0" + "@scure/base" "~1.1.0" + +"@scure/bip39@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.0.tgz#a207e2ef96de354de7d0002292ba1503538fc77b" + integrity sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg== + dependencies: + "@noble/hashes" "~1.3.0" + "@scure/base" "~1.1.0" + "@sentry-internal/tracing@7.56.0": version "7.56.0" resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.56.0.tgz#ba709258f2f0f3d8a36f9740403088b39212b843" @@ -4396,6 +4440,11 @@ dependencies: "@types/yargs-parser" "*" +"@wagmi/chains@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.2.0.tgz#d59eaa70ec51a5fdcd113975926992acfb17ab12" + integrity sha512-dmDRipsE54JfyudOBkuhEexqQWcrZqxn/qiujG8SBzMh/az/AH5xlJSA+j1CPWTx9+QofSMF3B7A4gb6XRmSaQ== + "@xmldom/xmldom@^0.7.5": version "0.7.5" resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d" @@ -4411,6 +4460,11 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abitype@0.8.11: + version "0.8.11" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.8.11.tgz#66e1cf2cbf46f48d0e57132d7c1c392447536cc1" + integrity sha512-bM4v2dKvX08sZ9IU38IN5BKmN+ZkOSd2oI4a9f0ejHYZQYV6cDr7j+d95ga0z2XHG36Y4jzoG5Z7qDqxp7fi/A== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -7490,6 +7544,11 @@ isomorphic-ws@4.0.1: resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== +isomorphic-ws@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" + integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== + istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" @@ -10418,6 +10477,21 @@ vary@^1, vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +viem@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/viem/-/viem-1.2.9.tgz#8ccf786cd00d28b14b644f2b9fe35fc6bf2bdc41" + integrity sha512-EnEbTuAAHv43unUgMISdQXbD9mrhZLvOdmf6eRGbDFl+XwP/PEzZAT79RaWAuDPnLXGMP1gBCJF++NFjSMukUw== + dependencies: + "@adraffy/ens-normalize" "1.9.0" + "@noble/curves" "1.0.0" + "@noble/hashes" "1.3.0" + "@scure/bip32" "1.3.0" + "@scure/bip39" "1.2.0" + "@wagmi/chains" "1.2.0" + abitype "0.8.11" + isomorphic-ws "5.0.0" + ws "8.12.0" + walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" @@ -10555,6 +10629,11 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.12.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.0.tgz#485074cc392689da78e1828a9ff23585e06cddd8" + integrity sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig== + ws@8.2.3: version "8.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" From 6120e3a00db04a78aa534ffbd35350f73d89a972 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Fri, 7 Jul 2023 23:04:19 -0300 Subject: [PATCH 04/42] Adapting contracts from apr handler to ethers instead of viem; --- .../apr-data-sources/ib-tokens-apr.service.ts | 19 +- .../lib/token-apr-handler/sources/aave.ts | 19 +- .../lib/token-apr-handler/sources/ovix.ts | 37 +- .../lib/token-apr-handler/sources/reaper.ts | 27 +- .../lib/token-apr-handler/sources/tessera.ts | 23 +- modules/token/lib/token-apr-handler/tokens.ts | 2 +- package.json | 1 + yarn.lock | 775 +++++++++--------- 8 files changed, 453 insertions(+), 450 deletions(-) diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 717ab3465..30a8dce7d 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -1,10 +1,9 @@ import { PoolAprService } from "../../pool-types"; -import axios from "axios"; import { PrismaPoolWithExpandedNesting } from "../../../../prisma/prisma-types"; -import { zipObject } from "lodash"; import { prisma } from "../../../../prisma/prisma-client"; import { networkContext } from "../../../network/network-context.service"; import { prismaBulkExecuteOperations } from "../../../../prisma/prisma-util"; +import { fetchAllAprs } from "../../../token/lib/token-apr-handler/fetch-all"; export class IbTokensAprService implements PoolAprService { @@ -15,14 +14,16 @@ export class IbTokensAprService implements PoolAprService { public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { const operations: any[] = []; const aprs = await this.fetchYieldTokensApr(); - const tokenYieldPools = pools.filter((pool) => pool.tokens.find((token) => { - return Array.from(aprs.keys()).includes(token.address); - })); - + const tokenYieldPools = pools.filter((pool) => { + return pool.tokens.find((token) => { + return Array.from(aprs.keys()).map((key) => key.toLowerCase()).includes(token.address.toLowerCase()); + }) + } + ); for (const pool of tokenYieldPools) { for (const token of pool.tokens) { if (Array.from(aprs.keys()).includes(token.address)) { - const itemId = `${ pool.id }-tokens-yield-apr` + const itemId = `${ pool.id }-token-${token.token.symbol || token.address}-yield-apr` operations.push(prisma.prismaPoolAprItem.upsert({ where: { id_chain: { id: itemId, chain: networkContext.chain } }, create: { id: itemId, @@ -42,8 +43,8 @@ export class IbTokensAprService implements PoolAprService { } private async fetchYieldTokensApr(): Promise> { - const res = await axios.get("https://yield-tokens.balancer.workers.dev/"); - const aprs = new Map(Object.entries(res.data as { + const data = await fetchAllAprs() + const aprs = new Map(Object.entries(data as { [key: string]: number }).map(([key, apr]) => [key, apr * 0.0001])); return aprs; diff --git a/modules/token/lib/token-apr-handler/sources/aave.ts b/modules/token/lib/token-apr-handler/sources/aave.ts index 91744e0d9..c8408734e 100644 --- a/modules/token/lib/token-apr-handler/sources/aave.ts +++ b/modules/token/lib/token-apr-handler/sources/aave.ts @@ -3,7 +3,7 @@ // or directly from RPC: // wrappedAaveToken.LENDING_POOL.getReserveCurrentLiquidityRate(mainTokenAddress) -import axios from "axios"; +import axios, { AxiosError } from "axios"; const wrappedTokensMap = { v2: { @@ -212,20 +212,7 @@ const endpoints = [ { version: 'v3', network: 42161, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum' }, ] -const query = ` - query getReserves($aTokens: [String!], $underlyingAssets: [Bytes!]) { - reserves( - where: { - aToken_in: $aTokens - underlyingAsset_in: $underlyingAssets - isActive: true - } - ) { - underlyingAsset - liquidityRate - } - } -` +const query = `\nquery getReserves($aTokens: [String!], $underlyingAssets: [Bytes!]) {\nreserves(where: {\naToken_in: $aTokens\nunderlyingAsset_in: $underlyingAssets\nisActive: true\n}\n) {\nunderlyingAsset\nliquidityRate\n}\n}\n` interface ReserveResponse { data: { @@ -296,7 +283,7 @@ export const aave = async (network: number, version: keyof (typeof wrappedTokens return Object.fromEntries(aprEntries) } catch (error) { - console.log(error) + console.log((error as AxiosError).response?.data) return noRates } diff --git a/modules/token/lib/token-apr-handler/sources/ovix.ts b/modules/token/lib/token-apr-handler/sources/ovix.ts index 3c79b7619..eb624be3d 100644 --- a/modules/token/lib/token-apr-handler/sources/ovix.ts +++ b/modules/token/lib/token-apr-handler/sources/ovix.ts @@ -1,19 +1,11 @@ import { abi } from './abis/oErc20' -import { ContractFunctionConfig, createPublicClient, http } from 'viem' -import { polygonZkEvm } from 'viem/chains' - -const client = createPublicClient({ - chain: { - ...polygonZkEvm, - contracts: { - multicall3: { - address: '0xca11bde05977b3631167028862be2a173976ca11', - blockCreated: 57_746, - }, - } - }, - transport: http('https://zkevm-rpc.com'), -}) +import { Contract } from "ethers"; +import { ethers } from "ethers"; +import { MulticallWrapper } from "ethers-multicall-provider"; +import { JsonRpcProvider } from "@ethersproject/providers"; + +const jsonRpcProvider = new JsonRpcProvider('https://zkevm-rpc.com', 1101 /*ARBITRUM*/) +const provider = MulticallWrapper.wrap(jsonRpcProvider) export const yieldTokens = { USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', @@ -30,14 +22,13 @@ const noRates = Object.fromEntries( ) const getBorrowRates = () => { - const contracts: ContractFunctionConfig[] = Object.keys(yieldTokens).map((coin) => ({ - address: yieldTokens[coin], - abi, - functionName: 'borrowRatePerTimestamp', - args: [] - })) - - return client.multicall({ contracts }) + + const calls = Object.keys(yieldTokens).map(async (coin) => { + const contract = new Contract(yieldTokens[coin], abi, provider) + return contract.borrowRatePerTimestamp() + }) + + return Promise.all(calls) } export const ovix = async () => { diff --git a/modules/token/lib/token-apr-handler/sources/reaper.ts b/modules/token/lib/token-apr-handler/sources/reaper.ts index e29f7da66..8dd50a253 100644 --- a/modules/token/lib/token-apr-handler/sources/reaper.ts +++ b/modules/token/lib/token-apr-handler/sources/reaper.ts @@ -1,13 +1,16 @@ import { abi } from './abis/reaperStrategy' import { ContractFunctionConfig, createPublicClient, http, Narrow } from 'viem' -import { arbitrum } from 'viem/chains' -import { MulticallContracts } from "viem/src/types/multicall"; +import { JsonRpcProvider } from "@ethersproject/providers"; +import { MulticallWrapper } from "ethers-multicall-provider"; import { Contract } from "ethers"; -const client = createPublicClient({ - chain: arbitrum, - transport: http('https://arb1.arbitrum.io/rpc'), -}) +// const client = createPublicClient({ +// chain: arbitrum, +// transport: http('https://arb1.arbitrum.io/rpc'), +// }) + +const jsonRpcProvider = new JsonRpcProvider('https://arb1.arbitrum.io/rpc', 42161 /*ARBITRUM*/) +const provider = MulticallWrapper.wrap(jsonRpcProvider) export const yieldTokens = { DAI: '0x12f256109e744081f633a827be80e06d97ff7447', @@ -27,14 +30,12 @@ const noRates = Object.fromEntries( const getAprs = () => { - const contracts: ContractFunctionConfig[] = Object.keys(strategiesMap).map((coin) => ({ - address: strategiesMap[coin], - abi, - functionName: 'averageAPRAcrossLastNHarvests', - args: [3] as never, - })) + const calls = Object.keys(strategiesMap).map(async (coin) => { + const contract = new Contract(strategiesMap[coin], abi, provider) + return contract.averageAPRAcrossLastNHarvests(3) + }) - return client.multicall({ contracts }) + return Promise.all(calls) } export const reaper = async () => { diff --git a/modules/token/lib/token-apr-handler/sources/tessera.ts b/modules/token/lib/token-apr-handler/sources/tessera.ts index 18f146732..5890e492d 100644 --- a/modules/token/lib/token-apr-handler/sources/tessera.ts +++ b/modules/token/lib/token-apr-handler/sources/tessera.ts @@ -1,11 +1,15 @@ import { abi } from './abis/tesseraPool' -import { createPublicClient, http } from 'viem' -import { mainnet } from 'viem/chains' +import { JsonRpcProvider } from "@ethersproject/providers"; +import { MulticallWrapper } from "ethers-multicall-provider"; +import { Contract } from "ethers"; -const client = createPublicClient({ - chain: mainnet, - transport: http('https://rpc.ankr.com/eth'), -}) +// const client = createPublicClient({ +// chain: mainnet, +// transport: http('https://rpc.ankr.com/eth'), +// }) + +const jsonRpcProvider = new JsonRpcProvider('https://rpc.ankr.com/eth', 1 /*MAINNET*/) +const provider = MulticallWrapper.wrap(jsonRpcProvider) const yieldTokens = { sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', @@ -20,11 +24,8 @@ export const tessera = async () => { let apr = 0 try { - const poolsUI = await client.readContract({ - address: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9', - abi, - functionName: 'getPoolsUI', - }) as unknown as { stakedAmount: bigint; currentTimeRange: { rewardsPerHour: bigint } }[] + const contract = new Contract('0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9', abi, provider) + const poolsUI = await contract.getPoolsUI() const apePool = poolsUI[0] const staked = apePool.stakedAmount diff --git a/modules/token/lib/token-apr-handler/tokens.ts b/modules/token/lib/token-apr-handler/tokens.ts index 06f68ad65..ed81bbe79 100644 --- a/modules/token/lib/token-apr-handler/tokens.ts +++ b/modules/token/lib/token-apr-handler/tokens.ts @@ -21,7 +21,7 @@ export const tokens = [ { name: 'stEth', fetchFn: () => defaultFetch({ tokens: ['0x6c76971f98945ae98dd7d4dfca8711ebea946ea6', '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9', '0xae7ab96520de3a18e5e111b5eaab095312d7fe84', '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd', '0x5979d7b546e38e414f7e9822514be443a4800529'], url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr' }) }, { name: 'stMatic', fetchFn: () => defaultFetch({ tokens: ['0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'], url: 'https://polygon.lido.fi/api/stats', path: 'apr' }) }, { name: 'cbEth', fetchFn: () => defaultFetch({ tokens: ['0xbe9895146f7af43049ca1c1ae358b0541ea49704'], url: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', path: 'apy', scale: 10000 }) }, - { name: 'rETH', fetchFn: () => defaultFetch({ tokens: ['0xb23c20efce6e24acca0cef9b7b7aa196b84ec942', '0xae78736cd615f374d3085123a210448e74fc6393', '0xec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8'], url: 'https://api.rocketpool.net/api/apr', path: 'yearlyAPR' }) }, + // { name: 'rETH', fetchFn: () => defaultFetch({ tokens: ['0xb23c20efce6e24acca0cef9b7b7aa196b84ec942', '0xae78736cd615f374d3085123a210448e74fc6393', '0xec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8'], url: 'https://api.rocketpool.net/api/apr', path: 'yearlyAPR' }) }, { name: 'sfrxETH', fetchFn: () => defaultFetch({ tokens: ['0xac3e018457b222d93114458476f3e3416abbe38f'], url: 'https://api.frax.finance/v2/frxeth/summary/latest', path: 'sfrxethApr' }) }, { name: 'stafi', fetchFn: () => defaultFetch({ tokens: ['0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'], url: 'https://drop-api.stafi.io/reth/v1/poolData', path: 'data.stakeApr' }) }, { name: 'usdr', fetchFn: () => defaultFetch({ tokens: ['0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'], url: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', path: 'usdr' }) }, diff --git a/package.json b/package.json index 9eee14d2a..d24a3d4e8 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "decimal.js": "^10.3.1", "dotenv": "^10.0.0", "ethers": "^5.5.1", + "ethers-multicall-provider": "^3.0.4", "express": "^4.17.1", "express-promise-router": "^4.1.0", "googleapis": "^108.0.0", diff --git a/yarn.lock b/yarn.lock index 0f664734a..05330769a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2585,55 +2585,55 @@ ts-node "^9" tslib "^2" -"@ethersproject/abi@5.5.0", "@ethersproject/abi@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.5.0.tgz#fb52820e22e50b854ff15ce1647cc508d6660613" - integrity sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w== - dependencies: - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/hash" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/abstract-provider@5.5.1", "@ethersproject/abstract-provider@^5.5.0": - version "5.5.1" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz#2f1f6e8a3ab7d378d8ad0b5718460f85649710c5" - integrity sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/networks" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/web" "^5.5.0" - -"@ethersproject/abstract-signer@5.5.0", "@ethersproject/abstract-signer@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz#590ff6693370c60ae376bf1c7ada59eb2a8dd08d" - integrity sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA== - dependencies: - "@ethersproject/abstract-provider" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - -"@ethersproject/address@5.5.0", "@ethersproject/address@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.5.0.tgz#bcc6f576a553f21f3dd7ba17248f81b473c9c78f" - integrity sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/rlp" "^5.5.0" +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" "@ethersproject/address@^5.6.0": version "5.6.0" @@ -2646,29 +2646,29 @@ "@ethersproject/logger" "^5.6.0" "@ethersproject/rlp" "^5.6.0" -"@ethersproject/base64@5.5.0", "@ethersproject/base64@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.5.0.tgz#881e8544e47ed976930836986e5eb8fab259c090" - integrity sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA== +"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== dependencies: - "@ethersproject/bytes" "^5.5.0" + "@ethersproject/bytes" "^5.7.0" -"@ethersproject/basex@5.5.0", "@ethersproject/basex@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.5.0.tgz#e40a53ae6d6b09ab4d977bd037010d4bed21b4d3" - integrity sha512-ZIodwhHpVJ0Y3hUCfUucmxKsWQA5TMnavp5j/UOuDdzZWzJlRmuOjcTMIGgHCYuZmHt36BfiSyQPSRskPxbfaQ== +"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/properties" "^5.5.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" -"@ethersproject/bignumber@5.5.0", "@ethersproject/bignumber@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.5.0.tgz#875b143f04a216f4f8b96245bde942d42d279527" - integrity sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg== +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - bn.js "^4.11.9" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" "@ethersproject/bignumber@^5.6.0": version "5.6.0" @@ -2679,12 +2679,12 @@ "@ethersproject/logger" "^5.6.0" bn.js "^4.11.9" -"@ethersproject/bytes@5.5.0", "@ethersproject/bytes@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" - integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== dependencies: - "@ethersproject/logger" "^5.5.0" + "@ethersproject/logger" "^5.7.0" "@ethersproject/bytes@^5.6.0": version "5.6.0" @@ -2693,12 +2693,12 @@ dependencies: "@ethersproject/logger" "^5.6.0" -"@ethersproject/constants@5.5.0", "@ethersproject/constants@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.5.0.tgz#d2a2cd7d94bd1d58377d1d66c4f53c9be4d0a45e" - integrity sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ== +"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== dependencies: - "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bignumber" "^5.7.0" "@ethersproject/constants@^5.6.0": version "5.6.0" @@ -2707,79 +2707,80 @@ dependencies: "@ethersproject/bignumber" "^5.6.0" -"@ethersproject/contracts@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.5.0.tgz#b735260d4bd61283a670a82d5275e2a38892c197" - integrity sha512-2viY7NzyvJkh+Ug17v7g3/IJC8HqZBDcOjYARZLdzRxrfGlRgmYgl6xPRKVbEzy1dWKw/iv7chDcS83pg6cLxg== - dependencies: - "@ethersproject/abi" "^5.5.0" - "@ethersproject/abstract-provider" "^5.5.0" - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - -"@ethersproject/hash@5.5.0", "@ethersproject/hash@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.5.0.tgz#7cee76d08f88d1873574c849e0207dcb32380cc9" - integrity sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg== - dependencies: - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/hdnode@5.5.0", "@ethersproject/hdnode@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.5.0.tgz#4a04e28f41c546f7c978528ea1575206a200ddf6" - integrity sha512-mcSOo9zeUg1L0CoJH7zmxwUG5ggQHU1UrRf8jyTYy6HxdZV+r0PBoL1bxr+JHIPXRzS6u/UW4mEn43y0tmyF8Q== - dependencies: - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/basex" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/pbkdf2" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/sha2" "^5.5.0" - "@ethersproject/signing-key" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/wordlists" "^5.5.0" - -"@ethersproject/json-wallets@5.5.0", "@ethersproject/json-wallets@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.5.0.tgz#dd522d4297e15bccc8e1427d247ec8376b60e325" - integrity sha512-9lA21XQnCdcS72xlBn1jfQdj2A1VUxZzOzi9UkNdnokNKke/9Ya2xA9aIK1SC3PQyBDLt4C+dfps7ULpkvKikQ== - dependencies: - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/hdnode" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/pbkdf2" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/random" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" aes-js "3.0.0" scrypt-js "3.0.1" -"@ethersproject/keccak256@5.5.0", "@ethersproject/keccak256@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.5.0.tgz#e4b1f9d7701da87c564ffe336f86dcee82983492" - integrity sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg== +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== dependencies: - "@ethersproject/bytes" "^5.5.0" + "@ethersproject/bytes" "^5.7.0" js-sha3 "0.8.0" "@ethersproject/keccak256@^5.6.0": @@ -2790,78 +2791,79 @@ "@ethersproject/bytes" "^5.6.0" js-sha3 "0.8.0" -"@ethersproject/logger@5.5.0", "@ethersproject/logger@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" - integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== +"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== "@ethersproject/logger@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== -"@ethersproject/networks@5.5.0", "@ethersproject/networks@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.5.0.tgz#babec47cab892c51f8dd652ce7f2e3e14283981a" - integrity sha512-KWfP3xOnJeF89Uf/FCJdV1a2aDJe5XTN2N52p4fcQ34QhDqQFkgQKZ39VGtiqUgHcLI8DfT0l9azC3KFTunqtA== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/pbkdf2@5.5.0", "@ethersproject/pbkdf2@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.5.0.tgz#e25032cdf02f31505d47afbf9c3e000d95c4a050" - integrity sha512-SaDvQFvXPnz1QGpzr6/HToLifftSXGoXrbpZ6BvoZhmx4bNLHrxDe8MZisuecyOziP1aVEwzC2Hasj+86TgWVg== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/sha2" "^5.5.0" - -"@ethersproject/properties@5.5.0", "@ethersproject/properties@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.5.0.tgz#61f00f2bb83376d2071baab02245f92070c59995" - integrity sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/providers@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.5.0.tgz#bc2876a8fe5e0053ed9828b1f3767ae46e43758b" - integrity sha512-xqMbDnS/FPy+J/9mBLKddzyLLAQFjrVff5g00efqxPzcAwXiR+SiCGVy6eJ5iAIirBOATjx7QLhDNPGV+AEQsw== - dependencies: - "@ethersproject/abstract-provider" "^5.5.0" - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/basex" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/hash" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/networks" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/random" "^5.5.0" - "@ethersproject/rlp" "^5.5.0" - "@ethersproject/sha2" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/web" "^5.5.0" +"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.2": + version "5.7.2" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" bech32 "1.1.4" ws "7.4.6" -"@ethersproject/random@5.5.0", "@ethersproject/random@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.5.0.tgz#305ed9e033ca537735365ac12eed88580b0f81f9" - integrity sha512-egGYZwZ/YIFKMHcoBUo8t3a8Hb/TKYX8BCBoLjudVCZh892welR3jOxgOmb48xznc9bTcMm7Tpwc1gHC1PFNFQ== +"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" -"@ethersproject/rlp@5.5.0", "@ethersproject/rlp@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.5.0.tgz#530f4f608f9ca9d4f89c24ab95db58ab56ab99a0" - integrity sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA== +"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" "@ethersproject/rlp@^5.6.0": version "5.6.0" @@ -2871,114 +2873,114 @@ "@ethersproject/bytes" "^5.6.0" "@ethersproject/logger" "^5.6.0" -"@ethersproject/sha2@5.5.0", "@ethersproject/sha2@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.5.0.tgz#a40a054c61f98fd9eee99af2c3cc6ff57ec24db7" - integrity sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA== +"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" hash.js "1.1.7" -"@ethersproject/signing-key@5.5.0", "@ethersproject/signing-key@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.5.0.tgz#2aa37169ce7e01e3e80f2c14325f624c29cedbe0" - integrity sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng== +"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - bn.js "^4.11.9" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" elliptic "6.5.4" hash.js "1.1.7" -"@ethersproject/solidity@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.5.0.tgz#2662eb3e5da471b85a20531e420054278362f93f" - integrity sha512-9NgZs9LhGMj6aCtHXhtmFQ4AN4sth5HuFXVvAQtzmm0jpSCNOTGtrHZJAeYTh7MBjRR8brylWZxBZR9zDStXbw== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/sha2" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/strings@5.5.0", "@ethersproject/strings@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.5.0.tgz#e6784d00ec6c57710755699003bc747e98c5d549" - integrity sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/transactions@5.5.0", "@ethersproject/transactions@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.5.0.tgz#7e9bf72e97bcdf69db34fe0d59e2f4203c7a2908" - integrity sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA== - dependencies: - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/rlp" "^5.5.0" - "@ethersproject/signing-key" "^5.5.0" - -"@ethersproject/units@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.5.0.tgz#104d02db5b5dc42cc672cc4587bafb87a95ee45e" - integrity sha512-7+DpjiZk4v6wrikj+TCyWWa9dXLNU73tSTa7n0TSJDxkYbV3Yf1eRh9ToMLlZtuctNYu9RDNNy2USq3AdqSbag== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/wallet@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.5.0.tgz#322a10527a440ece593980dca6182f17d54eae75" - integrity sha512-Mlu13hIctSYaZmUOo7r2PhNSd8eaMPVXe1wxrz4w4FCE4tDYBywDH+bAR1Xz2ADyXGwqYMwstzTrtUVIsKDO0Q== - dependencies: - "@ethersproject/abstract-provider" "^5.5.0" - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/hash" "^5.5.0" - "@ethersproject/hdnode" "^5.5.0" - "@ethersproject/json-wallets" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/random" "^5.5.0" - "@ethersproject/signing-key" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/wordlists" "^5.5.0" - -"@ethersproject/web@5.5.0", "@ethersproject/web@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.0.tgz#0e5bb21a2b58fb4960a705bfc6522a6acf461e28" - integrity sha512-BEgY0eL5oH4mAo37TNYVrFeHsIXLRxggCRG/ksRIxI2X5uj5IsjGmcNiRN/VirQOlBxcUhCgHhaDLG4m6XAVoA== - dependencies: - "@ethersproject/base64" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/wordlists@5.5.0", "@ethersproject/wordlists@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.5.0.tgz#aac74963aa43e643638e5172353d931b347d584f" - integrity sha512-bL0UTReWDiaQJJYOC9sh/XcRu/9i2jMrzf8VLRmPKx58ckSlOJiohODkECCO50dtLZHcGU6MLXQ4OOrgBwP77Q== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/hash" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" "@gnosis.pm/safe-core-sdk-types@^0.1.1": version "0.1.1" @@ -2986,19 +2988,21 @@ integrity sha512-PghXGDaI5Foq37nZGmI90U2OKMeGtxh5KqkDqou9aFHwGVa/nf9HRQPxG9/XUzcyfe9OlKttDlJnR3XnC3dSDw== "@gnosis.pm/safe-core-sdk@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@gnosis.pm/safe-core-sdk/-/safe-core-sdk-1.2.0.tgz#634c783394f697645d3ab4b0ba231b4798e8fc8c" - integrity sha512-ax/zFqjn+hWMiL1/JBTxWk8UU1HkX8Yh7pH2QNLuGN6Ysy1vVUfDDxMv89OKqSHbCLEGvYlM1yV3JbYGfhtifA== + version "1.3.0" + resolved "https://registry.yarnpkg.com/@gnosis.pm/safe-core-sdk/-/safe-core-sdk-1.3.0.tgz#ba21c6163c6a06e3fc51f5c7dac650e46fe8a779" + integrity sha512-laKkyJUv0llPPG5ep2+18v/anIEGi+KjarNoeVAutYzIeAAkSvvVbY8qyfczh5bWQkqvQ3K1l/QLUJ8Kx4hm3g== dependencies: "@gnosis.pm/safe-core-sdk-types" "^0.1.1" - "@gnosis.pm/safe-deployments" "^1.5.0" + "@gnosis.pm/safe-deployments" "^1.7.0" ethereumjs-util "^7.1.3" semver "^7.3.5" -"@gnosis.pm/safe-deployments@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@gnosis.pm/safe-deployments/-/safe-deployments-1.5.0.tgz#5e01ccc2e2d78bf91ecb4453a64d1cac3a5ba2d6" - integrity sha512-IDU7I+IQr1zUU94/uD8shDVI+/nUA1unQUg8jtbTG0YGcmm49Lu8G01rqtWt2mhLxZWzFsgbLWGnU+/BzUqk7g== +"@gnosis.pm/safe-deployments@^1.7.0": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@gnosis.pm/safe-deployments/-/safe-deployments-1.19.0.tgz#f4ba8cf92cd6fdff4241ac50e410b4a6ff89babe" + integrity sha512-EvHR/LjMwJm0QKXyTscRXqR9vnJwCUDiMnRNKRyXe1akW+udiYXjJTAiGuleFS4DOUSqs6DpAjYlLnXMzUsVMw== + dependencies: + semver "^7.3.7" "@graphql-codegen/add@^3.1.0": version "3.1.0" @@ -4080,9 +4084,9 @@ "@babel/types" "^7.3.0" "@types/bn.js@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68" - integrity sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA== + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" + integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== dependencies: "@types/node" "*" @@ -4957,19 +4961,19 @@ bl@^4.0.3, bl@^4.1.0: readable-stream "^3.4.0" blakejs@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.1.tgz#bf313053978b2cd4c444a48795710be05c785702" - integrity sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg== + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.1.2, bn.js@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== +bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== body-parser@1.19.0, body-parser@^1.19.0: version "1.19.0" @@ -5069,7 +5073,7 @@ bs-logger@0.x: bs58@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== dependencies: base-x "^3.0.2" @@ -5125,7 +5129,7 @@ buffer-from@^1.0.0: buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== buffer@^5.5.0, buffer@^5.7.0: version "5.7.1" @@ -5955,7 +5959,7 @@ elegant-spinner@^1.0.1: resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= -elliptic@6.5.4, elliptic@^6.5.2: +elliptic@6.5.4, elliptic@^6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -6115,9 +6119,9 @@ ethereum-cryptography@^0.1.3: setimmediate "^1.0.5" ethereumjs-util@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.3.tgz#b55d7b64dde3e3e45749e4c41288238edec32d23" - integrity sha512-y+82tEbyASO0K0X1/SRhbJJoAlfcvq8JbrG4a5cjrOks7HS/36efU/0j2flxCPOUM++HFahk33kr/ZxyC4vNuw== + version "7.1.5" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" + integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== dependencies: "@types/bn.js" "^5.1.0" bn.js "^5.1.2" @@ -6125,41 +6129,51 @@ ethereumjs-util@^7.1.3: ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethers@^5.5.1: - version "5.5.1" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.5.1.tgz#d3259a95a42557844aa543906c537106c0406fbf" - integrity sha512-RodEvUFZI+EmFcE6bwkuJqpCYHazdzeR1nMzg+YWQSmQEsNtfl1KHGfp/FWZYl48bI/g7cgBeP2IlPthjiVngw== - dependencies: - "@ethersproject/abi" "5.5.0" - "@ethersproject/abstract-provider" "5.5.1" - "@ethersproject/abstract-signer" "5.5.0" - "@ethersproject/address" "5.5.0" - "@ethersproject/base64" "5.5.0" - "@ethersproject/basex" "5.5.0" - "@ethersproject/bignumber" "5.5.0" - "@ethersproject/bytes" "5.5.0" - "@ethersproject/constants" "5.5.0" - "@ethersproject/contracts" "5.5.0" - "@ethersproject/hash" "5.5.0" - "@ethersproject/hdnode" "5.5.0" - "@ethersproject/json-wallets" "5.5.0" - "@ethersproject/keccak256" "5.5.0" - "@ethersproject/logger" "5.5.0" - "@ethersproject/networks" "5.5.0" - "@ethersproject/pbkdf2" "5.5.0" - "@ethersproject/properties" "5.5.0" - "@ethersproject/providers" "5.5.0" - "@ethersproject/random" "5.5.0" - "@ethersproject/rlp" "5.5.0" - "@ethersproject/sha2" "5.5.0" - "@ethersproject/signing-key" "5.5.0" - "@ethersproject/solidity" "5.5.0" - "@ethersproject/strings" "5.5.0" - "@ethersproject/transactions" "5.5.0" - "@ethersproject/units" "5.5.0" - "@ethersproject/wallet" "5.5.0" - "@ethersproject/web" "5.5.0" - "@ethersproject/wordlists" "5.5.0" +ethers-multicall-provider@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/ethers-multicall-provider/-/ethers-multicall-provider-3.0.4.tgz#68826e01a613bdc99531257027488c426f43ee4c" + integrity sha512-jTVpi7o7Ugv/wuSKjuUHLnNO+NA0Z4r0uOYlQ0mzvNKzh79bNU0FMvgnFLtTYPRQflIe70TTTzh9fv81bzboHw== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/providers" "^5.7.2" + ethers "^5.0.0" + lodash "^4.17.0" + +ethers@^5.0.0, ethers@^5.5.1: + version "5.7.2" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" event-target-shim@^5.0.0: version "5.0.1" @@ -8163,9 +8177,9 @@ jws@^4.0.0: safe-buffer "^5.0.1" keccak@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" - integrity sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ== + version "3.0.3" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.3.tgz#4bc35ad917be1ef54ff246f904c2bbbf9ac61276" + integrity sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ== dependencies: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" @@ -8345,7 +8359,7 @@ lodash.union@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= -lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0: +lodash@^4.17.0, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -8723,9 +8737,9 @@ node-forge@^1.3.1: integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== node-gyp-build@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" - integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== + version "4.6.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== node-int64@^0.4.0: version "0.4.0" @@ -9558,11 +9572,11 @@ scuid@^1.1.0: integrity sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg== secp256k1@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.2.tgz#15dd57d0f0b9fdb54ac1fa1694f40e5e9a54f4a1" - integrity sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg== + version "4.0.3" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" + integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== dependencies: - elliptic "^6.5.2" + elliptic "^6.5.4" node-addon-api "^2.0.0" node-gyp-build "^4.2.0" @@ -9590,6 +9604,13 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.7: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" From 65211ed24d10a52b06e149a91c1e00ad5a3d08fe Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Fri, 7 Jul 2023 23:08:18 -0300 Subject: [PATCH 05/42] Changing apr type if pool type is linear; --- modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 30a8dce7d..4e9baa28a 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -32,7 +32,7 @@ export class IbTokensAprService implements PoolAprService { title: `${ token.token.symbol || token.address } APR`, apr: aprs.get(token.address) ?? 0, group: null, - type: 'IB_YIELD', + type: pool.type==='LINEAR'? 'LINEAR_BOOSTED':'IB_YIELD', }, update: { title: `${ token.token.symbol || token.address } APR`, apr: aprs.get(token.address) }, })); } From 304988ebc75eaa0b5f10849f1f5f13aa16df76fa Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Fri, 7 Jul 2023 23:15:05 -0300 Subject: [PATCH 06/42] removing viem --- package.json | 1 - yarn.lock | 79 ---------------------------------------------------- 2 files changed, 80 deletions(-) diff --git a/package.json b/package.json index d24a3d4e8..599598695 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,6 @@ "stellate": "^1.15.2", "ts-dotenv": "^0.8.1", "uuid": "^8.3.2", - "viem": "^1.2.9", "yarn": "^1.22.19" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 05330769a..e6bb59dc4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@adraffy/ens-normalize@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz#223572538f6bea336750039bb43a4016dcc8182d" - integrity sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ== - "@ampproject/remapping@^2.1.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" @@ -3725,23 +3720,6 @@ resolved "https://registry.yarnpkg.com/@n1ru4l/graphql-live-query/-/graphql-live-query-0.9.0.tgz#defaebdd31f625bee49e6745934f36312532b2bc" integrity sha512-BTpWy1e+FxN82RnLz4x1+JcEewVdfmUhV1C6/XYD5AjS7PQp9QFF7K8bCD6gzPTr2l+prvqOyVueQhFJxB1vfg== -"@noble/curves@1.0.0", "@noble/curves@~1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.0.0.tgz#e40be8c7daf088aaf291887cbc73f43464a92932" - integrity sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw== - dependencies: - "@noble/hashes" "1.3.0" - -"@noble/hashes@1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1" - integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg== - -"@noble/hashes@~1.3.0": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" - integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -3889,28 +3867,6 @@ resolved "https://registry.yarnpkg.com/@sanity/timed-out/-/timed-out-4.0.2.tgz#c9f61f9a1609baa1eb3e4235a24ea2a775022cdf" integrity sha512-NBDKGj14g9Z+bopIvZcQKWCzJq5JSrdmzRR1CS+iyA3Gm8SnIWBfZa7I3mTg2X6Nu8LQXG0EPKXdOGozLS4i3w== -"@scure/base@~1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" - integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== - -"@scure/bip32@1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.0.tgz#6c8d980ef3f290987736acd0ee2e0f0d50068d87" - integrity sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q== - dependencies: - "@noble/curves" "~1.0.0" - "@noble/hashes" "~1.3.0" - "@scure/base" "~1.1.0" - -"@scure/bip39@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.0.tgz#a207e2ef96de354de7d0002292ba1503538fc77b" - integrity sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg== - dependencies: - "@noble/hashes" "~1.3.0" - "@scure/base" "~1.1.0" - "@sentry-internal/tracing@7.56.0": version "7.56.0" resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.56.0.tgz#ba709258f2f0f3d8a36f9740403088b39212b843" @@ -4444,11 +4400,6 @@ dependencies: "@types/yargs-parser" "*" -"@wagmi/chains@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.2.0.tgz#d59eaa70ec51a5fdcd113975926992acfb17ab12" - integrity sha512-dmDRipsE54JfyudOBkuhEexqQWcrZqxn/qiujG8SBzMh/az/AH5xlJSA+j1CPWTx9+QofSMF3B7A4gb6XRmSaQ== - "@xmldom/xmldom@^0.7.5": version "0.7.5" resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d" @@ -4464,11 +4415,6 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abitype@0.8.11: - version "0.8.11" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.8.11.tgz#66e1cf2cbf46f48d0e57132d7c1c392447536cc1" - integrity sha512-bM4v2dKvX08sZ9IU38IN5BKmN+ZkOSd2oI4a9f0ejHYZQYV6cDr7j+d95ga0z2XHG36Y4jzoG5Z7qDqxp7fi/A== - abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -7558,11 +7504,6 @@ isomorphic-ws@4.0.1: resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== -isomorphic-ws@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" - integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== - istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" @@ -10498,21 +10439,6 @@ vary@^1, vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -viem@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/viem/-/viem-1.2.9.tgz#8ccf786cd00d28b14b644f2b9fe35fc6bf2bdc41" - integrity sha512-EnEbTuAAHv43unUgMISdQXbD9mrhZLvOdmf6eRGbDFl+XwP/PEzZAT79RaWAuDPnLXGMP1gBCJF++NFjSMukUw== - dependencies: - "@adraffy/ens-normalize" "1.9.0" - "@noble/curves" "1.0.0" - "@noble/hashes" "1.3.0" - "@scure/bip32" "1.3.0" - "@scure/bip39" "1.2.0" - "@wagmi/chains" "1.2.0" - abitype "0.8.11" - isomorphic-ws "5.0.0" - ws "8.12.0" - walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" @@ -10650,11 +10576,6 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== -ws@8.12.0: - version "8.12.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.0.tgz#485074cc392689da78e1828a9ff23585e06cddd8" - integrity sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig== - ws@8.2.3: version "8.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" From 11cd51921bab4e070289918a94099bfa71439b5a Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Thu, 13 Jul 2023 17:49:20 -0300 Subject: [PATCH 07/42] Fixing Ovix APR; --- modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts | 2 +- modules/token/lib/token-apr-handler/sources/ovix.ts | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 51808034a..d3eab8463 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -53,7 +53,7 @@ export class IbTokensAprService implements PoolAprService { private async fetchYieldTokensApr(): Promise> { const data = await fetchAllAprs() - return new Map(data.map((apr) => [apr.address, apr])); + return new Map(data.filter((apr)=>!isNaN(apr.val)).map((apr) => [apr.address, apr])); } } \ No newline at end of file diff --git a/modules/token/lib/token-apr-handler/sources/ovix.ts b/modules/token/lib/token-apr-handler/sources/ovix.ts index a4b2e61a0..e84bbeb0b 100644 --- a/modules/token/lib/token-apr-handler/sources/ovix.ts +++ b/modules/token/lib/token-apr-handler/sources/ovix.ts @@ -1,5 +1,5 @@ import { abi } from './abis/oErc20' -import { Contract } from "ethers"; +import { BigNumber, Contract } from "ethers"; import { ethers } from "ethers"; import { MulticallWrapper } from "ethers-multicall-provider"; import { JsonRpcProvider } from "@ethersproject/providers"; @@ -34,12 +34,10 @@ const getBorrowRates = () => { export const ovix = async () => { try { const borrowRates = await getBorrowRates() - const aprs = Object.keys(wrappedTokens).map((coin, i) => [ wrappedTokens[coin], - Math.round(10000 * (Math.pow(1 + Number(borrowRates[i].result) / 1e18, 365 * 24 * 60 * 60) - 1)) + Math.round(10000 * (Math.pow(1 + (borrowRates[i] as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1)) ]) - return Object.fromEntries(aprs) } catch (error) { console.log(error) From a1a20ddc5994337d6142fd23f6c3854c71187e76 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Fri, 28 Jul 2023 01:01:24 -0300 Subject: [PATCH 08/42] Redesigning Ib Apr Handlers to be more scalable and open to new networks, tokens and urls; --- modules/balancer/loadRestRoutes.ts | 16 + modules/network/mainnet.ts | 6 +- .../apr-data-sources/ib-tokens-apr.service.ts | 18 +- .../ib-yield-apr-handlers.ts | 28 ++ .../sources/aave/aave-apr-handler.ts | 102 ++++++ .../sources/aave/tokens.ts | 90 +++++ .../sources/aave/types.ts | 10 + .../sources/abis/oErc20.ts | 0 .../sources/abis/reaperStrategy.ts | 0 .../sources/abis/tesseraPool.ts | 0 .../sources/ankr/ankr-apr-handler.ts | 36 ++ .../default-fetch/default-apr-handler.ts | 78 +++++ .../sources/default-fetch/tokens.ts | 35 ++ .../sources/euler/euler-apr-handler.ts | 58 ++++ .../sources/euler/tokens.ts | 7 + .../sources/euler/types.ts | 10 + .../sources/gearbox/gearbox-apr-handler.ts | 37 ++ .../sources/gearbox/tokens.ts | 4 + .../sources/idle/idle-apr-handler.ts | 55 +++ .../sources/idle/tokens.ts | 11 + .../ib-yield-apr-handlers/sources/index.ts | 50 +++ .../overnight/overnight-apr-handler.ts | 32 ++ .../sources/overnight/tokens.ts | 5 + .../sources/ovix/ovix-apr-handler.ts | 47 +++ .../sources/ovix/tokens.ts | 9 + .../sources/reaper/reaper-apr-handler.ts | 47 +++ .../sources/reaper/tokens.ts | 11 + .../sources/tessera/tessera-apr-handler.ts | 48 +++ .../sources/tessera/tokens.ts | 4 + .../sources/tetu/tetu-apr-handler.ts | 30 ++ .../tranchess/tranchess-apr-handler.ts | 33 ++ .../ib-yield-apr-handlers/types.ts | 10 + modules/pool/pool.prisma | 1 + .../token/lib/token-apr-handler/fetch-all.ts | 16 - .../lib/token-apr-handler/sources/aave.ts | 317 ------------------ .../lib/token-apr-handler/sources/ankr.ts | 16 - .../lib/token-apr-handler/sources/default.ts | 23 -- .../lib/token-apr-handler/sources/euler.ts | 60 ---- .../lib/token-apr-handler/sources/gearbox.ts | 26 -- .../lib/token-apr-handler/sources/idle.ts | 22 -- .../lib/token-apr-handler/sources/index.ts | 14 - .../token-apr-handler/sources/overnight.ts | 17 - .../lib/token-apr-handler/sources/ovix.ts | 46 --- .../lib/token-apr-handler/sources/reaper.ts | 50 --- .../lib/token-apr-handler/sources/tessera.ts | 42 --- .../lib/token-apr-handler/sources/tetu.ts | 9 - .../token-apr-handler/sources/tranchess.ts | 11 - modules/token/lib/token-apr-handler/tokens.ts | 116 ------- modules/token/lib/token-apr-handler/types.ts | 6 - 49 files changed, 919 insertions(+), 800 deletions(-) create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts rename modules/{token/lib/token-apr-handler => pool/lib/apr-data-sources/ib-yield-apr-handlers}/sources/abis/oErc20.ts (100%) rename modules/{token/lib/token-apr-handler => pool/lib/apr-data-sources/ib-yield-apr-handlers}/sources/abis/reaperStrategy.ts (100%) rename modules/{token/lib/token-apr-handler => pool/lib/apr-data-sources/ib-yield-apr-handlers}/sources/abis/tesseraPool.ts (100%) create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/tokens.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/tokens.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tokens.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts delete mode 100644 modules/token/lib/token-apr-handler/fetch-all.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/aave.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/ankr.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/default.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/euler.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/gearbox.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/idle.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/index.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/overnight.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/ovix.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/reaper.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/tessera.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/tetu.ts delete mode 100644 modules/token/lib/token-apr-handler/sources/tranchess.ts delete mode 100644 modules/token/lib/token-apr-handler/tokens.ts delete mode 100644 modules/token/lib/token-apr-handler/types.ts diff --git a/modules/balancer/loadRestRoutes.ts b/modules/balancer/loadRestRoutes.ts index aad0efca7..0eba79946 100644 --- a/modules/balancer/loadRestRoutes.ts +++ b/modules/balancer/loadRestRoutes.ts @@ -1,5 +1,21 @@ import { Express } from 'express'; +import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; +import { networkContext } from "../network/network-context.service"; +import { prismaPoolWithExpandedNesting } from "../../prisma/prisma-types"; +import { prisma } from "../../prisma/prisma-client"; +import { ibYieldAprHandlers } from "../pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers"; export function loadRestRoutesBalancer(app: Express) { app.use('/health', (req, res) => res.sendStatus(200)); + app.use('/test', async (req, res) => { + const pools = await prisma.prismaPool.findMany({ + ...prismaPoolWithExpandedNesting, + where: { chain: networkContext.chain }, + }); + const ibTokensAprService = new IbTokensAprService(ibYieldAprHandlers); + await ibTokensAprService.updateAprForPools(pools); + + return res.sendStatus(200) + }); + } diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 839914431..9d7fa9189 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -18,7 +18,9 @@ import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; -import { networkContext } from "./network-context.service"; +import { + ibYieldAprHandlers +} from "../pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers"; const mainnetNetworkData: NetworkData = { chain: { @@ -159,7 +161,7 @@ export const mainnetNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(mainnetNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(), + new IbTokensAprService(ibYieldAprHandlers), new WstethAprService(tokenService, mainnetNetworkData.lido!.wstEthContract), new ReaperCryptAprService( mainnetNetworkData.reaper.linearPoolFactories, diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index d3eab8463..dd91ee864 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -3,12 +3,14 @@ import { PrismaPoolWithExpandedNesting } from "../../../../prisma/prisma-types"; import { prisma } from "../../../../prisma/prisma-client"; import { networkContext } from "../../../network/network-context.service"; import { prismaBulkExecuteOperations } from "../../../../prisma/prisma-util"; -import { fetchAllAprs } from "../../../token/lib/token-apr-handler/fetch-all"; -import { TokenApr } from "../../../token/lib/token-apr-handler/types"; import { PrismaPoolAprItemGroup } from "@prisma/client"; +import { TokenApr } from "./ib-yield-apr-handlers/types"; +import { IbYieldAprHandlers } from "./ib-yield-apr-handlers/ib-yield-apr-handlers"; export class IbTokensAprService implements PoolAprService { + constructor(private readonly ibYieldAprHandlers: IbYieldAprHandlers) {} + getAprServiceName(): string { return "IbTokensAprService"; } @@ -25,16 +27,16 @@ export class IbTokensAprService implements PoolAprService { for (const pool of tokenYieldPools) { for (const token of pool.tokens) { if ((aprs.get(token.address) !== undefined)) { - const tokenSymbol = token.token.symbol ?? (aprs.get(token.address)).name + const tokenSymbol = token.token.symbol; const itemId = `${ pool.id }-${ tokenSymbol }-yield-apr` - + operations.push(prisma.prismaPoolAprItem.upsert({ where: { id_chain: { id: itemId, chain: networkContext.chain } }, create: { id: itemId, chain: networkContext.chain, poolId: pool.id, - title: `${ tokenSymbol} APR`, + title: `${ tokenSymbol } APR`, apr: aprs.get(token.address)?.val ?? 0, group: (aprs.get(token.address)?.group as PrismaPoolAprItemGroup) ?? null, type: pool.type === 'LINEAR' ? 'LINEAR_BOOSTED' : 'IB_YIELD', @@ -52,8 +54,10 @@ export class IbTokensAprService implements PoolAprService { } private async fetchYieldTokensApr(): Promise> { - const data = await fetchAllAprs() - return new Map(data.filter((apr)=>!isNaN(apr.val)).map((apr) => [apr.address, apr])); + const data = await this.ibYieldAprHandlers.getHandlersAprs() + return new Map( + data.filter((apr) => !isNaN(apr.val)).map((apr) => [apr.address, apr]) + ); } } \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts new file mode 100644 index 000000000..6b3faf32a --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts @@ -0,0 +1,28 @@ +import { AprHandler, TokenApr } from "./types"; +import { aprHandlers } from "./sources"; + +export class IbYieldAprHandlers { + + private handlers: AprHandler[] = []; + constructor(handlers: AprHandler[]) { + this.handlers = handlers; + } + + getHandlersAprs = async (): Promise => { + const aprPromises = this.handlers.map(async (handler) => { + const fetchedResponse: { [key: string]: number } = await handler.getAprs() + return Object.entries(fetchedResponse).map(([address, aprValue]) => ({ + val: aprValue, + group: handler.group, + address + })) + }); + const res = Array(this.handlers.length) + for (const [index, aprPromise] of aprPromises.entries()) { + res[index] = await aprPromise + } + return res.flat(); + } +} + +export const ibYieldAprHandlers = new IbYieldAprHandlers(aprHandlers); \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts new file mode 100644 index 000000000..9091e1eba --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts @@ -0,0 +1,102 @@ +import axios from "axios"; +import { ReserveResponse } from "./types"; +import { + aaveTokensV2Mainnet, + aaveTokensV2Polygon, + aaveTokensV3Arbitrum, + aaveTokensV3Mainnet, + aaveTokensV3Polygon, underlyingTokensArbitrum, + underlyingTokensMainnet, + underlyingTokensPolygon, + wrappedAaveTokensV2Mainnet, + wrappedAaveTokensV2Polygon, + wrappedAaveTokensV3Arbitrum, + wrappedAaveTokensV3Mainnet, + wrappedAaveTokensV3Polygon +} from "./tokens"; + +class AaveAprHandler { + + wrappedTokens: Map + aaveTokens: Map + underlyingTokens: Map + subgraphUrl: string + + readonly group = 'AAVE'; + + readonly query = `query getReserves($aTokens: [String!], $underlyingAssets: [Bytes!]) { + reserves( + where: { + aToken_in: $aTokens + underlyingAsset_in: $underlyingAssets + isActive: true + } + ) { + id + underlyingAsset + liquidityRate + } + }` + + constructor(wrappedTokens: Map, + aaveTokens: Map, + underlyingTokens: Map, + subgraphUrl: string + ) { + this.wrappedTokens = wrappedTokens + this.aaveTokens = aaveTokens + this.underlyingTokens = underlyingTokens + this.subgraphUrl = subgraphUrl + } + + async getAprs() { + try { + const requestQuery = { + operationName: 'getReserves', + query: this.query, + variables: { + aTokens: Array.from(this.aaveTokens.values()), + underlyingAssets: Array.from(this.underlyingTokens.values()), + }, + } + const { data } = await axios({ + url: this.subgraphUrl, + method: "post", + data: requestQuery, + headers: { "Content-Type": "application/json" } + }) + const { + data: { reserves }, + } = data as ReserveResponse + + const aprsByUnderlyingAddress = Object.fromEntries(reserves.map((r) => [ + r.underlyingAsset, + // Note: our assumption is frontend usage, this service is not a good source where more accuracy is needed. + // Converting from aave ray number (27 digits) to bsp + // essentially same as here: + // https://github.com/aave/aave-utilities/blob/master/packages/math-utils/src/formatters/reserve/index.ts#L231 + Number(r.liquidityRate.slice(0, 27)) / 1e27, + ])) + const aprEntries = Object.fromEntries( + Array.from(this.underlyingTokens.entries()) + //Removing undefined aprs + .filter(([, address]) => !!aprsByUnderlyingAddress[address]) + //Mapping aprs by wrapped instead of underlying addresses + .map(([underlyingTokenName, underlyingTokenAddress]) => [ + this.wrappedTokens.get('wa' + underlyingTokenName) as string, + aprsByUnderlyingAddress[underlyingTokenAddress], + ])) + return aprEntries; + } catch (e) { + console.error(`Failed to fetch Aave APR in subgraph ${ this.subgraphUrl }:`, e) + return {} + } + } +} + +export const aaveV2MainnetAprHandler = new AaveAprHandler(wrappedAaveTokensV2Mainnet, aaveTokensV2Mainnet, underlyingTokensMainnet, 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2') +export const aaveV2PolygonAprHandler = new AaveAprHandler(wrappedAaveTokensV2Polygon, aaveTokensV2Polygon, underlyingTokensPolygon, 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic') +export const aaveV3MainnetAprHandler = new AaveAprHandler(wrappedAaveTokensV3Mainnet, aaveTokensV3Mainnet, underlyingTokensMainnet, 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3') +export const aaveV3PolygonAprHandler = new AaveAprHandler(wrappedAaveTokensV3Polygon, aaveTokensV3Polygon, underlyingTokensPolygon, 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon'); +export const aaveV3ArbitrumAprHandler = new AaveAprHandler(wrappedAaveTokensV3Arbitrum, aaveTokensV3Arbitrum, underlyingTokensArbitrum, 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum') + diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts new file mode 100644 index 000000000..860d876e2 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts @@ -0,0 +1,90 @@ +export const wrappedAaveTokensV2Mainnet = new Map(Object.entries({ + waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', + waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', + waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', +})); + +export const aaveTokensV2Mainnet = new Map(Object.entries({ + aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', + aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c', + aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', +})); + +export const wrappedAaveTokensV2Polygon = new Map(Object.entries({ + waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', + waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', + waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', +})); + +export const aaveTokensV2Polygon = new Map(Object.entries({ + aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', + aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', + aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', +})); + +export const wrappedAaveTokensV3Mainnet = new Map(Object.entries({ + waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', + waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', + waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', + waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', +})); + +export const aaveTokensV3Mainnet = new Map(Object.entries({ + aUSDT: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', + aUSDC: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', + aDAI: '0x018008bfb33d285247a21d44e50697654f754e63', + aWETH: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8' +})); + + +export const wrappedAaveTokensV3Polygon = new Map(Object.entries({ + waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', + waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', + waUSDC: '0x9719d867a500ef117cc201206b8ab51e794d3f82', + waDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', +})); + +export const aaveTokensV3Polygon = new Map(Object.entries({ + aMATIC: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', + aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', + aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', + aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', +})); + + +export const wrappedAaveTokensV3Arbitrum = new Map(Object.entries({ + waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', + waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', + waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', + waWETH: '0x18c100415988bef4354effad1188d1c22041b046' +})); + +export const aaveTokensV3Arbitrum = new Map(Object.entries({ + aUSDT: '0x6ab707aca953edaefbc4fd23ba73294241490620', + aUSDC: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', + aDAI: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', + aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', +})); +export const underlyingTokensMainnet = new Map(Object.entries({ + USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', + USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', + WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' +})); +export const underlyingTokensPolygon = new Map(Object.entries({ + MATIC: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', + USDT: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + DAI: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + WETH: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619' +})); + +export const underlyingTokensArbitrum = new Map(Object.entries({ + USDT: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + USDC: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', + DAI: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + WETH: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', +})); + diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts new file mode 100644 index 000000000..23d86d1fa --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts @@ -0,0 +1,10 @@ +export interface ReserveResponse { + data: { + reserves: [ + { + underlyingAsset: string + liquidityRate: string + } + ] + } +} \ No newline at end of file diff --git a/modules/token/lib/token-apr-handler/sources/abis/oErc20.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/oErc20.ts similarity index 100% rename from modules/token/lib/token-apr-handler/sources/abis/oErc20.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/oErc20.ts diff --git a/modules/token/lib/token-apr-handler/sources/abis/reaperStrategy.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/reaperStrategy.ts similarity index 100% rename from modules/token/lib/token-apr-handler/sources/abis/reaperStrategy.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/reaperStrategy.ts diff --git a/modules/token/lib/token-apr-handler/sources/abis/tesseraPool.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/tesseraPool.ts similarity index 100% rename from modules/token/lib/token-apr-handler/sources/abis/tesseraPool.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/tesseraPool.ts diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts new file mode 100644 index 000000000..8f05f23aa --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts @@ -0,0 +1,36 @@ +import axios from "axios"; + +const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb' + +class AnkrAprHandler { + serviceName: string + tokenAddress: string + readonly url: string = 'https://api.staking.ankr.com/v1alpha/metrics'; + readonly group = 'ANKR'; + + constructor(serviceName: string, tokenAddress: string) { + this.serviceName = serviceName + this.tokenAddress = tokenAddress + } + + async getAprs() { + try { + + const { data } = await axios.get(this.url) + const json = data as { services: { serviceName: string; apy: string }[] } + const service = json.services.find((service) => service.serviceName === this.serviceName) + if (!service) { + return {} + } + const scaledValue = parseFloat(service.apy) / 1e2 + return { + [this.tokenAddress]: scaledValue + } + } catch (error) { + console.error('Failed to fetch Ankr APR:', error) + return {} + } + } +} + +export const ankrEthMainnetAprHandler = new AnkrAprHandler('eth', ankrEthMainnet); \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts new file mode 100644 index 000000000..c7600cb80 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts @@ -0,0 +1,78 @@ +import axios from "axios"; +import { + cbETHMainnet, MATICXMainnet, rETHMainnet, sfrxETHMainnet, + stETHMainnet, stMATICPolygon, swETHMainnet, USDRMainnet, + vETHMainnet, wbETHMainnet, + wstETHArbitrum, + wstETHGnosis, + wstETHMainnet, + wstETHPolygon, + wstETHZkEVM +} from "./tokens"; + +class DefaultAprHandler { + + tokens: string[]; + url: string; + path: string; + scale: number; + readonly group = undefined; + + constructor(tokens: string[], url:string, path?:string, scale?:number){ + this.tokens = tokens; + this.url = url; + this.path = path ?? ''; + this.scale = scale ?? 100; + } + + async getAprs() { + try{ + + const { data } = await axios.get(this.url, { headers: { 'User-Agent': 'cf' } }) + const value = (this.path === '') ? data : this.getValueFromPath(data, this.path) + const scaledValue = parseFloat(value) / this.scale + + return this.tokens.reduce((acc, token) => { + acc[token] = scaledValue + return acc + }, {} as { [key: string]: number }) + } catch (error) { + console.error(`Failed to fetch APRs in url ${this.url}}:`, error) + return {} + } + } + + getValueFromPath = (obj: any, path: string) => { + const parts = path.split('.') + let value = obj + for (const part of parts) { + value = value[part] + } + return value + } + +} + +export const vETHAprHandler = new DefaultAprHandler([vETHMainnet], 'https://apy.liebi.com/veth', 'veth') +export const stETHAprHandler = new DefaultAprHandler([ + wstETHPolygon, + wstETHZkEVM, + wstETHGnosis, + stETHMainnet, + wstETHMainnet, + wstETHArbitrum +], + 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + 'data.smaApr') + +export const stMaticAprHandler = new DefaultAprHandler([stMATICPolygon], 'https://polygon.lido.fi/api/stats', 'apr') +export const cbEthAprHandler = new DefaultAprHandler([cbETHMainnet], 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', 'apy', 1) +export const sfrxEthAprHandler = new DefaultAprHandler([sfrxETHMainnet], 'https://api.frax.finance/v2/frxeth/summary/latest', 'sfrxethApr') +export const rETHAprHandler = new DefaultAprHandler([rETHMainnet], 'https://drop-api.stafi.io/reth/v1/poolData', 'data.stakeApr') +export const USDRAprHandler = new DefaultAprHandler([USDRMainnet], 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', 'usdr') + +export const MATICXAprHandler = new DefaultAprHandler([MATICXMainnet], 'https://universe.staderlabs.com/polygon/apy', 'value') +export const wbETHAprHandler = new DefaultAprHandler([wbETHMainnet], 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', 'data.0.rewardRate', 1); + +export const swETHAprHandler = new DefaultAprHandler([swETHMainnet], 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr') +export const wjAURAAprHandler = new DefaultAprHandler([swETHMainnet], 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', 'wjauraApy') \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts new file mode 100644 index 000000000..5d5fc68ef --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts @@ -0,0 +1,35 @@ +const vETHMainnet = '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f' +const wstETHGnosis = '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6'; +const wstETHZkEVM = '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9' +const stETHMainnet = '0xae7ab96520de3a18e5e111b5eaab095312d7fe84' +const wstETHMainnet = '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0' +const wstETHPolygon = '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd' +const wstETHArbitrum = '0x5979d7b546e38e414f7e9822514be443a4800529'; +const stMATICPolygon = '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'; +const cbETHMainnet = '0xbe9895146f7af43049ca1c1ae358b0541ea49704'; +const sfrxETHMainnet = '0xac3e018457b222d93114458476f3e3416abbe38f'; +const rETHMainnet = '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'; +const USDRMainnet = '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'; +const MATICXMainnet = '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'; +const wbETHMainnet = '0xa2e3356610840701bdf5611a53974510ae27e2e1'; +const swETHMainnet = '0xf951e335afb289353dc249e82926178eac7ded78'; +const wjAURAMainnet = '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'; + +export { + vETHMainnet, + wstETHGnosis, + wstETHZkEVM, + stETHMainnet, + wstETHMainnet, + wstETHPolygon, + wstETHArbitrum, + stMATICPolygon, + cbETHMainnet, + sfrxETHMainnet, + rETHMainnet, + USDRMainnet, + MATICXMainnet, + wbETHMainnet, + swETHMainnet, + wjAURAMainnet +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts new file mode 100644 index 000000000..c0f12621a --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts @@ -0,0 +1,58 @@ +import axios from "axios"; +import { EulerResponse } from "./types"; +import { eulerTokensMainnet } from "./tokens"; +import { AprHandler } from "../../types"; + +class EulerAprHandler implements AprHandler { + tokens: Map + subgraphUrl: string + readonly group = 'EULER'; + + readonly query = ` + query getAssetsAPY($eTokenAddress_in: [String!]) { + assets( + where: { + eTokenAddress_in: $eTokenAddress_in + } + ) { + eTokenAddress + supplyAPY + } + } +` + + constructor(tokens: Map, subgraphUrl: string) { + this.tokens = tokens + this.subgraphUrl = subgraphUrl + } + + async getAprs() { + const requestQuery = { + operationName: 'getAssetsAPY', + query: this.query, + variables: { + eTokenAddress_in: Array.from(this.tokens.values()), + }, + } + + const { data } = await axios({ + url: this.subgraphUrl, + method: 'POST', + data: JSON.stringify(requestQuery) + }) + + const { + data: { assets }, + } = data as EulerResponse + + const aprEntries = assets.map(({ eTokenAddress, supplyAPY }) => [ + eTokenAddress, + // supplyAPY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 + Number(supplyAPY.slice(0, 27)) / 1e27 + ]) + + return Object.fromEntries(aprEntries) + } +} + +export const eulerMainnetAprHandler = new EulerAprHandler(eulerTokensMainnet, 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet'); \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts new file mode 100644 index 000000000..92f2326d3 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts @@ -0,0 +1,7 @@ +export const eulerTokensMainnet = new Map(Object.entries( + { + eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', + eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', + eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', + eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', + })) \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts new file mode 100644 index 000000000..eab65cf8a --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts @@ -0,0 +1,10 @@ +export interface EulerResponse { + data: { + assets: [ + { + eTokenAddress: string + supplyAPY: string + } + ] + } +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts new file mode 100644 index 000000000..e92ea3ad0 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts @@ -0,0 +1,37 @@ +import axios from "axios"; +import { gearboxTokensMainnet } from "./tokens"; +import { AprHandler } from "../../types"; + +class GearboxAprHandler implements AprHandler { + url: string; + tokens: Map; + readonly group = 'GEARBOX'; + + constructor(tokens: Map, url: string,) { + this.tokens = tokens; + this.url = url; + } + + async getAprs() { + try { + + const { data } = await axios.get(this.url) + const json = data as { data: { dieselToken: string; depositAPY_RAY: string }[] } + + const aprEntries = json.data + .filter((t) => Array.from(this.tokens.values()).includes(t.dieselToken.toLowerCase())) + .map((({ dieselToken, depositAPY_RAY }) => { + return [dieselToken, Number(depositAPY_RAY.slice(0, 27)) / 1e27] + })) + return Object.fromEntries(aprEntries); + } catch (error) { + console.error('Failed to fetch Gearbox APR:', error) + return {} + } + } +} + +export const gearboxMainnetAprHandler = new GearboxAprHandler( + gearboxTokensMainnet, + 'https://mainnet.gearbox.foundation/api/pools' +) \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts new file mode 100644 index 000000000..7c23d878f --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts @@ -0,0 +1,4 @@ +export const gearboxTokensMainnet = new Map(Object.entries({ + dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', + dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', +})); \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts new file mode 100644 index 000000000..b05bde775 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts @@ -0,0 +1,55 @@ +import axios from "axios"; +import { idleTokensMainnet, wrapped4626IdleTokensMainnet } from "./tokens"; +import { AprHandler } from "../../types"; + +class IdleAprHandler implements AprHandler { + wrappedIdleTokens: Map; + idleTokens: Map + baseIdleApiUrl: string; + authorizationHeader: string; + readonly group = 'IDLE'; + + constructor(wrappedIdleTokens: Map, + idleTokens: Map, + baseIdleApiUrl: string, + authorizationHeader: string) { + this.wrappedIdleTokens = wrappedIdleTokens; + this.idleTokens = idleTokens; + this.baseIdleApiUrl = baseIdleApiUrl; + this.authorizationHeader = authorizationHeader; + } + + async getAprs() { + try { + + const aprPromises = Array.from(this.idleTokens.entries()).map(async ([tokenName, idleTokenAddress]) => { + const { data } = await axios.get([this.baseIdleApiUrl, idleTokenAddress, "?isRisk=false&order=desc&limit=1"].join(''), { + headers: { + Authorization: this.authorizationHeader, + }, + }) + const [json] = data as { idleRate: string }[] + const value = Number(json.idleRate) / 1e20 + return [ + this.wrappedIdleTokens.get(tokenName), + value, + ] + }) + const res = Array(this.idleTokens.size) + for (const [index, aprPromise] of aprPromises.entries()) { + res[index] = await aprPromise + } + return Object.fromEntries(res); + } catch (error) { + console.error('Failed to fetch Idle APR:', error) + return {} + } + } +} + +export const idleMainnetAprHandler = new IdleAprHandler( + wrapped4626IdleTokensMainnet, + idleTokensMainnet, + 'https://api.idle.finance/junior-rates/', + 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M' +); \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts new file mode 100644 index 000000000..ec49dffde --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts @@ -0,0 +1,11 @@ +export const wrapped4626IdleTokensMainnet = new Map(Object.entries({ + idleDAI: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', + idleUSDC: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', + idleUSDT: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', +})) + +export const idleTokensMainnet = new Map(Object.entries({ + idleDAI: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', + idleUSDC: '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', + idleUSDT: '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', +})) \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts new file mode 100644 index 000000000..fc02fe07d --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts @@ -0,0 +1,50 @@ +import { + aaveV2MainnetAprHandler, + aaveV2PolygonAprHandler, aaveV3ArbitrumAprHandler, + aaveV3MainnetAprHandler, + aaveV3PolygonAprHandler +} from "./aave/aave-apr-handler"; +import { ankrEthMainnetAprHandler } from "./ankr/ankr-apr-handler"; +import { + cbEthAprHandler, MATICXAprHandler, + rETHAprHandler, + sfrxEthAprHandler, + stMaticAprHandler, swETHAprHandler, USDRAprHandler, wbETHAprHandler, wjAURAAprHandler +} from "./default-fetch/default-apr-handler"; +import { eulerMainnetAprHandler } from "./euler/euler-apr-handler"; +import { gearboxMainnetAprHandler } from "./gearbox/gearbox-apr-handler"; +import { idleMainnetAprHandler } from "./idle/idle-apr-handler"; +import { overnightMainnetAprHandler } from "./overnight/overnight-apr-handler"; +import { AprHandler } from "../types"; +import { ovixZkEVMAprHandler } from "./ovix/ovix-apr-handler"; +import { reaperArbitrumAprHandler } from "./reaper/reaper-apr-handler"; +import { tesseraApePoolAprHandler } from "./tessera/tessera-apr-handler"; +import { tetuAprHandler } from "./tetu/tetu-apr-handler"; +import { tranchessMainnetAprHandler } from "./tranchess/tranchess-apr-handler"; + +export const aprHandlers: AprHandler[] = [ + aaveV2MainnetAprHandler, + aaveV2PolygonAprHandler, + aaveV3MainnetAprHandler, + aaveV3PolygonAprHandler, + aaveV3ArbitrumAprHandler, + ankrEthMainnetAprHandler, + stMaticAprHandler, + cbEthAprHandler, + sfrxEthAprHandler, + rETHAprHandler, + USDRAprHandler, + MATICXAprHandler, + wbETHAprHandler, + swETHAprHandler, + wjAURAAprHandler, + eulerMainnetAprHandler, + gearboxMainnetAprHandler, + idleMainnetAprHandler, + overnightMainnetAprHandler, + ovixZkEVMAprHandler, + reaperArbitrumAprHandler, + tesseraApePoolAprHandler, + tetuAprHandler, + tranchessMainnetAprHandler, +] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts new file mode 100644 index 000000000..e5a7403eb --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts @@ -0,0 +1,32 @@ +import axios from "axios"; +import { overnightTokens } from "./tokens"; +import { AprHandler } from "../../types"; + +class OvernightAprHandler implements AprHandler { + overnightTokens: Map; + url: string; + readonly group = 'OVERNIGHT'; + + constructor(tokens: Map, url: string) { + this.overnightTokens = tokens; + this.url = url; + } + + getAprs = async () => { + try { + + const { data } = await axios.get(this.url) + const rate = data as number + + return Array.from(this.overnightTokens.values()).reduce((acc, token) => { + acc[token] = rate + return acc + }, {} as { [key: string]: number }) + } catch (error) { + console.error(`Failed to fetch Overnight APRs in url:`, error) + return {} + } + } +} + +export const overnightMainnetAprHandler = new OvernightAprHandler(overnightTokens, 'https://app.overnight.fi/api/balancer/week/apr') \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts new file mode 100644 index 000000000..774b8bc88 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts @@ -0,0 +1,5 @@ +export const overnightTokens = new Map(Object.entries({ + lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus + UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f' // UsdcUsdPlus + } +)) \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts new file mode 100644 index 000000000..227f2e766 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts @@ -0,0 +1,47 @@ +import { BigNumber, Contract } from "ethers"; +import { abi } from "../abis/oErc20"; +import { JsonRpcProvider } from "@ethersproject/providers"; +import { ovixWrappedTokensZkEvm, ovixYieldTokensZkEvm } from "./tokens"; +import { AprHandler } from "../../types"; + +class OvixAprHandler implements AprHandler { + provider: JsonRpcProvider; + yieldTokens: { [key: string]: `0x${ string }` }; + wrappedTokens: { [key: string]: `0x${ string }` }; + readonly group = 'OVIX'; + + constructor(network: number, rpcUrl: string, yieldTokens: { [key: string]: `0x${ string }` }, wrappedTokens: { + [key: string]: `0x${ string }` + }) { + this.provider = new JsonRpcProvider(rpcUrl, network); + this.yieldTokens = yieldTokens; + this.wrappedTokens = wrappedTokens; + } + + getAprs = async () => { + try { + + const calls = Object.keys(this.yieldTokens).map(async (tokenName) => { + const contract = new Contract(this.yieldTokens[tokenName], abi, this.provider) + return contract.borrowRatePerTimestamp() + }) + + const borrowRates = Array(Object.keys(this.yieldTokens).length) + for (const [index, aprPromise] of calls.entries()) { + borrowRates[index] = await aprPromise + } + + const aprs = Object.keys(this.wrappedTokens).map((tokenName, i) => [ + this.wrappedTokens[tokenName], + (Math.pow(1 + (borrowRates[i] as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1) + ]) + + return Object.fromEntries(aprs) + } catch (error) { + console.error('Failed to fetch Ovix APR:', error) + return {} + } + } +} + +export const ovixZkEVMAprHandler = new OvixAprHandler(1101, 'https://zkevm-rpc.com', ovixYieldTokensZkEvm, ovixWrappedTokensZkEvm); diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/tokens.ts new file mode 100644 index 000000000..5072c8755 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/tokens.ts @@ -0,0 +1,9 @@ +export const ovixYieldTokensZkEvm = { + USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', + USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', +} as { [key: string]: `0x${string}` } + +export const ovixWrappedTokensZkEvm = { + USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', + USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', +} as { [key: string]: `0x${string}` } \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts new file mode 100644 index 000000000..94598e1f6 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts @@ -0,0 +1,47 @@ +import { JsonRpcProvider } from "@ethersproject/providers"; +import { BigNumber, Contract } from "ethers"; +import { abi } from "../abis/reaperStrategy"; +import { reaperStrategiesMapArbitrum, reaperYieldTokensArbitrum } from "./tokens"; +import { AprHandler } from "../../types"; + +class ReaperAprHandler implements AprHandler { + provider: JsonRpcProvider; + yieldTokens: { [key: string]: `0x${ string }` }; + strategiesMap: { [key: string]: `0x${ string }` }; + readonly group = 'REAPER'; + + constructor(network: number, rpcUrl: string, yieldTokens: { [key: string]: `0x${ string }` }, strategiesMap: { + [key: string]: `0x${ string }` + }) { + this.provider = new JsonRpcProvider(rpcUrl, network); + this.yieldTokens = yieldTokens; + this.strategiesMap = strategiesMap; + } + + async getAprs() { + try { + + const contractCalls = Object.keys(this.strategiesMap).map(async (tokenName) => { + const contract = new Contract(this.strategiesMap[tokenName], abi, this.provider) + return contract.averageAPRAcrossLastNHarvests(3) + }) + const callsAprResults: BigNumber[] = Array(Object.keys(this.yieldTokens).length) + for (const [index, aprPromise] of contractCalls.entries()) { + callsAprResults[index] = await aprPromise + } + const aprs = Object.keys(this.strategiesMap).map((tokenName, i) => { + return [ + this.yieldTokens[tokenName], + callsAprResults[i].toNumber() / 1e4, + ] + }) + + return Object.fromEntries(aprs) + } catch (error) { + console.error('Failed to fetch Reaper APR:', error) + return {} + } + } +} + +export const reaperArbitrumAprHandler = new ReaperAprHandler(42161, 'https://arb1.arbitrum.io/rpc', reaperYieldTokensArbitrum, reaperStrategiesMapArbitrum) \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/tokens.ts new file mode 100644 index 000000000..f1df590e4 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/tokens.ts @@ -0,0 +1,11 @@ +export const reaperYieldTokensArbitrum = { + DAI: '0x12f256109e744081f633a827be80e06d97ff7447', + USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', + USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', +} as { [key: string]: `0x${ string }` } + +export const reaperStrategiesMapArbitrum = { + DAI: '0xd4d5321b04e4832772a4d70e1eed6bcb7402d7ac', + USDT: '0x8a674ebbe33d6b03825626fa432e9ece888e13b5', + USDC: '0x6f6c0c5b7af2a326111ba6a9fa4926f7ca3adf44', +} as { [key: string]: `0x${ string }` } \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts new file mode 100644 index 000000000..60c7568f3 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts @@ -0,0 +1,48 @@ +import { Contract } from "ethers"; +import { abi } from "../abis/tesseraPool"; +import { JsonRpcProvider } from "@ethersproject/providers"; +import { tesseraYieldTokensMainnet } from "./tokens"; +import { AprHandler } from "../../types"; + +class TesseraAprHandler implements AprHandler { + provider: JsonRpcProvider; + yieldTokens: { [key: string]: `0x${ string }` }; + stakingContractAddress: `0x${ string }`; + readonly group = 'TESSERA'; + + constructor(network: number, rpcUrl: string, yieldTokens: { + [key: string]: `0x${ string }` + }, contractAddress: `0x${ string }`) { + this.provider = new JsonRpcProvider(rpcUrl, network); + this.yieldTokens = yieldTokens; + this.stakingContractAddress = contractAddress; + } + + getAprs = async () => { + try { + + let apr = 0 + + try { + const contract = new Contract(this.stakingContractAddress, abi, this.provider) + const poolsUI = await contract.getPoolsUI() + + const pool = poolsUI[0] + const staked = BigInt(pool.stakedAmount) + const reward = BigInt(pool.currentTimeRange.rewardsPerHour) * BigInt(24 * 365) + apr = Number(reward.toString()) / Number(staked.toString()); + } catch (error) { + console.error('Failed to fetch Tessera Ape Coin APR:', error) + } + + return { + [this.yieldTokens.sApe]: apr, + } + } catch (error) { + console.error('Failed to fetch Tessera APR:', error) + return {} + } + } +} + +export const tesseraApePoolAprHandler = new TesseraAprHandler(1, 'https://rpc.ankr.com/eth', tesseraYieldTokensMainnet, '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9' /*ApeCoinStaking*/) diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tokens.ts new file mode 100644 index 000000000..df736704e --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tokens.ts @@ -0,0 +1,4 @@ +export const tesseraYieldTokensMainnet = { + sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', +} as { [key: string]: `0x${ string }` } + diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts new file mode 100644 index 000000000..2fa56b489 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts @@ -0,0 +1,30 @@ +import axios from "axios"; +import { AprHandler } from "../../types"; + +class TetuAprHandler implements AprHandler { + + baseUrl: string; + networkName: string; + readonly group = 'TETU'; + + constructor(baseUrl: string, networkName: string) { + this.baseUrl = baseUrl; + this.networkName = networkName; + } + + async getAprs() { + try{ + + const { data } = await axios.get(`${this.baseUrl}?network=${ this.networkName }`) + const json = data as { vault: string, apr: number }[] + const aprs = json.map((t) => [t.vault, t.apr / 100]) + + return Object.fromEntries(aprs) + } catch (error) { + console.error('Failed to fetch Tetu APR:', error) + return {} + } + } +} + +export const tetuAprHandler = new TetuAprHandler('https://api.tetu.io/api/v1/reader/compoundAPRs', 'MATIC') \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts new file mode 100644 index 000000000..b48cdc6f8 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts @@ -0,0 +1,33 @@ +import axios from "axios"; +import { AprHandler } from "../../types"; + +const qETHMainnet = '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d' + +class TranchessAprHandler implements AprHandler { + url: string; + token: string; + readonly group = 'TRANCHESS'; + + constructor(token: string, url: string) { + this.token = token; + this.url = url; + } + + async getAprs() { + try { + + const { data } = await axios.get('https://tranchess.com/eth/api/v3/funds'); + const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[] + // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. + const value = (365 * Number(weeklyAveragePnlPercentage)) / 1e18 + return { + [this.token]: value + } + } catch (error) { + console.error('Failed to fetch Tranchess APR:', error) + return {} + } + } +} + +export const tranchessMainnetAprHandler = new TranchessAprHandler(qETHMainnet, 'https://tranchess.com/eth/api/v3/funds') \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts new file mode 100644 index 000000000..cdfa3a06c --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts @@ -0,0 +1,10 @@ +export type TokenApr = { + val: number; + address: string; + group?: string; +} + +export interface AprHandler { + readonly group: string | undefined; + getAprs(): Promise<{ [key: string]: number }>; +} \ No newline at end of file diff --git a/modules/pool/pool.prisma b/modules/pool/pool.prisma index 6f9a76816..42d01c7bd 100644 --- a/modules/pool/pool.prisma +++ b/modules/pool/pool.prisma @@ -307,6 +307,7 @@ enum PrismaPoolAprItemGroup { TESSERA TETU OVIX + EULER } model PrismaPoolCategory { diff --git a/modules/token/lib/token-apr-handler/fetch-all.ts b/modules/token/lib/token-apr-handler/fetch-all.ts deleted file mode 100644 index 4ab39b8aa..000000000 --- a/modules/token/lib/token-apr-handler/fetch-all.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { tokens } from "./tokens"; -import { TokenApr } from "./types"; - -export const fetchAllAprs = async (): Promise => { - const res = await Promise.all( - tokens.map(async ({ name, group, fetchFn }) => { - const fetchedResponse: {[key:string]:number} = await fetchFn() - return Object.entries(fetchedResponse).map(([address, aprValue]) => ({ - val: aprValue * 0.0001 /*Values come in BPS 10000=>100% */, - group, - name, - address - })) - })); - return res.flat(); -} \ No newline at end of file diff --git a/modules/token/lib/token-apr-handler/sources/aave.ts b/modules/token/lib/token-apr-handler/sources/aave.ts deleted file mode 100644 index 13c10a119..000000000 --- a/modules/token/lib/token-apr-handler/sources/aave.ts +++ /dev/null @@ -1,317 +0,0 @@ -// can be fetched from subgraph -// aave-js: supplyAPR = graph.liquidityRate = core.getReserveCurrentLiquidityRate(_reserve) -// or directly from RPC: -// wrappedAaveToken.LENDING_POOL.getReserveCurrentLiquidityRate(mainTokenAddress) - -import axios, { AxiosError } from "axios"; -import { gql } from "apollo-server-express"; - -const wrappedTokensMap = { - v2: { - [1]: { - // USDT - '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58': { - aToken: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', - underlying: '0xdac17f958d2ee523a2206206994597c13d831ec7', - }, - // USDC - '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de': { - aToken: '0xbcca60bb61934080951369a648fb03df4f96263c', - underlying: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - }, - // DAI - '0x02d60b84491589974263d922d9cc7a3152618ef6': { - aToken: '0x028171bca77440897b824ca71d1c56cac55b68a3', - underlying: '0x6b175474e89094c44da98b954eedeac495271d0f', - }, - }, - [137]: { - // USDT - '0x19c60a251e525fa88cd6f3768416a8024e98fc19': { - aToken: '0x60d55f02a771d515e077c9c2403a1ef324885cec', - underlying: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', - }, - // USDC - '0x221836a597948dce8f3568e044ff123108acc42a': { - aToken: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', - underlying: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', - }, - // DAI - '0xee029120c72b0607344f35b17cdd90025e647b00': { - aToken: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', - underlying: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', - }, - }, - }, - v3: { - [1]: { - // USDT - '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455': { - aToken: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', - underlying: '0xdac17f958d2ee523a2206206994597c13d831ec7', - }, - // USDC - '0x57d20c946a7a3812a7225b881cdcd8431d23431c': { - aToken: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', - underlying: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - }, - // DAI - '0x098256c06ab24f5655c5506a6488781bd711c14b': { - aToken: '0x018008bfb33d285247a21d44e50697654f754e63', - underlying: '0x6b175474e89094c44da98b954eedeac495271d0f', - }, - // WETH - '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6': { - aToken: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8', - underlying: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - }, - }, - [137]: { - // Matic - '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1': { - aToken: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', - underlying: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', - }, - // USDT - '0x715d73a88f2f0115d87cfe5e0f25d756b2f9679f': { - aToken: '0x6ab707aca953edaefbc4fd23ba73294241490620', - underlying: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', - }, - // USDC - '0xac69e38ed4298490906a3f8d84aefe883f3e86b5': { - aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', - underlying: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', - }, - // DAI - '0xdb6df721a6e7fdb97363079b01f107860ac156f9': { - aToken: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', - underlying: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', - }, - // WETH - '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5': { - aToken: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', - underlying: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619', - }, - }, - [42161]: { - // USDT - '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db': { - aToken: '0x6ab707aca953edaefbc4fd23ba73294241490620', - underlying: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - }, - // USDC - '0xe719aef17468c7e10c0c205be62c990754dff7e5': { - aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', - underlying: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - }, - // DAI - '0x345a864ac644c82c2d649491c905c71f240700b2': { - aToken: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', - underlying: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', - }, - // WETH - '0x18c100415988bef4354effad1188d1c22041b046': { - aToken: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', - underlying: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', - } - }, - } -} - -const aTokens = { - v2: { - [1]: Object.values(wrappedTokensMap.v2[1]).map( - (t) => t.aToken - ), - [137]: Object.values(wrappedTokensMap.v2[137]).map( - (t) => t.aToken - ), - [42161]: {}, - }, - v3: { - [1]: Object.values(wrappedTokensMap.v3[1]).map( - (t) => t.aToken - ), - [137]: Object.values(wrappedTokensMap.v3[137]).map( - (t) => t.aToken - ), - [42161]: Object.values(wrappedTokensMap.v3[42161]).map( - (t) => t.aToken - ), - } -} - -const underlyingAssets = { - v2: { - [1]: Object.values(wrappedTokensMap.v2[1]).map( - (t) => t.underlying - ), - [137]: Object.values(wrappedTokensMap.v2[137]).map( - (t) => t.underlying - ), - [42161]: {}, - }, - v3: { - [1]: Object.values(wrappedTokensMap.v3[1]).map( - (t) => t.underlying - ), - [137]: Object.values(wrappedTokensMap.v3[137]).map( - (t) => t.underlying - ), - [42161]: Object.values(wrappedTokensMap.v3[42161]).map( - (t) => t.underlying - ), - } -} - -const underlyingsToWrapped = [ - { - version: 'v2', network: 1, tokens: Object.fromEntries( - Object.keys(wrappedTokensMap.v2[1]).map((wrapped) => [ - wrappedTokensMap.v2[1][wrapped as keyof (typeof wrappedTokensMap)['v2'][1]].underlying, - wrapped, - ]) - ) - }, - { - version: 'v2', network: 137, tokens: Object.fromEntries( - Object.keys(wrappedTokensMap.v2[137]).map((wrapped) => [ - wrappedTokensMap.v2[137][ - wrapped as keyof (typeof wrappedTokensMap)['v2'][137] - ].underlying, - wrapped, - ]) - ) - }, - { - version: 'v3', network: 1, tokens: Object.fromEntries( - Object.keys(wrappedTokensMap.v3[1]).map((wrapped) => [ - wrappedTokensMap.v3[1][wrapped as keyof (typeof wrappedTokensMap)['v3'][1]].underlying, - wrapped, - ]) - ) - }, - { - version: 'v3', network: 137, tokens: Object.fromEntries( - Object.keys(wrappedTokensMap.v3[137]).map((wrapped) => [ - wrappedTokensMap.v3[137][ - wrapped as keyof (typeof wrappedTokensMap)['v3'][137] - ].underlying, - wrapped, - ]) - ) - }, - { - version: 'v3', network: 42161, tokens: Object.fromEntries( - Object.keys(wrappedTokensMap.v3[42161]).map((wrapped) => [ - wrappedTokensMap.v3[42161][ - wrapped as keyof (typeof wrappedTokensMap)['v3'][42161] - ].underlying, - wrapped, - ]) - ) - }, -] - -// Subgraph -// liquidityRate, depositors APR (in rays - 27 digits) -const endpoints = [ - { version: 'v2', network: 1, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2' }, - { version: 'v2', network: 137, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic' }, - { version: 'v3', network: 1, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3' }, - { version: 'v3', network: 137, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon' }, - { version: 'v3', network: 42161, subgraph: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum' }, -] - -const query = `query getReserves($aTokens: [String!], $underlyingAssets: [Bytes!]) { - reserves( - where: { - aToken_in: $aTokens - underlyingAsset_in: $underlyingAssets - isActive: true - } - ) { - underlyingAsset - liquidityRate - } - }` - -interface ReserveResponse { - data: { - reserves: [ - { - underlyingAsset: string - liquidityRate: string - } - ] - } -} - -/** - * Fetching and parsing aave APRs from a subgraph - * - * @returns APRs for aave tokens - */ -export const aave = async (network: number, version: keyof (typeof wrappedTokensMap) = 'v2') => { - const noRates = Object.fromEntries( - Object.keys(wrappedTokensMap[version]).map((key) => [key, 0]) - ) - - if (!network || (network != 1 && network != 137 && network != 42161)) { - return noRates - } - - if (network == 42161 && version != 'v3') { - return noRates - } - - try { - const requestQuery = { - operationName: 'getReserves', - query, - variables: { - aTokens: aTokens[version][network], - underlyingAssets: underlyingAssets[version][network], - }, - } - - const endpoint = endpoints.find((e) => e.version == version && e.network == network)?.subgraph - const underlyingToWrapped = underlyingsToWrapped.find((e) => e.version == version && e.network == network)?.tokens - - if (!endpoint) { - throw 'no endpoint found' - } - - if (!underlyingToWrapped) { - throw 'no underlyingToWrapped found' - } - const { data } = await axios({ - url: endpoint, - method: "post", - data: requestQuery, - headers: { "Content-Type": "application/json" } - }) - - const { - data: { reserves }, - } = data as ReserveResponse - - const aprEntries = reserves.map((r) => [ - underlyingToWrapped[r.underlyingAsset], - // Note: our assumption is frontend usage, this service is not a good source where more accuracy is needed. - // Converting from aave ray number (27 digits) to bsp - // essentially same as here: - // https://github.com/aave/aave-utilities/blob/master/packages/math-utils/src/formatters/reserve/index.ts#L231 - Math.round(Number(r.liquidityRate.slice(0, -20)) / 1e3), - ]) - - return Object.fromEntries(aprEntries) - } catch (error) { - console.log((error as AxiosError).response?.data) - return noRates - } -} - -// TODO: RPC multicall -// always upto date -// const lendingPoolAddress = '0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9'; diff --git a/modules/token/lib/token-apr-handler/sources/ankr.ts b/modules/token/lib/token-apr-handler/sources/ankr.ts deleted file mode 100644 index bd29e78d1..000000000 --- a/modules/token/lib/token-apr-handler/sources/ankr.ts +++ /dev/null @@ -1,16 +0,0 @@ -import axios from "axios"; - -const ankrEth = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb' - -export const ankr = async () => { - const { data } = await axios.get('https://api.staking.ankr.com/v1alpha/metrics') - const json = data as { services: { serviceName: string; apy: string }[] } - const service = json.services.find((service) => service.serviceName === 'eth') - if (!service) { - return null - } - const scaledValue = Math.round(parseFloat(service.apy) * 100) - return { - [ankrEth]: scaledValue - } -} diff --git a/modules/token/lib/token-apr-handler/sources/default.ts b/modules/token/lib/token-apr-handler/sources/default.ts deleted file mode 100644 index 11213fb53..000000000 --- a/modules/token/lib/token-apr-handler/sources/default.ts +++ /dev/null @@ -1,23 +0,0 @@ -import axios from "axios"; - -export const defaultFetch = async (options: { tokens: string[]; url: string; path: string; scale?: number }) => { - const { tokens, url, path, scale = 100 } = options - const { data } = await axios.get(url, { headers: { 'User-Agent': 'cf' } }) - const value = (path === '') ? data : getValueFromPath(data, path) - const scaledValue = Math.round(parseFloat(value) * scale) - - return tokens.reduce((acc, token) => { - acc[token] = scaledValue - return acc - }, {} as { [key: string]: number }) -} - -// Get a specific value from a JSON object based on a path -export const getValueFromPath = (obj: any, path: string) => { - const parts = path.split('.') - let value = obj - for (const part of parts) { - value = value[part] - } - return value -} diff --git a/modules/token/lib/token-apr-handler/sources/euler.ts b/modules/token/lib/token-apr-handler/sources/euler.ts deleted file mode 100644 index 9c9cce379..000000000 --- a/modules/token/lib/token-apr-handler/sources/euler.ts +++ /dev/null @@ -1,60 +0,0 @@ -import axios from "axios"; - -const yieldTokens = { - eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', - eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', - eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', - eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', -} - -const query = ` - query getAssetsAPY($eTokenAddress_in: [String!]) { - assets( - where: { - eTokenAddress_in: $eTokenAddress_in - } - ) { - eTokenAddress - supplyAPY - } - } -` - -const requestQuery = { - operationName: 'getAssetsAPY', - query, - variables: { - eTokenAddress_in: Object.values(yieldTokens), - }, -} - -const url = 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet' - -interface EulerResponse { - data: { - assets: [ - { - eTokenAddress: string - supplyAPY: string - } - ] - } -} - -export const euler = async () => { - const {data} = await axios.post(url, { - body: JSON.stringify(requestQuery) - }) - - const { - data: { assets }, - } = data as EulerResponse - - const aprEntries = assets.map(({ eTokenAddress, supplyAPY }) => [ - eTokenAddress, - // supplyAPY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 - Math.round(Number(supplyAPY.slice(0, -20)) / 1e3) - ]) - - return Object.fromEntries(aprEntries) -} diff --git a/modules/token/lib/token-apr-handler/sources/gearbox.ts b/modules/token/lib/token-apr-handler/sources/gearbox.ts deleted file mode 100644 index 4575806b4..000000000 --- a/modules/token/lib/token-apr-handler/sources/gearbox.ts +++ /dev/null @@ -1,26 +0,0 @@ -import axios from "axios"; - -const ddai = '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba' -const dusdc = '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3' - -export const gearbox = async () => { - const {data} = await axios.get('https://mainnet.gearbox.foundation/api/pools') - const json = data as { data: { dieselToken: string; depositAPY_RAY: string }[] } - const dai = json.data.find((t) => t.dieselToken.toLowerCase() == ddai) - const usdc = json.data.find((t) => t.dieselToken.toLowerCase() == dusdc) - if (!dai || !usdc) { - return null - } - - const scaleDai = Math.round( - // depositAPY_RAY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 - Number(dai.depositAPY_RAY.slice(0, -20)) / 1e3 - ) - const scaleUsdc = Math.round( - Number(usdc.depositAPY_RAY.slice(0, -20)) / 1e3 - ) - return { - [ddai]: scaleDai, - [dusdc]: scaleUsdc - } -} \ No newline at end of file diff --git a/modules/token/lib/token-apr-handler/sources/idle.ts b/modules/token/lib/token-apr-handler/sources/idle.ts deleted file mode 100644 index 0321de2c7..000000000 --- a/modules/token/lib/token-apr-handler/sources/idle.ts +++ /dev/null @@ -1,22 +0,0 @@ -import axios from "axios"; - -const contracts = { - '0x0c80f31b840c6564e6c5e18f386fad96b63514ca': '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', // DAI - '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133': '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', // USDC - '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1': '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', // USDT -} as { [key: string]: string } - -export const idle = async (token: string) => { - const { data } = await axios.get(`https://api.idle.finance/junior-rates/${contracts[token]}?isRisk=false&order=desc&limit=1`, { - headers: { - Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M' - } - }) - const [json] = data as { idleRate: string }[] - const value = json.idleRate - const scaledValue = Math.round(Number(value) / 1e16) - - return { - [token]: scaledValue - } -} diff --git a/modules/token/lib/token-apr-handler/sources/index.ts b/modules/token/lib/token-apr-handler/sources/index.ts deleted file mode 100644 index 4b205dbc8..000000000 --- a/modules/token/lib/token-apr-handler/sources/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { aave } from './aave'; -import { ankr } from './ankr'; -import { defaultFetch } from './default'; -import { euler } from './euler'; -import { gearbox } from "./gearbox"; -import { idle } from './idle'; -import { overnight } from "./overnight"; -import { ovix } from "./ovix"; -import { reaper } from "./reaper"; -import { tessera } from "./tessera"; -import { tetu } from "./tetu"; -import { tranchess } from "./tranchess"; - -export { aave, ankr, defaultFetch, euler, gearbox, idle, overnight, ovix, reaper, tessera, tetu, tranchess } \ No newline at end of file diff --git a/modules/token/lib/token-apr-handler/sources/overnight.ts b/modules/token/lib/token-apr-handler/sources/overnight.ts deleted file mode 100644 index a73967d82..000000000 --- a/modules/token/lib/token-apr-handler/sources/overnight.ts +++ /dev/null @@ -1,17 +0,0 @@ -import axios from "axios"; - -const tokens = [ - '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', - '0x6933ec1ca55c06a894107860c92acdfd2dd8512f' -] - -export const overnight = async () => { - const {data} = await axios.get('https://app.overnight.fi/api/balancer/week/apr') - const rate = data as string - const scaledValue = Math.round(Number(rate) * 10000) - - return tokens.reduce((acc, token) => { - acc[token] = scaledValue - return acc - }, {} as { [key: string]: number }) -} diff --git a/modules/token/lib/token-apr-handler/sources/ovix.ts b/modules/token/lib/token-apr-handler/sources/ovix.ts deleted file mode 100644 index e84bbeb0b..000000000 --- a/modules/token/lib/token-apr-handler/sources/ovix.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { abi } from './abis/oErc20' -import { BigNumber, Contract } from "ethers"; -import { ethers } from "ethers"; -import { MulticallWrapper } from "ethers-multicall-provider"; -import { JsonRpcProvider } from "@ethersproject/providers"; - -const jsonRpcProvider = new JsonRpcProvider('https://zkevm-rpc.com', 1101) -const provider = MulticallWrapper.wrap(jsonRpcProvider) - -export const yieldTokens = { - USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', - USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', -} as { [key: string]: `0x${string}` } - -export const wrappedTokens = { - USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', - USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', -} as { [key: string]: `0x${string}` } - -const noRates = Object.fromEntries( - Object.values(yieldTokens).map((v) => [v, 0]) -) - -const getBorrowRates = () => { - - const calls = Object.keys(yieldTokens).map(async (coin) => { - const contract = new Contract(yieldTokens[coin], abi, provider) - return contract.borrowRatePerTimestamp() - }) - - return Promise.all(calls) -} - -export const ovix = async () => { - try { - const borrowRates = await getBorrowRates() - const aprs = Object.keys(wrappedTokens).map((coin, i) => [ - wrappedTokens[coin], - Math.round(10000 * (Math.pow(1 + (borrowRates[i] as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1)) - ]) - return Object.fromEntries(aprs) - } catch (error) { - console.log(error) - return noRates - } -} diff --git a/modules/token/lib/token-apr-handler/sources/reaper.ts b/modules/token/lib/token-apr-handler/sources/reaper.ts deleted file mode 100644 index 5c64abec8..000000000 --- a/modules/token/lib/token-apr-handler/sources/reaper.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { abi } from './abis/reaperStrategy' -import { JsonRpcProvider } from "@ethersproject/providers"; -import { MulticallWrapper } from "ethers-multicall-provider"; -import { Contract } from "ethers"; - - -const jsonRpcProvider = new JsonRpcProvider('https://arb1.arbitrum.io/rpc', 42161 /*ARBITRUM*/) -const provider = MulticallWrapper.wrap(jsonRpcProvider) - -export const yieldTokens = { - DAI: '0x12f256109e744081f633a827be80e06d97ff7447', - USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', - USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', -} as { [key: string]: `0x${ string }` } - -export const strategiesMap = { - DAI: '0xd4d5321b04e4832772a4d70e1eed6bcb7402d7ac', - USDT: '0x8a674ebbe33d6b03825626fa432e9ece888e13b5', - USDC: '0x6f6c0c5b7af2a326111ba6a9fa4926f7ca3adf44', -} as { [key: string]: `0x${ string }` } - -const noRates = Object.fromEntries( - Object.values(yieldTokens).map((v) => [v, 0]) -) - -const getAprs = () => { - - const calls = Object.keys(strategiesMap).map(async (coin) => { - const contract = new Contract(strategiesMap[coin], abi, provider) - return contract.averageAPRAcrossLastNHarvests(3) - }) - - return Promise.all(calls) -} - -export const reaper = async () => { - try { - const results = await getAprs() - - const aprs = Object.keys(strategiesMap).map((coin, i) => [ - yieldTokens[coin], - Math.round(Number(results[i].result)), - ]) - - return Object.fromEntries(aprs) - } catch (error) { - console.log(error) - return noRates - } -} diff --git a/modules/token/lib/token-apr-handler/sources/tessera.ts b/modules/token/lib/token-apr-handler/sources/tessera.ts deleted file mode 100644 index a29c2941c..000000000 --- a/modules/token/lib/token-apr-handler/sources/tessera.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { abi } from './abis/tesseraPool' -import { JsonRpcProvider } from "@ethersproject/providers"; -import { MulticallWrapper } from "ethers-multicall-provider"; -import { Contract } from "ethers"; - -// const client = createPublicClient({ -// chain: mainnet, -// transport: http('https://rpc.ankr.com/eth'), -// }) - -const jsonRpcProvider = new JsonRpcProvider('https://rpc.ankr.com/eth', 1 /*MAINNET*/) -const provider = MulticallWrapper.wrap(jsonRpcProvider) - -const yieldTokens = { - sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', -} - -/** - * Staked ApeCoin APR fetching - * - * @returns apr in bsp - */ -export const tessera = async () => { - let apr = 0 - - try { - const contract = new Contract('0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9', abi, provider) - const poolsUI = await contract.getPoolsUI() - - const apePool = poolsUI[0] - const staked = BigInt(apePool.stakedAmount) - const reward = BigInt(apePool.currentTimeRange.rewardsPerHour) * BigInt(24 * 365) - - apr = Number(reward * BigInt(1e4) / staked) - } catch (error) { - console.error('Failed to fetch Tessera Ape Coin APR:', error) - } - - return { - [yieldTokens.sApe]: apr, - } -} diff --git a/modules/token/lib/token-apr-handler/sources/tetu.ts b/modules/token/lib/token-apr-handler/sources/tetu.ts deleted file mode 100644 index 72bccfe5c..000000000 --- a/modules/token/lib/token-apr-handler/sources/tetu.ts +++ /dev/null @@ -1,9 +0,0 @@ -import axios from "axios"; - -export const tetu = async () => { - const { data } = await axios.get('https://api.tetu.io/api/v1/reader/compoundAPRs?network=MATIC') - const json = data as { vault: string, apr: number }[] - const aprs = json.map((t) => [t.vault, Math.round(t.apr * 100)]) - - return Object.fromEntries(aprs) -} diff --git a/modules/token/lib/token-apr-handler/sources/tranchess.ts b/modules/token/lib/token-apr-handler/sources/tranchess.ts deleted file mode 100644 index 398b24309..000000000 --- a/modules/token/lib/token-apr-handler/sources/tranchess.ts +++ /dev/null @@ -1,11 +0,0 @@ -import axios from "axios"; - -export const tranchess = async () => { - const { data } = await axios.get('https://tranchess.com/eth/api/v3/funds'); - const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[] - // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. - const scaledValue = Math.round(365 * Number(weeklyAveragePnlPercentage) / 1e14) - return { - '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d': scaledValue - } -} diff --git a/modules/token/lib/token-apr-handler/tokens.ts b/modules/token/lib/token-apr-handler/tokens.ts deleted file mode 100644 index 8b89f9a61..000000000 --- a/modules/token/lib/token-apr-handler/tokens.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { aave, ankr, defaultFetch, gearbox, idle, overnight, ovix, reaper, tessera, tetu, tranchess } from "./sources"; - -export const tokens = [ - { name: 'idleDai', group: "IDLE", fetchFn: () => idle('0x0c80f31b840c6564e6c5e18f386fad96b63514ca') }, - { name: 'idleUsdc', group: "IDLE", fetchFn: () => idle('0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133') }, - { name: 'idleUsdt', group: "IDLE", fetchFn: () => idle('0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1') }, - { name: 'qETH', group: "TRANCHESS", fetchFn: tranchess }, - { name: 'gearbox', group: "GEARBOX", fetchFn: gearbox }, - { name: 'overnight', group: "OVERNIGHT", fetchFn: overnight }, - { name: 'aaveV2Mainnet', group: "AAVE", fetchFn: () => aave(1) }, - { name: 'aaveV2Polygon', group: "AAVE", fetchFn: () => aave(137) }, - { name: 'aaveV3Mainnet', group: "AAVE", fetchFn: () => aave(1, 'v3') }, - { name: 'aaveV3Polygon', group: "AAVE", fetchFn: () => aave(137, 'v3') }, - { name: 'aaveV3Arbitrum', group: "AAVE", fetchFn: () => aave(42161, 'v3') }, - { name: 'ankr', group: "ANKR", fetchFn: ankr }, - { name: 'reaper', group: "REAPER", fetchFn: reaper }, - { name: 'tessera', group: "TESSERA", fetchFn: tessera }, - { name: 'tetu', group: "TETU", fetchFn: tetu }, - { name: 'ovix', group: "OVIX", fetchFn: ovix }, - { - name: 'vEth', - fetchFn: () => defaultFetch({ - tokens: ['0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f'], - url: 'https://apy.liebi.com/veth', - path: 'veth' - }) - }, - { - name: 'stEth', - fetchFn: () => defaultFetch({ - tokens: ['0x6c76971f98945ae98dd7d4dfca8711ebea946ea6', '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9', '0xae7ab96520de3a18e5e111b5eaab095312d7fe84', '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd', '0x5979d7b546e38e414f7e9822514be443a4800529'], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr' - }) - }, - { - name: 'stMatic', - fetchFn: () => defaultFetch({ - tokens: ['0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'], - url: 'https://polygon.lido.fi/api/stats', - path: 'apr' - }) - }, - { - name: 'cbEth', - fetchFn: () => defaultFetch({ - tokens: ['0xbe9895146f7af43049ca1c1ae358b0541ea49704'], - url: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', - path: 'apy', - scale: 10000 - }) - }, - // { name: 'rETH', fetchFn: () => defaultFetch({ tokens: ['0xb23c20efce6e24acca0cef9b7b7aa196b84ec942', '0xae78736cd615f374d3085123a210448e74fc6393', '0xec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8'], url: 'https://api.rocketpool.net/api/apr', path: 'yearlyAPR' }) }, - { - name: 'sfrxETH', - fetchFn: () => defaultFetch({ - tokens: ['0xac3e018457b222d93114458476f3e3416abbe38f'], - url: 'https://api.frax.finance/v2/frxeth/summary/latest', - path: 'sfrxethApr' - }) - }, - { - name: 'stafi', - fetchFn: () => defaultFetch({ - tokens: ['0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'], - url: 'https://drop-api.stafi.io/reth/v1/poolData', - path: 'data.stakeApr' - }) - }, - { - name: 'usdr', - fetchFn: () => defaultFetch({ - tokens: ['0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'], - url: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', - path: 'usdr' - }) - }, - { - name: 'maticX', - fetchFn: () => defaultFetch({ - tokens: ['0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'], - url: 'https://universe.staderlabs.com/polygon/apy', - path: 'value' - }) - }, - // Had to proxy this one because Binance API was blocking requests from Cloudflare, original URL: https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH - // { name: 'wbETH', fetchFn: () => defaultFetch({ tokens: ['0xa2e3356610840701bdf5611a53974510ae27e2e1'], url: 'https://faas-ams3-2a2df116.doserverless.co/api/v1/web/fn-683e4669-de62-4f89-9609-2e24ba8acfa7/default/binance', path: 'data.0.rewardRate', scale: 10000 }) }, - { - name: 'wbETH', - fetchFn: () => defaultFetch({ - tokens: ['0xa2e3356610840701bdf5611a53974510ae27e2e1'], - url: 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', - path: 'data.0.rewardRate', - scale: 10000 - }) - }, - { - name: 'swETH', - fetchFn: () => defaultFetch({ - tokens: ['0xf951e335afb289353dc249e82926178eac7ded78'], - url: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', - path: '', - scale: 100 - }) - }, - { - name: 'wjAURA', - fetchFn: () => defaultFetch({ - tokens: ['0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'], - url: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', - path: 'wjauraApy', - scale: 200 - }) - }, - // { name: 'euler', fetchFn: euler }, -] diff --git a/modules/token/lib/token-apr-handler/types.ts b/modules/token/lib/token-apr-handler/types.ts deleted file mode 100644 index fb2fcc17c..000000000 --- a/modules/token/lib/token-apr-handler/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type TokenApr = { - val: number; - name: string; - address: string; - group?: string; -} \ No newline at end of file From b3d557524f94e889bcdfd854dd279d101667893b Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Fri, 28 Jul 2023 14:48:57 -0300 Subject: [PATCH 09/42] adding interface to default, ankr and aave apr handlers; --- .../ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts | 3 ++- .../ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts | 3 ++- .../sources/default-fetch/default-apr-handler.ts | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts index 9091e1eba..69ccd2a61 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts @@ -14,8 +14,9 @@ import { wrappedAaveTokensV3Mainnet, wrappedAaveTokensV3Polygon } from "./tokens"; +import { AprHandler } from "../../types"; -class AaveAprHandler { +class AaveAprHandler implements AprHandler { wrappedTokens: Map aaveTokens: Map diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts index 8f05f23aa..794d151fc 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts @@ -1,8 +1,9 @@ import axios from "axios"; +import { AprHandler } from "../../types"; const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb' -class AnkrAprHandler { +class AnkrAprHandler implements AprHandler{ serviceName: string tokenAddress: string readonly url: string = 'https://api.staking.ankr.com/v1alpha/metrics'; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts index c7600cb80..36cad21b2 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts @@ -9,8 +9,9 @@ import { wstETHPolygon, wstETHZkEVM } from "./tokens"; +import { AprHandler } from "../../types"; -class DefaultAprHandler { +class DefaultAprHandler implements AprHandler{ tokens: string[]; url: string; From 65047bb16b3e505262208266e0316f25d8d78c00 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 1 Aug 2023 19:25:51 -0300 Subject: [PATCH 10/42] Adding multichain support; Changing arrow functions to normal functions; --- modules/balancer/loadRestRoutes.ts | 3 +- modules/network/arbitrum.ts | 3 + modules/network/avalanche.ts | 1 + modules/network/gnosis.ts | 2 + modules/network/mainnet.ts | 6 +- modules/network/polygon.ts | 2 + modules/network/zkevm.ts | 2 + .../apr-data-sources/ib-tokens-apr.service.ts | 11 +- .../ib-yield-apr-handlers.ts | 10 +- .../sources/aave/aave-apr-handler.ts | 85 +++++--- .../sources/aave/tokens.ts | 53 +++-- .../sources/aave/types.ts | 8 + .../sources/ankr/ankr-apr-handler.ts | 20 +- .../default-fetch/default-apr-handler.ts | 192 ++++++++++++++---- .../sources/default-fetch/tokens.ts | 4 +- .../sources/euler/euler-apr-handler.ts | 22 +- .../sources/euler/tokens.ts | 13 +- .../sources/euler/types.ts | 7 + .../sources/gearbox/gearbox-apr-handler.ts | 24 ++- .../sources/gearbox/tokens.ts | 4 +- .../sources/gearbox/types.ts | 6 + .../sources/idle/idle-apr-handler.ts | 63 +++--- .../sources/idle/tokens.ts | 8 +- .../sources/idle/types.ts | 7 + .../ib-yield-apr-handlers/sources/index.ts | 71 +++---- .../overnight/overnight-apr-handler.ts | 23 ++- .../sources/overnight/tokens.ts | 9 +- .../sources/overnight/types.ts | 5 + .../sources/ovix/ovix-apr-handler.ts | 24 ++- .../sources/ovix/types.ts | 8 + .../sources/reaper/reaper-apr-handler.ts | 22 +- .../sources/reaper/types.ts | 8 + .../sources/tessera/tessera-apr-handler.ts | 26 ++- .../sources/tessera/types.ts | 6 + .../sources/tetu/tetu-apr-handler.ts | 34 ++-- .../sources/tetu/types.ts | 5 + .../tranchess/tranchess-apr-handler.ts | 18 +- .../sources/tranchess/types.ts | 5 + modules/pool/pool.prisma | 1 + 39 files changed, 541 insertions(+), 280 deletions(-) create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/types.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/types.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/types.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/types.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/types.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/types.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/types.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/types.ts diff --git a/modules/balancer/loadRestRoutes.ts b/modules/balancer/loadRestRoutes.ts index 0eba79946..893502fd1 100644 --- a/modules/balancer/loadRestRoutes.ts +++ b/modules/balancer/loadRestRoutes.ts @@ -3,7 +3,6 @@ import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.s import { networkContext } from "../network/network-context.service"; import { prismaPoolWithExpandedNesting } from "../../prisma/prisma-types"; import { prisma } from "../../prisma/prisma-client"; -import { ibYieldAprHandlers } from "../pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers"; export function loadRestRoutesBalancer(app: Express) { app.use('/health', (req, res) => res.sendStatus(200)); @@ -12,7 +11,7 @@ export function loadRestRoutesBalancer(app: Express) { ...prismaPoolWithExpandedNesting, where: { chain: networkContext.chain }, }); - const ibTokensAprService = new IbTokensAprService(ibYieldAprHandlers); + const ibTokensAprService = new IbTokensAprService(1); await ibTokensAprService.updateAprForPools(pools); return res.sendStatus(200) diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index c4c5f8937..18ab83b57 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -17,6 +17,8 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { coingeckoService } from '../coingecko/coingecko.service'; +import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; +import { IbYieldAprHandlers } from "../pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers"; const arbitrumNetworkData: NetworkData = { chain: { @@ -156,6 +158,7 @@ export const arbitrumNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(arbitrumNetworkData.rpcUrl), poolAprServices: [ + new IbTokensAprService(arbitrumNetworkData.chain.id), new WstethAprService(tokenService, arbitrumNetworkData.lido!.wstEthContract), new ReaperCryptAprService( arbitrumNetworkData.reaper.linearPoolFactories, diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index a7db595d4..3dde2ba51 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -15,6 +15,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; +import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; const avalancheNetworkData: NetworkData = { chain: { diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index bdf27bd4c..18122b1ba 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -15,6 +15,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; +import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; const gnosisNetworkData: NetworkData = { chain: { @@ -145,6 +146,7 @@ export const gnosisNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(gnosisNetworkData.rpcUrl), poolAprServices: [ + new IbTokensAprService(gnosisNetworkData.chain.id), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(gnosisNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 9d7fa9189..4c8c0d30f 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -18,9 +18,7 @@ import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; -import { - ibYieldAprHandlers -} from "../pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers"; +import { IbYieldAprHandlers } from "../pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers"; const mainnetNetworkData: NetworkData = { chain: { @@ -161,7 +159,7 @@ export const mainnetNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(mainnetNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(ibYieldAprHandlers), + new IbTokensAprService(mainnetNetworkData.chain.id), new WstethAprService(tokenService, mainnetNetworkData.lido!.wstEthContract), new ReaperCryptAprService( mainnetNetworkData.reaper.linearPoolFactories, diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index 46b57fdd7..76bcdc800 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -16,6 +16,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; +import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; const polygonNetworkData: NetworkData = { chain: { @@ -151,6 +152,7 @@ export const polygonNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(polygonNetworkData.rpcUrl), poolAprServices: [ + new IbTokensAprService(polygonNetworkData.chain.id), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(polygonNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index 59a323ab5..d21c71707 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -16,6 +16,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { coingeckoService } from '../coingecko/coingecko.service'; +import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; const zkevmNetworkData: NetworkData = { chain: { @@ -146,6 +147,7 @@ export const zkevmNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(zkevmNetworkData.rpcUrl), poolAprServices: [ + new IbTokensAprService(zkevmNetworkData.chain.id), new WstethAprService(tokenService, zkevmNetworkData.lido!.wstEthContract), new PhantomStableAprService(), new BoostedPoolAprService(), diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index dd91ee864..04fca7e77 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -8,8 +8,12 @@ import { TokenApr } from "./ib-yield-apr-handlers/types"; import { IbYieldAprHandlers } from "./ib-yield-apr-handlers/ib-yield-apr-handlers"; export class IbTokensAprService implements PoolAprService { - - constructor(private readonly ibYieldAprHandlers: IbYieldAprHandlers) {} + + private ibYieldAprHandlers: IbYieldAprHandlers; + + constructor(chainId: number) { + this.ibYieldAprHandlers = new IbYieldAprHandlers(chainId); + } getAprServiceName(): string { return "IbTokensAprService"; @@ -54,7 +58,8 @@ export class IbTokensAprService implements PoolAprService { } private async fetchYieldTokensApr(): Promise> { - const data = await this.ibYieldAprHandlers.getHandlersAprs() + const data = await this.ibYieldAprHandlers.getHandlersAprs(); + console.log(data); return new Map( data.filter((apr) => !isNaN(apr.val)).map((apr) => [apr.address, apr]) ); diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts index 6b3faf32a..c9343654b 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts @@ -4,11 +4,11 @@ import { aprHandlers } from "./sources"; export class IbYieldAprHandlers { private handlers: AprHandler[] = []; - constructor(handlers: AprHandler[]) { - this.handlers = handlers; + constructor(network: number) { + this.handlers = aprHandlers.filter((handler) => handler.network === network); } - getHandlersAprs = async (): Promise => { + async getHandlersAprs (): Promise { const aprPromises = this.handlers.map(async (handler) => { const fetchedResponse: { [key: string]: number } = await handler.getAprs() return Object.entries(fetchedResponse).map(([address, aprValue]) => ({ @@ -23,6 +23,4 @@ export class IbYieldAprHandlers { } return res.flat(); } -} - -export const ibYieldAprHandlers = new IbYieldAprHandlers(aprHandlers); \ No newline at end of file +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts index 69ccd2a61..ac7fb5f25 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts @@ -1,5 +1,5 @@ import axios from "axios"; -import { ReserveResponse } from "./types"; +import { AaveAprHandlerConfig, ReserveResponse } from "./types"; import { aaveTokensV2Mainnet, aaveTokensV2Polygon, @@ -18,10 +18,11 @@ import { AprHandler } from "../../types"; class AaveAprHandler implements AprHandler { - wrappedTokens: Map - aaveTokens: Map - underlyingTokens: Map + wrappedTokens: { [key: string]: string } + aaveTokens: { [key: string]: string } + underlyingTokens: { [key: string]: string } subgraphUrl: string + network: number; readonly group = 'AAVE'; @@ -39,15 +40,12 @@ class AaveAprHandler implements AprHandler { } }` - constructor(wrappedTokens: Map, - aaveTokens: Map, - underlyingTokens: Map, - subgraphUrl: string - ) { - this.wrappedTokens = wrappedTokens - this.aaveTokens = aaveTokens - this.underlyingTokens = underlyingTokens - this.subgraphUrl = subgraphUrl + constructor(aprHandlerConfig: AaveAprHandlerConfig) { + this.wrappedTokens = aprHandlerConfig.wrappedTokens + this.aaveTokens = aprHandlerConfig.aaveTokens + this.underlyingTokens = aprHandlerConfig.underlyingTokens + this.subgraphUrl = aprHandlerConfig.subgraphUrl + this.network = aprHandlerConfig.network; } async getAprs() { @@ -56,8 +54,8 @@ class AaveAprHandler implements AprHandler { operationName: 'getReserves', query: this.query, variables: { - aTokens: Array.from(this.aaveTokens.values()), - underlyingAssets: Array.from(this.underlyingTokens.values()), + aTokens: Object.values(this.aaveTokens), + underlyingAssets: Object.values(this.underlyingTokens), }, } const { data } = await axios({ @@ -72,19 +70,16 @@ class AaveAprHandler implements AprHandler { const aprsByUnderlyingAddress = Object.fromEntries(reserves.map((r) => [ r.underlyingAsset, - // Note: our assumption is frontend usage, this service is not a good source where more accuracy is needed. - // Converting from aave ray number (27 digits) to bsp - // essentially same as here: - // https://github.com/aave/aave-utilities/blob/master/packages/math-utils/src/formatters/reserve/index.ts#L231 + // Converting from aave ray number (27 digits) to float Number(r.liquidityRate.slice(0, 27)) / 1e27, ])) const aprEntries = Object.fromEntries( - Array.from(this.underlyingTokens.entries()) + Object.values(this.underlyingTokens) //Removing undefined aprs .filter(([, address]) => !!aprsByUnderlyingAddress[address]) //Mapping aprs by wrapped instead of underlying addresses .map(([underlyingTokenName, underlyingTokenAddress]) => [ - this.wrappedTokens.get('wa' + underlyingTokenName) as string, + this.wrappedTokens['wa' + underlyingTokenName] as string, aprsByUnderlyingAddress[underlyingTokenAddress], ])) return aprEntries; @@ -95,9 +90,47 @@ class AaveAprHandler implements AprHandler { } } -export const aaveV2MainnetAprHandler = new AaveAprHandler(wrappedAaveTokensV2Mainnet, aaveTokensV2Mainnet, underlyingTokensMainnet, 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2') -export const aaveV2PolygonAprHandler = new AaveAprHandler(wrappedAaveTokensV2Polygon, aaveTokensV2Polygon, underlyingTokensPolygon, 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic') -export const aaveV3MainnetAprHandler = new AaveAprHandler(wrappedAaveTokensV3Mainnet, aaveTokensV3Mainnet, underlyingTokensMainnet, 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3') -export const aaveV3PolygonAprHandler = new AaveAprHandler(wrappedAaveTokensV3Polygon, aaveTokensV3Polygon, underlyingTokensPolygon, 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon'); -export const aaveV3ArbitrumAprHandler = new AaveAprHandler(wrappedAaveTokensV3Arbitrum, aaveTokensV3Arbitrum, underlyingTokensArbitrum, 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum') +const aaveV2MainnetAprHandler = new AaveAprHandler({ + wrappedTokens: wrappedAaveTokensV2Mainnet, + aaveTokens: aaveTokensV2Mainnet, + underlyingTokens: underlyingTokensMainnet, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2', + network: 1 +}) +const aaveV2PolygonAprHandler = new AaveAprHandler({ + wrappedTokens: wrappedAaveTokensV2Polygon, + aaveTokens: aaveTokensV2Polygon, + underlyingTokens: underlyingTokensPolygon, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic', + network: 137 +}) +const aaveV3MainnetAprHandler = new AaveAprHandler({ + wrappedTokens: wrappedAaveTokensV3Mainnet, + aaveTokens: aaveTokensV3Mainnet, + underlyingTokens: underlyingTokensMainnet, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3', + network: 1 +}) +const aaveV3PolygonAprHandler = new AaveAprHandler({ + wrappedTokens: wrappedAaveTokensV3Polygon, + aaveTokens: aaveTokensV3Polygon, + underlyingTokens: underlyingTokensPolygon, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon', + network: 137 +}); +const aaveV3ArbitrumAprHandler = new AaveAprHandler({ + wrappedTokens: wrappedAaveTokensV3Arbitrum, + aaveTokens: aaveTokensV3Arbitrum, + underlyingTokens: underlyingTokensArbitrum, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum', + network: 42161 +}) + +export const aaveHandlers = [ + aaveV2MainnetAprHandler, + aaveV2PolygonAprHandler, + aaveV3MainnetAprHandler, + aaveV3PolygonAprHandler, + aaveV3ArbitrumAprHandler +] diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts index 860d876e2..cc8d0a9cc 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts @@ -1,90 +1,89 @@ -export const wrappedAaveTokensV2Mainnet = new Map(Object.entries({ +export const wrappedAaveTokensV2Mainnet = { waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', -})); +}; -export const aaveTokensV2Mainnet = new Map(Object.entries({ +export const aaveTokensV2Mainnet = { aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c', aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', -})); +}; -export const wrappedAaveTokensV2Polygon = new Map(Object.entries({ +export const wrappedAaveTokensV2Polygon = { waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', -})); +}; -export const aaveTokensV2Polygon = new Map(Object.entries({ +export const aaveTokensV2Polygon = { aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', -})); +}; -export const wrappedAaveTokensV3Mainnet = new Map(Object.entries({ +export const wrappedAaveTokensV3Mainnet = { waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', -})); +}; -export const aaveTokensV3Mainnet = new Map(Object.entries({ +export const aaveTokensV3Mainnet = { aUSDT: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', aUSDC: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', aDAI: '0x018008bfb33d285247a21d44e50697654f754e63', aWETH: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8' -})); +}; -export const wrappedAaveTokensV3Polygon = new Map(Object.entries({ +export const wrappedAaveTokensV3Polygon = { waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', waUSDC: '0x9719d867a500ef117cc201206b8ab51e794d3f82', waDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', -})); +}; -export const aaveTokensV3Polygon = new Map(Object.entries({ +export const aaveTokensV3Polygon = { aMATIC: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', -})); +}; -export const wrappedAaveTokensV3Arbitrum = new Map(Object.entries({ +export const wrappedAaveTokensV3Arbitrum = { waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', waWETH: '0x18c100415988bef4354effad1188d1c22041b046' -})); +}; -export const aaveTokensV3Arbitrum = new Map(Object.entries({ +export const aaveTokensV3Arbitrum = { aUSDT: '0x6ab707aca953edaefbc4fd23ba73294241490620', aUSDC: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', aDAI: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', -})); -export const underlyingTokensMainnet = new Map(Object.entries({ +}; +export const underlyingTokensMainnet = { USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' -})); -export const underlyingTokensPolygon = new Map(Object.entries({ +}; +export const underlyingTokensPolygon = { MATIC: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', USDT: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', DAI: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', WETH: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619' -})); +}; -export const underlyingTokensArbitrum = new Map(Object.entries({ +export const underlyingTokensArbitrum = { USDT: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', USDC: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', DAI: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', WETH: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', -})); - +}; \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts index 23d86d1fa..e44924fef 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts @@ -7,4 +7,12 @@ export interface ReserveResponse { } ] } +} + +export type AaveAprHandlerConfig = { + wrappedTokens: { [key: string]: string } + aaveTokens: { [key: string]: string } + underlyingTokens: { [key: string]: string } + subgraphUrl: string + network: number; } \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts index 794d151fc..43dda9600 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts @@ -1,17 +1,20 @@ import axios from "axios"; import { AprHandler } from "../../types"; +import { AnkrAprHandlerConfig } from "./types"; const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb' -class AnkrAprHandler implements AprHandler{ +class AnkrAprHandler implements AprHandler { serviceName: string tokenAddress: string + network: number readonly url: string = 'https://api.staking.ankr.com/v1alpha/metrics'; readonly group = 'ANKR'; - constructor(serviceName: string, tokenAddress: string) { - this.serviceName = serviceName - this.tokenAddress = tokenAddress + constructor(aprHandlerConfig: AnkrAprHandlerConfig) { + this.serviceName = aprHandlerConfig.serviceName + this.tokenAddress = aprHandlerConfig.tokenAddress + this.network = aprHandlerConfig.network } async getAprs() { @@ -34,4 +37,11 @@ class AnkrAprHandler implements AprHandler{ } } -export const ankrEthMainnetAprHandler = new AnkrAprHandler('eth', ankrEthMainnet); \ No newline at end of file +const ankrEthMainnetAprHandler = new AnkrAprHandler( + { + serviceName: 'eth', + tokenAddress: ankrEthMainnet, + network: 1 + }); + +export const ankrHandlers = [ankrEthMainnetAprHandler]; \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts index 36cad21b2..a2c7719c6 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts @@ -1,8 +1,8 @@ import axios from "axios"; import { - cbETHMainnet, MATICXMainnet, rETHMainnet, sfrxETHMainnet, + cbETHMainnet, MATICXPolygon, rETHMainnet, sfrxETHMainnet, stETHMainnet, stMATICPolygon, swETHMainnet, USDRMainnet, - vETHMainnet, wbETHMainnet, + vETHMainnet, wbETHMainnet, wjAURAMainnet, wstETHArbitrum, wstETHGnosis, wstETHMainnet, @@ -10,40 +10,43 @@ import { wstETHZkEVM } from "./tokens"; import { AprHandler } from "../../types"; +import { DefaultAprHandlerConfig } from "./types"; + +class DefaultAprHandler implements AprHandler { -class DefaultAprHandler implements AprHandler{ - tokens: string[]; url: string; path: string; scale: number; + network: number; readonly group = undefined; - - constructor(tokens: string[], url:string, path?:string, scale?:number){ - this.tokens = tokens; - this.url = url; - this.path = path ?? ''; - this.scale = scale ?? 100; + + constructor(aprHandlerConfig: DefaultAprHandlerConfig) { + this.tokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.url; + this.network = aprHandlerConfig.network; + this.path = aprHandlerConfig.path ?? ''; + this.scale = aprHandlerConfig.scale ?? 100; } - - async getAprs() { - try{ - - const { data } = await axios.get(this.url, { headers: { 'User-Agent': 'cf' } }) - const value = (this.path === '') ? data : this.getValueFromPath(data, this.path) - const scaledValue = parseFloat(value) / this.scale - return this.tokens.reduce((acc, token) => { - acc[token] = scaledValue - return acc - }, {} as { [key: string]: number }) + async getAprs() { + try { + + const { data } = await axios.get(this.url, { headers: { 'User-Agent': 'cf' } }) + const value = (this.path === '') ? data : this.getValueFromPath(data, this.path) + const scaledValue = parseFloat(value) / this.scale + + return this.tokens.reduce((acc, token) => { + acc[token] = scaledValue + return acc + }, {} as { [key: string]: number }) } catch (error) { - console.error(`Failed to fetch APRs in url ${this.url}}:`, error) + console.error(`Failed to fetch APRs in url ${ this.url }}:`, error) return {} } } - getValueFromPath = (obj: any, path: string) => { + getValueFromPath(obj: any, path: string) { const parts = path.split('.') let value = obj for (const part of parts) { @@ -51,29 +54,130 @@ class DefaultAprHandler implements AprHandler{ } return value } - + } -export const vETHAprHandler = new DefaultAprHandler([vETHMainnet], 'https://apy.liebi.com/veth', 'veth') -export const stETHAprHandler = new DefaultAprHandler([ - wstETHPolygon, - wstETHZkEVM, - wstETHGnosis, - stETHMainnet, - wstETHMainnet, - wstETHArbitrum -], - 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - 'data.smaApr') +const vETHMainnetAprHandler = new DefaultAprHandler({ + tokens: [vETHMainnet], + url: 'https://apy.liebi.com/veth', + path: 'veth', + network: 1 +}) +const stETHMainnetAprHandler = new DefaultAprHandler({ + tokens: [ + stETHMainnet, + wstETHMainnet, + ], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 1 +}) +const stETHPolygonAprHandler = new DefaultAprHandler({ + tokens: [ + wstETHPolygon, + ], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 137 +}) +const stETHZkEVMAprHandler = new DefaultAprHandler({ + tokens: [ + wstETHZkEVM, + ], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 1101 +}) +const stETHGnosisAprHandler = new DefaultAprHandler({ + tokens: [ + wstETHGnosis, + ], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 100 +}) +const stETHArbitrumAprHandler = new DefaultAprHandler({ + tokens: [ + wstETHArbitrum + ], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 42161 +}) + +const stMaticPolygonAprHandler = new DefaultAprHandler({ + tokens: [stMATICPolygon], + url: 'https://polygon.lido.fi/api/stats', + path: 'apr', + network: 137 +}) +const cbEthMainnetAprHandler = new DefaultAprHandler({ + tokens: [cbETHMainnet], + url: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', + path: 'apy', + scale: 1, + network: 1 + } +) +const sfrxEthMainnetAprHandler = new DefaultAprHandler({ + tokens: [sfrxETHMainnet], + url: 'https://api.frax.finance/v2/frxeth/summary/latest', + path: 'sfrxethApr', + network: 1 +}) +const rETHMainnetAprHandler = new DefaultAprHandler({ + tokens: [rETHMainnet], + url: 'https://drop-api.stafi.io/reth/v1/poolData', + path: 'data.stakeApr', + network: 1 +}) +const USDRMainnetAprHandler = new DefaultAprHandler({ + tokens: [USDRMainnet], + url: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', + path: 'usdr', + network: 1 +}) -export const stMaticAprHandler = new DefaultAprHandler([stMATICPolygon], 'https://polygon.lido.fi/api/stats', 'apr') -export const cbEthAprHandler = new DefaultAprHandler([cbETHMainnet], 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', 'apy', 1) -export const sfrxEthAprHandler = new DefaultAprHandler([sfrxETHMainnet], 'https://api.frax.finance/v2/frxeth/summary/latest', 'sfrxethApr') -export const rETHAprHandler = new DefaultAprHandler([rETHMainnet], 'https://drop-api.stafi.io/reth/v1/poolData', 'data.stakeApr') -export const USDRAprHandler = new DefaultAprHandler([USDRMainnet], 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', 'usdr') +const MATICXPolygonAprHandler = new DefaultAprHandler({ + tokens: [MATICXPolygon], + url: 'https://universe.staderlabs.com/polygon/apy', + path: 'value', + network: 137 +}) +const wbETHPolygonAprHandler = new DefaultAprHandler({ + tokens: [wbETHMainnet], + url: 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', + path: 'data.0.rewardRate', + scale: 1, + network: 137 , +}); -export const MATICXAprHandler = new DefaultAprHandler([MATICXMainnet], 'https://universe.staderlabs.com/polygon/apy', 'value') -export const wbETHAprHandler = new DefaultAprHandler([wbETHMainnet], 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', 'data.0.rewardRate', 1); +const swETHMainnetAprHandler = new DefaultAprHandler({ + tokens: [swETHMainnet], + url: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', + network: 1 +}) +const wjAURAMainnetAprHandler = new DefaultAprHandler({ + tokens: [wjAURAMainnet], + url: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', + path: 'wjauraApy', + network: 1, +}) -export const swETHAprHandler = new DefaultAprHandler([swETHMainnet], 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr') -export const wjAURAAprHandler = new DefaultAprHandler([swETHMainnet], 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', 'wjauraApy') \ No newline at end of file +export const defaultHandlers = [ + vETHMainnetAprHandler, + stETHMainnetAprHandler, + stETHPolygonAprHandler, + stETHZkEVMAprHandler, + stETHGnosisAprHandler, + stETHArbitrumAprHandler, + stMaticPolygonAprHandler, + cbEthMainnetAprHandler, + sfrxEthMainnetAprHandler, + rETHMainnetAprHandler, + USDRMainnetAprHandler, + MATICXPolygonAprHandler, + wbETHPolygonAprHandler, + swETHMainnetAprHandler, + wjAURAMainnetAprHandler, +] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts index 5d5fc68ef..9698768f8 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts @@ -10,7 +10,7 @@ const cbETHMainnet = '0xbe9895146f7af43049ca1c1ae358b0541ea49704'; const sfrxETHMainnet = '0xac3e018457b222d93114458476f3e3416abbe38f'; const rETHMainnet = '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'; const USDRMainnet = '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'; -const MATICXMainnet = '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'; +const MATICXPolygon = '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'; const wbETHMainnet = '0xa2e3356610840701bdf5611a53974510ae27e2e1'; const swETHMainnet = '0xf951e335afb289353dc249e82926178eac7ded78'; const wjAURAMainnet = '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'; @@ -28,7 +28,7 @@ export { sfrxETHMainnet, rETHMainnet, USDRMainnet, - MATICXMainnet, + MATICXPolygon, wbETHMainnet, swETHMainnet, wjAURAMainnet diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts index c0f12621a..43890bd38 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts @@ -1,11 +1,12 @@ import axios from "axios"; -import { EulerResponse } from "./types"; +import { EulerAprHandlerConfig, EulerResponse } from "./types"; import { eulerTokensMainnet } from "./tokens"; import { AprHandler } from "../../types"; class EulerAprHandler implements AprHandler { - tokens: Map + tokens: { [key: string]: string } subgraphUrl: string + network: number; readonly group = 'EULER'; readonly query = ` @@ -21,9 +22,10 @@ class EulerAprHandler implements AprHandler { } ` - constructor(tokens: Map, subgraphUrl: string) { - this.tokens = tokens - this.subgraphUrl = subgraphUrl + constructor(aprHandlerConfig: EulerAprHandlerConfig) { + this.tokens = aprHandlerConfig.tokens + this.subgraphUrl = aprHandlerConfig.subgraphUrl + this.network = aprHandlerConfig.network; } async getAprs() { @@ -31,7 +33,7 @@ class EulerAprHandler implements AprHandler { operationName: 'getAssetsAPY', query: this.query, variables: { - eTokenAddress_in: Array.from(this.tokens.values()), + eTokenAddress_in: Object.values(this.tokens), }, } @@ -55,4 +57,10 @@ class EulerAprHandler implements AprHandler { } } -export const eulerMainnetAprHandler = new EulerAprHandler(eulerTokensMainnet, 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet'); \ No newline at end of file +const eulerMainnetAprHandler = new EulerAprHandler({ + tokens: eulerTokensMainnet, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet', + network: 1, +}); + +export const eulerHandlers = [eulerMainnetAprHandler]; \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts index 92f2326d3..8824bbe1b 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts @@ -1,7 +1,6 @@ -export const eulerTokensMainnet = new Map(Object.entries( - { - eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', - eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', - eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', - eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', - })) \ No newline at end of file +export const eulerTokensMainnet = { + eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', + eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', + eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', + eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts index eab65cf8a..ed8427705 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts @@ -7,4 +7,11 @@ export interface EulerResponse { } ] } +} + +export type EulerAprHandlerConfig = { + tokens: {[key: string]: string}; + subgraphUrl: string; + network: number; + } \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts index e92ea3ad0..9ae434370 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts @@ -1,15 +1,18 @@ import axios from "axios"; import { gearboxTokensMainnet } from "./tokens"; import { AprHandler } from "../../types"; +import { GearboxAprHandlerConfig } from "./types"; class GearboxAprHandler implements AprHandler { url: string; - tokens: Map; + tokens: { [key: string]: string} + network: number; readonly group = 'GEARBOX'; - constructor(tokens: Map, url: string,) { - this.tokens = tokens; - this.url = url; + constructor(aprHandlerConfig: GearboxAprHandlerConfig) { + this.tokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.url; + this.network = aprHandlerConfig.network; } async getAprs() { @@ -19,7 +22,7 @@ class GearboxAprHandler implements AprHandler { const json = data as { data: { dieselToken: string; depositAPY_RAY: string }[] } const aprEntries = json.data - .filter((t) => Array.from(this.tokens.values()).includes(t.dieselToken.toLowerCase())) + .filter((t) => Object.values(this.tokens).includes(t.dieselToken.toLowerCase())) .map((({ dieselToken, depositAPY_RAY }) => { return [dieselToken, Number(depositAPY_RAY.slice(0, 27)) / 1e27] })) @@ -31,7 +34,10 @@ class GearboxAprHandler implements AprHandler { } } -export const gearboxMainnetAprHandler = new GearboxAprHandler( - gearboxTokensMainnet, - 'https://mainnet.gearbox.foundation/api/pools' -) \ No newline at end of file +const gearboxMainnetAprHandler = new GearboxAprHandler({ + tokens: gearboxTokensMainnet, + url: 'https://mainnet.gearbox.foundation/api/pools', + network: 1 + }) + +export const gearboxHandlers = [gearboxMainnetAprHandler] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts index 7c23d878f..1dad2dbd9 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts @@ -1,4 +1,4 @@ -export const gearboxTokensMainnet = new Map(Object.entries({ +export const gearboxTokensMainnet = { dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', -})); \ No newline at end of file +}; \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/types.ts new file mode 100644 index 000000000..bb48d30b1 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/types.ts @@ -0,0 +1,6 @@ +export type GearboxAprHandlerConfig = { + tokens: {[key: string]: string}; + url: string; + network: number; + +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts index b05bde775..1329914a4 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts @@ -1,41 +1,42 @@ import axios from "axios"; import { idleTokensMainnet, wrapped4626IdleTokensMainnet } from "./tokens"; import { AprHandler } from "../../types"; +import { IdleAprHandlerConfig } from "./types"; class IdleAprHandler implements AprHandler { - wrappedIdleTokens: Map; - idleTokens: Map + wrappedIdleTokens: { [key: string]: string }; + idleTokens: { [key: string]: string }; baseIdleApiUrl: string; authorizationHeader: string; + network: number; readonly group = 'IDLE'; - constructor(wrappedIdleTokens: Map, - idleTokens: Map, - baseIdleApiUrl: string, - authorizationHeader: string) { - this.wrappedIdleTokens = wrappedIdleTokens; - this.idleTokens = idleTokens; - this.baseIdleApiUrl = baseIdleApiUrl; - this.authorizationHeader = authorizationHeader; + constructor(aprHandlerConfig: IdleAprHandlerConfig) { + this.wrappedIdleTokens = aprHandlerConfig.wrappedIdleTokens; + this.idleTokens = aprHandlerConfig.idleTokens; + this.baseIdleApiUrl = aprHandlerConfig.baseIdleApiUrl; + this.authorizationHeader = aprHandlerConfig.authorizationHeader; + this.network = aprHandlerConfig.network; } async getAprs() { try { - const aprPromises = Array.from(this.idleTokens.entries()).map(async ([tokenName, idleTokenAddress]) => { - const { data } = await axios.get([this.baseIdleApiUrl, idleTokenAddress, "?isRisk=false&order=desc&limit=1"].join(''), { - headers: { - Authorization: this.authorizationHeader, - }, + const aprPromises = Object.entries(this.idleTokens) + .map(async ([tokenName, idleTokenAddress]) => { + const { data } = await axios.get([this.baseIdleApiUrl, idleTokenAddress, "?isRisk=false&order=desc&limit=1"].join(''), { + headers: { + Authorization: this.authorizationHeader, + }, + }) + const [json] = data as { idleRate: string }[] + const value = Number(json.idleRate) / 1e20 + return [ + this.wrappedIdleTokens[tokenName], + value, + ] }) - const [json] = data as { idleRate: string }[] - const value = Number(json.idleRate) / 1e20 - return [ - this.wrappedIdleTokens.get(tokenName), - value, - ] - }) - const res = Array(this.idleTokens.size) + const res = Array(Object.keys(this.idleTokens).length) for (const [index, aprPromise] of aprPromises.entries()) { res[index] = await aprPromise } @@ -47,9 +48,13 @@ class IdleAprHandler implements AprHandler { } } -export const idleMainnetAprHandler = new IdleAprHandler( - wrapped4626IdleTokensMainnet, - idleTokensMainnet, - 'https://api.idle.finance/junior-rates/', - 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M' -); \ No newline at end of file +const idleMainnetAprHandler = new IdleAprHandler( + { + wrappedIdleTokens: wrapped4626IdleTokensMainnet, + idleTokens: idleTokensMainnet, + baseIdleApiUrl: 'https://api.idle.finance/junior-rates/', + authorizationHeader: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M', + network: 1 + }); + +export const idleAprHandlers = [idleMainnetAprHandler] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts index ec49dffde..9358f64da 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts @@ -1,11 +1,11 @@ -export const wrapped4626IdleTokensMainnet = new Map(Object.entries({ +export const wrapped4626IdleTokensMainnet = { idleDAI: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', idleUSDC: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', idleUSDT: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', -})) +} -export const idleTokensMainnet = new Map(Object.entries({ +export const idleTokensMainnet = { idleDAI: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', idleUSDC: '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', idleUSDT: '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', -})) \ No newline at end of file +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/types.ts new file mode 100644 index 000000000..b37c220c5 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/types.ts @@ -0,0 +1,7 @@ +export type IdleAprHandlerConfig = { + wrappedIdleTokens: {[key: string]: string}; + idleTokens: {[key: string]: string}; + baseIdleApiUrl: string; + authorizationHeader: string; + network: number; +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts index fc02fe07d..b6d455f68 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts @@ -1,50 +1,25 @@ -import { - aaveV2MainnetAprHandler, - aaveV2PolygonAprHandler, aaveV3ArbitrumAprHandler, - aaveV3MainnetAprHandler, - aaveV3PolygonAprHandler -} from "./aave/aave-apr-handler"; -import { ankrEthMainnetAprHandler } from "./ankr/ankr-apr-handler"; -import { - cbEthAprHandler, MATICXAprHandler, - rETHAprHandler, - sfrxEthAprHandler, - stMaticAprHandler, swETHAprHandler, USDRAprHandler, wbETHAprHandler, wjAURAAprHandler -} from "./default-fetch/default-apr-handler"; -import { eulerMainnetAprHandler } from "./euler/euler-apr-handler"; -import { gearboxMainnetAprHandler } from "./gearbox/gearbox-apr-handler"; -import { idleMainnetAprHandler } from "./idle/idle-apr-handler"; -import { overnightMainnetAprHandler } from "./overnight/overnight-apr-handler"; -import { AprHandler } from "../types"; -import { ovixZkEVMAprHandler } from "./ovix/ovix-apr-handler"; -import { reaperArbitrumAprHandler } from "./reaper/reaper-apr-handler"; -import { tesseraApePoolAprHandler } from "./tessera/tessera-apr-handler"; -import { tetuAprHandler } from "./tetu/tetu-apr-handler"; -import { tranchessMainnetAprHandler } from "./tranchess/tranchess-apr-handler"; +import { aaveHandlers } from "./aave/aave-apr-handler"; +import { ankrHandlers } from "./ankr/ankr-apr-handler"; +import { defaultHandlers } from "./default-fetch/default-apr-handler"; +import { eulerHandlers } from "./euler/euler-apr-handler"; +import { gearboxHandlers } from "./gearbox/gearbox-apr-handler"; +import { idleAprHandlers } from "./idle/idle-apr-handler"; +import { overnightHandlers } from "./overnight/overnight-apr-handler"; +import { ovixHandlers } from "./ovix/ovix-apr-handler"; +import { reaperHandlers } from "./reaper/reaper-apr-handler"; +import { tesseraHandlers } from "./tessera/tessera-apr-handler"; +import { tetuHandlers } from "./tetu/tetu-apr-handler"; -export const aprHandlers: AprHandler[] = [ - aaveV2MainnetAprHandler, - aaveV2PolygonAprHandler, - aaveV3MainnetAprHandler, - aaveV3PolygonAprHandler, - aaveV3ArbitrumAprHandler, - ankrEthMainnetAprHandler, - stMaticAprHandler, - cbEthAprHandler, - sfrxEthAprHandler, - rETHAprHandler, - USDRAprHandler, - MATICXAprHandler, - wbETHAprHandler, - swETHAprHandler, - wjAURAAprHandler, - eulerMainnetAprHandler, - gearboxMainnetAprHandler, - idleMainnetAprHandler, - overnightMainnetAprHandler, - ovixZkEVMAprHandler, - reaperArbitrumAprHandler, - tesseraApePoolAprHandler, - tetuAprHandler, - tranchessMainnetAprHandler, +export const aprHandlers = [ + ...aaveHandlers, + ...ankrHandlers, + ...defaultHandlers, + ...eulerHandlers, + ...gearboxHandlers, + ...idleAprHandlers, + ...overnightHandlers, + ...ovixHandlers, + ...reaperHandlers, + ...tesseraHandlers, + ...tetuHandlers, ] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts index e5a7403eb..5777d5d7d 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts @@ -1,24 +1,27 @@ import axios from "axios"; import { overnightTokens } from "./tokens"; import { AprHandler } from "../../types"; +import { OvernightAprHandlerConfig } from "./types"; class OvernightAprHandler implements AprHandler { - overnightTokens: Map; + overnightTokens: { [key: string]: string }; url: string; + network: number; readonly group = 'OVERNIGHT'; - constructor(tokens: Map, url: string) { - this.overnightTokens = tokens; - this.url = url; + constructor(aprHandlerConfig: OvernightAprHandlerConfig) { + this.overnightTokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.url; + this.network = aprHandlerConfig.network; } - getAprs = async () => { + async getAprs() { try { const { data } = await axios.get(this.url) const rate = data as number - return Array.from(this.overnightTokens.values()).reduce((acc, token) => { + return Object.values(this.overnightTokens).reduce((acc, token) => { acc[token] = rate return acc }, {} as { [key: string]: number }) @@ -29,4 +32,10 @@ class OvernightAprHandler implements AprHandler { } } -export const overnightMainnetAprHandler = new OvernightAprHandler(overnightTokens, 'https://app.overnight.fi/api/balancer/week/apr') \ No newline at end of file +const overnightMainnetAprHandler = new OvernightAprHandler({ + tokens: overnightTokens, + url: 'https://app.overnight.fi/api/balancer/week/apr', + network: 1 +}) + +export const overnightHandlers = [overnightMainnetAprHandler] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts index 774b8bc88..bb24d105b 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts @@ -1,5 +1,4 @@ -export const overnightTokens = new Map(Object.entries({ - lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus - UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f' // UsdcUsdPlus - } -)) \ No newline at end of file +export const overnightTokens = { + lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus + UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f' // UsdcUsdPlus +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/types.ts new file mode 100644 index 000000000..d4862ff7d --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/types.ts @@ -0,0 +1,5 @@ +export type OvernightAprHandlerConfig = { + tokens: {[key: string]: string}; + url: string; + network: number; +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts index 227f2e766..588367e93 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts @@ -3,22 +3,23 @@ import { abi } from "../abis/oErc20"; import { JsonRpcProvider } from "@ethersproject/providers"; import { ovixWrappedTokensZkEvm, ovixYieldTokensZkEvm } from "./tokens"; import { AprHandler } from "../../types"; +import { OvixAprHandlerConfig } from "./types"; class OvixAprHandler implements AprHandler { + network: number; provider: JsonRpcProvider; yieldTokens: { [key: string]: `0x${ string }` }; wrappedTokens: { [key: string]: `0x${ string }` }; readonly group = 'OVIX'; - constructor(network: number, rpcUrl: string, yieldTokens: { [key: string]: `0x${ string }` }, wrappedTokens: { - [key: string]: `0x${ string }` - }) { - this.provider = new JsonRpcProvider(rpcUrl, network); - this.yieldTokens = yieldTokens; - this.wrappedTokens = wrappedTokens; + constructor(aprHandlerConfig: OvixAprHandlerConfig) { + this.network = aprHandlerConfig.network; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); + this.yieldTokens = aprHandlerConfig.yieldTokens; + this.wrappedTokens = aprHandlerConfig.wrappedTokens; } - getAprs = async () => { + async getAprs() { try { const calls = Object.keys(this.yieldTokens).map(async (tokenName) => { @@ -44,4 +45,11 @@ class OvixAprHandler implements AprHandler { } } -export const ovixZkEVMAprHandler = new OvixAprHandler(1101, 'https://zkevm-rpc.com', ovixYieldTokensZkEvm, ovixWrappedTokensZkEvm); +const ovixZkEVMAprHandler = new OvixAprHandler({ + network: 1101, + rpcUrl: 'https://zkevm-rpc.com', + yieldTokens: ovixYieldTokensZkEvm, + wrappedTokens: ovixWrappedTokensZkEvm +}); + +export const ovixHandlers = [ovixZkEVMAprHandler] diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/types.ts new file mode 100644 index 000000000..8947108c2 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/types.ts @@ -0,0 +1,8 @@ +export type OvixAprHandlerConfig = { + network: number; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${ string }` } + wrappedTokens: { + [key: string]: `0x${ string }` + } +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts index 94598e1f6..077302bf3 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts @@ -3,19 +3,20 @@ import { BigNumber, Contract } from "ethers"; import { abi } from "../abis/reaperStrategy"; import { reaperStrategiesMapArbitrum, reaperYieldTokensArbitrum } from "./tokens"; import { AprHandler } from "../../types"; +import { ReaperAprHandlerConfig } from "./types"; class ReaperAprHandler implements AprHandler { + network: number; provider: JsonRpcProvider; yieldTokens: { [key: string]: `0x${ string }` }; strategiesMap: { [key: string]: `0x${ string }` }; readonly group = 'REAPER'; - constructor(network: number, rpcUrl: string, yieldTokens: { [key: string]: `0x${ string }` }, strategiesMap: { - [key: string]: `0x${ string }` - }) { - this.provider = new JsonRpcProvider(rpcUrl, network); - this.yieldTokens = yieldTokens; - this.strategiesMap = strategiesMap; + constructor(aprHandlerConfig: ReaperAprHandlerConfig) { + this.network = aprHandlerConfig.network; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); + this.yieldTokens = aprHandlerConfig.yieldTokens; + this.strategiesMap = aprHandlerConfig.strategiesMap; } async getAprs() { @@ -44,4 +45,11 @@ class ReaperAprHandler implements AprHandler { } } -export const reaperArbitrumAprHandler = new ReaperAprHandler(42161, 'https://arb1.arbitrum.io/rpc', reaperYieldTokensArbitrum, reaperStrategiesMapArbitrum) \ No newline at end of file +const reaperArbitrumAprHandler = new ReaperAprHandler({ + network: 42161, + rpcUrl: 'https://arb1.arbitrum.io/rpc', + yieldTokens: reaperYieldTokensArbitrum, + strategiesMap: reaperStrategiesMapArbitrum, +}) + +export const reaperHandlers = [reaperArbitrumAprHandler] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/types.ts new file mode 100644 index 000000000..642d560f0 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/types.ts @@ -0,0 +1,8 @@ +export type ReaperAprHandlerConfig = { + network: number; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${ string }` } + strategiesMap: { + [key: string]: `0x${ string }` + } +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts index 60c7568f3..e7eb12003 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts @@ -3,26 +3,25 @@ import { abi } from "../abis/tesseraPool"; import { JsonRpcProvider } from "@ethersproject/providers"; import { tesseraYieldTokensMainnet } from "./tokens"; import { AprHandler } from "../../types"; +import { TesseraAprHandlerConfig } from "./types"; class TesseraAprHandler implements AprHandler { + network: number; provider: JsonRpcProvider; yieldTokens: { [key: string]: `0x${ string }` }; stakingContractAddress: `0x${ string }`; readonly group = 'TESSERA'; - constructor(network: number, rpcUrl: string, yieldTokens: { - [key: string]: `0x${ string }` - }, contractAddress: `0x${ string }`) { - this.provider = new JsonRpcProvider(rpcUrl, network); - this.yieldTokens = yieldTokens; - this.stakingContractAddress = contractAddress; + constructor(aprHandlerConfig: TesseraAprHandlerConfig) { + this.network = aprHandlerConfig.network; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); + this.yieldTokens = aprHandlerConfig.yieldTokens; + this.stakingContractAddress = aprHandlerConfig.contractAddress; } - getAprs = async () => { + async getAprs() { try { - let apr = 0 - try { const contract = new Contract(this.stakingContractAddress, abi, this.provider) const poolsUI = await contract.getPoolsUI() @@ -45,4 +44,11 @@ class TesseraAprHandler implements AprHandler { } } -export const tesseraApePoolAprHandler = new TesseraAprHandler(1, 'https://rpc.ankr.com/eth', tesseraYieldTokensMainnet, '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9' /*ApeCoinStaking*/) +const tesseraMainnetAprHandler = new TesseraAprHandler({ + network: 1, + rpcUrl: 'https://rpc.ankr.com/eth', + yieldTokens: tesseraYieldTokensMainnet, + contractAddress: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9' /*ApeCoinStaking*/ + }) + +export const tesseraHandlers = [tesseraMainnetAprHandler] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/types.ts new file mode 100644 index 000000000..cc72f0552 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/types.ts @@ -0,0 +1,6 @@ +export type TesseraAprHandlerConfig = { + network: number; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${ string }` }; + contractAddress: `0x${ string }`; +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts index 2fa56b489..799a27b4b 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts @@ -1,25 +1,27 @@ import axios from "axios"; import { AprHandler } from "../../types"; +import { TetuAprHandlerConfig } from "./types"; class TetuAprHandler implements AprHandler { - + network: number; baseUrl: string; networkName: string; readonly group = 'TETU'; - - constructor(baseUrl: string, networkName: string) { - this.baseUrl = baseUrl; - this.networkName = networkName; + + constructor(aprHandlerConfig: TetuAprHandlerConfig) { + this.network = aprHandlerConfig.network; + this.baseUrl = aprHandlerConfig.baseUrl; + this.networkName = aprHandlerConfig.networkName; } - + async getAprs() { - try{ - - const { data } = await axios.get(`${this.baseUrl}?network=${ this.networkName }`) - const json = data as { vault: string, apr: number }[] - const aprs = json.map((t) => [t.vault, t.apr / 100]) + try { - return Object.fromEntries(aprs) + const { data } = await axios.get(`${ this.baseUrl }?network=${ this.networkName }`) + const json = data as { vault: string, apr: number }[] + const aprs = json.map((t) => [t.vault, t.apr / 100]) + + return Object.fromEntries(aprs) } catch (error) { console.error('Failed to fetch Tetu APR:', error) return {} @@ -27,4 +29,10 @@ class TetuAprHandler implements AprHandler { } } -export const tetuAprHandler = new TetuAprHandler('https://api.tetu.io/api/v1/reader/compoundAPRs', 'MATIC') \ No newline at end of file +const tetuPolygonAprHandler = new TetuAprHandler({ + network: 137, + baseUrl: 'https://api.tetu.io/api/v1/reader/compoundAPRs', + networkName: 'MATIC' +}) + +export const tetuHandlers = [tetuPolygonAprHandler] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/types.ts new file mode 100644 index 000000000..92c0c540d --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/types.ts @@ -0,0 +1,5 @@ +export type TetuAprHandlerConfig = { + network: number; + baseUrl: string; + networkName: string; +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts index b48cdc6f8..384fa0c2a 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts @@ -1,21 +1,23 @@ import axios from "axios"; import { AprHandler } from "../../types"; +import { TranchessAprHandlerConfig } from "./types"; const qETHMainnet = '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d' class TranchessAprHandler implements AprHandler { + network: number; url: string; token: string; readonly group = 'TRANCHESS'; - constructor(token: string, url: string) { - this.token = token; - this.url = url; + constructor(aprHandlerConfig: TranchessAprHandlerConfig) { + this.network = aprHandlerConfig.network; + this.token = aprHandlerConfig.token; + this.url = aprHandlerConfig.url; } async getAprs() { try { - const { data } = await axios.get('https://tranchess.com/eth/api/v3/funds'); const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[] // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. @@ -30,4 +32,10 @@ class TranchessAprHandler implements AprHandler { } } -export const tranchessMainnetAprHandler = new TranchessAprHandler(qETHMainnet, 'https://tranchess.com/eth/api/v3/funds') \ No newline at end of file +const tranchessMainnetAprHandler = new TranchessAprHandler({ + network: 1, + token: qETHMainnet, + url: 'https://tranchess.com/eth/api/v3/funds' +}) + +export const tranchessHandlers = [tranchessMainnetAprHandler] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/types.ts new file mode 100644 index 000000000..d8e23e276 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/types.ts @@ -0,0 +1,5 @@ +export type TranchessAprHandlerConfig = { + network: number; + token: string; + url: string; +} \ No newline at end of file diff --git a/modules/pool/pool.prisma b/modules/pool/pool.prisma index 42d01c7bd..e73d9b6bb 100644 --- a/modules/pool/pool.prisma +++ b/modules/pool/pool.prisma @@ -308,6 +308,7 @@ enum PrismaPoolAprItemGroup { TETU OVIX EULER + DEFAULT } model PrismaPoolCategory { From 19a48fcc4f49cbf6cec02974b11424b04eec0b5c Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 1 Aug 2023 19:26:35 -0300 Subject: [PATCH 11/42] Types files for ankr and default-fetch; (Missing in the last commit) --- .../ib-yield-apr-handlers/sources/ankr/types.ts | 5 +++++ .../ib-yield-apr-handlers/sources/default-fetch/types.ts | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/types.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/types.ts diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/types.ts new file mode 100644 index 000000000..7ccc108d0 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/types.ts @@ -0,0 +1,5 @@ +export type AnkrAprHandlerConfig = { + serviceName: string; + tokenAddress: string; + network: number; +} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/types.ts new file mode 100644 index 000000000..cd7dfcae8 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/types.ts @@ -0,0 +1,7 @@ +export type DefaultAprHandlerConfig = { + tokens: string[]; + url: string; + network: number; + scale?: number; + path?: string; +} \ No newline at end of file From a7b904b9b80e73806ad6aade21a690dcb12aa0ca Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 1 Aug 2023 21:19:05 -0300 Subject: [PATCH 12/42] Creating new migration file; --- .../sources/default-fetch/default-apr-handler.ts | 4 ++-- .../migration.sql | 16 ---------------- prisma/schema.prisma | 2 ++ 3 files changed, 4 insertions(+), 18 deletions(-) delete mode 100644 prisma/migrations/20230712222318_add_new_apr_item_groups/migration.sql diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts index a2c7719c6..60abad05d 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts @@ -19,7 +19,7 @@ class DefaultAprHandler implements AprHandler { path: string; scale: number; network: number; - readonly group = undefined; + readonly group = "DEFAULT"; constructor(aprHandlerConfig: DefaultAprHandlerConfig) { this.tokens = aprHandlerConfig.tokens; @@ -41,7 +41,7 @@ class DefaultAprHandler implements AprHandler { return acc }, {} as { [key: string]: number }) } catch (error) { - console.error(`Failed to fetch APRs in url ${ this.url }}:`, error) + console.error(`Failed to fetch APRs in url ${ this.url }:`, error) return {} } } diff --git a/prisma/migrations/20230712222318_add_new_apr_item_groups/migration.sql b/prisma/migrations/20230712222318_add_new_apr_item_groups/migration.sql deleted file mode 100644 index 6caa80d08..000000000 --- a/prisma/migrations/20230712222318_add_new_apr_item_groups/migration.sql +++ /dev/null @@ -1,16 +0,0 @@ --- AlterEnum --- This migration adds more than one value to an enum. --- With PostgreSQL versions 11 and earlier, this is not possible --- in a single migration. This can be worked around by creating --- multiple migrations, each migration adding only one value to --- the enum. - - -ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'IDLE'; -ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'TRANCHESS'; -ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'GEARBOX'; -ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'AAVE'; -ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'ANKR'; -ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'TESSERA'; -ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'TETU'; -ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'OVIX'; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 09cafdcb7..8d83a0545 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -352,6 +352,8 @@ enum PrismaPoolAprItemGroup { TESSERA TETU OVIX + EULER + DEFAULT } model PrismaPoolCategory { From 4cff5b7305571966f6f964e24f8732486041889e Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 1 Aug 2023 21:22:28 -0300 Subject: [PATCH 13/42] Removing test route; Adding migration file; --- modules/balancer/loadRestRoutes.ts | 11 ----------- .../migration.sql | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 prisma/migrations/20230802001731_adding_apr_item_groups/migration.sql diff --git a/modules/balancer/loadRestRoutes.ts b/modules/balancer/loadRestRoutes.ts index 893502fd1..632920075 100644 --- a/modules/balancer/loadRestRoutes.ts +++ b/modules/balancer/loadRestRoutes.ts @@ -6,15 +6,4 @@ import { prisma } from "../../prisma/prisma-client"; export function loadRestRoutesBalancer(app: Express) { app.use('/health', (req, res) => res.sendStatus(200)); - app.use('/test', async (req, res) => { - const pools = await prisma.prismaPool.findMany({ - ...prismaPoolWithExpandedNesting, - where: { chain: networkContext.chain }, - }); - const ibTokensAprService = new IbTokensAprService(1); - await ibTokensAprService.updateAprForPools(pools); - - return res.sendStatus(200) - }); - } diff --git a/prisma/migrations/20230802001731_adding_apr_item_groups/migration.sql b/prisma/migrations/20230802001731_adding_apr_item_groups/migration.sql new file mode 100644 index 000000000..d6a91ea1f --- /dev/null +++ b/prisma/migrations/20230802001731_adding_apr_item_groups/migration.sql @@ -0,0 +1,18 @@ +-- AlterEnum +-- This migration adds more than one value to an enum. +-- With PostgreSQL versions 11 and earlier, this is not possible +-- in a single migration. This can be worked around by creating +-- multiple migrations, each migration adding only one value to +-- the enum. + + +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'IDLE'; +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'TRANCHESS'; +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'GEARBOX'; +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'AAVE'; +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'ANKR'; +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'TESSERA'; +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'TETU'; +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'OVIX'; +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'EULER'; +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'DEFAULT'; From 1e74f53b7e8b896656f5c87403854571578de922 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Mon, 7 Aug 2023 10:07:08 -0300 Subject: [PATCH 14/42] removing unused imports; --- modules/balancer/loadRestRoutes.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/balancer/loadRestRoutes.ts b/modules/balancer/loadRestRoutes.ts index 632920075..aad0efca7 100644 --- a/modules/balancer/loadRestRoutes.ts +++ b/modules/balancer/loadRestRoutes.ts @@ -1,8 +1,4 @@ import { Express } from 'express'; -import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; -import { networkContext } from "../network/network-context.service"; -import { prismaPoolWithExpandedNesting } from "../../prisma/prisma-types"; -import { prisma } from "../../prisma/prisma-client"; export function loadRestRoutesBalancer(app: Express) { app.use('/health', (req, res) => res.sendStatus(200)); From 6b00046a2ed18399b77653a136599742cb60b578 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Mon, 7 Aug 2023 10:20:33 -0300 Subject: [PATCH 15/42] Removing ethers-multicall-provider package --- package.json | 1 - yarn.lock | 395 +-------------------------------------------------- 2 files changed, 1 insertion(+), 395 deletions(-) diff --git a/package.json b/package.json index 40d2d6c21..dfb8cce34 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "decimal.js": "^10.3.1", "dotenv": "^10.0.0", "ethers": "^5.5.1", - "ethers-multicall-provider": "^3.0.4", "express": "^4.17.1", "express-promise-router": "^4.1.0", "googleapis": "^108.0.0", diff --git a/yarn.lock b/yarn.lock index 652a03cb9..4f3175a6f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2705,21 +2705,6 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/strings" "^5.5.0" -"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" - integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/abstract-provider@5.5.1", "@ethersproject/abstract-provider@^5.5.0": version "5.5.1" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz#2f1f6e8a3ab7d378d8ad0b5718460f85649710c5" @@ -2733,19 +2718,6 @@ "@ethersproject/transactions" "^5.5.0" "@ethersproject/web" "^5.5.0" -"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" - integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - "@ethersproject/abstract-signer@5.5.0", "@ethersproject/abstract-signer@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz#590ff6693370c60ae376bf1c7ada59eb2a8dd08d" @@ -2757,17 +2729,6 @@ "@ethersproject/logger" "^5.5.0" "@ethersproject/properties" "^5.5.0" -"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" - integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/address@5.5.0", "@ethersproject/address@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.5.0.tgz#bcc6f576a553f21f3dd7ba17248f81b473c9c78f" @@ -2779,17 +2740,6 @@ "@ethersproject/logger" "^5.5.0" "@ethersproject/rlp" "^5.5.0" -"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" - integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/address@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.0.tgz#13c49836d73e7885fc148ad633afad729da25012" @@ -2808,13 +2758,6 @@ dependencies: "@ethersproject/bytes" "^5.5.0" -"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" - integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/basex@5.5.0", "@ethersproject/basex@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.5.0.tgz#e40a53ae6d6b09ab4d977bd037010d4bed21b4d3" @@ -2823,14 +2766,6 @@ "@ethersproject/bytes" "^5.5.0" "@ethersproject/properties" "^5.5.0" -"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" - integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/bignumber@5.5.0", "@ethersproject/bignumber@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.5.0.tgz#875b143f04a216f4f8b96245bde942d42d279527" @@ -2840,15 +2775,6 @@ "@ethersproject/logger" "^5.5.0" bn.js "^4.11.9" -"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" - integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - bn.js "^5.2.1" - "@ethersproject/bignumber@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.0.tgz#116c81b075c57fa765a8f3822648cf718a8a0e26" @@ -2865,13 +2791,6 @@ dependencies: "@ethersproject/logger" "^5.5.0" -"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" - integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== - dependencies: - "@ethersproject/logger" "^5.7.0" - "@ethersproject/bytes@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.0.tgz#81652f2a0e04533575befadce555213c11d8aa20" @@ -2886,13 +2805,6 @@ dependencies: "@ethersproject/bignumber" "^5.5.0" -"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" - integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/constants@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.6.0.tgz#55e3eb0918584d3acc0688e9958b0cedef297088" @@ -2916,22 +2828,6 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/transactions" "^5.5.0" -"@ethersproject/contracts@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" - integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== - dependencies: - "@ethersproject/abi" "^5.7.0" - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/hash@5.5.0", "@ethersproject/hash@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.5.0.tgz#7cee76d08f88d1873574c849e0207dcb32380cc9" @@ -2946,21 +2842,6 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/strings" "^5.5.0" -"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" - integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/hdnode@5.5.0", "@ethersproject/hdnode@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.5.0.tgz#4a04e28f41c546f7c978528ea1575206a200ddf6" @@ -2979,24 +2860,6 @@ "@ethersproject/transactions" "^5.5.0" "@ethersproject/wordlists" "^5.5.0" -"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" - integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - "@ethersproject/json-wallets@5.5.0", "@ethersproject/json-wallets@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.5.0.tgz#dd522d4297e15bccc8e1427d247ec8376b60e325" @@ -3016,25 +2879,6 @@ aes-js "3.0.0" scrypt-js "3.0.1" -"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" - integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - aes-js "3.0.0" - scrypt-js "3.0.1" - "@ethersproject/keccak256@5.5.0", "@ethersproject/keccak256@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.5.0.tgz#e4b1f9d7701da87c564ffe336f86dcee82983492" @@ -3043,14 +2887,6 @@ "@ethersproject/bytes" "^5.5.0" js-sha3 "0.8.0" -"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" - integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - js-sha3 "0.8.0" - "@ethersproject/keccak256@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.6.0.tgz#fea4bb47dbf8f131c2e1774a1cecbfeb9d606459" @@ -3064,11 +2900,6 @@ resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== -"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" - integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== - "@ethersproject/logger@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" @@ -3081,13 +2912,6 @@ dependencies: "@ethersproject/logger" "^5.5.0" -"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" - integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== - dependencies: - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2@5.5.0", "@ethersproject/pbkdf2@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.5.0.tgz#e25032cdf02f31505d47afbf9c3e000d95c4a050" @@ -3096,14 +2920,6 @@ "@ethersproject/bytes" "^5.5.0" "@ethersproject/sha2" "^5.5.0" -"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" - integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/properties@5.5.0", "@ethersproject/properties@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.5.0.tgz#61f00f2bb83376d2071baab02245f92070c59995" @@ -3111,13 +2927,6 @@ dependencies: "@ethersproject/logger" "^5.5.0" -"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" - integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== - dependencies: - "@ethersproject/logger" "^5.7.0" - "@ethersproject/providers@5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.5.0.tgz#bc2876a8fe5e0053ed9828b1f3767ae46e43758b" @@ -3143,32 +2952,6 @@ bech32 "1.1.4" ws "7.4.6" -"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.2": - version "5.7.2" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" - integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - bech32 "1.1.4" - ws "7.4.6" - "@ethersproject/random@5.5.0", "@ethersproject/random@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.5.0.tgz#305ed9e033ca537735365ac12eed88580b0f81f9" @@ -3177,14 +2960,6 @@ "@ethersproject/bytes" "^5.5.0" "@ethersproject/logger" "^5.5.0" -"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" - integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/rlp@5.5.0", "@ethersproject/rlp@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.5.0.tgz#530f4f608f9ca9d4f89c24ab95db58ab56ab99a0" @@ -3193,14 +2968,6 @@ "@ethersproject/bytes" "^5.5.0" "@ethersproject/logger" "^5.5.0" -"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" - integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/rlp@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.0.tgz#55a7be01c6f5e64d6e6e7edb6061aa120962a717" @@ -3218,15 +2985,6 @@ "@ethersproject/logger" "^5.5.0" hash.js "1.1.7" -"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" - integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - hash.js "1.1.7" - "@ethersproject/signing-key@5.5.0", "@ethersproject/signing-key@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.5.0.tgz#2aa37169ce7e01e3e80f2c14325f624c29cedbe0" @@ -3239,18 +2997,6 @@ elliptic "6.5.4" hash.js "1.1.7" -"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" - integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - bn.js "^5.2.1" - elliptic "6.5.4" - hash.js "1.1.7" - "@ethersproject/solidity@5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.5.0.tgz#2662eb3e5da471b85a20531e420054278362f93f" @@ -3263,18 +3009,6 @@ "@ethersproject/sha2" "^5.5.0" "@ethersproject/strings" "^5.5.0" -"@ethersproject/solidity@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" - integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/strings@5.5.0", "@ethersproject/strings@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.5.0.tgz#e6784d00ec6c57710755699003bc747e98c5d549" @@ -3284,15 +3018,6 @@ "@ethersproject/constants" "^5.5.0" "@ethersproject/logger" "^5.5.0" -"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" - integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/transactions@5.5.0", "@ethersproject/transactions@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.5.0.tgz#7e9bf72e97bcdf69db34fe0d59e2f4203c7a2908" @@ -3308,21 +3033,6 @@ "@ethersproject/rlp" "^5.5.0" "@ethersproject/signing-key" "^5.5.0" -"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" - integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/units@5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.5.0.tgz#104d02db5b5dc42cc672cc4587bafb87a95ee45e" @@ -3332,15 +3042,6 @@ "@ethersproject/constants" "^5.5.0" "@ethersproject/logger" "^5.5.0" -"@ethersproject/units@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" - integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/wallet@5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.5.0.tgz#322a10527a440ece593980dca6182f17d54eae75" @@ -3362,27 +3063,6 @@ "@ethersproject/transactions" "^5.5.0" "@ethersproject/wordlists" "^5.5.0" -"@ethersproject/wallet@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" - integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/json-wallets" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - "@ethersproject/web@5.5.0", "@ethersproject/web@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.0.tgz#0e5bb21a2b58fb4960a705bfc6522a6acf461e28" @@ -3394,17 +3074,6 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/strings" "^5.5.0" -"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" - integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== - dependencies: - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/wordlists@5.5.0", "@ethersproject/wordlists@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.5.0.tgz#aac74963aa43e643638e5172353d931b347d584f" @@ -3416,17 +3085,6 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/strings" "^5.5.0" -"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" - integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@gnosis.pm/safe-core-sdk-types@^0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@gnosis.pm/safe-core-sdk-types/-/safe-core-sdk-types-0.1.1.tgz#908c394cb4660493b4e9c8e01b5a7aa36efafd30" @@ -5451,11 +5109,6 @@ bn.js@^5.1.2, bn.js@^5.2.0: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== -bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - body-parser@1.19.0, body-parser@^1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -6673,52 +6326,6 @@ ethereumjs-util@^7.1.3: ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethers-multicall-provider@^3.0.4: - version "3.1.1" - resolved "https://registry.yarnpkg.com/ethers-multicall-provider/-/ethers-multicall-provider-3.1.1.tgz#aac9f37a27960d2df46a819a9bf31c03a6143354" - integrity sha512-NQ13RLYoB/q0Ussjkrh2u4ZQr0JLNEzga96YKCfhlzZukQJwOdZf7GkPO4sB3hjzjQMeTS0A+H60bZTd/4eHsQ== - dependencies: - "@ethersproject/abi" "^5.7.0" - "@ethersproject/providers" "^5.7.2" - ethers "^5.0.0" - lodash "^4.17.0" - -ethers@^5.0.0: - version "5.7.2" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" - integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.2" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" - ethers@^5.5.1: version "5.5.1" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.5.1.tgz#d3259a95a42557844aa543906c537106c0406fbf" @@ -8949,7 +8556,7 @@ lodash.union@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= -lodash@^4.17.0, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0: +lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== From 8c2432eca0b3216def28d25e646fb3c3c269d0cd Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Mon, 7 Aug 2023 10:22:14 -0300 Subject: [PATCH 16/42] removing undefined from "group" type --- .../pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts index cdfa3a06c..438f3df0e 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts @@ -5,6 +5,6 @@ export type TokenApr = { } export interface AprHandler { - readonly group: string | undefined; + readonly group: string; getAprs(): Promise<{ [key: string]: number }>; } \ No newline at end of file From 500f6c4437e855891e3ccb2a9fb6eb4caae66285 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Wed, 9 Aug 2023 20:26:18 -0300 Subject: [PATCH 17/42] Moving tokens and types to apr-handler file; Changing map to for..of loop --- .../apr-data-sources/ib-tokens-apr.service.ts | 2 +- .../ib-yield-apr-handlers.ts | 54 ++++++-- .../sources/{aave => }/aave-apr-handler.ts | 128 +++++++++++++++--- .../sources/aave/tokens.ts | 89 ------------ .../sources/aave/types.ts | 18 --- .../sources/{ankr => }/ankr-apr-handler.ts | 9 +- .../sources/ankr/types.ts | 5 - .../default-apr-handler.ts | 38 ++++-- .../sources/default-fetch/tokens.ts | 35 ----- .../sources/default-fetch/types.ts | 7 - .../sources/{euler => }/euler-apr-handler.ts | 29 +++- .../sources/euler/tokens.ts | 6 - .../sources/euler/types.ts | 17 --- .../{gearbox => }/gearbox-apr-handler.ts | 15 +- .../sources/gearbox/tokens.ts | 4 - .../sources/gearbox/types.ts | 6 - .../sources/{idle => }/idle-apr-handler.ts | 27 +++- .../sources/idle/tokens.ts | 11 -- .../sources/idle/types.ts | 7 - .../ib-yield-apr-handlers/sources/index.ts | 25 ---- .../{overnight => }/overnight-apr-handler.ts | 15 +- .../sources/overnight/tokens.ts | 4 - .../sources/overnight/types.ts | 5 - .../sources/{ovix => }/ovix-apr-handler.ts | 25 +++- .../sources/ovix/tokens.ts | 9 -- .../sources/ovix/types.ts | 8 -- .../{reaper => }/reaper-apr-handler.ts | 27 +++- .../sources/reaper/tokens.ts | 11 -- .../sources/reaper/types.ts | 8 -- .../{tessera => }/tessera-apr-handler.ts | 17 ++- .../sources/tessera/tokens.ts | 4 - .../sources/tessera/types.ts | 6 - .../sources/{tetu => }/tetu-apr-handler.ts | 9 +- .../sources/tetu/types.ts | 5 - .../{tranchess => }/tranchess-apr-handler.ts | 9 +- .../sources/tranchess/types.ts | 5 - 36 files changed, 328 insertions(+), 371 deletions(-) rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{aave => }/aave-apr-handler.ts (51%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{ankr => }/ankr-apr-handler.ts (89%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/types.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{default-fetch => }/default-apr-handler.ts (77%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/types.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{euler => }/euler-apr-handler.ts (73%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{gearbox => }/gearbox-apr-handler.ts (80%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/types.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{idle => }/idle-apr-handler.ts (73%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/types.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{overnight => }/overnight-apr-handler.ts (75%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/types.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{ovix => }/ovix-apr-handler.ts (73%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/tokens.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/types.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{reaper => }/reaper-apr-handler.ts (70%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/tokens.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/types.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{tessera => }/tessera-apr-handler.ts (81%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tokens.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/types.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{tetu => }/tetu-apr-handler.ts (87%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/types.ts rename modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/{tranchess => }/tranchess-apr-handler.ts (90%) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/types.ts diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 04fca7e77..c11dfdd99 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -58,7 +58,7 @@ export class IbTokensAprService implements PoolAprService { } private async fetchYieldTokensApr(): Promise> { - const data = await this.ibYieldAprHandlers.getHandlersAprs(); + const data = await this.ibYieldAprHandlers.fetchAprsFromAllHandlers(); console.log(data); return new Map( data.filter((apr) => !isNaN(apr.val)).map((apr) => [apr.address, apr]) diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts index c9343654b..9caca0117 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts @@ -1,26 +1,50 @@ import { AprHandler, TokenApr } from "./types"; -import { aprHandlers } from "./sources"; +import { aaveHandlers } from "./sources/aave-apr-handler"; +import { ankrHandlers } from "./sources/ankr-apr-handler"; +import { defaultHandlers } from "./sources/default-apr-handler"; +import { eulerHandlers } from "./sources/euler-apr-handler"; +import { gearboxHandlers } from "./sources/gearbox-apr-handler"; +import { idleAprHandlers } from "./sources/idle-apr-handler"; +import { overnightHandlers } from "./sources/overnight-apr-handler"; +import { ovixHandlers } from "./sources/ovix-apr-handler"; +import { reaperHandlers } from "./sources/reaper-apr-handler"; +import { tesseraHandlers } from "./sources/tessera-apr-handler"; +import { tetuHandlers } from "./sources/tetu-apr-handler"; + +const aprHandlers = [ + ...aaveHandlers, + ...ankrHandlers, + ...defaultHandlers, + ...eulerHandlers, + ...gearboxHandlers, + ...idleAprHandlers, + ...overnightHandlers, + ...ovixHandlers, + ...reaperHandlers, + ...tesseraHandlers, + ...tetuHandlers, +] export class IbYieldAprHandlers { - + private handlers: AprHandler[] = []; + constructor(network: number) { this.handlers = aprHandlers.filter((handler) => handler.network === network); } - - async getHandlersAprs (): Promise { - const aprPromises = this.handlers.map(async (handler) => { + + async fetchAprsFromAllHandlers(): Promise { + let aprs: { val: number, group: string, address: string }[] = []; + for (const handler of this.handlers) { const fetchedResponse: { [key: string]: number } = await handler.getAprs() - return Object.entries(fetchedResponse).map(([address, aprValue]) => ({ - val: aprValue, - group: handler.group, - address - })) - }); - const res = Array(this.handlers.length) - for (const [index, aprPromise] of aprPromises.entries()) { - res[index] = await aprPromise + for (const [address, aprValue] of Object.entries(fetchedResponse)) { + aprs.push({ + val: aprValue, + group: handler.group, + address + }) + } } - return res.flat(); + return aprs; } } \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts similarity index 51% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts index ac7fb5f25..3de200306 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts @@ -1,20 +1,116 @@ import axios from "axios"; -import { AaveAprHandlerConfig, ReserveResponse } from "./types"; -import { - aaveTokensV2Mainnet, - aaveTokensV2Polygon, - aaveTokensV3Arbitrum, - aaveTokensV3Mainnet, - aaveTokensV3Polygon, underlyingTokensArbitrum, - underlyingTokensMainnet, - underlyingTokensPolygon, - wrappedAaveTokensV2Mainnet, - wrappedAaveTokensV2Polygon, - wrappedAaveTokensV3Arbitrum, - wrappedAaveTokensV3Mainnet, - wrappedAaveTokensV3Polygon -} from "./tokens"; -import { AprHandler } from "../../types"; +import { AprHandler } from "../types"; + +const wrappedAaveTokensV2Mainnet = { + waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', + waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', + waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', +}; + +const aaveTokensV2Mainnet = { + aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', + aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c', + aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', +}; + +const wrappedAaveTokensV2Polygon = { + waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', + waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', + waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', +}; + +const aaveTokensV2Polygon = { + aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', + aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', + aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', +}; + +const wrappedAaveTokensV3Mainnet = { + waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', + waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', + waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', + waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', +}; + +const aaveTokensV3Mainnet = { + aUSDT: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', + aUSDC: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', + aDAI: '0x018008bfb33d285247a21d44e50697654f754e63', + aWETH: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8' +}; + + +const wrappedAaveTokensV3Polygon = { + waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', + waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', + waUSDC: '0x9719d867a500ef117cc201206b8ab51e794d3f82', + waDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', +}; + +const aaveTokensV3Polygon = { + aMATIC: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', + aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', + aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', + aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', +}; + + +const wrappedAaveTokensV3Arbitrum = { + waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', + waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', + waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', + waWETH: '0x18c100415988bef4354effad1188d1c22041b046' +}; + +const aaveTokensV3Arbitrum = { + aUSDT: '0x6ab707aca953edaefbc4fd23ba73294241490620', + aUSDC: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', + aDAI: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', + aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', +}; + +const underlyingTokensMainnet = { + USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', + USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', + WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' +}; + +const underlyingTokensPolygon = { + MATIC: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', + USDT: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + DAI: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + WETH: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619' +}; + +const underlyingTokensArbitrum = { + USDT: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + USDC: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', + DAI: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + WETH: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', +}; + +interface ReserveResponse { + data: { + reserves: [ + { + underlyingAsset: string + liquidityRate: string + } + ] + } +} + +type AaveAprHandlerConfig = { + wrappedTokens: { [key: string]: string } + aaveTokens: { [key: string]: string } + underlyingTokens: { [key: string]: string } + subgraphUrl: string + network: number; +} class AaveAprHandler implements AprHandler { diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts deleted file mode 100644 index cc8d0a9cc..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/tokens.ts +++ /dev/null @@ -1,89 +0,0 @@ -export const wrappedAaveTokensV2Mainnet = { - waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', - waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', - waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', -}; - -export const aaveTokensV2Mainnet = { - aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', - aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c', - aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', -}; - -export const wrappedAaveTokensV2Polygon = { - waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', - waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', - waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', -}; - -export const aaveTokensV2Polygon = { - aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', - aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', - aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', -}; - -export const wrappedAaveTokensV3Mainnet = { - waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', - waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', - waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', - waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', -}; - -export const aaveTokensV3Mainnet = { - aUSDT: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', - aUSDC: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', - aDAI: '0x018008bfb33d285247a21d44e50697654f754e63', - aWETH: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8' -}; - - -export const wrappedAaveTokensV3Polygon = { - waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', - waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', - waUSDC: '0x9719d867a500ef117cc201206b8ab51e794d3f82', - waDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', - waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', -}; - -export const aaveTokensV3Polygon = { - aMATIC: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', - aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', - aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', - aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', - aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', -}; - - -export const wrappedAaveTokensV3Arbitrum = { - waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', - waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', - waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', - waWETH: '0x18c100415988bef4354effad1188d1c22041b046' -}; - -export const aaveTokensV3Arbitrum = { - aUSDT: '0x6ab707aca953edaefbc4fd23ba73294241490620', - aUSDC: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', - aDAI: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', - aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', -}; -export const underlyingTokensMainnet = { - USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', - USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', - WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' -}; -export const underlyingTokensPolygon = { - MATIC: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', - USDT: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', - USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', - DAI: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', - WETH: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619' -}; - -export const underlyingTokensArbitrum = { - USDT: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - USDC: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - DAI: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', - WETH: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', -}; \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts deleted file mode 100644 index e44924fef..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave/types.ts +++ /dev/null @@ -1,18 +0,0 @@ -export interface ReserveResponse { - data: { - reserves: [ - { - underlyingAsset: string - liquidityRate: string - } - ] - } -} - -export type AaveAprHandlerConfig = { - wrappedTokens: { [key: string]: string } - aaveTokens: { [key: string]: string } - underlyingTokens: { [key: string]: string } - subgraphUrl: string - network: number; -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts similarity index 89% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts index 43dda9600..6b17c698f 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/ankr-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts @@ -1,9 +1,14 @@ import axios from "axios"; -import { AprHandler } from "../../types"; -import { AnkrAprHandlerConfig } from "./types"; +import { AprHandler } from "../types"; const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb' +type AnkrAprHandlerConfig = { + serviceName: string; + tokenAddress: string; + network: number; +} + class AnkrAprHandler implements AprHandler { serviceName: string tokenAddress: string diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/types.ts deleted file mode 100644 index 7ccc108d0..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type AnkrAprHandlerConfig = { - serviceName: string; - tokenAddress: string; - network: number; -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts similarity index 77% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts index 60abad05d..0eb8d047b 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts @@ -1,16 +1,5 @@ import axios from "axios"; -import { - cbETHMainnet, MATICXPolygon, rETHMainnet, sfrxETHMainnet, - stETHMainnet, stMATICPolygon, swETHMainnet, USDRMainnet, - vETHMainnet, wbETHMainnet, wjAURAMainnet, - wstETHArbitrum, - wstETHGnosis, - wstETHMainnet, - wstETHPolygon, - wstETHZkEVM -} from "./tokens"; -import { AprHandler } from "../../types"; -import { DefaultAprHandlerConfig } from "./types"; +import { AprHandler } from "../types"; class DefaultAprHandler implements AprHandler { @@ -57,6 +46,31 @@ class DefaultAprHandler implements AprHandler { } +export type DefaultAprHandlerConfig = { + tokens: string[]; + url: string; + network: number; + scale?: number; + path?: string; +} + +const vETHMainnet = '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f' +const wstETHGnosis = '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6'; +const wstETHZkEVM = '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9' +const stETHMainnet = '0xae7ab96520de3a18e5e111b5eaab095312d7fe84' +const wstETHMainnet = '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0' +const wstETHPolygon = '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd' +const wstETHArbitrum = '0x5979d7b546e38e414f7e9822514be443a4800529'; +const stMATICPolygon = '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'; +const cbETHMainnet = '0xbe9895146f7af43049ca1c1ae358b0541ea49704'; +const sfrxETHMainnet = '0xac3e018457b222d93114458476f3e3416abbe38f'; +const rETHMainnet = '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'; +const USDRMainnet = '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'; +const MATICXPolygon = '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'; +const wbETHMainnet = '0xa2e3356610840701bdf5611a53974510ae27e2e1'; +const swETHMainnet = '0xf951e335afb289353dc249e82926178eac7ded78'; +const wjAURAMainnet = '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'; + const vETHMainnetAprHandler = new DefaultAprHandler({ tokens: [vETHMainnet], url: 'https://apy.liebi.com/veth', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts deleted file mode 100644 index 9698768f8..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/tokens.ts +++ /dev/null @@ -1,35 +0,0 @@ -const vETHMainnet = '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f' -const wstETHGnosis = '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6'; -const wstETHZkEVM = '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9' -const stETHMainnet = '0xae7ab96520de3a18e5e111b5eaab095312d7fe84' -const wstETHMainnet = '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0' -const wstETHPolygon = '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd' -const wstETHArbitrum = '0x5979d7b546e38e414f7e9822514be443a4800529'; -const stMATICPolygon = '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'; -const cbETHMainnet = '0xbe9895146f7af43049ca1c1ae358b0541ea49704'; -const sfrxETHMainnet = '0xac3e018457b222d93114458476f3e3416abbe38f'; -const rETHMainnet = '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'; -const USDRMainnet = '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'; -const MATICXPolygon = '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'; -const wbETHMainnet = '0xa2e3356610840701bdf5611a53974510ae27e2e1'; -const swETHMainnet = '0xf951e335afb289353dc249e82926178eac7ded78'; -const wjAURAMainnet = '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'; - -export { - vETHMainnet, - wstETHGnosis, - wstETHZkEVM, - stETHMainnet, - wstETHMainnet, - wstETHPolygon, - wstETHArbitrum, - stMATICPolygon, - cbETHMainnet, - sfrxETHMainnet, - rETHMainnet, - USDRMainnet, - MATICXPolygon, - wbETHMainnet, - swETHMainnet, - wjAURAMainnet -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/types.ts deleted file mode 100644 index cd7dfcae8..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-fetch/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type DefaultAprHandlerConfig = { - tokens: string[]; - url: string; - network: number; - scale?: number; - path?: string; -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts similarity index 73% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts index 43890bd38..bf21430ab 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/euler-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts @@ -1,7 +1,30 @@ import axios from "axios"; -import { EulerAprHandlerConfig, EulerResponse } from "./types"; -import { eulerTokensMainnet } from "./tokens"; -import { AprHandler } from "../../types"; +import { AprHandler } from "../types"; + +const eulerTokensMainnet = { + eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', + eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', + eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', + eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', +} + +interface EulerResponse { + data: { + assets: [ + { + eTokenAddress: string + supplyAPY: string + } + ] + } +} + +type EulerAprHandlerConfig = { + tokens: {[key: string]: string}; + subgraphUrl: string; + network: number; + +} class EulerAprHandler implements AprHandler { tokens: { [key: string]: string } diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts deleted file mode 100644 index 8824bbe1b..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/tokens.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const eulerTokensMainnet = { - eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', - eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', - eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', - eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts deleted file mode 100644 index ed8427705..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler/types.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface EulerResponse { - data: { - assets: [ - { - eTokenAddress: string - supplyAPY: string - } - ] - } -} - -export type EulerAprHandlerConfig = { - tokens: {[key: string]: string}; - subgraphUrl: string; - network: number; - -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts similarity index 80% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts index 9ae434370..7731a25b6 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/gearbox-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts @@ -1,7 +1,5 @@ import axios from "axios"; -import { gearboxTokensMainnet } from "./tokens"; -import { AprHandler } from "../../types"; -import { GearboxAprHandlerConfig } from "./types"; +import { AprHandler } from "../types"; class GearboxAprHandler implements AprHandler { url: string; @@ -34,6 +32,17 @@ class GearboxAprHandler implements AprHandler { } } +type GearboxAprHandlerConfig = { + tokens: {[key: string]: string}; + url: string; + network: number; +} + +const gearboxTokensMainnet = { + dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', + dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', +}; + const gearboxMainnetAprHandler = new GearboxAprHandler({ tokens: gearboxTokensMainnet, url: 'https://mainnet.gearbox.foundation/api/pools', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts deleted file mode 100644 index 1dad2dbd9..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/tokens.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const gearboxTokensMainnet = { - dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', - dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', -}; \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/types.ts deleted file mode 100644 index bb48d30b1..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type GearboxAprHandlerConfig = { - tokens: {[key: string]: string}; - url: string; - network: number; - -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts similarity index 73% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts index 1329914a4..de4bac094 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/idle-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts @@ -1,7 +1,5 @@ import axios from "axios"; -import { idleTokensMainnet, wrapped4626IdleTokensMainnet } from "./tokens"; -import { AprHandler } from "../../types"; -import { IdleAprHandlerConfig } from "./types"; +import { AprHandler } from "../types"; class IdleAprHandler implements AprHandler { wrappedIdleTokens: { [key: string]: string }; @@ -48,8 +46,27 @@ class IdleAprHandler implements AprHandler { } } -const idleMainnetAprHandler = new IdleAprHandler( - { +const wrapped4626IdleTokensMainnet = { + idleDAI: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', + idleUSDC: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', + idleUSDT: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', +} + +const idleTokensMainnet = { + idleDAI: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', + idleUSDC: '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', + idleUSDT: '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', +} + +type IdleAprHandlerConfig = { + wrappedIdleTokens: {[key: string]: string}; + idleTokens: {[key: string]: string}; + baseIdleApiUrl: string; + authorizationHeader: string; + network: number; +} + +const idleMainnetAprHandler = new IdleAprHandler({ wrappedIdleTokens: wrapped4626IdleTokensMainnet, idleTokens: idleTokensMainnet, baseIdleApiUrl: 'https://api.idle.finance/junior-rates/', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts deleted file mode 100644 index 9358f64da..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/tokens.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const wrapped4626IdleTokensMainnet = { - idleDAI: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', - idleUSDC: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', - idleUSDT: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', -} - -export const idleTokensMainnet = { - idleDAI: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', - idleUSDC: '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', - idleUSDT: '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/types.ts deleted file mode 100644 index b37c220c5..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type IdleAprHandlerConfig = { - wrappedIdleTokens: {[key: string]: string}; - idleTokens: {[key: string]: string}; - baseIdleApiUrl: string; - authorizationHeader: string; - network: number; -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts deleted file mode 100644 index b6d455f68..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { aaveHandlers } from "./aave/aave-apr-handler"; -import { ankrHandlers } from "./ankr/ankr-apr-handler"; -import { defaultHandlers } from "./default-fetch/default-apr-handler"; -import { eulerHandlers } from "./euler/euler-apr-handler"; -import { gearboxHandlers } from "./gearbox/gearbox-apr-handler"; -import { idleAprHandlers } from "./idle/idle-apr-handler"; -import { overnightHandlers } from "./overnight/overnight-apr-handler"; -import { ovixHandlers } from "./ovix/ovix-apr-handler"; -import { reaperHandlers } from "./reaper/reaper-apr-handler"; -import { tesseraHandlers } from "./tessera/tessera-apr-handler"; -import { tetuHandlers } from "./tetu/tetu-apr-handler"; - -export const aprHandlers = [ - ...aaveHandlers, - ...ankrHandlers, - ...defaultHandlers, - ...eulerHandlers, - ...gearboxHandlers, - ...idleAprHandlers, - ...overnightHandlers, - ...ovixHandlers, - ...reaperHandlers, - ...tesseraHandlers, - ...tetuHandlers, -] \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts similarity index 75% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts index 5777d5d7d..df2fa23af 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/overnight-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts @@ -1,7 +1,5 @@ import axios from "axios"; -import { overnightTokens } from "./tokens"; -import { AprHandler } from "../../types"; -import { OvernightAprHandlerConfig } from "./types"; +import { AprHandler } from "../types"; class OvernightAprHandler implements AprHandler { overnightTokens: { [key: string]: string }; @@ -32,6 +30,17 @@ class OvernightAprHandler implements AprHandler { } } +const overnightTokens = { + lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus + UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f' // UsdcUsdPlus +} + +type OvernightAprHandlerConfig = { + tokens: {[key: string]: string}; + url: string; + network: number; +} + const overnightMainnetAprHandler = new OvernightAprHandler({ tokens: overnightTokens, url: 'https://app.overnight.fi/api/balancer/week/apr', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts deleted file mode 100644 index bb24d105b..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/tokens.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const overnightTokens = { - lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus - UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f' // UsdcUsdPlus -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/types.ts deleted file mode 100644 index d4862ff7d..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type OvernightAprHandlerConfig = { - tokens: {[key: string]: string}; - url: string; - network: number; -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts similarity index 73% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts index 588367e93..137c1714b 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/ovix-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts @@ -1,9 +1,7 @@ import { BigNumber, Contract } from "ethers"; -import { abi } from "../abis/oErc20"; +import { abi } from "./abis/oErc20"; import { JsonRpcProvider } from "@ethersproject/providers"; -import { ovixWrappedTokensZkEvm, ovixYieldTokensZkEvm } from "./tokens"; -import { AprHandler } from "../../types"; -import { OvixAprHandlerConfig } from "./types"; +import { AprHandler } from "../types"; class OvixAprHandler implements AprHandler { network: number; @@ -45,6 +43,25 @@ class OvixAprHandler implements AprHandler { } } +type OvixAprHandlerConfig = { + network: number; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${ string }` } + wrappedTokens: { + [key: string]: `0x${ string }` + } +} + +const ovixYieldTokensZkEvm = { + USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', + USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', +} as { [key: string]: `0x${string}` } + +const ovixWrappedTokensZkEvm = { + USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', + USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', +} as { [key: string]: `0x${string}` } + const ovixZkEVMAprHandler = new OvixAprHandler({ network: 1101, rpcUrl: 'https://zkevm-rpc.com', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/tokens.ts deleted file mode 100644 index 5072c8755..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/tokens.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const ovixYieldTokensZkEvm = { - USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', - USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', -} as { [key: string]: `0x${string}` } - -export const ovixWrappedTokensZkEvm = { - USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', - USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', -} as { [key: string]: `0x${string}` } \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/types.ts deleted file mode 100644 index 8947108c2..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type OvixAprHandlerConfig = { - network: number; - rpcUrl: string; - yieldTokens: { [key: string]: `0x${ string }` } - wrappedTokens: { - [key: string]: `0x${ string }` - } -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts similarity index 70% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts index 077302bf3..b7617026a 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/reaper-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts @@ -1,9 +1,7 @@ import { JsonRpcProvider } from "@ethersproject/providers"; import { BigNumber, Contract } from "ethers"; -import { abi } from "../abis/reaperStrategy"; -import { reaperStrategiesMapArbitrum, reaperYieldTokensArbitrum } from "./tokens"; -import { AprHandler } from "../../types"; -import { ReaperAprHandlerConfig } from "./types"; +import { abi } from "./abis/reaperStrategy"; +import { AprHandler } from "../types"; class ReaperAprHandler implements AprHandler { network: number; @@ -45,6 +43,27 @@ class ReaperAprHandler implements AprHandler { } } +type ReaperAprHandlerConfig = { + network: number; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${ string }` } + strategiesMap: { + [key: string]: `0x${ string }` + } +} + +const reaperYieldTokensArbitrum = { + DAI: '0x12f256109e744081f633a827be80e06d97ff7447', + USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', + USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', +} as { [key: string]: `0x${ string }` } + +const reaperStrategiesMapArbitrum = { + DAI: '0xd4d5321b04e4832772a4d70e1eed6bcb7402d7ac', + USDT: '0x8a674ebbe33d6b03825626fa432e9ece888e13b5', + USDC: '0x6f6c0c5b7af2a326111ba6a9fa4926f7ca3adf44', +} as { [key: string]: `0x${ string }` } + const reaperArbitrumAprHandler = new ReaperAprHandler({ network: 42161, rpcUrl: 'https://arb1.arbitrum.io/rpc', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/tokens.ts deleted file mode 100644 index f1df590e4..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/tokens.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const reaperYieldTokensArbitrum = { - DAI: '0x12f256109e744081f633a827be80e06d97ff7447', - USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', - USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', -} as { [key: string]: `0x${ string }` } - -export const reaperStrategiesMapArbitrum = { - DAI: '0xd4d5321b04e4832772a4d70e1eed6bcb7402d7ac', - USDT: '0x8a674ebbe33d6b03825626fa432e9ece888e13b5', - USDC: '0x6f6c0c5b7af2a326111ba6a9fa4926f7ca3adf44', -} as { [key: string]: `0x${ string }` } \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/types.ts deleted file mode 100644 index 642d560f0..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type ReaperAprHandlerConfig = { - network: number; - rpcUrl: string; - yieldTokens: { [key: string]: `0x${ string }` } - strategiesMap: { - [key: string]: `0x${ string }` - } -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts similarity index 81% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts index e7eb12003..a7270b6b4 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tessera-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts @@ -1,9 +1,7 @@ import { Contract } from "ethers"; -import { abi } from "../abis/tesseraPool"; +import { abi } from "./abis/tesseraPool"; import { JsonRpcProvider } from "@ethersproject/providers"; -import { tesseraYieldTokensMainnet } from "./tokens"; -import { AprHandler } from "../../types"; -import { TesseraAprHandlerConfig } from "./types"; +import { AprHandler } from "../types"; class TesseraAprHandler implements AprHandler { network: number; @@ -44,6 +42,17 @@ class TesseraAprHandler implements AprHandler { } } +type TesseraAprHandlerConfig = { + network: number; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${ string }` }; + contractAddress: `0x${ string }`; +} + +const tesseraYieldTokensMainnet = { + sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', +} as { [key: string]: `0x${ string }` } + const tesseraMainnetAprHandler = new TesseraAprHandler({ network: 1, rpcUrl: 'https://rpc.ankr.com/eth', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tokens.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tokens.ts deleted file mode 100644 index df736704e..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/tokens.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const tesseraYieldTokensMainnet = { - sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', -} as { [key: string]: `0x${ string }` } - diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/types.ts deleted file mode 100644 index cc72f0552..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type TesseraAprHandlerConfig = { - network: number; - rpcUrl: string; - yieldTokens: { [key: string]: `0x${ string }` }; - contractAddress: `0x${ string }`; -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts similarity index 87% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts index 799a27b4b..e7fd7466d 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/tetu-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts @@ -1,6 +1,5 @@ import axios from "axios"; -import { AprHandler } from "../../types"; -import { TetuAprHandlerConfig } from "./types"; +import { AprHandler } from "../types"; class TetuAprHandler implements AprHandler { network: number; @@ -29,6 +28,12 @@ class TetuAprHandler implements AprHandler { } } +type TetuAprHandlerConfig = { + network: number; + baseUrl: string; + networkName: string; +} + const tetuPolygonAprHandler = new TetuAprHandler({ network: 137, baseUrl: 'https://api.tetu.io/api/v1/reader/compoundAPRs', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/types.ts deleted file mode 100644 index 92c0c540d..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type TetuAprHandlerConfig = { - network: number; - baseUrl: string; - networkName: string; -} \ No newline at end of file diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts similarity index 90% rename from modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts index 384fa0c2a..eabb1cda6 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/tranchess-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts @@ -1,6 +1,5 @@ import axios from "axios"; -import { AprHandler } from "../../types"; -import { TranchessAprHandlerConfig } from "./types"; +import { AprHandler } from "../types"; const qETHMainnet = '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d' @@ -32,6 +31,12 @@ class TranchessAprHandler implements AprHandler { } } +type TranchessAprHandlerConfig = { + network: number; + token: string; + url: string; +} + const tranchessMainnetAprHandler = new TranchessAprHandler({ network: 1, token: qETHMainnet, diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/types.ts deleted file mode 100644 index d8e23e276..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type TranchessAprHandlerConfig = { - network: number; - token: string; - url: string; -} \ No newline at end of file From 4d97f4876f7990d13d454d3994381575473c6e49 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Fri, 11 Aug 2023 17:42:55 -0300 Subject: [PATCH 18/42] Using prismaId instead of chain id; moving apr handler types file to ib-yield-apr-handlers; --- modules/network/arbitrum.ts | 5 +- modules/network/gnosis.ts | 4 +- modules/network/mainnet.ts | 5 +- modules/network/polygon.ts | 4 +- modules/network/zkevm.ts | 14 +- .../apr-data-sources/ib-tokens-apr.service.ts | 118 +++--- .../ib-yield-apr-handlers.ts | 99 ++--- .../sources/aave-apr-handler.ts | 356 +++++++++--------- .../sources/ankr-apr-handler.ts | 84 ++--- .../sources/default-apr-handler.ts | 282 +++++++------- .../sources/euler-apr-handler.ts | 129 ++++--- .../sources/gearbox-apr-handler.ts | 76 ++-- .../sources/idle-apr-handler.ts | 118 +++--- .../sources/overnight-apr-handler.ts | 78 ++-- .../sources/ovix-apr-handler.ts | 106 +++--- .../sources/reaper-apr-handler.ts | 113 +++--- .../sources/tessera-apr-handler.ts | 101 ++--- .../sources/tetu-apr-handler.ts | 68 ++-- .../sources/tranchess-apr-handler.ts | 73 ++-- .../ib-yield-apr-handlers/types.ts | 10 - 20 files changed, 911 insertions(+), 932 deletions(-) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 5843bf3d2..af66a29cf 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -17,8 +17,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { coingeckoService } from '../coingecko/coingecko.service'; -import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; -import { IbYieldAprHandlers } from "../pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers"; +import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; const arbitrumNetworkData: NetworkData = { chain: { @@ -162,7 +161,7 @@ export const arbitrumNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(arbitrumNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(arbitrumNetworkData.chain.id), + new IbTokensAprService(arbitrumNetworkData.chain.prismaId), new WstethAprService(tokenService, arbitrumNetworkData.lido!.wstEthContract), new ReaperCryptAprService( arbitrumNetworkData.reaper.linearPoolFactories, diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index 7ba22aff4..bc6c2678f 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -15,7 +15,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; -import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; +import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; const gnosisNetworkData: NetworkData = { chain: { @@ -152,7 +152,7 @@ export const gnosisNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(gnosisNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(gnosisNetworkData.chain.id), + new IbTokensAprService(gnosisNetworkData.chain.prismaId), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(gnosisNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 9bfe8f77b..e0beb1576 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -17,8 +17,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; -import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; -import { IbYieldAprHandlers } from "../pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers"; +import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; const mainnetNetworkData: NetworkData = { chain: { @@ -164,7 +163,7 @@ export const mainnetNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(mainnetNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(mainnetNetworkData.chain.id), + new IbTokensAprService(mainnetNetworkData.chain.prismaId), new WstethAprService(tokenService, mainnetNetworkData.lido!.wstEthContract), new PhantomStableAprService(), new BoostedPoolAprService(), diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index a1ae3750d..c9e22a301 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -16,7 +16,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; -import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; +import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; const polygonNetworkData: NetworkData = { chain: { @@ -156,7 +156,7 @@ export const polygonNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(polygonNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(polygonNetworkData.chain.id), + new IbTokensAprService(polygonNetworkData.chain.prismaId), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(polygonNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index 5dc063ea5..ed60dfd6d 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -16,7 +16,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { coingeckoService } from '../coingecko/coingecko.service'; -import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; +import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; const zkevmNetworkData: NetworkData = { chain: { @@ -153,7 +153,7 @@ export const zkevmNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(zkevmNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(zkevmNetworkData.chain.id), + new IbTokensAprService(zkevmNetworkData.chain.prismaId), new WstethAprService(tokenService, zkevmNetworkData.lido!.wstEthContract), new PhantomStableAprService(), new BoostedPoolAprService(), @@ -172,12 +172,12 @@ export const zkevmNetworkConfig: NetworkConfig = { ], userStakedBalanceServices: [new UserSyncGaugeBalanceService()], /* - For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. - This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. + For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. + This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. - For every 1 days jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. - This is needed because the maximum alarm evaluation period is 1 day (period * evaluationPeriod). - */ + For every 1 days jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. + This is needed because the maximum alarm evaluation period is 1 day (period * evaluationPeriod). + */ workerJobs: [ { name: 'update-token-prices', diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index c11dfdd99..4ae27af67 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -1,68 +1,66 @@ -import { PoolAprService } from "../../pool-types"; -import { PrismaPoolWithExpandedNesting } from "../../../../prisma/prisma-types"; -import { prisma } from "../../../../prisma/prisma-client"; -import { networkContext } from "../../../network/network-context.service"; -import { prismaBulkExecuteOperations } from "../../../../prisma/prisma-util"; -import { PrismaPoolAprItemGroup } from "@prisma/client"; -import { TokenApr } from "./ib-yield-apr-handlers/types"; -import { IbYieldAprHandlers } from "./ib-yield-apr-handlers/ib-yield-apr-handlers"; +import { PoolAprService } from '../../pool-types'; +import { PrismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; +import { prisma } from '../../../../prisma/prisma-client'; +import { networkContext } from '../../../network/network-context.service'; +import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; +import { PrismaPoolAprItemGroup } from '@prisma/client'; +import { IbYieldAprHandlers, TokenApr } from './ib-yield-apr-handlers/ib-yield-apr-handlers'; export class IbTokensAprService implements PoolAprService { - - private ibYieldAprHandlers: IbYieldAprHandlers; - - constructor(chainId: number) { - this.ibYieldAprHandlers = new IbYieldAprHandlers(chainId); - } + private ibYieldAprHandlers: IbYieldAprHandlers; - getAprServiceName(): string { - return "IbTokensAprService"; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const operations: any[] = []; - const aprs = await this.fetchYieldTokensApr(); - const tokenYieldPools = pools.filter((pool) => { - return pool.tokens.find((token) => { - return Array.from(aprs.keys()).map((key) => key.toLowerCase()).includes(token.address.toLowerCase()); - }) - } - ); - for (const pool of tokenYieldPools) { - for (const token of pool.tokens) { - if ((aprs.get(token.address) !== undefined)) { - const tokenSymbol = token.token.symbol; - const itemId = `${ pool.id }-${ tokenSymbol }-yield-apr` + constructor(networkPrismaId: string) { + this.ibYieldAprHandlers = new IbYieldAprHandlers(networkPrismaId); + } - operations.push(prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `${ tokenSymbol } APR`, - apr: aprs.get(token.address)?.val ?? 0, - group: (aprs.get(token.address)?.group as PrismaPoolAprItemGroup) ?? null, - type: pool.type === 'LINEAR' ? 'LINEAR_BOOSTED' : 'IB_YIELD', - }, - update: { - title: `${ tokenSymbol } APR`, - apr: aprs.get(token.address)?.val - }, - })); - } - } + getAprServiceName(): string { + return 'IbTokensAprService'; } - await prismaBulkExecuteOperations(operations); - } + public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { + const operations: any[] = []; + const aprs = await this.fetchYieldTokensApr(); + const tokenYieldPools = pools.filter((pool) => { + return pool.tokens.find((token) => { + return Array.from(aprs.keys()) + .map((key) => key.toLowerCase()) + .includes(token.address.toLowerCase()); + }); + }); + for (const pool of tokenYieldPools) { + for (const token of pool.tokens) { + if (aprs.get(token.address) !== undefined) { + const tokenSymbol = token.token.symbol; + const itemId = `${pool.id}-${tokenSymbol}-yield-apr`; - private async fetchYieldTokensApr(): Promise> { - const data = await this.ibYieldAprHandlers.fetchAprsFromAllHandlers(); - console.log(data); - return new Map( - data.filter((apr) => !isNaN(apr.val)).map((apr) => [apr.address, apr]) - ); - } + operations.push( + prisma.prismaPoolAprItem.upsert({ + where: { id_chain: { id: itemId, chain: networkContext.chain } }, + create: { + id: itemId, + chain: networkContext.chain, + poolId: pool.id, + title: `${tokenSymbol} APR`, + apr: aprs.get(token.address)?.val ?? 0, + group: (aprs.get(token.address)?.group as PrismaPoolAprItemGroup) ?? null, + type: pool.type === 'LINEAR' ? 'LINEAR_BOOSTED' : 'IB_YIELD', + }, + update: { + title: `${tokenSymbol} APR`, + apr: aprs.get(token.address)?.val, + }, + }), + ); + } + } + } -} \ No newline at end of file + await prismaBulkExecuteOperations(operations); + } + + private async fetchYieldTokensApr(): Promise> { + const data = await this.ibYieldAprHandlers.fetchAprsFromAllHandlers(); + console.log(data); + return new Map(data.filter((apr) => !isNaN(apr.val)).map((apr) => [apr.address, apr])); + } +} diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts index 9caca0117..775e3fa34 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts @@ -1,50 +1,61 @@ -import { AprHandler, TokenApr } from "./types"; -import { aaveHandlers } from "./sources/aave-apr-handler"; -import { ankrHandlers } from "./sources/ankr-apr-handler"; -import { defaultHandlers } from "./sources/default-apr-handler"; -import { eulerHandlers } from "./sources/euler-apr-handler"; -import { gearboxHandlers } from "./sources/gearbox-apr-handler"; -import { idleAprHandlers } from "./sources/idle-apr-handler"; -import { overnightHandlers } from "./sources/overnight-apr-handler"; -import { ovixHandlers } from "./sources/ovix-apr-handler"; -import { reaperHandlers } from "./sources/reaper-apr-handler"; -import { tesseraHandlers } from "./sources/tessera-apr-handler"; -import { tetuHandlers } from "./sources/tetu-apr-handler"; +import { aaveHandlers } from './sources/aave-apr-handler'; +import { ankrHandlers } from './sources/ankr-apr-handler'; +import { defaultHandlers } from './sources/default-apr-handler'; +import { eulerHandlers } from './sources/euler-apr-handler'; +import { gearboxHandlers } from './sources/gearbox-apr-handler'; +import { idleAprHandlers } from './sources/idle-apr-handler'; +import { overnightHandlers } from './sources/overnight-apr-handler'; +import { ovixHandlers } from './sources/ovix-apr-handler'; +import { reaperHandlers } from './sources/reaper-apr-handler'; +import { tesseraHandlers } from './sources/tessera-apr-handler'; +import { tetuHandlers } from './sources/tetu-apr-handler'; -const aprHandlers = [ - ...aaveHandlers, - ...ankrHandlers, - ...defaultHandlers, - ...eulerHandlers, - ...gearboxHandlers, - ...idleAprHandlers, - ...overnightHandlers, - ...ovixHandlers, - ...reaperHandlers, - ...tesseraHandlers, - ...tetuHandlers, -] +const aprHandlers: AprHandler[] = [ + ...aaveHandlers, + ...ankrHandlers, + ...defaultHandlers, + ...eulerHandlers, + ...gearboxHandlers, + ...idleAprHandlers, + ...overnightHandlers, + ...ovixHandlers, + ...reaperHandlers, + ...tesseraHandlers, + ...tetuHandlers, +]; export class IbYieldAprHandlers { + private handlers: AprHandler[] = []; - private handlers: AprHandler[] = []; - - constructor(network: number) { - this.handlers = aprHandlers.filter((handler) => handler.network === network); - } + constructor(networkPrismaId: string) { + this.handlers = aprHandlers.filter((handler) => handler.networkPrismaId === networkPrismaId); + } - async fetchAprsFromAllHandlers(): Promise { - let aprs: { val: number, group: string, address: string }[] = []; - for (const handler of this.handlers) { - const fetchedResponse: { [key: string]: number } = await handler.getAprs() - for (const [address, aprValue] of Object.entries(fetchedResponse)) { - aprs.push({ - val: aprValue, - group: handler.group, - address - }) - } + async fetchAprsFromAllHandlers(): Promise { + let aprs: { val: number; group: string; address: string }[] = []; + for (const handler of this.handlers) { + const fetchedResponse: { [key: string]: number } = await handler.getAprs(); + for (const [address, aprValue] of Object.entries(fetchedResponse)) { + aprs.push({ + val: aprValue, + group: handler.group, + address, + }); + } + } + return aprs; } - return aprs; - } -} \ No newline at end of file +} + +export interface AprHandler { + readonly group: string; + networkPrismaId: string; + + getAprs(): Promise<{ [tokenAddress: string]: number }>; +} + +export type TokenApr = { + val: number; + address: string; + group?: string; +}; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts index 3de200306..27e54e9a1 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts @@ -1,232 +1,232 @@ -import axios from "axios"; -import { AprHandler } from "../types"; +import axios from 'axios'; +import { AprHandler } from '../ib-yield-apr-handlers'; + +class AaveAprHandler implements AprHandler { + wrappedTokens: { [key: string]: string }; + aaveTokens: { [key: string]: string }; + underlyingTokens: { [key: string]: string }; + subgraphUrl: string; + networkPrismaId: string; + + readonly group = 'AAVE'; + + readonly query = `query getReserves($aTokens: [String!], $underlyingAssets: [Bytes!]) { + reserves( + where: { + aToken_in: $aTokens + underlyingAsset_in: $underlyingAssets + isActive: true + } + ) { + id + underlyingAsset + liquidityRate + } + }`; + + constructor(aprHandlerConfig: AaveAprHandlerConfig) { + this.wrappedTokens = aprHandlerConfig.wrappedTokens; + this.aaveTokens = aprHandlerConfig.aaveTokens; + this.underlyingTokens = aprHandlerConfig.underlyingTokens; + this.subgraphUrl = aprHandlerConfig.subgraphUrl; + this.networkPrismaId = aprHandlerConfig.network; + } + + async getAprs() { + try { + const requestQuery = { + operationName: 'getReserves', + query: this.query, + variables: { + aTokens: Object.values(this.aaveTokens), + underlyingAssets: Object.values(this.underlyingTokens), + }, + }; + const { data } = await axios({ + url: this.subgraphUrl, + method: 'post', + data: requestQuery, + headers: { 'Content-Type': 'application/json' }, + }); + const { + data: { reserves }, + } = data as ReserveResponse; + + const aprsByUnderlyingAddress = Object.fromEntries( + reserves.map((r) => [ + r.underlyingAsset, + // Converting from aave ray number (27 digits) to float + Number(r.liquidityRate.slice(0, 27)) / 1e27, + ]), + ); + const aprEntries = Object.fromEntries( + Object.values(this.underlyingTokens) + //Removing undefined aprs + .filter(([, address]) => !!aprsByUnderlyingAddress[address]) + //Mapping aprs by wrapped instead of underlying addresses + .map(([underlyingTokenName, underlyingTokenAddress]) => [ + this.wrappedTokens['wa' + underlyingTokenName] as string, + aprsByUnderlyingAddress[underlyingTokenAddress], + ]), + ); + return aprEntries; + } catch (e) { + console.error(`Failed to fetch Aave APR in subgraph ${this.subgraphUrl}:`, e); + return {}; + } + } +} const wrappedAaveTokensV2Mainnet = { - waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', - waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', - waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', + waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', + waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', + waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', }; const aaveTokensV2Mainnet = { - aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', - aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c', - aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', + aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', + aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c', + aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', }; const wrappedAaveTokensV2Polygon = { - waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', - waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', - waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', + waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', + waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', + waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', }; const aaveTokensV2Polygon = { - aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', - aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', - aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', + aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', + aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', }; const wrappedAaveTokensV3Mainnet = { - waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', - waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', - waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', - waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', + waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', + waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', + waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', + waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', }; const aaveTokensV3Mainnet = { - aUSDT: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', - aUSDC: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', - aDAI: '0x018008bfb33d285247a21d44e50697654f754e63', - aWETH: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8' + aUSDT: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', + aUSDC: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', + aDAI: '0x018008bfb33d285247a21d44e50697654f754e63', + aWETH: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8', }; - const wrappedAaveTokensV3Polygon = { - waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', - waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', - waUSDC: '0x9719d867a500ef117cc201206b8ab51e794d3f82', - waDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', - waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', + waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', + waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', + waUSDC: '0x9719d867a500ef117cc201206b8ab51e794d3f82', + waDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', }; const aaveTokensV3Polygon = { - aMATIC: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', - aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', - aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', - aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', - aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', + aMATIC: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', + aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', + aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', + aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', }; - const wrappedAaveTokensV3Arbitrum = { - waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', - waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', - waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', - waWETH: '0x18c100415988bef4354effad1188d1c22041b046' + waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', + waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', + waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', + waWETH: '0x18c100415988bef4354effad1188d1c22041b046', }; const aaveTokensV3Arbitrum = { - aUSDT: '0x6ab707aca953edaefbc4fd23ba73294241490620', - aUSDC: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', - aDAI: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', - aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', + aUSDT: '0x6ab707aca953edaefbc4fd23ba73294241490620', + aUSDC: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', + aDAI: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', + aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', }; const underlyingTokensMainnet = { - USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', - USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', - WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' + USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', + USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', + WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', }; const underlyingTokensPolygon = { - MATIC: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', - USDT: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', - USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', - DAI: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', - WETH: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619' + MATIC: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', + USDT: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + DAI: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + WETH: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619', }; const underlyingTokensArbitrum = { - USDT: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - USDC: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - DAI: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', - WETH: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', + USDT: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + USDC: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', + DAI: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + WETH: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', }; interface ReserveResponse { - data: { - reserves: [ - { - underlyingAsset: string - liquidityRate: string - } - ] - } + data: { + reserves: [ + { + underlyingAsset: string; + liquidityRate: string; + }, + ]; + }; } type AaveAprHandlerConfig = { - wrappedTokens: { [key: string]: string } - aaveTokens: { [key: string]: string } - underlyingTokens: { [key: string]: string } - subgraphUrl: string - network: number; -} - -class AaveAprHandler implements AprHandler { - - wrappedTokens: { [key: string]: string } - aaveTokens: { [key: string]: string } - underlyingTokens: { [key: string]: string } - subgraphUrl: string - network: number; - - readonly group = 'AAVE'; - - readonly query = `query getReserves($aTokens: [String!], $underlyingAssets: [Bytes!]) { - reserves( - where: { - aToken_in: $aTokens - underlyingAsset_in: $underlyingAssets - isActive: true - } - ) { - id - underlyingAsset - liquidityRate - } - }` - - constructor(aprHandlerConfig: AaveAprHandlerConfig) { - this.wrappedTokens = aprHandlerConfig.wrappedTokens - this.aaveTokens = aprHandlerConfig.aaveTokens - this.underlyingTokens = aprHandlerConfig.underlyingTokens - this.subgraphUrl = aprHandlerConfig.subgraphUrl - this.network = aprHandlerConfig.network; - } - - async getAprs() { - try { - const requestQuery = { - operationName: 'getReserves', - query: this.query, - variables: { - aTokens: Object.values(this.aaveTokens), - underlyingAssets: Object.values(this.underlyingTokens), - }, - } - const { data } = await axios({ - url: this.subgraphUrl, - method: "post", - data: requestQuery, - headers: { "Content-Type": "application/json" } - }) - const { - data: { reserves }, - } = data as ReserveResponse - - const aprsByUnderlyingAddress = Object.fromEntries(reserves.map((r) => [ - r.underlyingAsset, - // Converting from aave ray number (27 digits) to float - Number(r.liquidityRate.slice(0, 27)) / 1e27, - ])) - const aprEntries = Object.fromEntries( - Object.values(this.underlyingTokens) - //Removing undefined aprs - .filter(([, address]) => !!aprsByUnderlyingAddress[address]) - //Mapping aprs by wrapped instead of underlying addresses - .map(([underlyingTokenName, underlyingTokenAddress]) => [ - this.wrappedTokens['wa' + underlyingTokenName] as string, - aprsByUnderlyingAddress[underlyingTokenAddress], - ])) - return aprEntries; - } catch (e) { - console.error(`Failed to fetch Aave APR in subgraph ${ this.subgraphUrl }:`, e) - return {} - } - } -} + wrappedTokens: { [key: string]: string }; + aaveTokens: { [key: string]: string }; + underlyingTokens: { [key: string]: string }; + subgraphUrl: string; + network: string; +}; const aaveV2MainnetAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV2Mainnet, - aaveTokens: aaveTokensV2Mainnet, - underlyingTokens: underlyingTokensMainnet, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2', - network: 1 -}) + wrappedTokens: wrappedAaveTokensV2Mainnet, + aaveTokens: aaveTokensV2Mainnet, + underlyingTokens: underlyingTokensMainnet, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2', + network: 'MAINNET', +}); const aaveV2PolygonAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV2Polygon, - aaveTokens: aaveTokensV2Polygon, - underlyingTokens: underlyingTokensPolygon, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic', - network: 137 -}) + wrappedTokens: wrappedAaveTokensV2Polygon, + aaveTokens: aaveTokensV2Polygon, + underlyingTokens: underlyingTokensPolygon, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic', + network: 'POLYGON', +}); const aaveV3MainnetAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV3Mainnet, - aaveTokens: aaveTokensV3Mainnet, - underlyingTokens: underlyingTokensMainnet, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3', - network: 1 -}) + wrappedTokens: wrappedAaveTokensV3Mainnet, + aaveTokens: aaveTokensV3Mainnet, + underlyingTokens: underlyingTokensMainnet, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3', + network: 'MAINNET', +}); const aaveV3PolygonAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV3Polygon, - aaveTokens: aaveTokensV3Polygon, - underlyingTokens: underlyingTokensPolygon, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon', - network: 137 + wrappedTokens: wrappedAaveTokensV3Polygon, + aaveTokens: aaveTokensV3Polygon, + underlyingTokens: underlyingTokensPolygon, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon', + network: 'POLYGON', }); const aaveV3ArbitrumAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV3Arbitrum, - aaveTokens: aaveTokensV3Arbitrum, - underlyingTokens: underlyingTokensArbitrum, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum', - network: 42161 -}) + wrappedTokens: wrappedAaveTokensV3Arbitrum, + aaveTokens: aaveTokensV3Arbitrum, + underlyingTokens: underlyingTokensArbitrum, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum', + network: 'ARBITRUM', +}); export const aaveHandlers = [ - aaveV2MainnetAprHandler, - aaveV2PolygonAprHandler, - aaveV3MainnetAprHandler, - aaveV3PolygonAprHandler, - aaveV3ArbitrumAprHandler -] + aaveV2MainnetAprHandler, + aaveV2PolygonAprHandler, + aaveV3MainnetAprHandler, + aaveV3PolygonAprHandler, + aaveV3ArbitrumAprHandler, +]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts index 6b17c698f..af7234583 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts @@ -1,52 +1,50 @@ -import axios from "axios"; -import { AprHandler } from "../types"; - -const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb' - -type AnkrAprHandlerConfig = { - serviceName: string; - tokenAddress: string; - network: number; -} +import axios from 'axios'; +import { AprHandler } from '../ib-yield-apr-handlers'; class AnkrAprHandler implements AprHandler { - serviceName: string - tokenAddress: string - network: number - readonly url: string = 'https://api.staking.ankr.com/v1alpha/metrics'; - readonly group = 'ANKR'; - - constructor(aprHandlerConfig: AnkrAprHandlerConfig) { - this.serviceName = aprHandlerConfig.serviceName - this.tokenAddress = aprHandlerConfig.tokenAddress - this.network = aprHandlerConfig.network - } - - async getAprs() { - try { + serviceName: string; + tokenAddress: string; + networkPrismaId: string; + readonly url: string = 'https://api.staking.ankr.com/v1alpha/metrics'; + readonly group = 'ANKR'; + + constructor(aprHandlerConfig: AnkrAprHandlerConfig) { + this.serviceName = aprHandlerConfig.serviceName; + this.tokenAddress = aprHandlerConfig.tokenAddress; + this.networkPrismaId = aprHandlerConfig.network; + } - const { data } = await axios.get(this.url) - const json = data as { services: { serviceName: string; apy: string }[] } - const service = json.services.find((service) => service.serviceName === this.serviceName) - if (!service) { - return {} - } - const scaledValue = parseFloat(service.apy) / 1e2 - return { - [this.tokenAddress]: scaledValue - } - } catch (error) { - console.error('Failed to fetch Ankr APR:', error) - return {} + async getAprs() { + try { + const { data } = await axios.get(this.url); + const json = data as { services: { serviceName: string; apy: string }[] }; + const service = json.services.find((service) => service.serviceName === this.serviceName); + if (!service) { + return {}; + } + const scaledValue = parseFloat(service.apy) / 1e2; + return { + [this.tokenAddress]: scaledValue, + }; + } catch (error) { + console.error('Failed to fetch Ankr APR:', error); + return {}; + } } - } } -const ankrEthMainnetAprHandler = new AnkrAprHandler( - { +const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb'; + +type AnkrAprHandlerConfig = { + serviceName: string; + tokenAddress: string; + network: string; +}; + +const ankrEthMainnetAprHandler = new AnkrAprHandler({ serviceName: 'eth', tokenAddress: ankrEthMainnet, - network: 1 - }); + network: 'MAINNET', +}); -export const ankrHandlers = [ankrEthMainnetAprHandler]; \ No newline at end of file +export const ankrHandlers = [ankrEthMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts index 0eb8d047b..9fb12f6a2 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts @@ -1,65 +1,63 @@ -import axios from "axios"; -import { AprHandler } from "../types"; +import axios from 'axios'; -class DefaultAprHandler implements AprHandler { - - tokens: string[]; - url: string; - path: string; - scale: number; - network: number; - readonly group = "DEFAULT"; +import { AprHandler } from '../ib-yield-apr-handlers'; - constructor(aprHandlerConfig: DefaultAprHandlerConfig) { - this.tokens = aprHandlerConfig.tokens; - this.url = aprHandlerConfig.url; - this.network = aprHandlerConfig.network; - this.path = aprHandlerConfig.path ?? ''; - this.scale = aprHandlerConfig.scale ?? 100; - } +class DefaultAprHandler implements AprHandler { + tokens: string[]; + url: string; + path: string; + scale: number; + networkPrismaId: string; + readonly group = 'DEFAULT'; - async getAprs() { - try { + constructor(aprHandlerConfig: DefaultAprHandlerConfig) { + this.tokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.url; + this.networkPrismaId = aprHandlerConfig.network; + this.path = aprHandlerConfig.path ?? ''; + this.scale = aprHandlerConfig.scale ?? 100; + } - const { data } = await axios.get(this.url, { headers: { 'User-Agent': 'cf' } }) - const value = (this.path === '') ? data : this.getValueFromPath(data, this.path) - const scaledValue = parseFloat(value) / this.scale + async getAprs() { + try { + const { data } = await axios.get(this.url, { headers: { 'User-Agent': 'cf' } }); + const value = this.path === '' ? data : this.getValueFromPath(data, this.path); + const scaledValue = parseFloat(value) / this.scale; - return this.tokens.reduce((acc, token) => { - acc[token] = scaledValue - return acc - }, {} as { [key: string]: number }) - } catch (error) { - console.error(`Failed to fetch APRs in url ${ this.url }:`, error) - return {} + return this.tokens.reduce((acc, token) => { + acc[token] = scaledValue; + return acc; + }, {} as { [key: string]: number }); + } catch (error) { + console.error(`Failed to fetch APRs in url ${this.url}:`, error); + return {}; + } } - } - getValueFromPath(obj: any, path: string) { - const parts = path.split('.') - let value = obj - for (const part of parts) { - value = value[part] + getValueFromPath(obj: any, path: string) { + const parts = path.split('.'); + let value = obj; + for (const part of parts) { + value = value[part]; + } + return value; } - return value - } - } export type DefaultAprHandlerConfig = { - tokens: string[]; - url: string; - network: number; - scale?: number; - path?: string; -} + tokens: string[]; + url: string; + network: string; + scale?: number; + path?: string; +}; -const vETHMainnet = '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f' +const vETHMainnet = '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f'; const wstETHGnosis = '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6'; -const wstETHZkEVM = '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9' -const stETHMainnet = '0xae7ab96520de3a18e5e111b5eaab095312d7fe84' -const wstETHMainnet = '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0' -const wstETHPolygon = '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd' +const wstETHZkEVM = '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9'; +const stETHMainnet = '0xae7ab96520de3a18e5e111b5eaab095312d7fe84'; +const wstETHMainnet = '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0'; +const wstETHPolygon = '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd'; const wstETHArbitrum = '0x5979d7b546e38e414f7e9822514be443a4800529'; const stMATICPolygon = '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'; const cbETHMainnet = '0xbe9895146f7af43049ca1c1ae358b0541ea49704'; @@ -72,126 +70,114 @@ const swETHMainnet = '0xf951e335afb289353dc249e82926178eac7ded78'; const wjAURAMainnet = '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'; const vETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [vETHMainnet], - url: 'https://apy.liebi.com/veth', - path: 'veth', - network: 1 -}) + tokens: [vETHMainnet], + url: 'https://apy.liebi.com/veth', + path: 'veth', + network: 'MAINNET', +}); const stETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [ - stETHMainnet, - wstETHMainnet, - ], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 1 -}) + tokens: [stETHMainnet, wstETHMainnet], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'MAINNET', +}); const stETHPolygonAprHandler = new DefaultAprHandler({ - tokens: [ - wstETHPolygon, - ], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 137 -}) + tokens: [wstETHPolygon], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'POLYGON', +}); const stETHZkEVMAprHandler = new DefaultAprHandler({ - tokens: [ - wstETHZkEVM, - ], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 1101 -}) + tokens: [wstETHZkEVM], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'ZKEVM', +}); const stETHGnosisAprHandler = new DefaultAprHandler({ - tokens: [ - wstETHGnosis, - ], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 100 -}) + tokens: [wstETHGnosis], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'GNOSIS', +}); const stETHArbitrumAprHandler = new DefaultAprHandler({ - tokens: [ - wstETHArbitrum - ], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 42161 -}) + tokens: [wstETHArbitrum], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'ARBITRUM', +}); const stMaticPolygonAprHandler = new DefaultAprHandler({ - tokens: [stMATICPolygon], - url: 'https://polygon.lido.fi/api/stats', - path: 'apr', - network: 137 -}) + tokens: [stMATICPolygon], + url: 'https://polygon.lido.fi/api/stats', + path: 'apr', + network: 'POLYGON', +}); const cbEthMainnetAprHandler = new DefaultAprHandler({ tokens: [cbETHMainnet], url: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', path: 'apy', scale: 1, - network: 1 - } -) + network: 'MAINNET', +}); const sfrxEthMainnetAprHandler = new DefaultAprHandler({ - tokens: [sfrxETHMainnet], - url: 'https://api.frax.finance/v2/frxeth/summary/latest', - path: 'sfrxethApr', - network: 1 -}) + tokens: [sfrxETHMainnet], + url: 'https://api.frax.finance/v2/frxeth/summary/latest', + path: 'sfrxethApr', + network: 'MAINNET', +}); const rETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [rETHMainnet], - url: 'https://drop-api.stafi.io/reth/v1/poolData', - path: 'data.stakeApr', - network: 1 -}) + tokens: [rETHMainnet], + url: 'https://drop-api.stafi.io/reth/v1/poolData', + path: 'data.stakeApr', + network: 'MAINNET', +}); const USDRMainnetAprHandler = new DefaultAprHandler({ - tokens: [USDRMainnet], - url: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', - path: 'usdr', - network: 1 -}) + tokens: [USDRMainnet], + url: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', + path: 'usdr', + network: 'MAINNET', +}); const MATICXPolygonAprHandler = new DefaultAprHandler({ - tokens: [MATICXPolygon], - url: 'https://universe.staderlabs.com/polygon/apy', - path: 'value', - network: 137 -}) + tokens: [MATICXPolygon], + url: 'https://universe.staderlabs.com/polygon/apy', + path: 'value', + network: 'POLYGON', +}); const wbETHPolygonAprHandler = new DefaultAprHandler({ - tokens: [wbETHMainnet], - url: 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', - path: 'data.0.rewardRate', - scale: 1, - network: 137 , + tokens: [wbETHMainnet], + url: 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', + path: 'data.0.rewardRate', + scale: 1, + network: 'POLYGON', }); const swETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [swETHMainnet], - url: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', - network: 1 -}) + tokens: [swETHMainnet], + url: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', + network: 'MAINNET', +}); const wjAURAMainnetAprHandler = new DefaultAprHandler({ - tokens: [wjAURAMainnet], - url: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', - path: 'wjauraApy', - network: 1, -}) + tokens: [wjAURAMainnet], + url: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', + path: 'wjauraApy', + network: 'MAINNET', +}); export const defaultHandlers = [ - vETHMainnetAprHandler, - stETHMainnetAprHandler, - stETHPolygonAprHandler, - stETHZkEVMAprHandler, - stETHGnosisAprHandler, - stETHArbitrumAprHandler, - stMaticPolygonAprHandler, - cbEthMainnetAprHandler, - sfrxEthMainnetAprHandler, - rETHMainnetAprHandler, - USDRMainnetAprHandler, - MATICXPolygonAprHandler, - wbETHPolygonAprHandler, - swETHMainnetAprHandler, - wjAURAMainnetAprHandler, -] \ No newline at end of file + vETHMainnetAprHandler, + stETHMainnetAprHandler, + stETHPolygonAprHandler, + stETHZkEVMAprHandler, + stETHGnosisAprHandler, + stETHArbitrumAprHandler, + stMaticPolygonAprHandler, + cbEthMainnetAprHandler, + sfrxEthMainnetAprHandler, + rETHMainnetAprHandler, + USDRMainnetAprHandler, + MATICXPolygonAprHandler, + wbETHPolygonAprHandler, + swETHMainnetAprHandler, + wjAURAMainnetAprHandler, +]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts index bf21430ab..1cbabceb8 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts @@ -1,38 +1,13 @@ -import axios from "axios"; -import { AprHandler } from "../types"; - -const eulerTokensMainnet = { - eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', - eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', - eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', - eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', -} - -interface EulerResponse { - data: { - assets: [ - { - eTokenAddress: string - supplyAPY: string - } - ] - } -} - -type EulerAprHandlerConfig = { - tokens: {[key: string]: string}; - subgraphUrl: string; - network: number; - -} +import axios from 'axios'; +import { AprHandler } from '../ib-yield-apr-handlers'; class EulerAprHandler implements AprHandler { - tokens: { [key: string]: string } - subgraphUrl: string - network: number; - readonly group = 'EULER'; + tokens: { [key: string]: string }; + subgraphUrl: string; + networkPrismaId: string; + readonly group = 'EULER'; - readonly query = ` + readonly query = ` query getAssetsAPY($eTokenAddress_in: [String!]) { assets( where: { @@ -43,47 +18,71 @@ class EulerAprHandler implements AprHandler { supplyAPY } } -` +`; - constructor(aprHandlerConfig: EulerAprHandlerConfig) { - this.tokens = aprHandlerConfig.tokens - this.subgraphUrl = aprHandlerConfig.subgraphUrl - this.network = aprHandlerConfig.network; - } - - async getAprs() { - const requestQuery = { - operationName: 'getAssetsAPY', - query: this.query, - variables: { - eTokenAddress_in: Object.values(this.tokens), - }, + constructor(aprHandlerConfig: EulerAprHandlerConfig) { + this.tokens = aprHandlerConfig.tokens; + this.subgraphUrl = aprHandlerConfig.subgraphUrl; + this.networkPrismaId = aprHandlerConfig.network; } - const { data } = await axios({ - url: this.subgraphUrl, - method: 'POST', - data: JSON.stringify(requestQuery) - }) + async getAprs() { + const requestQuery = { + operationName: 'getAssetsAPY', + query: this.query, + variables: { + eTokenAddress_in: Object.values(this.tokens), + }, + }; - const { - data: { assets }, - } = data as EulerResponse + const { data } = await axios({ + url: this.subgraphUrl, + method: 'POST', + data: JSON.stringify(requestQuery), + }); - const aprEntries = assets.map(({ eTokenAddress, supplyAPY }) => [ - eTokenAddress, - // supplyAPY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 - Number(supplyAPY.slice(0, 27)) / 1e27 - ]) + const { + data: { assets }, + } = data as EulerResponse; - return Object.fromEntries(aprEntries) - } + const aprEntries = assets.map(({ eTokenAddress, supplyAPY }) => [ + eTokenAddress, + // supplyAPY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 + Number(supplyAPY.slice(0, 27)) / 1e27, + ]); + + return Object.fromEntries(aprEntries); + } +} + +const eulerTokensMainnet = { + eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', + eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', + eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', + eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', +}; + +interface EulerResponse { + data: { + assets: [ + { + eTokenAddress: string; + supplyAPY: string; + }, + ]; + }; } +type EulerAprHandlerConfig = { + tokens: { [key: string]: string }; + subgraphUrl: string; + network: string; +}; + const eulerMainnetAprHandler = new EulerAprHandler({ - tokens: eulerTokensMainnet, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet', - network: 1, + tokens: eulerTokensMainnet, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet', + network: 'MAINNET', }); -export const eulerHandlers = [eulerMainnetAprHandler]; \ No newline at end of file +export const eulerHandlers = [eulerMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts index 7731a25b6..06121c271 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts @@ -1,52 +1,52 @@ -import axios from "axios"; -import { AprHandler } from "../types"; +import axios from 'axios'; + +import { AprHandler } from '../ib-yield-apr-handlers'; class GearboxAprHandler implements AprHandler { - url: string; - tokens: { [key: string]: string} - network: number; - readonly group = 'GEARBOX'; - - constructor(aprHandlerConfig: GearboxAprHandlerConfig) { - this.tokens = aprHandlerConfig.tokens; - this.url = aprHandlerConfig.url; - this.network = aprHandlerConfig.network; - } - - async getAprs() { - try { - - const { data } = await axios.get(this.url) - const json = data as { data: { dieselToken: string; depositAPY_RAY: string }[] } - - const aprEntries = json.data - .filter((t) => Object.values(this.tokens).includes(t.dieselToken.toLowerCase())) - .map((({ dieselToken, depositAPY_RAY }) => { - return [dieselToken, Number(depositAPY_RAY.slice(0, 27)) / 1e27] - })) - return Object.fromEntries(aprEntries); - } catch (error) { - console.error('Failed to fetch Gearbox APR:', error) - return {} + url: string; + tokens: { [key: string]: string }; + networkPrismaId: string; + readonly group = 'GEARBOX'; + + constructor(aprHandlerConfig: GearboxAprHandlerConfig) { + this.tokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.url; + this.networkPrismaId = aprHandlerConfig.network; + } + + async getAprs() { + try { + const { data } = await axios.get(this.url); + const json = data as { data: { dieselToken: string; depositAPY_RAY: string }[] }; + + const aprEntries = json.data + .filter((t) => Object.values(this.tokens).includes(t.dieselToken.toLowerCase())) + .map(({ dieselToken, depositAPY_RAY }) => { + return [dieselToken, Number(depositAPY_RAY.slice(0, 27)) / 1e27]; + }); + return Object.fromEntries(aprEntries); + } catch (error) { + console.error('Failed to fetch Gearbox APR:', error); + return {}; + } } - } } type GearboxAprHandlerConfig = { - tokens: {[key: string]: string}; - url: string; - network: number; -} + tokens: { [key: string]: string }; + url: string; + network: string; +}; const gearboxTokensMainnet = { - dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', - dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', + dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', + dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', }; const gearboxMainnetAprHandler = new GearboxAprHandler({ tokens: gearboxTokensMainnet, url: 'https://mainnet.gearbox.foundation/api/pools', - network: 1 - }) + network: 'MAINNET', +}); -export const gearboxHandlers = [gearboxMainnetAprHandler] \ No newline at end of file +export const gearboxHandlers = [gearboxMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts index de4bac094..ff14e4785 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts @@ -1,77 +1,77 @@ -import axios from "axios"; -import { AprHandler } from "../types"; +import axios from 'axios'; -class IdleAprHandler implements AprHandler { - wrappedIdleTokens: { [key: string]: string }; - idleTokens: { [key: string]: string }; - baseIdleApiUrl: string; - authorizationHeader: string; - network: number; - readonly group = 'IDLE'; +import { AprHandler } from '../ib-yield-apr-handlers'; - constructor(aprHandlerConfig: IdleAprHandlerConfig) { - this.wrappedIdleTokens = aprHandlerConfig.wrappedIdleTokens; - this.idleTokens = aprHandlerConfig.idleTokens; - this.baseIdleApiUrl = aprHandlerConfig.baseIdleApiUrl; - this.authorizationHeader = aprHandlerConfig.authorizationHeader; - this.network = aprHandlerConfig.network; - } +class IdleAprHandler implements AprHandler { + wrappedIdleTokens: { [key: string]: string }; + idleTokens: { [key: string]: string }; + baseIdleApiUrl: string; + authorizationHeader: string; + networkPrismaId: string; + readonly group = 'IDLE'; - async getAprs() { - try { + constructor(aprHandlerConfig: IdleAprHandlerConfig) { + this.wrappedIdleTokens = aprHandlerConfig.wrappedIdleTokens; + this.idleTokens = aprHandlerConfig.idleTokens; + this.baseIdleApiUrl = aprHandlerConfig.baseIdleApiUrl; + this.authorizationHeader = aprHandlerConfig.authorizationHeader; + this.networkPrismaId = aprHandlerConfig.network; + } - const aprPromises = Object.entries(this.idleTokens) - .map(async ([tokenName, idleTokenAddress]) => { - const { data } = await axios.get([this.baseIdleApiUrl, idleTokenAddress, "?isRisk=false&order=desc&limit=1"].join(''), { - headers: { - Authorization: this.authorizationHeader, - }, - }) - const [json] = data as { idleRate: string }[] - const value = Number(json.idleRate) / 1e20 - return [ - this.wrappedIdleTokens[tokenName], - value, - ] - }) - const res = Array(Object.keys(this.idleTokens).length) - for (const [index, aprPromise] of aprPromises.entries()) { - res[index] = await aprPromise - } - return Object.fromEntries(res); - } catch (error) { - console.error('Failed to fetch Idle APR:', error) - return {} + async getAprs() { + try { + const aprPromises = Object.entries(this.idleTokens).map(async ([tokenName, idleTokenAddress]) => { + const { data } = await axios.get( + [this.baseIdleApiUrl, idleTokenAddress, '?isRisk=false&order=desc&limit=1'].join(''), + { + headers: { + Authorization: this.authorizationHeader, + }, + }, + ); + const [json] = data as { idleRate: string }[]; + const value = Number(json.idleRate) / 1e20; + return [this.wrappedIdleTokens[tokenName], value]; + }); + const res = Array(Object.keys(this.idleTokens).length); + for (const [index, aprPromise] of aprPromises.entries()) { + res[index] = await aprPromise; + } + return Object.fromEntries(res); + } catch (error) { + console.error('Failed to fetch Idle APR:', error); + return {}; + } } - } } const wrapped4626IdleTokensMainnet = { - idleDAI: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', - idleUSDC: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', - idleUSDT: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', -} + idleDAI: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', + idleUSDC: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', + idleUSDT: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', +}; const idleTokensMainnet = { - idleDAI: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', - idleUSDC: '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', - idleUSDT: '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', -} + idleDAI: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', + idleUSDC: '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', + idleUSDT: '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', +}; type IdleAprHandlerConfig = { - wrappedIdleTokens: {[key: string]: string}; - idleTokens: {[key: string]: string}; - baseIdleApiUrl: string; - authorizationHeader: string; - network: number; -} + wrappedIdleTokens: { [key: string]: string }; + idleTokens: { [key: string]: string }; + baseIdleApiUrl: string; + authorizationHeader: string; + network: string; +}; const idleMainnetAprHandler = new IdleAprHandler({ wrappedIdleTokens: wrapped4626IdleTokensMainnet, idleTokens: idleTokensMainnet, baseIdleApiUrl: 'https://api.idle.finance/junior-rates/', - authorizationHeader: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M', - network: 1 - }); + authorizationHeader: + 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M', + network: 'MAINNET', +}); -export const idleAprHandlers = [idleMainnetAprHandler] \ No newline at end of file +export const idleAprHandlers = [idleMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts index df2fa23af..0c23c350c 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts @@ -1,50 +1,50 @@ -import axios from "axios"; -import { AprHandler } from "../types"; +import axios from 'axios'; + +import { AprHandler } from '../ib-yield-apr-handlers'; class OvernightAprHandler implements AprHandler { - overnightTokens: { [key: string]: string }; - url: string; - network: number; - readonly group = 'OVERNIGHT'; - - constructor(aprHandlerConfig: OvernightAprHandlerConfig) { - this.overnightTokens = aprHandlerConfig.tokens; - this.url = aprHandlerConfig.url; - this.network = aprHandlerConfig.network; - } - - async getAprs() { - try { - - const { data } = await axios.get(this.url) - const rate = data as number - - return Object.values(this.overnightTokens).reduce((acc, token) => { - acc[token] = rate - return acc - }, {} as { [key: string]: number }) - } catch (error) { - console.error(`Failed to fetch Overnight APRs in url:`, error) - return {} + overnightTokens: { [key: string]: string }; + url: string; + networkPrismaId: string; + readonly group = 'OVERNIGHT'; + + constructor(aprHandlerConfig: OvernightAprHandlerConfig) { + this.overnightTokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.url; + this.networkPrismaId = aprHandlerConfig.network; + } + + async getAprs() { + try { + const { data } = await axios.get(this.url); + const rate = data as number; + + return Object.values(this.overnightTokens).reduce((acc, token) => { + acc[token] = rate; + return acc; + }, {} as { [key: string]: number }); + } catch (error) { + console.error(`Failed to fetch Overnight APRs in url:`, error); + return {}; + } } - } } const overnightTokens = { - lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus - UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f' // UsdcUsdPlus -} + lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus + UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f', // UsdcUsdPlus +}; type OvernightAprHandlerConfig = { - tokens: {[key: string]: string}; - url: string; - network: number; -} + tokens: { [key: string]: string }; + url: string; + network: string; +}; const overnightMainnetAprHandler = new OvernightAprHandler({ - tokens: overnightTokens, - url: 'https://app.overnight.fi/api/balancer/week/apr', - network: 1 -}) + tokens: overnightTokens, + url: 'https://app.overnight.fi/api/balancer/week/apr', + network: 'MAINNET', +}); -export const overnightHandlers = [overnightMainnetAprHandler] \ No newline at end of file +export const overnightHandlers = [overnightMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts index 137c1714b..842b85fa5 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts @@ -1,72 +1,72 @@ -import { BigNumber, Contract } from "ethers"; -import { abi } from "./abis/oErc20"; -import { JsonRpcProvider } from "@ethersproject/providers"; -import { AprHandler } from "../types"; +import { BigNumber, Contract } from 'ethers'; +import { abi } from './abis/oErc20'; +import { JsonRpcProvider } from '@ethersproject/providers'; -class OvixAprHandler implements AprHandler { - network: number; - provider: JsonRpcProvider; - yieldTokens: { [key: string]: `0x${ string }` }; - wrappedTokens: { [key: string]: `0x${ string }` }; - readonly group = 'OVIX'; +import { AprHandler } from '../ib-yield-apr-handlers'; - constructor(aprHandlerConfig: OvixAprHandlerConfig) { - this.network = aprHandlerConfig.network; - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); - this.yieldTokens = aprHandlerConfig.yieldTokens; - this.wrappedTokens = aprHandlerConfig.wrappedTokens; - } +class OvixAprHandler implements AprHandler { + networkPrismaId: string; + provider: JsonRpcProvider; + yieldTokens: { [key: string]: `0x${string}` }; + wrappedTokens: { [key: string]: `0x${string}` }; + readonly group = 'OVIX'; - async getAprs() { - try { + constructor(aprHandlerConfig: OvixAprHandlerConfig) { + this.networkPrismaId = aprHandlerConfig.network; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); + this.yieldTokens = aprHandlerConfig.yieldTokens; + this.wrappedTokens = aprHandlerConfig.wrappedTokens; + } - const calls = Object.keys(this.yieldTokens).map(async (tokenName) => { - const contract = new Contract(this.yieldTokens[tokenName], abi, this.provider) - return contract.borrowRatePerTimestamp() - }) + async getAprs() { + try { + const calls = Object.keys(this.yieldTokens).map(async (tokenName) => { + const contract = new Contract(this.yieldTokens[tokenName], abi, this.provider); + return contract.borrowRatePerTimestamp(); + }); - const borrowRates = Array(Object.keys(this.yieldTokens).length) - for (const [index, aprPromise] of calls.entries()) { - borrowRates[index] = await aprPromise - } + const borrowRates = Array(Object.keys(this.yieldTokens).length); + for (const [index, aprPromise] of calls.entries()) { + borrowRates[index] = await aprPromise; + } - const aprs = Object.keys(this.wrappedTokens).map((tokenName, i) => [ - this.wrappedTokens[tokenName], - (Math.pow(1 + (borrowRates[i] as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1) - ]) + const aprs = Object.keys(this.wrappedTokens).map((tokenName, i) => [ + this.wrappedTokens[tokenName], + Math.pow(1 + (borrowRates[i] as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1, + ]); - return Object.fromEntries(aprs) - } catch (error) { - console.error('Failed to fetch Ovix APR:', error) - return {} + return Object.fromEntries(aprs); + } catch (error) { + console.error('Failed to fetch Ovix APR:', error); + return {}; + } } - } } type OvixAprHandlerConfig = { - network: number; - rpcUrl: string; - yieldTokens: { [key: string]: `0x${ string }` } - wrappedTokens: { - [key: string]: `0x${ string }` - } -} + network: string; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${string}` }; + wrappedTokens: { + [key: string]: `0x${string}`; + }; +}; const ovixYieldTokensZkEvm = { - USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', - USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', -} as { [key: string]: `0x${string}` } + USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', + USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', +} as { [key: string]: `0x${string}` }; const ovixWrappedTokensZkEvm = { - USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', - USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', -} as { [key: string]: `0x${string}` } + USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', + USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', +} as { [key: string]: `0x${string}` }; const ovixZkEVMAprHandler = new OvixAprHandler({ - network: 1101, - rpcUrl: 'https://zkevm-rpc.com', - yieldTokens: ovixYieldTokensZkEvm, - wrappedTokens: ovixWrappedTokensZkEvm + network: 'ZKEVM', + rpcUrl: 'https://zkevm-rpc.com', + yieldTokens: ovixYieldTokensZkEvm, + wrappedTokens: ovixWrappedTokensZkEvm, }); -export const ovixHandlers = [ovixZkEVMAprHandler] +export const ovixHandlers = [ovixZkEVMAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts index b7617026a..c856b1516 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts @@ -1,74 +1,71 @@ -import { JsonRpcProvider } from "@ethersproject/providers"; -import { BigNumber, Contract } from "ethers"; -import { abi } from "./abis/reaperStrategy"; -import { AprHandler } from "../types"; +import { JsonRpcProvider } from '@ethersproject/providers'; +import { BigNumber, Contract } from 'ethers'; +import { abi } from './abis/reaperStrategy'; -class ReaperAprHandler implements AprHandler { - network: number; - provider: JsonRpcProvider; - yieldTokens: { [key: string]: `0x${ string }` }; - strategiesMap: { [key: string]: `0x${ string }` }; - readonly group = 'REAPER'; +import { AprHandler } from '../ib-yield-apr-handlers'; - constructor(aprHandlerConfig: ReaperAprHandlerConfig) { - this.network = aprHandlerConfig.network; - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); - this.yieldTokens = aprHandlerConfig.yieldTokens; - this.strategiesMap = aprHandlerConfig.strategiesMap; - } +class ReaperAprHandler implements AprHandler { + networkPrismaId: string; + provider: JsonRpcProvider; + yieldTokens: { [key: string]: `0x${string}` }; + strategiesMap: { [key: string]: `0x${string}` }; + readonly group = 'REAPER'; - async getAprs() { - try { + constructor(aprHandlerConfig: ReaperAprHandlerConfig) { + this.networkPrismaId = aprHandlerConfig.network; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); + this.yieldTokens = aprHandlerConfig.yieldTokens; + this.strategiesMap = aprHandlerConfig.strategiesMap; + } - const contractCalls = Object.keys(this.strategiesMap).map(async (tokenName) => { - const contract = new Contract(this.strategiesMap[tokenName], abi, this.provider) - return contract.averageAPRAcrossLastNHarvests(3) - }) - const callsAprResults: BigNumber[] = Array(Object.keys(this.yieldTokens).length) - for (const [index, aprPromise] of contractCalls.entries()) { - callsAprResults[index] = await aprPromise - } - const aprs = Object.keys(this.strategiesMap).map((tokenName, i) => { - return [ - this.yieldTokens[tokenName], - callsAprResults[i].toNumber() / 1e4, - ] - }) + async getAprs() { + try { + const contractCalls = Object.keys(this.strategiesMap).map(async (tokenName) => { + const contract = new Contract(this.strategiesMap[tokenName], abi, this.provider); + return contract.averageAPRAcrossLastNHarvests(3); + }); + const callsAprResults: BigNumber[] = Array(Object.keys(this.yieldTokens).length); + for (const [index, aprPromise] of contractCalls.entries()) { + callsAprResults[index] = await aprPromise; + } + const aprs = Object.keys(this.strategiesMap).map((tokenName, i) => { + return [this.yieldTokens[tokenName], callsAprResults[i].toNumber() / 1e4]; + }); - return Object.fromEntries(aprs) - } catch (error) { - console.error('Failed to fetch Reaper APR:', error) - return {} + return Object.fromEntries(aprs); + } catch (error) { + console.error('Failed to fetch Reaper APR:', error); + return {}; + } } - } } type ReaperAprHandlerConfig = { - network: number; - rpcUrl: string; - yieldTokens: { [key: string]: `0x${ string }` } - strategiesMap: { - [key: string]: `0x${ string }` - } -} + network: string; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${string}` }; + strategiesMap: { + [key: string]: `0x${string}`; + }; +}; const reaperYieldTokensArbitrum = { - DAI: '0x12f256109e744081f633a827be80e06d97ff7447', - USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', - USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', -} as { [key: string]: `0x${ string }` } + DAI: '0x12f256109e744081f633a827be80e06d97ff7447', + USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', + USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', +} as { [key: string]: `0x${string}` }; const reaperStrategiesMapArbitrum = { - DAI: '0xd4d5321b04e4832772a4d70e1eed6bcb7402d7ac', - USDT: '0x8a674ebbe33d6b03825626fa432e9ece888e13b5', - USDC: '0x6f6c0c5b7af2a326111ba6a9fa4926f7ca3adf44', -} as { [key: string]: `0x${ string }` } + DAI: '0xd4d5321b04e4832772a4d70e1eed6bcb7402d7ac', + USDT: '0x8a674ebbe33d6b03825626fa432e9ece888e13b5', + USDC: '0x6f6c0c5b7af2a326111ba6a9fa4926f7ca3adf44', +} as { [key: string]: `0x${string}` }; const reaperArbitrumAprHandler = new ReaperAprHandler({ - network: 42161, - rpcUrl: 'https://arb1.arbitrum.io/rpc', - yieldTokens: reaperYieldTokensArbitrum, - strategiesMap: reaperStrategiesMapArbitrum, -}) + network: 'ARBITRUM', + rpcUrl: 'https://arb1.arbitrum.io/rpc', + yieldTokens: reaperYieldTokensArbitrum, + strategiesMap: reaperStrategiesMapArbitrum, +}); -export const reaperHandlers = [reaperArbitrumAprHandler] \ No newline at end of file +export const reaperHandlers = [reaperArbitrumAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts index a7270b6b4..87d662847 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts @@ -1,63 +1,64 @@ -import { Contract } from "ethers"; -import { abi } from "./abis/tesseraPool"; -import { JsonRpcProvider } from "@ethersproject/providers"; -import { AprHandler } from "../types"; +import { Contract } from 'ethers'; +import { abi } from './abis/tesseraPool'; +import { JsonRpcProvider } from '@ethersproject/providers'; + +import { AprHandler } from '../ib-yield-apr-handlers'; class TesseraAprHandler implements AprHandler { - network: number; - provider: JsonRpcProvider; - yieldTokens: { [key: string]: `0x${ string }` }; - stakingContractAddress: `0x${ string }`; - readonly group = 'TESSERA'; - - constructor(aprHandlerConfig: TesseraAprHandlerConfig) { - this.network = aprHandlerConfig.network; - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); - this.yieldTokens = aprHandlerConfig.yieldTokens; - this.stakingContractAddress = aprHandlerConfig.contractAddress; - } - - async getAprs() { - try { - let apr = 0 - try { - const contract = new Contract(this.stakingContractAddress, abi, this.provider) - const poolsUI = await contract.getPoolsUI() - - const pool = poolsUI[0] - const staked = BigInt(pool.stakedAmount) - const reward = BigInt(pool.currentTimeRange.rewardsPerHour) * BigInt(24 * 365) - apr = Number(reward.toString()) / Number(staked.toString()); - } catch (error) { - console.error('Failed to fetch Tessera Ape Coin APR:', error) - } - - return { - [this.yieldTokens.sApe]: apr, - } - } catch (error) { - console.error('Failed to fetch Tessera APR:', error) - return {} + networkPrismaId: string; + provider: JsonRpcProvider; + yieldTokens: { [key: string]: `0x${string}` }; + stakingContractAddress: `0x${string}`; + readonly group = 'TESSERA'; + + constructor(aprHandlerConfig: TesseraAprHandlerConfig) { + this.networkPrismaId = aprHandlerConfig.network; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); + this.yieldTokens = aprHandlerConfig.yieldTokens; + this.stakingContractAddress = aprHandlerConfig.contractAddress; + } + + async getAprs() { + try { + let apr = 0; + try { + const contract = new Contract(this.stakingContractAddress, abi, this.provider); + const poolsUI = await contract.getPoolsUI(); + + const pool = poolsUI[0]; + const staked = BigInt(pool.stakedAmount); + const reward = BigInt(pool.currentTimeRange.rewardsPerHour) * BigInt(24 * 365); + apr = Number(reward.toString()) / Number(staked.toString()); + } catch (error) { + console.error('Failed to fetch Tessera Ape Coin APR:', error); + } + + return { + [this.yieldTokens.sApe]: apr, + }; + } catch (error) { + console.error('Failed to fetch Tessera APR:', error); + return {}; + } } - } } type TesseraAprHandlerConfig = { - network: number; - rpcUrl: string; - yieldTokens: { [key: string]: `0x${ string }` }; - contractAddress: `0x${ string }`; -} + network: string; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${string}` }; + contractAddress: `0x${string}`; +}; const tesseraYieldTokensMainnet = { - sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', -} as { [key: string]: `0x${ string }` } + sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', +} as { [key: string]: `0x${string}` }; const tesseraMainnetAprHandler = new TesseraAprHandler({ - network: 1, + network: 'MAINNET', rpcUrl: 'https://rpc.ankr.com/eth', yieldTokens: tesseraYieldTokensMainnet, - contractAddress: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9' /*ApeCoinStaking*/ - }) + contractAddress: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9' /*ApeCoinStaking*/, +}); -export const tesseraHandlers = [tesseraMainnetAprHandler] \ No newline at end of file +export const tesseraHandlers = [tesseraMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts index e7fd7466d..5f07ad2aa 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts @@ -1,43 +1,43 @@ -import axios from "axios"; -import { AprHandler } from "../types"; +import axios from 'axios'; + +import { AprHandler } from '../ib-yield-apr-handlers'; class TetuAprHandler implements AprHandler { - network: number; - baseUrl: string; - networkName: string; - readonly group = 'TETU'; - - constructor(aprHandlerConfig: TetuAprHandlerConfig) { - this.network = aprHandlerConfig.network; - this.baseUrl = aprHandlerConfig.baseUrl; - this.networkName = aprHandlerConfig.networkName; - } - - async getAprs() { - try { - - const { data } = await axios.get(`${ this.baseUrl }?network=${ this.networkName }`) - const json = data as { vault: string, apr: number }[] - const aprs = json.map((t) => [t.vault, t.apr / 100]) - - return Object.fromEntries(aprs) - } catch (error) { - console.error('Failed to fetch Tetu APR:', error) - return {} + networkPrismaId: string; + baseUrl: string; + networkName: string; + readonly group = 'TETU'; + + constructor(aprHandlerConfig: TetuAprHandlerConfig) { + this.networkPrismaId = aprHandlerConfig.network; + this.baseUrl = aprHandlerConfig.baseUrl; + this.networkName = aprHandlerConfig.networkName; + } + + async getAprs() { + try { + const { data } = await axios.get(`${this.baseUrl}?network=${this.networkName}`); + const json = data as { vault: string; apr: number }[]; + const aprs = json.map((t) => [t.vault, t.apr / 100]); + + return Object.fromEntries(aprs); + } catch (error) { + console.error('Failed to fetch Tetu APR:', error); + return {}; + } } - } } type TetuAprHandlerConfig = { - network: number; - baseUrl: string; - networkName: string; -} + network: string; + baseUrl: string; + networkName: string; +}; const tetuPolygonAprHandler = new TetuAprHandler({ - network: 137, - baseUrl: 'https://api.tetu.io/api/v1/reader/compoundAPRs', - networkName: 'MATIC' -}) + network: 'POLYGON', + baseUrl: 'https://api.tetu.io/api/v1/reader/compoundAPRs', + networkName: 'MATIC', +}); -export const tetuHandlers = [tetuPolygonAprHandler] \ No newline at end of file +export const tetuHandlers = [tetuPolygonAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts index eabb1cda6..732f205ba 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts @@ -1,46 +1,47 @@ -import axios from "axios"; -import { AprHandler } from "../types"; +import axios from 'axios'; -const qETHMainnet = '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d' +import { AprHandler } from '../ib-yield-apr-handlers'; + +const qETHMainnet = '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d'; class TranchessAprHandler implements AprHandler { - network: number; - url: string; - token: string; - readonly group = 'TRANCHESS'; - - constructor(aprHandlerConfig: TranchessAprHandlerConfig) { - this.network = aprHandlerConfig.network; - this.token = aprHandlerConfig.token; - this.url = aprHandlerConfig.url; - } - - async getAprs() { - try { - const { data } = await axios.get('https://tranchess.com/eth/api/v3/funds'); - const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[] - // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. - const value = (365 * Number(weeklyAveragePnlPercentage)) / 1e18 - return { - [this.token]: value - } - } catch (error) { - console.error('Failed to fetch Tranchess APR:', error) - return {} + networkPrismaId: string; + url: string; + token: string; + readonly group = 'TRANCHESS'; + + constructor(aprHandlerConfig: TranchessAprHandlerConfig) { + this.networkPrismaId = aprHandlerConfig.network; + this.token = aprHandlerConfig.token; + this.url = aprHandlerConfig.url; + } + + async getAprs() { + try { + const { data } = await axios.get('https://tranchess.com/eth/api/v3/funds'); + const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[]; + // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. + const value = (365 * Number(weeklyAveragePnlPercentage)) / 1e18; + return { + [this.token]: value, + }; + } catch (error) { + console.error('Failed to fetch Tranchess APR:', error); + return {}; + } } - } } type TranchessAprHandlerConfig = { - network: number; - token: string; - url: string; -} + network: string; + token: string; + url: string; +}; const tranchessMainnetAprHandler = new TranchessAprHandler({ - network: 1, - token: qETHMainnet, - url: 'https://tranchess.com/eth/api/v3/funds' -}) + network: 'MAINNET', + token: qETHMainnet, + url: 'https://tranchess.com/eth/api/v3/funds', +}); -export const tranchessHandlers = [tranchessMainnetAprHandler] \ No newline at end of file +export const tranchessHandlers = [tranchessMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts deleted file mode 100644 index 438f3df0e..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -export type TokenApr = { - val: number; - address: string; - group?: string; -} - -export interface AprHandler { - readonly group: string; - getAprs(): Promise<{ [key: string]: number }>; -} \ No newline at end of file From 37366a40058a069949dc123da6d360a67992f74f Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Fri, 18 Aug 2023 16:06:18 -0300 Subject: [PATCH 19/42] Checking if the pool is linear boosted by the token address; Fixing network id type error on json rpc provider creation; --- .../apr-data-sources/ib-tokens-apr.service.ts | 7 ++- .../ib-yield-apr-handlers.ts | 54 +++++++++++++++---- .../sources/aave-apr-handler.ts | 10 ++-- .../sources/ankr-apr-handler.ts | 2 +- .../sources/default-apr-handler.ts | 13 ++--- .../sources/euler-apr-handler.ts | 2 +- .../sources/gearbox-apr-handler.ts | 2 +- .../sources/idle-apr-handler.ts | 2 +- .../sources/overnight-apr-handler.ts | 2 +- .../sources/ovix-apr-handler.ts | 12 +++-- .../sources/reaper-apr-handler.ts | 12 +++-- .../sources/tessera-apr-handler.ts | 12 +++-- .../sources/tetu-apr-handler.ts | 14 ++++- .../sources/tranchess-apr-handler.ts | 2 +- 14 files changed, 97 insertions(+), 49 deletions(-) diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 4ae27af67..1646246ae 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -4,7 +4,7 @@ import { prisma } from '../../../../prisma/prisma-client'; import { networkContext } from '../../../network/network-context.service'; import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; import { PrismaPoolAprItemGroup } from '@prisma/client'; -import { IbYieldAprHandlers, TokenApr } from './ib-yield-apr-handlers/ib-yield-apr-handlers'; +import { IbYieldAprHandlers, TokenApr, wrappedTokens } from './ib-yield-apr-handlers/ib-yield-apr-handlers'; export class IbTokensAprService implements PoolAprService { private ibYieldAprHandlers: IbYieldAprHandlers; @@ -32,7 +32,7 @@ export class IbTokensAprService implements PoolAprService { if (aprs.get(token.address) !== undefined) { const tokenSymbol = token.token.symbol; const itemId = `${pool.id}-${tokenSymbol}-yield-apr`; - + const isBoosted = wrappedTokens.includes(token.address); operations.push( prisma.prismaPoolAprItem.upsert({ where: { id_chain: { id: itemId, chain: networkContext.chain } }, @@ -43,7 +43,7 @@ export class IbTokensAprService implements PoolAprService { title: `${tokenSymbol} APR`, apr: aprs.get(token.address)?.val ?? 0, group: (aprs.get(token.address)?.group as PrismaPoolAprItemGroup) ?? null, - type: pool.type === 'LINEAR' ? 'LINEAR_BOOSTED' : 'IB_YIELD', + type: pool.type === 'LINEAR' && isBoosted ? 'LINEAR_BOOSTED' : 'IB_YIELD', }, update: { title: `${tokenSymbol} APR`, @@ -60,7 +60,6 @@ export class IbTokensAprService implements PoolAprService { private async fetchYieldTokensApr(): Promise> { const data = await this.ibYieldAprHandlers.fetchAprsFromAllHandlers(); - console.log(data); return new Map(data.filter((apr) => !isNaN(apr.val)).map((apr) => [apr.address, apr])); } } diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts index 775e3fa34..ad757ebae 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts @@ -1,14 +1,22 @@ -import { aaveHandlers } from './sources/aave-apr-handler'; -import { ankrHandlers } from './sources/ankr-apr-handler'; -import { defaultHandlers } from './sources/default-apr-handler'; -import { eulerHandlers } from './sources/euler-apr-handler'; -import { gearboxHandlers } from './sources/gearbox-apr-handler'; -import { idleAprHandlers } from './sources/idle-apr-handler'; -import { overnightHandlers } from './sources/overnight-apr-handler'; -import { ovixHandlers } from './sources/ovix-apr-handler'; -import { reaperHandlers } from './sources/reaper-apr-handler'; -import { tesseraHandlers } from './sources/tessera-apr-handler'; -import { tetuHandlers } from './sources/tetu-apr-handler'; +import { + aaveHandlers, + wrappedAaveTokensV2Mainnet, + wrappedAaveTokensV2Polygon, + wrappedAaveTokensV3Arbitrum, + wrappedAaveTokensV3Mainnet, + wrappedAaveTokensV3Polygon, +} from './sources/aave-apr-handler'; +import { ankrEthMainnet, ankrHandlers } from './sources/ankr-apr-handler'; +import { defaultHandlers, rETHMainnet, swETHMainnet, USDRMainnet, wjAURAMainnet } from './sources/default-apr-handler'; +import { eulerHandlers, eulerTokensMainnet } from './sources/euler-apr-handler'; +import { gearboxHandlers, gearboxTokensMainnet } from './sources/gearbox-apr-handler'; +import { idleAprHandlers, wrapped4626IdleTokensMainnet } from './sources/idle-apr-handler'; +import { overnightHandlers, overnightTokens } from './sources/overnight-apr-handler'; +import { ovixHandlers, ovixWrappedTokensZkEvm } from './sources/ovix-apr-handler'; +import { reaperHandlers, reaperYieldTokensArbitrum } from './sources/reaper-apr-handler'; +import { tesseraHandlers, tesseraYieldTokensMainnet } from './sources/tessera-apr-handler'; +import { tDAIPolygon, tetuHandlers, tUSDCPolygon, tUSDTPolygon } from './sources/tetu-apr-handler'; +import { qETHMainnet } from './sources/tranchess-apr-handler'; const aprHandlers: AprHandler[] = [ ...aaveHandlers, @@ -59,3 +67,27 @@ export type TokenApr = { address: string; group?: string; }; + +export const wrappedTokens = [ + ...Object.values(wrappedAaveTokensV2Mainnet), + ...Object.values(wrappedAaveTokensV2Polygon), + ...Object.values(wrappedAaveTokensV3Mainnet), + ...Object.values(wrappedAaveTokensV3Polygon), + ...Object.values(wrappedAaveTokensV3Arbitrum), + ankrEthMainnet, + rETHMainnet, + USDRMainnet, + swETHMainnet, + wjAURAMainnet, + ...Object.values(eulerTokensMainnet), + ...Object.values(gearboxTokensMainnet), + ...Object.values(wrapped4626IdleTokensMainnet), + ...Object.values(overnightTokens), + ...Object.values(ovixWrappedTokensZkEvm), + ...Object.values(reaperYieldTokensArbitrum), + ...Object.values(tesseraYieldTokensMainnet), + tUSDTPolygon, + tUSDCPolygon, + tDAIPolygon, + qETHMainnet, +]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts index 27e54e9a1..c863e1afa 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts @@ -77,7 +77,7 @@ class AaveAprHandler implements AprHandler { } } -const wrappedAaveTokensV2Mainnet = { +export const wrappedAaveTokensV2Mainnet = { waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', @@ -89,7 +89,7 @@ const aaveTokensV2Mainnet = { aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', }; -const wrappedAaveTokensV2Polygon = { +export const wrappedAaveTokensV2Polygon = { waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', @@ -101,7 +101,7 @@ const aaveTokensV2Polygon = { aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', }; -const wrappedAaveTokensV3Mainnet = { +export const wrappedAaveTokensV3Mainnet = { waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', @@ -115,7 +115,7 @@ const aaveTokensV3Mainnet = { aWETH: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8', }; -const wrappedAaveTokensV3Polygon = { +export const wrappedAaveTokensV3Polygon = { waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', waUSDC: '0x9719d867a500ef117cc201206b8ab51e794d3f82', @@ -131,7 +131,7 @@ const aaveTokensV3Polygon = { aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', }; -const wrappedAaveTokensV3Arbitrum = { +export const wrappedAaveTokensV3Arbitrum = { waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts index af7234583..dddf92a3b 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts @@ -33,7 +33,7 @@ class AnkrAprHandler implements AprHandler { } } -const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb'; +export const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb'; type AnkrAprHandlerConfig = { serviceName: string; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts index 9fb12f6a2..8b24b7766 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts @@ -52,7 +52,7 @@ export type DefaultAprHandlerConfig = { path?: string; }; -const vETHMainnet = '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f'; +export const vETHMainnet = '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f'; const wstETHGnosis = '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6'; const wstETHZkEVM = '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9'; const stETHMainnet = '0xae7ab96520de3a18e5e111b5eaab095312d7fe84'; @@ -60,14 +60,15 @@ const wstETHMainnet = '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0'; const wstETHPolygon = '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd'; const wstETHArbitrum = '0x5979d7b546e38e414f7e9822514be443a4800529'; const stMATICPolygon = '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'; -const cbETHMainnet = '0xbe9895146f7af43049ca1c1ae358b0541ea49704'; +export const cbETHMainnet = '0xbe9895146f7af43049ca1c1ae358b0541ea49704'; + const sfrxETHMainnet = '0xac3e018457b222d93114458476f3e3416abbe38f'; -const rETHMainnet = '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'; -const USDRMainnet = '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'; +export const rETHMainnet = '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'; +export const USDRMainnet = '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'; const MATICXPolygon = '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'; const wbETHMainnet = '0xa2e3356610840701bdf5611a53974510ae27e2e1'; -const swETHMainnet = '0xf951e335afb289353dc249e82926178eac7ded78'; -const wjAURAMainnet = '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'; +export const swETHMainnet = '0xf951e335afb289353dc249e82926178eac7ded78'; +export const wjAURAMainnet = '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'; const vETHMainnetAprHandler = new DefaultAprHandler({ tokens: [vETHMainnet], diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts index 1cbabceb8..d6cc43d72 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts @@ -55,7 +55,7 @@ class EulerAprHandler implements AprHandler { } } -const eulerTokensMainnet = { +export const eulerTokensMainnet = { eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts index 06121c271..ff5bab3b5 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts @@ -38,7 +38,7 @@ type GearboxAprHandlerConfig = { network: string; }; -const gearboxTokensMainnet = { +export const gearboxTokensMainnet = { dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', }; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts index ff14e4785..975497fe7 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts @@ -45,7 +45,7 @@ class IdleAprHandler implements AprHandler { } } -const wrapped4626IdleTokensMainnet = { +export const wrapped4626IdleTokensMainnet = { idleDAI: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', idleUSDC: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', idleUSDT: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts index 0c23c350c..64c64d88e 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts @@ -30,7 +30,7 @@ class OvernightAprHandler implements AprHandler { } } -const overnightTokens = { +export const overnightTokens = { lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f', // UsdcUsdPlus }; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts index 842b85fa5..b4a78b613 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts @@ -12,8 +12,8 @@ class OvixAprHandler implements AprHandler { readonly group = 'OVIX'; constructor(aprHandlerConfig: OvixAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.network; - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); + this.networkPrismaId = aprHandlerConfig.networkPrismaId; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); this.yieldTokens = aprHandlerConfig.yieldTokens; this.wrappedTokens = aprHandlerConfig.wrappedTokens; } @@ -44,7 +44,8 @@ class OvixAprHandler implements AprHandler { } type OvixAprHandlerConfig = { - network: string; + networkPrismaId: string; + networkChainId: number; rpcUrl: string; yieldTokens: { [key: string]: `0x${string}` }; wrappedTokens: { @@ -57,13 +58,14 @@ const ovixYieldTokensZkEvm = { USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', } as { [key: string]: `0x${string}` }; -const ovixWrappedTokensZkEvm = { +export const ovixWrappedTokensZkEvm = { USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', } as { [key: string]: `0x${string}` }; const ovixZkEVMAprHandler = new OvixAprHandler({ - network: 'ZKEVM', + networkPrismaId: 'ZKEVM', + networkChainId: 1101, rpcUrl: 'https://zkevm-rpc.com', yieldTokens: ovixYieldTokensZkEvm, wrappedTokens: ovixWrappedTokensZkEvm, diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts index c856b1516..ad3cd4a7c 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts @@ -12,8 +12,8 @@ class ReaperAprHandler implements AprHandler { readonly group = 'REAPER'; constructor(aprHandlerConfig: ReaperAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.network; - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); + this.networkPrismaId = aprHandlerConfig.networkPrismaId; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); this.yieldTokens = aprHandlerConfig.yieldTokens; this.strategiesMap = aprHandlerConfig.strategiesMap; } @@ -41,7 +41,8 @@ class ReaperAprHandler implements AprHandler { } type ReaperAprHandlerConfig = { - network: string; + networkPrismaId: string; + networkChainId: number; rpcUrl: string; yieldTokens: { [key: string]: `0x${string}` }; strategiesMap: { @@ -49,7 +50,7 @@ type ReaperAprHandlerConfig = { }; }; -const reaperYieldTokensArbitrum = { +export const reaperYieldTokensArbitrum = { DAI: '0x12f256109e744081f633a827be80e06d97ff7447', USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', @@ -62,7 +63,8 @@ const reaperStrategiesMapArbitrum = { } as { [key: string]: `0x${string}` }; const reaperArbitrumAprHandler = new ReaperAprHandler({ - network: 'ARBITRUM', + networkPrismaId: 'ARBITRUM', + networkChainId: 42161, rpcUrl: 'https://arb1.arbitrum.io/rpc', yieldTokens: reaperYieldTokensArbitrum, strategiesMap: reaperStrategiesMapArbitrum, diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts index 87d662847..3b9f8f4e0 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts @@ -12,8 +12,8 @@ class TesseraAprHandler implements AprHandler { readonly group = 'TESSERA'; constructor(aprHandlerConfig: TesseraAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.network; - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.network); + this.networkPrismaId = aprHandlerConfig.networkPrismaId; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); this.yieldTokens = aprHandlerConfig.yieldTokens; this.stakingContractAddress = aprHandlerConfig.contractAddress; } @@ -44,18 +44,20 @@ class TesseraAprHandler implements AprHandler { } type TesseraAprHandlerConfig = { - network: string; + networkPrismaId: string; + networkChainId: number; rpcUrl: string; yieldTokens: { [key: string]: `0x${string}` }; contractAddress: `0x${string}`; }; -const tesseraYieldTokensMainnet = { +export const tesseraYieldTokensMainnet = { sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', } as { [key: string]: `0x${string}` }; const tesseraMainnetAprHandler = new TesseraAprHandler({ - network: 'MAINNET', + networkPrismaId: 'MAINNET', + networkChainId: 1, rpcUrl: 'https://rpc.ankr.com/eth', yieldTokens: tesseraYieldTokensMainnet, contractAddress: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9' /*ApeCoinStaking*/, diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts index 5f07ad2aa..34541ac8e 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts @@ -6,19 +6,23 @@ class TetuAprHandler implements AprHandler { networkPrismaId: string; baseUrl: string; networkName: string; + tetuTokens: string[]; readonly group = 'TETU'; constructor(aprHandlerConfig: TetuAprHandlerConfig) { this.networkPrismaId = aprHandlerConfig.network; this.baseUrl = aprHandlerConfig.baseUrl; this.networkName = aprHandlerConfig.networkName; + this.tetuTokens = aprHandlerConfig.tetuTokens; } async getAprs() { try { const { data } = await axios.get(`${this.baseUrl}?network=${this.networkName}`); const json = data as { vault: string; apr: number }[]; - const aprs = json.map((t) => [t.vault, t.apr / 100]); + const aprs = json + .filter(({ vault }) => this.tetuTokens.includes(vault.toLowerCase())) + .map((t) => [t.vault, t.apr / 100]); return Object.fromEntries(aprs); } catch (error) { @@ -32,12 +36,18 @@ type TetuAprHandlerConfig = { network: string; baseUrl: string; networkName: string; + tetuTokens: string[]; }; +export const tUSDCPolygon = '0x113f3d54c31ebc71510fd664c8303b34fbc2b355'; +export const tUSDTPolygon = '0x236975da9f0761e9cf3c2b0f705d705e22829886'; +export const tDAIPolygon = '0xace2ac58e1e5a7bfe274916c4d82914d490ed4a5'; +const tetuStQIPolygon = '0x4cd44ced63d9a6fef595f6ad3f7ced13fceac768'; + const tetuPolygonAprHandler = new TetuAprHandler({ network: 'POLYGON', baseUrl: 'https://api.tetu.io/api/v1/reader/compoundAPRs', networkName: 'MATIC', + tetuTokens: [tUSDCPolygon, tUSDTPolygon, tDAIPolygon, tetuStQIPolygon], }); - export const tetuHandlers = [tetuPolygonAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts index 732f205ba..fbe85c14a 100644 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { AprHandler } from '../ib-yield-apr-handlers'; -const qETHMainnet = '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d'; +export const qETHMainnet = '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d'; class TranchessAprHandler implements AprHandler { networkPrismaId: string; From 32b5a524d84dec3a74f82c8a80592c6ad02093d5 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Mon, 21 Aug 2023 02:06:41 -0300 Subject: [PATCH 20/42] Renaming ib-yield-apr-handlers to base-apr-handlers Moving tokens to base-apr-handlers: - Ankr eth fantom, ankr ftm fantom; - Overnight Optimism usd+ and dai+ (moved overnight aprs to default base-apr-handlers) - wstETH Optimism MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Didn't move: - Stader-staked-ftm <- Fixed Base APR Value? - spooky <- Not being used on Fantom, so I didn’t add it to base apr handlers - Yearn <- Using Base APR’s based on wrapped tokens in linear pools, not able to define which tokens to take - Rocket Pool staked <- Fixed rETH base APR Value, I have rETH APR from url on main net, maybe I can use the same? https://drop-api.stafi.io/reth/v1/poolData - Beefy <- Using beefy linear pools Id’s to get vaultAddress, there’s 2 options here:
1 - Let the beefy apr handler separated
2 - Create APR Handlers for each vault/beefy token. - Reaper-Crypt <- The current apr handler verifies if the pool is from a ERC 4626 Factory, and build contract from wrappedToken.address, So I didn’t move this reaper to the base apr handler, same problem as Beefy --- modules/network/arbitrum.ts | 2 +- modules/network/gnosis.ts | 2 +- modules/network/mainnet.ts | 2 +- modules/network/polygon.ts | 2 +- modules/network/zkevm.ts | 2 +- .../base-apr-handlers/base-apr-handlers.ts | 105 ++++++++ .../sources/aave-apr-handler.ts | 232 ++++++++++++++++++ .../base-apr-handlers/sources/abis/oErc20.ts | 15 ++ .../sources/abis/reaperStrategy.ts | 21 ++ .../sources/abis/tesseraPool.ts | 154 ++++++++++++ .../sources/ankr-eth-apr-handler.ts | 64 +++++ .../sources/default-apr-handler.ts | 229 +++++++++++++++++ .../sources/euler-apr-handler.ts | 88 +++++++ .../sources/gearbox-apr-handler.ts | 52 ++++ .../sources/idle-apr-handler.ts | 77 ++++++ .../sources/overnight-apr-handler.ts | 50 ++++ .../sources/ovix-apr-handler.ts | 74 ++++++ .../sources/reaper-apr-handler.ts | 73 ++++++ .../sources/tessera-apr-handler.ts | 66 +++++ .../sources/tetu-apr-handler.ts | 53 ++++ .../sources/tranchess-apr-handler.ts | 47 ++++ .../apr-data-sources/ib-tokens-apr.service.ts | 36 ++- .../liquid-staked-base-apr.service.ts | 4 +- 23 files changed, 1434 insertions(+), 16 deletions(-) create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/oErc20.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/reaperStrategy.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/tesseraPool.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-eth-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/overnight-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/reaper-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index af66a29cf..7c977b0df 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -161,7 +161,7 @@ export const arbitrumNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(arbitrumNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(arbitrumNetworkData.chain.prismaId), + new IbTokensAprService(arbitrumNetworkData.chain.prismaId, tokenService), new WstethAprService(tokenService, arbitrumNetworkData.lido!.wstEthContract), new ReaperCryptAprService( arbitrumNetworkData.reaper.linearPoolFactories, diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index bc6c2678f..6e04c09d4 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -152,7 +152,7 @@ export const gnosisNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(gnosisNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(gnosisNetworkData.chain.prismaId), + new IbTokensAprService(gnosisNetworkData.chain.prismaId, tokenService), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(gnosisNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index e0beb1576..4be39a202 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -163,7 +163,7 @@ export const mainnetNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(mainnetNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(mainnetNetworkData.chain.prismaId), + new IbTokensAprService(mainnetNetworkData.chain.prismaId, tokenService), new WstethAprService(tokenService, mainnetNetworkData.lido!.wstEthContract), new PhantomStableAprService(), new BoostedPoolAprService(), diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index c9e22a301..e2a0168c6 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -156,7 +156,7 @@ export const polygonNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(polygonNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(polygonNetworkData.chain.prismaId), + new IbTokensAprService(polygonNetworkData.chain.prismaId, tokenService), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(polygonNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index ed60dfd6d..e55ec12b3 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -153,7 +153,7 @@ export const zkevmNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(zkevmNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(zkevmNetworkData.chain.prismaId), + new IbTokensAprService(zkevmNetworkData.chain.prismaId, tokenService), new WstethAprService(tokenService, zkevmNetworkData.lido!.wstEthContract), new PhantomStableAprService(), new BoostedPoolAprService(), diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts new file mode 100644 index 000000000..3b6f133c5 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts @@ -0,0 +1,105 @@ +import { + aaveHandlers, + wrappedAaveTokensV2Mainnet, + wrappedAaveTokensV2Polygon, + wrappedAaveTokensV3Arbitrum, + wrappedAaveTokensV3Mainnet, + wrappedAaveTokensV3Polygon, +} from './sources/aave-apr-handler'; +import { ankrEthMainnet, ankrEthHandlers, ankrEthFantom } from './sources/ankr-eth-apr-handler'; +import { + defaultHandlers, + overnightDaiPlusOptimism, + overnightLpUsdcUsdPlusMainnet, + overnightUsdcUsdPlusMainnet, + overnightUsdPlusOptimism, + rETHMainnet, + swETHMainnet, + USDRMainnet, + wjAURAMainnet, +} from './sources/default-apr-handler'; +import { eulerHandlers, eulerTokensMainnet } from './sources/euler-apr-handler'; +import { gearboxHandlers, gearboxTokensMainnet } from './sources/gearbox-apr-handler'; +import { idleAprHandlers, wrapped4626IdleTokensMainnet } from './sources/idle-apr-handler'; +import { ovixHandlers, ovixWrappedTokensZkEvm } from './sources/ovix-apr-handler'; +import { reaperHandlers, reaperYieldTokensArbitrum } from './sources/reaper-apr-handler'; +import { tesseraHandlers, tesseraYieldTokensMainnet } from './sources/tessera-apr-handler'; +import { tDAIPolygon, tetuHandlers, tUSDCPolygon, tUSDTPolygon } from './sources/tetu-apr-handler'; +import { qETHMainnet } from './sources/tranchess-apr-handler'; + +const aprHandlers: AprHandler[] = [ + ...aaveHandlers, + ...ankrEthHandlers, + ...defaultHandlers, + ...eulerHandlers, + ...gearboxHandlers, + ...idleAprHandlers, + ...ovixHandlers, + ...reaperHandlers, + ...tesseraHandlers, + ...tetuHandlers, +]; + +export class BaseAprHandlers { + private handlers: AprHandler[] = []; + + constructor(networkPrismaId: string) { + this.handlers = aprHandlers.filter((handler) => handler.networkPrismaId === networkPrismaId); + } + + async fetchAprsFromAllHandlers(): Promise { + let aprs: { val: number; group: string; address: string }[] = []; + for (const handler of this.handlers) { + const fetchedResponse: { [key: string]: number } = await handler.getAprs(); + for (const [address, aprValue] of Object.entries(fetchedResponse)) { + aprs.push({ + val: aprValue, + group: handler.group, + address, + }); + } + } + return aprs; + } +} + +export interface AprHandler { + group: string; + networkPrismaId: string; + + getAprs(): Promise<{ [tokenAddress: string]: number }>; +} + +export type TokenApr = { + val: number; + address: string; + group?: string; +}; + +export const wrappedBoostedTokens = [ + ...Object.values(wrappedAaveTokensV2Mainnet), + ...Object.values(wrappedAaveTokensV2Polygon), + ...Object.values(wrappedAaveTokensV3Mainnet), + ...Object.values(wrappedAaveTokensV3Polygon), + ...Object.values(wrappedAaveTokensV3Arbitrum), + ankrEthMainnet, + ankrEthFantom, + rETHMainnet, + USDRMainnet, + swETHMainnet, + wjAURAMainnet, + ...Object.values(eulerTokensMainnet), + ...Object.values(gearboxTokensMainnet), + ...Object.values(wrapped4626IdleTokensMainnet), + ...Object.values(ovixWrappedTokensZkEvm), + ...Object.values(reaperYieldTokensArbitrum), + ...Object.values(tesseraYieldTokensMainnet), + tUSDTPolygon, + tUSDCPolygon, + tDAIPolygon, + qETHMainnet, + overnightLpUsdcUsdPlusMainnet, + overnightUsdcUsdPlusMainnet, + overnightUsdPlusOptimism, + overnightDaiPlusOptimism, +]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts new file mode 100644 index 000000000..93b6e515e --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts @@ -0,0 +1,232 @@ +import axios from 'axios'; +import { AprHandler } from '../base-apr-handlers'; + +class AaveAprHandler implements AprHandler { + wrappedTokens: { [key: string]: string }; + aaveTokens: { [key: string]: string }; + underlyingTokens: { [key: string]: string }; + subgraphUrl: string; + networkPrismaId: string; + + readonly group = 'AAVE'; + + readonly query = `query getReserves($aTokens: [String!], $underlyingAssets: [Bytes!]) { + reserves( + where: { + aToken_in: $aTokens + underlyingAsset_in: $underlyingAssets + isActive: true + } + ) { + id + underlyingAsset + liquidityRate + } + }`; + + constructor(aprHandlerConfig: AaveAprHandlerConfig) { + this.wrappedTokens = aprHandlerConfig.wrappedTokens; + this.aaveTokens = aprHandlerConfig.aaveTokens; + this.underlyingTokens = aprHandlerConfig.underlyingTokens; + this.subgraphUrl = aprHandlerConfig.subgraphUrl; + this.networkPrismaId = aprHandlerConfig.network; + } + + async getAprs() { + try { + const requestQuery = { + operationName: 'getReserves', + query: this.query, + variables: { + aTokens: Object.values(this.aaveTokens), + underlyingAssets: Object.values(this.underlyingTokens), + }, + }; + const { data } = await axios({ + url: this.subgraphUrl, + method: 'post', + data: requestQuery, + headers: { 'Content-Type': 'application/json' }, + }); + const { + data: { reserves }, + } = data as ReserveResponse; + + const aprsByUnderlyingAddress = Object.fromEntries( + reserves.map((r) => [ + r.underlyingAsset, + // Converting from aave ray number (27 digits) to float + Number(r.liquidityRate.slice(0, 27)) / 1e27, + ]), + ); + const aprEntries = Object.fromEntries( + Object.values(this.underlyingTokens) + //Removing undefined aprs + .filter(([, address]) => !!aprsByUnderlyingAddress[address]) + //Mapping aprs by wrapped instead of underlying addresses + .map(([underlyingTokenName, underlyingTokenAddress]) => [ + this.wrappedTokens['wa' + underlyingTokenName] as string, + aprsByUnderlyingAddress[underlyingTokenAddress], + ]), + ); + return aprEntries; + } catch (e) { + console.error(`Failed to fetch Aave APR in subgraph ${this.subgraphUrl}:`, e); + return {}; + } + } +} + +export const wrappedAaveTokensV2Mainnet = { + waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', + waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', + waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', +}; + +const aaveTokensV2Mainnet = { + aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', + aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c', + aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', +}; + +export const wrappedAaveTokensV2Polygon = { + waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', + waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', + waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', +}; + +const aaveTokensV2Polygon = { + aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', + aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', + aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', +}; + +export const wrappedAaveTokensV3Mainnet = { + waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', + waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', + waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', + waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', +}; + +const aaveTokensV3Mainnet = { + aUSDT: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', + aUSDC: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', + aDAI: '0x018008bfb33d285247a21d44e50697654f754e63', + aWETH: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8', +}; + +export const wrappedAaveTokensV3Polygon = { + waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', + waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', + waUSDC: '0x9719d867a500ef117cc201206b8ab51e794d3f82', + waDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', +}; + +const aaveTokensV3Polygon = { + aMATIC: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', + aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', + aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', + aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', +}; + +export const wrappedAaveTokensV3Arbitrum = { + waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', + waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', + waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', + waWETH: '0x18c100415988bef4354effad1188d1c22041b046', +}; + +const aaveTokensV3Arbitrum = { + aUSDT: '0x6ab707aca953edaefbc4fd23ba73294241490620', + aUSDC: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', + aDAI: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', + aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', +}; + +const underlyingTokensMainnet = { + USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', + USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', + WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', +}; + +const underlyingTokensPolygon = { + MATIC: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', + USDT: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + DAI: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + WETH: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619', +}; + +const underlyingTokensArbitrum = { + USDT: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + USDC: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', + DAI: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + WETH: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', +}; + +interface ReserveResponse { + data: { + reserves: [ + { + underlyingAsset: string; + liquidityRate: string; + }, + ]; + }; +} + +type AaveAprHandlerConfig = { + wrappedTokens: { [key: string]: string }; + aaveTokens: { [key: string]: string }; + underlyingTokens: { [key: string]: string }; + subgraphUrl: string; + network: string; +}; + +const aaveV2MainnetAprHandler = new AaveAprHandler({ + wrappedTokens: wrappedAaveTokensV2Mainnet, + aaveTokens: aaveTokensV2Mainnet, + underlyingTokens: underlyingTokensMainnet, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2', + network: 'MAINNET', +}); + +const aaveV2PolygonAprHandler = new AaveAprHandler({ + wrappedTokens: wrappedAaveTokensV2Polygon, + aaveTokens: aaveTokensV2Polygon, + underlyingTokens: underlyingTokensPolygon, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic', + network: 'POLYGON', +}); +const aaveV3MainnetAprHandler = new AaveAprHandler({ + wrappedTokens: wrappedAaveTokensV3Mainnet, + aaveTokens: aaveTokensV3Mainnet, + underlyingTokens: underlyingTokensMainnet, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3', + network: 'MAINNET', +}); +const aaveV3PolygonAprHandler = new AaveAprHandler({ + wrappedTokens: wrappedAaveTokensV3Polygon, + aaveTokens: aaveTokensV3Polygon, + underlyingTokens: underlyingTokensPolygon, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon', + network: 'POLYGON', +}); +const aaveV3ArbitrumAprHandler = new AaveAprHandler({ + wrappedTokens: wrappedAaveTokensV3Arbitrum, + aaveTokens: aaveTokensV3Arbitrum, + underlyingTokens: underlyingTokensArbitrum, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum', + network: 'ARBITRUM', +}); + +export const aaveHandlers = [ + aaveV2MainnetAprHandler, + aaveV2PolygonAprHandler, + aaveV3MainnetAprHandler, + aaveV3PolygonAprHandler, + aaveV3ArbitrumAprHandler, +]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/oErc20.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/oErc20.ts new file mode 100644 index 000000000..6dde7bf68 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/oErc20.ts @@ -0,0 +1,15 @@ +export const abi = [ + { + inputs: [], + name: "borrowRatePerTimestamp", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + } +] as const diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/reaperStrategy.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/reaperStrategy.ts new file mode 100644 index 000000000..1a89f3754 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/reaperStrategy.ts @@ -0,0 +1,21 @@ +export const abi = [ + { + inputs: [ + { + internalType: 'int256', + name: '_n', + type: 'int256', + }, + ], + name: 'averageAPRAcrossLastNHarvests', + outputs: [ + { + internalType: 'int256', + name: '', + type: 'int256', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/tesseraPool.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/tesseraPool.ts new file mode 100644 index 000000000..a3fd8bb01 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/tesseraPool.ts @@ -0,0 +1,154 @@ +export const abi = [ + { + inputs: [], + name: 'getPoolsUI', + outputs: [ + { + components: [ + { internalType: 'uint256', name: 'poolId', type: 'uint256' }, + { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, + { + components: [ + { + internalType: 'uint48', + name: 'startTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'endTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint96', + name: 'rewardsPerHour', + type: 'uint96', + }, + { + internalType: 'uint96', + name: 'capPerPosition', + type: 'uint96', + }, + ], + internalType: 'struct ApeCoinStaking.TimeRange', + name: 'currentTimeRange', + type: 'tuple', + }, + ], + internalType: 'struct ApeCoinStaking.PoolUI', + name: '', + type: 'tuple', + }, + { + components: [ + { internalType: 'uint256', name: 'poolId', type: 'uint256' }, + { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, + { + components: [ + { + internalType: 'uint48', + name: 'startTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'endTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint96', + name: 'rewardsPerHour', + type: 'uint96', + }, + { + internalType: 'uint96', + name: 'capPerPosition', + type: 'uint96', + }, + ], + internalType: 'struct ApeCoinStaking.TimeRange', + name: 'currentTimeRange', + type: 'tuple', + }, + ], + internalType: 'struct ApeCoinStaking.PoolUI', + name: '', + type: 'tuple', + }, + { + components: [ + { internalType: 'uint256', name: 'poolId', type: 'uint256' }, + { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, + { + components: [ + { + internalType: 'uint48', + name: 'startTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'endTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint96', + name: 'rewardsPerHour', + type: 'uint96', + }, + { + internalType: 'uint96', + name: 'capPerPosition', + type: 'uint96', + }, + ], + internalType: 'struct ApeCoinStaking.TimeRange', + name: 'currentTimeRange', + type: 'tuple', + }, + ], + internalType: 'struct ApeCoinStaking.PoolUI', + name: '', + type: 'tuple', + }, + { + components: [ + { internalType: 'uint256', name: 'poolId', type: 'uint256' }, + { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, + { + components: [ + { + internalType: 'uint48', + name: 'startTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'endTimestampHour', + type: 'uint48', + }, + { + internalType: 'uint96', + name: 'rewardsPerHour', + type: 'uint96', + }, + { + internalType: 'uint96', + name: 'capPerPosition', + type: 'uint96', + }, + ], + internalType: 'struct ApeCoinStaking.TimeRange', + name: 'currentTimeRange', + type: 'tuple', + }, + ], + internalType: 'struct ApeCoinStaking.PoolUI', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, +] as const diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-eth-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-eth-apr-handler.ts new file mode 100644 index 000000000..9f01bcf0a --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-eth-apr-handler.ts @@ -0,0 +1,64 @@ +import axios from 'axios'; +import { AprHandler } from '../base-apr-handlers'; + +class AnkrAprHandler implements AprHandler { + serviceName: string; + tokenAddress: string; + networkPrismaId: string; + readonly url: string = 'https://api.staking.ankr.com/v1alpha/metrics'; + readonly group = 'ANKR'; + + constructor(aprHandlerConfig: AnkrAprHandlerConfig) { + this.serviceName = aprHandlerConfig.serviceName; + this.tokenAddress = aprHandlerConfig.tokenAddress; + this.networkPrismaId = aprHandlerConfig.network; + } + + async getAprs() { + try { + const { data } = await axios.get(this.url); + const json = data as { services: { serviceName: string; apy: string }[] }; + const service = json.services.find((service) => service.serviceName === this.serviceName); + if (!service) { + return {}; + } + const scaledValue = parseFloat(service.apy) / 1e2; + return { + [this.tokenAddress]: scaledValue, + }; + } catch (error) { + console.error('Failed to fetch Ankr APR:', error); + return {}; + } + } +} + +export const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb'; +export const ankrEthFantom = '0x12d8ce035c5de3ce39b1fdd4c1d5a745eaba3b8c'; + +export const ankrFtmFantom = '0xcfc785741dc0e98ad4c9f6394bb9d43cd1ef5179'; + +type AnkrAprHandlerConfig = { + serviceName: string; + tokenAddress: string; + network: string; +}; + +const ankrEthMainnetAprHandler = new AnkrAprHandler({ + serviceName: 'eth', + tokenAddress: ankrEthMainnet, + network: 'MAINNET', +}); + +const ankrEthFantomAprHandler = new AnkrAprHandler({ + serviceName: 'eth', + tokenAddress: ankrEthFantom, + network: 'FANTOM', +}); + +const ankrFtmFantomAprHandler = new AnkrAprHandler({ + serviceName: 'ftm', + tokenAddress: ankrFtmFantom, + network: 'FANTOM', +}); +export const ankrEthHandlers = [ankrEthMainnetAprHandler, ankrEthFantomAprHandler, ankrFtmFantomAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts new file mode 100644 index 000000000..50b5e1c95 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts @@ -0,0 +1,229 @@ +import axios from 'axios'; + +import { AprHandler } from '../base-apr-handlers'; + +class DefaultAprHandler implements AprHandler { + tokens: string[]; + url: string; + path: string; + scale: number; + networkPrismaId: string; + group = 'DEFAULT'; + + constructor(aprHandlerConfig: DefaultAprHandlerConfig) { + this.tokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.url; + this.networkPrismaId = aprHandlerConfig.network; + this.path = aprHandlerConfig.path ?? ''; + this.scale = aprHandlerConfig.scale ?? 100; + this.group = aprHandlerConfig.group ?? 'DEFAULT'; + } + + async getAprs() { + try { + const { data } = await axios.get(this.url, { headers: { 'User-Agent': 'cf' } }); + const value = this.path === '' ? data : this.getValueFromPath(data, this.path); + const scaledValue = parseFloat(value) / this.scale; + + return this.tokens.reduce((acc, token) => { + acc[token] = scaledValue; + return acc; + }, {} as { [key: string]: number }); + } catch (error) { + console.error(`Failed to fetch APRs in url ${this.url}:`, error); + return {}; + } + } + + getValueFromPath(obj: any, path: string) { + if (path === '') { + return obj; + } + const parts = path.split('.'); + let value = obj; + for (const part of parts) { + value = value[part]; + } + return value; + } +} + +export type DefaultAprHandlerConfig = { + tokens: string[]; + url: string; + network: string; + scale?: number; + path?: string; + group?: string; +}; + +export const vETHMainnet = '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f'; +const wstETHGnosis = '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6'; +const wstETHZkEVM = '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9'; +const stETHMainnet = '0xae7ab96520de3a18e5e111b5eaab095312d7fe84'; +const wstETHMainnet = '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0'; +const wstETHPolygon = '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd'; +const wstETHArbitrum = '0x5979d7b546e38e414f7e9822514be443a4800529'; +const wstETHOptimism = '0x1f32b1c2345538c0c6f582fcb0227;39c4a194ebb'; +const stMATICPolygon = '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'; +export const cbETHMainnet = '0xbe9895146f7af43049ca1c1ae358b0541ea49704'; + +const sfrxETHMainnet = '0xac3e018457b222d93114458476f3e3416abbe38f'; +export const rETHMainnet = '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'; +export const USDRMainnet = '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'; +const MATICXPolygon = '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'; +const wbETHMainnet = '0xa2e3356610840701bdf5611a53974510ae27e2e1'; +export const swETHMainnet = '0xf951e335afb289353dc249e82926178eac7ded78'; +export const wjAURAMainnet = '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'; +export const overnightLpUsdcUsdPlusMainnet = '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425'; +export const overnightUsdcUsdPlusMainnet = '0x6933ec1ca55c06a894107860c92acdfd2dd8512f'; +export const overnightUsdPlusOptimism = '0xa348700745d249c3b49d2c2acac9a5ae8155f826'; +export const overnightDaiPlusOptimism = '0x0b8f31480249cc717081928b8af733f45f6915bb'; + +const vETHMainnetAprHandler = new DefaultAprHandler({ + tokens: [vETHMainnet], + url: 'https://apy.liebi.com/veth', + path: 'veth', + network: 'MAINNET', +}); +const stETHMainnetAprHandler = new DefaultAprHandler({ + tokens: [stETHMainnet, wstETHMainnet], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'MAINNET', +}); +const stETHPolygonAprHandler = new DefaultAprHandler({ + tokens: [wstETHPolygon], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'POLYGON', +}); +const stETHZkEVMAprHandler = new DefaultAprHandler({ + tokens: [wstETHZkEVM], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'ZKEVM', +}); +const stETHGnosisAprHandler = new DefaultAprHandler({ + tokens: [wstETHGnosis], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'GNOSIS', +}); +const stETHArbitrumAprHandler = new DefaultAprHandler({ + tokens: [wstETHArbitrum], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'ARBITRUM', +}); + +const stETHOptimismAprHandler = new DefaultAprHandler({ + tokens: [wstETHOptimism], + url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + network: 'OPTIMISM', +}); + +const stMaticPolygonAprHandler = new DefaultAprHandler({ + tokens: [stMATICPolygon], + url: 'https://polygon.lido.fi/api/stats', + path: 'apr', + network: 'POLYGON', +}); +const cbEthMainnetAprHandler = new DefaultAprHandler({ + tokens: [cbETHMainnet], + url: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', + path: 'apy', + scale: 1, + network: 'MAINNET', +}); +const sfrxEthMainnetAprHandler = new DefaultAprHandler({ + tokens: [sfrxETHMainnet], + url: 'https://api.frax.finance/v2/frxeth/summary/latest', + path: 'sfrxethApr', + network: 'MAINNET', +}); +const rETHMainnetAprHandler = new DefaultAprHandler({ + tokens: [rETHMainnet], + url: 'https://drop-api.stafi.io/reth/v1/poolData', + path: 'data.stakeApr', + network: 'MAINNET', +}); +const USDRMainnetAprHandler = new DefaultAprHandler({ + tokens: [USDRMainnet], + url: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', + path: 'usdr', + network: 'MAINNET', +}); + +const MATICXPolygonAprHandler = new DefaultAprHandler({ + tokens: [MATICXPolygon], + url: 'https://universe.staderlabs.com/polygon/apy', + path: 'value', + network: 'POLYGON', +}); +const wbETHPolygonAprHandler = new DefaultAprHandler({ + tokens: [wbETHMainnet], + url: 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', + path: 'data.0.rewardRate', + scale: 1, + network: 'POLYGON', +}); + +const swETHMainnetAprHandler = new DefaultAprHandler({ + tokens: [swETHMainnet], + url: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', + network: 'MAINNET', +}); +const wjAURAMainnetAprHandler = new DefaultAprHandler({ + tokens: [wjAURAMainnet], + url: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', + path: 'wjauraApy', + network: 'MAINNET', +}); + +const overnightMainnetAprHandler = new DefaultAprHandler({ + tokens: [overnightLpUsdcUsdPlusMainnet, overnightUsdcUsdPlusMainnet], + url: 'https://app.overnight.fi/api/balancer/week/apr', + network: 'MAINNET', + scale: 1, + group: 'OVERNIGHT', +}); + +const overnightUsdPlusOptimismAprHandler = new DefaultAprHandler({ + tokens: [overnightUsdPlusOptimism], + url: 'https://api.overnight.fi/optimism/usd+/fin-data/avg-apr/week', + path: 'value', + network: 'OPTIMISM', + group: 'OVERNIGHT', +}); + +const overnightDaiPlusOptimismAprHandler = new DefaultAprHandler({ + tokens: [overnightDaiPlusOptimism], + url: 'https://api.overnight.fi/optimism/dai+/fin-data/avg-apr/week', + path: 'value', + network: 'OPTIMISM', + group: 'OVERNIGHT', +}); + +export const defaultHandlers = [ + vETHMainnetAprHandler, + stETHMainnetAprHandler, + stETHPolygonAprHandler, + stETHZkEVMAprHandler, + stETHGnosisAprHandler, + stETHArbitrumAprHandler, + stETHOptimismAprHandler, + stMaticPolygonAprHandler, + cbEthMainnetAprHandler, + sfrxEthMainnetAprHandler, + rETHMainnetAprHandler, + USDRMainnetAprHandler, + MATICXPolygonAprHandler, + wbETHPolygonAprHandler, + swETHMainnetAprHandler, + wjAURAMainnetAprHandler, + overnightMainnetAprHandler, + overnightUsdPlusOptimismAprHandler, + overnightDaiPlusOptimismAprHandler, +]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts new file mode 100644 index 000000000..cafb7b3f1 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts @@ -0,0 +1,88 @@ +import axios from 'axios'; +import { AprHandler } from '../base-apr-handlers'; + +class EulerAprHandler implements AprHandler { + tokens: { [key: string]: string }; + subgraphUrl: string; + networkPrismaId: string; + readonly group = 'EULER'; + + readonly query = ` + query getAssetsAPY($eTokenAddress_in: [String!]) { + assets( + where: { + eTokenAddress_in: $eTokenAddress_in + } + ) { + eTokenAddress + supplyAPY + } + } +`; + + constructor(aprHandlerConfig: EulerAprHandlerConfig) { + this.tokens = aprHandlerConfig.tokens; + this.subgraphUrl = aprHandlerConfig.subgraphUrl; + this.networkPrismaId = aprHandlerConfig.network; + } + + async getAprs() { + const requestQuery = { + operationName: 'getAssetsAPY', + query: this.query, + variables: { + eTokenAddress_in: Object.values(this.tokens), + }, + }; + + const { data } = await axios({ + url: this.subgraphUrl, + method: 'POST', + data: JSON.stringify(requestQuery), + }); + + const { + data: { assets }, + } = data as EulerResponse; + + const aprEntries = assets.map(({ eTokenAddress, supplyAPY }) => [ + eTokenAddress, + // supplyAPY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 + Number(supplyAPY.slice(0, 27)) / 1e27, + ]); + + return Object.fromEntries(aprEntries); + } +} + +export const eulerTokensMainnet = { + eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', + eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', + eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', + eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', +}; + +interface EulerResponse { + data: { + assets: [ + { + eTokenAddress: string; + supplyAPY: string; + }, + ]; + }; +} + +type EulerAprHandlerConfig = { + tokens: { [key: string]: string }; + subgraphUrl: string; + network: string; +}; + +const eulerMainnetAprHandler = new EulerAprHandler({ + tokens: eulerTokensMainnet, + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet', + network: 'MAINNET', +}); + +export const eulerHandlers = [eulerMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts new file mode 100644 index 000000000..803a2257f --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts @@ -0,0 +1,52 @@ +import axios from 'axios'; + +import { AprHandler } from '../base-apr-handlers'; + +class GearboxAprHandler implements AprHandler { + url: string; + tokens: { [key: string]: string }; + networkPrismaId: string; + readonly group = 'GEARBOX'; + + constructor(aprHandlerConfig: GearboxAprHandlerConfig) { + this.tokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.url; + this.networkPrismaId = aprHandlerConfig.network; + } + + async getAprs() { + try { + const { data } = await axios.get(this.url); + const json = data as { data: { dieselToken: string; depositAPY_RAY: string }[] }; + + const aprEntries = json.data + .filter((t) => Object.values(this.tokens).includes(t.dieselToken.toLowerCase())) + .map(({ dieselToken, depositAPY_RAY }) => { + return [dieselToken, Number(depositAPY_RAY.slice(0, 27)) / 1e27]; + }); + return Object.fromEntries(aprEntries); + } catch (error) { + console.error('Failed to fetch Gearbox APR:', error); + return {}; + } + } +} + +type GearboxAprHandlerConfig = { + tokens: { [key: string]: string }; + url: string; + network: string; +}; + +export const gearboxTokensMainnet = { + dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', + dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', +}; + +const gearboxMainnetAprHandler = new GearboxAprHandler({ + tokens: gearboxTokensMainnet, + url: 'https://mainnet.gearbox.foundation/api/pools', + network: 'MAINNET', +}); + +export const gearboxHandlers = [gearboxMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts new file mode 100644 index 000000000..382cb7c2d --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts @@ -0,0 +1,77 @@ +import axios from 'axios'; + +import { AprHandler } from '../base-apr-handlers'; + +class IdleAprHandler implements AprHandler { + wrappedIdleTokens: { [key: string]: string }; + idleTokens: { [key: string]: string }; + baseIdleApiUrl: string; + authorizationHeader: string; + networkPrismaId: string; + readonly group = 'IDLE'; + + constructor(aprHandlerConfig: IdleAprHandlerConfig) { + this.wrappedIdleTokens = aprHandlerConfig.wrappedIdleTokens; + this.idleTokens = aprHandlerConfig.idleTokens; + this.baseIdleApiUrl = aprHandlerConfig.baseIdleApiUrl; + this.authorizationHeader = aprHandlerConfig.authorizationHeader; + this.networkPrismaId = aprHandlerConfig.network; + } + + async getAprs() { + try { + const aprPromises = Object.entries(this.idleTokens).map(async ([tokenName, idleTokenAddress]) => { + const { data } = await axios.get( + [this.baseIdleApiUrl, idleTokenAddress, '?isRisk=false&order=desc&limit=1'].join(''), + { + headers: { + Authorization: this.authorizationHeader, + }, + }, + ); + const [json] = data as { idleRate: string }[]; + const value = Number(json.idleRate) / 1e20; + return [this.wrappedIdleTokens[tokenName], value]; + }); + const res = Array(Object.keys(this.idleTokens).length); + for (const [index, aprPromise] of aprPromises.entries()) { + res[index] = await aprPromise; + } + return Object.fromEntries(res); + } catch (error) { + console.error('Failed to fetch Idle APR:', error); + return {}; + } + } +} + +export const wrapped4626IdleTokensMainnet = { + idleDAI: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', + idleUSDC: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', + idleUSDT: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', +}; + +const idleTokensMainnet = { + idleDAI: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', + idleUSDC: '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', + idleUSDT: '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', +}; + +type IdleAprHandlerConfig = { + wrappedIdleTokens: { [key: string]: string }; + idleTokens: { [key: string]: string }; + baseIdleApiUrl: string; + authorizationHeader: string; + network: string; +}; + +const idleMainnetAprHandler = new IdleAprHandler({ + wrappedIdleTokens: wrapped4626IdleTokensMainnet, + idleTokens: idleTokensMainnet, + baseIdleApiUrl: 'https://api.idle.finance/junior-rates/', + authorizationHeader: + 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M', + network: 'MAINNET', +}); + +export const idleAprHandlers = [idleMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/overnight-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/overnight-apr-handler.ts new file mode 100644 index 000000000..956fc2bad --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/overnight-apr-handler.ts @@ -0,0 +1,50 @@ +import axios from 'axios'; + +import { AprHandler } from '../base-apr-handlers'; + +class OvernightAprHandler implements AprHandler { + overnightTokens: { [key: string]: string }; + url: string; + networkPrismaId: string; + readonly group = 'OVERNIGHT'; + + constructor(aprHandlerConfig: OvernightAprHandlerConfig) { + this.overnightTokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.url; + this.networkPrismaId = aprHandlerConfig.network; + } + + async getAprs() { + try { + const { data } = await axios.get(this.url); + const rate = data as number; + + return Object.values(this.overnightTokens).reduce((acc, token) => { + acc[token] = rate; + return acc; + }, {} as { [key: string]: number }); + } catch (error) { + console.error(`Failed to fetch Overnight APRs in url:`, error); + return {}; + } + } +} + +export const overnightTokensMainnet = { + lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus + UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f', // UsdcUsdPlus +}; + +type OvernightAprHandlerConfig = { + tokens: { [key: string]: string }; + url: string; + network: string; +}; + +const overnightMainnetAprHandler = new OvernightAprHandler({ + tokens: overnightTokensMainnet, + url: 'https://app.overnight.fi/api/balancer/week/apr', + network: 'MAINNET', +}); + +export const overnightHandlers = [overnightMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts new file mode 100644 index 000000000..0ffbc4c25 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts @@ -0,0 +1,74 @@ +import { BigNumber, Contract } from 'ethers'; +import { abi } from './abis/oErc20'; +import { JsonRpcProvider } from '@ethersproject/providers'; + +import { AprHandler } from '../base-apr-handlers'; + +class OvixAprHandler implements AprHandler { + networkPrismaId: string; + provider: JsonRpcProvider; + yieldTokens: { [key: string]: `0x${string}` }; + wrappedTokens: { [key: string]: `0x${string}` }; + readonly group = 'OVIX'; + + constructor(aprHandlerConfig: OvixAprHandlerConfig) { + this.networkPrismaId = aprHandlerConfig.networkPrismaId; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); + this.yieldTokens = aprHandlerConfig.yieldTokens; + this.wrappedTokens = aprHandlerConfig.wrappedTokens; + } + + async getAprs() { + try { + const calls = Object.keys(this.yieldTokens).map(async (tokenName) => { + const contract = new Contract(this.yieldTokens[tokenName], abi, this.provider); + return contract.borrowRatePerTimestamp(); + }); + + const borrowRates = Array(Object.keys(this.yieldTokens).length); + for (const [index, aprPromise] of calls.entries()) { + borrowRates[index] = await aprPromise; + } + + const aprs = Object.keys(this.wrappedTokens).map((tokenName, i) => [ + this.wrappedTokens[tokenName], + Math.pow(1 + (borrowRates[i] as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1, + ]); + + return Object.fromEntries(aprs); + } catch (error) { + console.error('Failed to fetch Ovix APR:', error); + return {}; + } + } +} + +type OvixAprHandlerConfig = { + networkPrismaId: string; + networkChainId: number; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${string}` }; + wrappedTokens: { + [key: string]: `0x${string}`; + }; +}; + +const ovixYieldTokensZkEvm = { + USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', + USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', +} as { [key: string]: `0x${string}` }; + +export const ovixWrappedTokensZkEvm = { + USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', + USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', +} as { [key: string]: `0x${string}` }; + +const ovixZkEVMAprHandler = new OvixAprHandler({ + networkPrismaId: 'ZKEVM', + networkChainId: 1101, + rpcUrl: 'https://zkevm-rpc.com', + yieldTokens: ovixYieldTokensZkEvm, + wrappedTokens: ovixWrappedTokensZkEvm, +}); + +export const ovixHandlers = [ovixZkEVMAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/reaper-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/reaper-apr-handler.ts new file mode 100644 index 000000000..da0aca61f --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/reaper-apr-handler.ts @@ -0,0 +1,73 @@ +import { JsonRpcProvider } from '@ethersproject/providers'; +import { BigNumber, Contract } from 'ethers'; +import { abi } from './abis/reaperStrategy'; + +import { AprHandler } from '../base-apr-handlers'; + +class ReaperAprHandler implements AprHandler { + networkPrismaId: string; + provider: JsonRpcProvider; + yieldTokens: { [key: string]: `0x${string}` }; + strategiesMap: { [key: string]: `0x${string}` }; + readonly group = 'REAPER'; + + constructor(aprHandlerConfig: ReaperAprHandlerConfig) { + this.networkPrismaId = aprHandlerConfig.networkPrismaId; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); + this.yieldTokens = aprHandlerConfig.yieldTokens; + this.strategiesMap = aprHandlerConfig.strategiesMap; + } + + async getAprs() { + try { + const contractCalls = Object.keys(this.strategiesMap).map(async (tokenName) => { + const contract = new Contract(this.strategiesMap[tokenName], abi, this.provider); + return contract.averageAPRAcrossLastNHarvests(3); + }); + const callsAprResults: BigNumber[] = Array(Object.keys(this.yieldTokens).length); + for (const [index, aprPromise] of contractCalls.entries()) { + callsAprResults[index] = await aprPromise; + } + const aprs = Object.keys(this.strategiesMap).map((tokenName, i) => { + return [this.yieldTokens[tokenName], callsAprResults[i].toNumber() / 1e4]; + }); + + return Object.fromEntries(aprs); + } catch (error) { + console.error('Failed to fetch Reaper APR:', error); + return {}; + } + } +} + +type ReaperAprHandlerConfig = { + networkPrismaId: string; + networkChainId: number; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${string}` }; + strategiesMap: { + [key: string]: `0x${string}`; + }; +}; + +export const reaperYieldTokensArbitrum = { + DAI: '0x12f256109e744081f633a827be80e06d97ff7447', + USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', + USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', +} as { [key: string]: `0x${string}` }; + +const reaperStrategiesMapArbitrum = { + DAI: '0xd4d5321b04e4832772a4d70e1eed6bcb7402d7ac', + USDT: '0x8a674ebbe33d6b03825626fa432e9ece888e13b5', + USDC: '0x6f6c0c5b7af2a326111ba6a9fa4926f7ca3adf44', +} as { [key: string]: `0x${string}` }; + +const reaperArbitrumAprHandler = new ReaperAprHandler({ + networkPrismaId: 'ARBITRUM', + networkChainId: 42161, + rpcUrl: 'https://arb1.arbitrum.io/rpc', + yieldTokens: reaperYieldTokensArbitrum, + strategiesMap: reaperStrategiesMapArbitrum, +}); + +export const reaperHandlers = [reaperArbitrumAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts new file mode 100644 index 000000000..a7acdf999 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts @@ -0,0 +1,66 @@ +import { Contract } from 'ethers'; +import { abi } from './abis/tesseraPool'; +import { JsonRpcProvider } from '@ethersproject/providers'; + +import { AprHandler } from '../base-apr-handlers'; + +class TesseraAprHandler implements AprHandler { + networkPrismaId: string; + provider: JsonRpcProvider; + yieldTokens: { [key: string]: `0x${string}` }; + stakingContractAddress: `0x${string}`; + readonly group = 'TESSERA'; + + constructor(aprHandlerConfig: TesseraAprHandlerConfig) { + this.networkPrismaId = aprHandlerConfig.networkPrismaId; + this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); + this.yieldTokens = aprHandlerConfig.yieldTokens; + this.stakingContractAddress = aprHandlerConfig.contractAddress; + } + + async getAprs() { + try { + let apr = 0; + try { + const contract = new Contract(this.stakingContractAddress, abi, this.provider); + const poolsUI = await contract.getPoolsUI(); + + const pool = poolsUI[0]; + const staked = BigInt(pool.stakedAmount); + const reward = BigInt(pool.currentTimeRange.rewardsPerHour) * BigInt(24 * 365); + apr = Number(reward.toString()) / Number(staked.toString()); + } catch (error) { + console.error('Failed to fetch Tessera Ape Coin APR:', error); + } + + return { + [this.yieldTokens.sApe]: apr, + }; + } catch (error) { + console.error('Failed to fetch Tessera APR:', error); + return {}; + } + } +} + +type TesseraAprHandlerConfig = { + networkPrismaId: string; + networkChainId: number; + rpcUrl: string; + yieldTokens: { [key: string]: `0x${string}` }; + contractAddress: `0x${string}`; +}; + +export const tesseraYieldTokensMainnet = { + sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', +} as { [key: string]: `0x${string}` }; + +const tesseraMainnetAprHandler = new TesseraAprHandler({ + networkPrismaId: 'MAINNET', + networkChainId: 1, + rpcUrl: 'https://rpc.ankr.com/eth', + yieldTokens: tesseraYieldTokensMainnet, + contractAddress: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9' /*ApeCoinStaking*/, +}); + +export const tesseraHandlers = [tesseraMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts new file mode 100644 index 000000000..9fd2c433d --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts @@ -0,0 +1,53 @@ +import axios from 'axios'; + +import { AprHandler } from '../base-apr-handlers'; + +class TetuAprHandler implements AprHandler { + networkPrismaId: string; + baseUrl: string; + networkName: string; + tetuTokens: string[]; + readonly group = 'TETU'; + + constructor(aprHandlerConfig: TetuAprHandlerConfig) { + this.networkPrismaId = aprHandlerConfig.network; + this.baseUrl = aprHandlerConfig.baseUrl; + this.networkName = aprHandlerConfig.networkName; + this.tetuTokens = aprHandlerConfig.tetuTokens; + } + + async getAprs() { + try { + const { data } = await axios.get(`${this.baseUrl}?network=${this.networkName}`); + const json = data as { vault: string; apr: number }[]; + const aprs = json + .filter(({ vault }) => this.tetuTokens.includes(vault.toLowerCase())) + .map((t) => [t.vault, t.apr / 100]); + + return Object.fromEntries(aprs); + } catch (error) { + console.error('Failed to fetch Tetu APR:', error); + return {}; + } + } +} + +type TetuAprHandlerConfig = { + network: string; + baseUrl: string; + networkName: string; + tetuTokens: string[]; +}; + +export const tUSDCPolygon = '0x113f3d54c31ebc71510fd664c8303b34fbc2b355'; +export const tUSDTPolygon = '0x236975da9f0761e9cf3c2b0f705d705e22829886'; +export const tDAIPolygon = '0xace2ac58e1e5a7bfe274916c4d82914d490ed4a5'; +const tetuStQIPolygon = '0x4cd44ced63d9a6fef595f6ad3f7ced13fceac768'; + +const tetuPolygonAprHandler = new TetuAprHandler({ + network: 'POLYGON', + baseUrl: 'https://api.tetu.io/api/v1/reader/compoundAPRs', + networkName: 'MATIC', + tetuTokens: [tUSDCPolygon, tUSDTPolygon, tDAIPolygon, tetuStQIPolygon], +}); +export const tetuHandlers = [tetuPolygonAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts new file mode 100644 index 000000000..bc00bd866 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts @@ -0,0 +1,47 @@ +import axios from 'axios'; + +import { AprHandler } from '../base-apr-handlers'; + +export const qETHMainnet = '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d'; + +class TranchessAprHandler implements AprHandler { + networkPrismaId: string; + url: string; + token: string; + readonly group = 'TRANCHESS'; + + constructor(aprHandlerConfig: TranchessAprHandlerConfig) { + this.networkPrismaId = aprHandlerConfig.network; + this.token = aprHandlerConfig.token; + this.url = aprHandlerConfig.url; + } + + async getAprs() { + try { + const { data } = await axios.get('https://tranchess.com/eth/api/v3/funds'); + const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[]; + // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. + const value = (365 * Number(weeklyAveragePnlPercentage)) / 1e18; + return { + [this.token]: value, + }; + } catch (error) { + console.error('Failed to fetch Tranchess APR:', error); + return {}; + } + } +} + +type TranchessAprHandlerConfig = { + network: string; + token: string; + url: string; +}; + +const tranchessMainnetAprHandler = new TranchessAprHandler({ + network: 'MAINNET', + token: qETHMainnet, + url: 'https://tranchess.com/eth/api/v3/funds', +}); + +export const tranchessHandlers = [tranchessMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 1646246ae..d51a20f3d 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -4,13 +4,15 @@ import { prisma } from '../../../../prisma/prisma-client'; import { networkContext } from '../../../network/network-context.service'; import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; import { PrismaPoolAprItemGroup } from '@prisma/client'; -import { IbYieldAprHandlers, TokenApr, wrappedTokens } from './ib-yield-apr-handlers/ib-yield-apr-handlers'; +import { BaseAprHandlers, TokenApr, wrappedBoostedTokens } from './base-apr-handlers/base-apr-handlers'; +import { TokenService } from '../../../token/token.service'; +import { collectsYieldFee } from '../pool-utils'; export class IbTokensAprService implements PoolAprService { - private ibYieldAprHandlers: IbYieldAprHandlers; + private baseAprHandlers: BaseAprHandlers; - constructor(networkPrismaId: string) { - this.ibYieldAprHandlers = new IbYieldAprHandlers(networkPrismaId); + constructor(networkPrismaId: string, private readonly tokenService: TokenService) { + this.baseAprHandlers = new BaseAprHandlers(networkPrismaId); } getAprServiceName(): string { @@ -19,6 +21,7 @@ export class IbTokensAprService implements PoolAprService { public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { const operations: any[] = []; + const tokenPrices = await this.tokenService.getTokenPrices(); const aprs = await this.fetchYieldTokensApr(); const tokenYieldPools = pools.filter((pool) => { return pool.tokens.find((token) => { @@ -28,11 +31,24 @@ export class IbTokensAprService implements PoolAprService { }); }); for (const pool of tokenYieldPools) { + const totalLiquidity = pool.dynamicData?.totalLiquidity; for (const token of pool.tokens) { - if (aprs.get(token.address) !== undefined) { + const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee + ? parseFloat(pool.dynamicData.protocolYieldFee) + : networkContext.data.balancer.yieldProtocolFeePercentage; + const tokenPrice = this.tokenService.getPriceForToken(tokenPrices, token.address); + const tokenBalance = token.dynamicData?.balance; + const tokenApr = aprs.get(token.address); + if (tokenPrice && tokenBalance && totalLiquidity !== undefined && tokenApr !== undefined) { + const tokenPercentage = (parseFloat(tokenBalance) * tokenPrice) / totalLiquidity; + const poolTokenApr = totalLiquidity > 0 ? tokenApr.val * tokenPercentage : 0; + const aprAfterFees = + pool.type === 'META_STABLE' + ? poolTokenApr * (1 - networkContext.data.balancer.swapProtocolFeePercentage) + : poolTokenApr * (1 - protocolYieldFeePercentage); const tokenSymbol = token.token.symbol; const itemId = `${pool.id}-${tokenSymbol}-yield-apr`; - const isBoosted = wrappedTokens.includes(token.address); + const isBoosted = wrappedBoostedTokens.includes(token.address); operations.push( prisma.prismaPoolAprItem.upsert({ where: { id_chain: { id: itemId, chain: networkContext.chain } }, @@ -41,13 +57,13 @@ export class IbTokensAprService implements PoolAprService { chain: networkContext.chain, poolId: pool.id, title: `${tokenSymbol} APR`, - apr: aprs.get(token.address)?.val ?? 0, - group: (aprs.get(token.address)?.group as PrismaPoolAprItemGroup) ?? null, + apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, + group: tokenApr.group as PrismaPoolAprItemGroup, type: pool.type === 'LINEAR' && isBoosted ? 'LINEAR_BOOSTED' : 'IB_YIELD', }, update: { title: `${tokenSymbol} APR`, - apr: aprs.get(token.address)?.val, + apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, }, }), ); @@ -59,7 +75,7 @@ export class IbTokensAprService implements PoolAprService { } private async fetchYieldTokensApr(): Promise> { - const data = await this.ibYieldAprHandlers.fetchAprsFromAllHandlers(); + const data = await this.baseAprHandlers.fetchAprsFromAllHandlers(); return new Map(data.filter((apr) => !isNaN(apr.val)).map((apr) => [apr.address, apr])); } } diff --git a/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts b/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts index eae278fe5..80197b5dc 100644 --- a/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts @@ -1,6 +1,7 @@ import axios from 'axios'; export class LiquidStakedBaseAprService { + //TODO - remove this, i public async getWstEthBaseApr(): Promise { const { data } = await axios.get<{ data: { aprs: [{ timeUnix: number; apr: number }]; smaApr: number }; @@ -12,6 +13,7 @@ export class LiquidStakedBaseAprService { return 0.046; } + //TODO - Remove this, since it's already in base-apr-handlers public async getAnkrFtmBaseApr(): Promise { const { data } = await axios.get<{ services: { serviceName: string; apy: string }[] }>( 'https://api.staking.ankr.com/v1alpha/metrics', @@ -21,7 +23,7 @@ export class LiquidStakedBaseAprService { const ankrFtmApy = data.services.find((service) => service.serviceName === 'ftm'); return parseFloat(ankrFtmApy?.apy || '0') / 100; } - + //TODO - Remove this, since it's already in base-apr-handlers public async getAnkrEthBaseApr(): Promise { const { data } = await axios.get<{ services: { serviceName: string; apy: string }[] }>( 'https://api.staking.ankr.com/v1alpha/metrics', From 74d2bce9e2dc2bf22f06c58ed8c855779b58e224 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Mon, 21 Aug 2023 02:11:19 -0300 Subject: [PATCH 21/42] Removing ib-yield-apr-handlers folder --- .../ib-yield-apr-handlers.ts | 93 ------- .../sources/aave-apr-handler.ts | 232 ------------------ .../sources/abis/oErc20.ts | 15 -- .../sources/abis/reaperStrategy.ts | 21 -- .../sources/abis/tesseraPool.ts | 154 ------------ .../sources/ankr-apr-handler.ts | 50 ---- .../sources/default-apr-handler.ts | 184 -------------- .../sources/euler-apr-handler.ts | 88 ------- .../sources/gearbox-apr-handler.ts | 52 ---- .../sources/idle-apr-handler.ts | 77 ------ .../sources/overnight-apr-handler.ts | 50 ---- .../sources/ovix-apr-handler.ts | 74 ------ .../sources/reaper-apr-handler.ts | 73 ------ .../sources/tessera-apr-handler.ts | 66 ----- .../sources/tetu-apr-handler.ts | 53 ---- .../sources/tranchess-apr-handler.ts | 47 ---- 16 files changed, 1329 deletions(-) delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/oErc20.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/reaperStrategy.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/tesseraPool.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts deleted file mode 100644 index ad757ebae..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/ib-yield-apr-handlers.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { - aaveHandlers, - wrappedAaveTokensV2Mainnet, - wrappedAaveTokensV2Polygon, - wrappedAaveTokensV3Arbitrum, - wrappedAaveTokensV3Mainnet, - wrappedAaveTokensV3Polygon, -} from './sources/aave-apr-handler'; -import { ankrEthMainnet, ankrHandlers } from './sources/ankr-apr-handler'; -import { defaultHandlers, rETHMainnet, swETHMainnet, USDRMainnet, wjAURAMainnet } from './sources/default-apr-handler'; -import { eulerHandlers, eulerTokensMainnet } from './sources/euler-apr-handler'; -import { gearboxHandlers, gearboxTokensMainnet } from './sources/gearbox-apr-handler'; -import { idleAprHandlers, wrapped4626IdleTokensMainnet } from './sources/idle-apr-handler'; -import { overnightHandlers, overnightTokens } from './sources/overnight-apr-handler'; -import { ovixHandlers, ovixWrappedTokensZkEvm } from './sources/ovix-apr-handler'; -import { reaperHandlers, reaperYieldTokensArbitrum } from './sources/reaper-apr-handler'; -import { tesseraHandlers, tesseraYieldTokensMainnet } from './sources/tessera-apr-handler'; -import { tDAIPolygon, tetuHandlers, tUSDCPolygon, tUSDTPolygon } from './sources/tetu-apr-handler'; -import { qETHMainnet } from './sources/tranchess-apr-handler'; - -const aprHandlers: AprHandler[] = [ - ...aaveHandlers, - ...ankrHandlers, - ...defaultHandlers, - ...eulerHandlers, - ...gearboxHandlers, - ...idleAprHandlers, - ...overnightHandlers, - ...ovixHandlers, - ...reaperHandlers, - ...tesseraHandlers, - ...tetuHandlers, -]; - -export class IbYieldAprHandlers { - private handlers: AprHandler[] = []; - - constructor(networkPrismaId: string) { - this.handlers = aprHandlers.filter((handler) => handler.networkPrismaId === networkPrismaId); - } - - async fetchAprsFromAllHandlers(): Promise { - let aprs: { val: number; group: string; address: string }[] = []; - for (const handler of this.handlers) { - const fetchedResponse: { [key: string]: number } = await handler.getAprs(); - for (const [address, aprValue] of Object.entries(fetchedResponse)) { - aprs.push({ - val: aprValue, - group: handler.group, - address, - }); - } - } - return aprs; - } -} - -export interface AprHandler { - readonly group: string; - networkPrismaId: string; - - getAprs(): Promise<{ [tokenAddress: string]: number }>; -} - -export type TokenApr = { - val: number; - address: string; - group?: string; -}; - -export const wrappedTokens = [ - ...Object.values(wrappedAaveTokensV2Mainnet), - ...Object.values(wrappedAaveTokensV2Polygon), - ...Object.values(wrappedAaveTokensV3Mainnet), - ...Object.values(wrappedAaveTokensV3Polygon), - ...Object.values(wrappedAaveTokensV3Arbitrum), - ankrEthMainnet, - rETHMainnet, - USDRMainnet, - swETHMainnet, - wjAURAMainnet, - ...Object.values(eulerTokensMainnet), - ...Object.values(gearboxTokensMainnet), - ...Object.values(wrapped4626IdleTokensMainnet), - ...Object.values(overnightTokens), - ...Object.values(ovixWrappedTokensZkEvm), - ...Object.values(reaperYieldTokensArbitrum), - ...Object.values(tesseraYieldTokensMainnet), - tUSDTPolygon, - tUSDCPolygon, - tDAIPolygon, - qETHMainnet, -]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts deleted file mode 100644 index c863e1afa..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/aave-apr-handler.ts +++ /dev/null @@ -1,232 +0,0 @@ -import axios from 'axios'; -import { AprHandler } from '../ib-yield-apr-handlers'; - -class AaveAprHandler implements AprHandler { - wrappedTokens: { [key: string]: string }; - aaveTokens: { [key: string]: string }; - underlyingTokens: { [key: string]: string }; - subgraphUrl: string; - networkPrismaId: string; - - readonly group = 'AAVE'; - - readonly query = `query getReserves($aTokens: [String!], $underlyingAssets: [Bytes!]) { - reserves( - where: { - aToken_in: $aTokens - underlyingAsset_in: $underlyingAssets - isActive: true - } - ) { - id - underlyingAsset - liquidityRate - } - }`; - - constructor(aprHandlerConfig: AaveAprHandlerConfig) { - this.wrappedTokens = aprHandlerConfig.wrappedTokens; - this.aaveTokens = aprHandlerConfig.aaveTokens; - this.underlyingTokens = aprHandlerConfig.underlyingTokens; - this.subgraphUrl = aprHandlerConfig.subgraphUrl; - this.networkPrismaId = aprHandlerConfig.network; - } - - async getAprs() { - try { - const requestQuery = { - operationName: 'getReserves', - query: this.query, - variables: { - aTokens: Object.values(this.aaveTokens), - underlyingAssets: Object.values(this.underlyingTokens), - }, - }; - const { data } = await axios({ - url: this.subgraphUrl, - method: 'post', - data: requestQuery, - headers: { 'Content-Type': 'application/json' }, - }); - const { - data: { reserves }, - } = data as ReserveResponse; - - const aprsByUnderlyingAddress = Object.fromEntries( - reserves.map((r) => [ - r.underlyingAsset, - // Converting from aave ray number (27 digits) to float - Number(r.liquidityRate.slice(0, 27)) / 1e27, - ]), - ); - const aprEntries = Object.fromEntries( - Object.values(this.underlyingTokens) - //Removing undefined aprs - .filter(([, address]) => !!aprsByUnderlyingAddress[address]) - //Mapping aprs by wrapped instead of underlying addresses - .map(([underlyingTokenName, underlyingTokenAddress]) => [ - this.wrappedTokens['wa' + underlyingTokenName] as string, - aprsByUnderlyingAddress[underlyingTokenAddress], - ]), - ); - return aprEntries; - } catch (e) { - console.error(`Failed to fetch Aave APR in subgraph ${this.subgraphUrl}:`, e); - return {}; - } - } -} - -export const wrappedAaveTokensV2Mainnet = { - waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', - waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', - waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', -}; - -const aaveTokensV2Mainnet = { - aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', - aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c', - aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', -}; - -export const wrappedAaveTokensV2Polygon = { - waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', - waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', - waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', -}; - -const aaveTokensV2Polygon = { - aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', - aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', - aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', -}; - -export const wrappedAaveTokensV3Mainnet = { - waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', - waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', - waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', - waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', -}; - -const aaveTokensV3Mainnet = { - aUSDT: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', - aUSDC: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', - aDAI: '0x018008bfb33d285247a21d44e50697654f754e63', - aWETH: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8', -}; - -export const wrappedAaveTokensV3Polygon = { - waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', - waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', - waUSDC: '0x9719d867a500ef117cc201206b8ab51e794d3f82', - waDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', - waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', -}; - -const aaveTokensV3Polygon = { - aMATIC: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', - aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', - aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', - aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', - aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', -}; - -export const wrappedAaveTokensV3Arbitrum = { - waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', - waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', - waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', - waWETH: '0x18c100415988bef4354effad1188d1c22041b046', -}; - -const aaveTokensV3Arbitrum = { - aUSDT: '0x6ab707aca953edaefbc4fd23ba73294241490620', - aUSDC: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', - aDAI: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', - aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', -}; - -const underlyingTokensMainnet = { - USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', - USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', - WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', -}; - -const underlyingTokensPolygon = { - MATIC: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', - USDT: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', - USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', - DAI: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', - WETH: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619', -}; - -const underlyingTokensArbitrum = { - USDT: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - USDC: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - DAI: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', - WETH: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', -}; - -interface ReserveResponse { - data: { - reserves: [ - { - underlyingAsset: string; - liquidityRate: string; - }, - ]; - }; -} - -type AaveAprHandlerConfig = { - wrappedTokens: { [key: string]: string }; - aaveTokens: { [key: string]: string }; - underlyingTokens: { [key: string]: string }; - subgraphUrl: string; - network: string; -}; - -const aaveV2MainnetAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV2Mainnet, - aaveTokens: aaveTokensV2Mainnet, - underlyingTokens: underlyingTokensMainnet, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2', - network: 'MAINNET', -}); - -const aaveV2PolygonAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV2Polygon, - aaveTokens: aaveTokensV2Polygon, - underlyingTokens: underlyingTokensPolygon, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic', - network: 'POLYGON', -}); -const aaveV3MainnetAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV3Mainnet, - aaveTokens: aaveTokensV3Mainnet, - underlyingTokens: underlyingTokensMainnet, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3', - network: 'MAINNET', -}); -const aaveV3PolygonAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV3Polygon, - aaveTokens: aaveTokensV3Polygon, - underlyingTokens: underlyingTokensPolygon, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon', - network: 'POLYGON', -}); -const aaveV3ArbitrumAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV3Arbitrum, - aaveTokens: aaveTokensV3Arbitrum, - underlyingTokens: underlyingTokensArbitrum, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum', - network: 'ARBITRUM', -}); - -export const aaveHandlers = [ - aaveV2MainnetAprHandler, - aaveV2PolygonAprHandler, - aaveV3MainnetAprHandler, - aaveV3PolygonAprHandler, - aaveV3ArbitrumAprHandler, -]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/oErc20.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/oErc20.ts deleted file mode 100644 index 6dde7bf68..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/oErc20.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const abi = [ - { - inputs: [], - name: "borrowRatePerTimestamp", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256" - } - ], - stateMutability: "view", - type: "function" - } -] as const diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/reaperStrategy.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/reaperStrategy.ts deleted file mode 100644 index 1a89f3754..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/reaperStrategy.ts +++ /dev/null @@ -1,21 +0,0 @@ -export const abi = [ - { - inputs: [ - { - internalType: 'int256', - name: '_n', - type: 'int256', - }, - ], - name: 'averageAPRAcrossLastNHarvests', - outputs: [ - { - internalType: 'int256', - name: '', - type: 'int256', - }, - ], - stateMutability: 'view', - type: 'function', - }, -] as const diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/tesseraPool.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/tesseraPool.ts deleted file mode 100644 index a3fd8bb01..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/abis/tesseraPool.ts +++ /dev/null @@ -1,154 +0,0 @@ -export const abi = [ - { - inputs: [], - name: 'getPoolsUI', - outputs: [ - { - components: [ - { internalType: 'uint256', name: 'poolId', type: 'uint256' }, - { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, - { - components: [ - { - internalType: 'uint48', - name: 'startTimestampHour', - type: 'uint48', - }, - { - internalType: 'uint48', - name: 'endTimestampHour', - type: 'uint48', - }, - { - internalType: 'uint96', - name: 'rewardsPerHour', - type: 'uint96', - }, - { - internalType: 'uint96', - name: 'capPerPosition', - type: 'uint96', - }, - ], - internalType: 'struct ApeCoinStaking.TimeRange', - name: 'currentTimeRange', - type: 'tuple', - }, - ], - internalType: 'struct ApeCoinStaking.PoolUI', - name: '', - type: 'tuple', - }, - { - components: [ - { internalType: 'uint256', name: 'poolId', type: 'uint256' }, - { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, - { - components: [ - { - internalType: 'uint48', - name: 'startTimestampHour', - type: 'uint48', - }, - { - internalType: 'uint48', - name: 'endTimestampHour', - type: 'uint48', - }, - { - internalType: 'uint96', - name: 'rewardsPerHour', - type: 'uint96', - }, - { - internalType: 'uint96', - name: 'capPerPosition', - type: 'uint96', - }, - ], - internalType: 'struct ApeCoinStaking.TimeRange', - name: 'currentTimeRange', - type: 'tuple', - }, - ], - internalType: 'struct ApeCoinStaking.PoolUI', - name: '', - type: 'tuple', - }, - { - components: [ - { internalType: 'uint256', name: 'poolId', type: 'uint256' }, - { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, - { - components: [ - { - internalType: 'uint48', - name: 'startTimestampHour', - type: 'uint48', - }, - { - internalType: 'uint48', - name: 'endTimestampHour', - type: 'uint48', - }, - { - internalType: 'uint96', - name: 'rewardsPerHour', - type: 'uint96', - }, - { - internalType: 'uint96', - name: 'capPerPosition', - type: 'uint96', - }, - ], - internalType: 'struct ApeCoinStaking.TimeRange', - name: 'currentTimeRange', - type: 'tuple', - }, - ], - internalType: 'struct ApeCoinStaking.PoolUI', - name: '', - type: 'tuple', - }, - { - components: [ - { internalType: 'uint256', name: 'poolId', type: 'uint256' }, - { internalType: 'uint256', name: 'stakedAmount', type: 'uint256' }, - { - components: [ - { - internalType: 'uint48', - name: 'startTimestampHour', - type: 'uint48', - }, - { - internalType: 'uint48', - name: 'endTimestampHour', - type: 'uint48', - }, - { - internalType: 'uint96', - name: 'rewardsPerHour', - type: 'uint96', - }, - { - internalType: 'uint96', - name: 'capPerPosition', - type: 'uint96', - }, - ], - internalType: 'struct ApeCoinStaking.TimeRange', - name: 'currentTimeRange', - type: 'tuple', - }, - ], - internalType: 'struct ApeCoinStaking.PoolUI', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, -] as const diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts deleted file mode 100644 index dddf92a3b..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ankr-apr-handler.ts +++ /dev/null @@ -1,50 +0,0 @@ -import axios from 'axios'; -import { AprHandler } from '../ib-yield-apr-handlers'; - -class AnkrAprHandler implements AprHandler { - serviceName: string; - tokenAddress: string; - networkPrismaId: string; - readonly url: string = 'https://api.staking.ankr.com/v1alpha/metrics'; - readonly group = 'ANKR'; - - constructor(aprHandlerConfig: AnkrAprHandlerConfig) { - this.serviceName = aprHandlerConfig.serviceName; - this.tokenAddress = aprHandlerConfig.tokenAddress; - this.networkPrismaId = aprHandlerConfig.network; - } - - async getAprs() { - try { - const { data } = await axios.get(this.url); - const json = data as { services: { serviceName: string; apy: string }[] }; - const service = json.services.find((service) => service.serviceName === this.serviceName); - if (!service) { - return {}; - } - const scaledValue = parseFloat(service.apy) / 1e2; - return { - [this.tokenAddress]: scaledValue, - }; - } catch (error) { - console.error('Failed to fetch Ankr APR:', error); - return {}; - } - } -} - -export const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb'; - -type AnkrAprHandlerConfig = { - serviceName: string; - tokenAddress: string; - network: string; -}; - -const ankrEthMainnetAprHandler = new AnkrAprHandler({ - serviceName: 'eth', - tokenAddress: ankrEthMainnet, - network: 'MAINNET', -}); - -export const ankrHandlers = [ankrEthMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts deleted file mode 100644 index 8b24b7766..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/default-apr-handler.ts +++ /dev/null @@ -1,184 +0,0 @@ -import axios from 'axios'; - -import { AprHandler } from '../ib-yield-apr-handlers'; - -class DefaultAprHandler implements AprHandler { - tokens: string[]; - url: string; - path: string; - scale: number; - networkPrismaId: string; - readonly group = 'DEFAULT'; - - constructor(aprHandlerConfig: DefaultAprHandlerConfig) { - this.tokens = aprHandlerConfig.tokens; - this.url = aprHandlerConfig.url; - this.networkPrismaId = aprHandlerConfig.network; - this.path = aprHandlerConfig.path ?? ''; - this.scale = aprHandlerConfig.scale ?? 100; - } - - async getAprs() { - try { - const { data } = await axios.get(this.url, { headers: { 'User-Agent': 'cf' } }); - const value = this.path === '' ? data : this.getValueFromPath(data, this.path); - const scaledValue = parseFloat(value) / this.scale; - - return this.tokens.reduce((acc, token) => { - acc[token] = scaledValue; - return acc; - }, {} as { [key: string]: number }); - } catch (error) { - console.error(`Failed to fetch APRs in url ${this.url}:`, error); - return {}; - } - } - - getValueFromPath(obj: any, path: string) { - const parts = path.split('.'); - let value = obj; - for (const part of parts) { - value = value[part]; - } - return value; - } -} - -export type DefaultAprHandlerConfig = { - tokens: string[]; - url: string; - network: string; - scale?: number; - path?: string; -}; - -export const vETHMainnet = '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f'; -const wstETHGnosis = '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6'; -const wstETHZkEVM = '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9'; -const stETHMainnet = '0xae7ab96520de3a18e5e111b5eaab095312d7fe84'; -const wstETHMainnet = '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0'; -const wstETHPolygon = '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd'; -const wstETHArbitrum = '0x5979d7b546e38e414f7e9822514be443a4800529'; -const stMATICPolygon = '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'; -export const cbETHMainnet = '0xbe9895146f7af43049ca1c1ae358b0541ea49704'; - -const sfrxETHMainnet = '0xac3e018457b222d93114458476f3e3416abbe38f'; -export const rETHMainnet = '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'; -export const USDRMainnet = '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'; -const MATICXPolygon = '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'; -const wbETHMainnet = '0xa2e3356610840701bdf5611a53974510ae27e2e1'; -export const swETHMainnet = '0xf951e335afb289353dc249e82926178eac7ded78'; -export const wjAURAMainnet = '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'; - -const vETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [vETHMainnet], - url: 'https://apy.liebi.com/veth', - path: 'veth', - network: 'MAINNET', -}); -const stETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [stETHMainnet, wstETHMainnet], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'MAINNET', -}); -const stETHPolygonAprHandler = new DefaultAprHandler({ - tokens: [wstETHPolygon], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'POLYGON', -}); -const stETHZkEVMAprHandler = new DefaultAprHandler({ - tokens: [wstETHZkEVM], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'ZKEVM', -}); -const stETHGnosisAprHandler = new DefaultAprHandler({ - tokens: [wstETHGnosis], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'GNOSIS', -}); -const stETHArbitrumAprHandler = new DefaultAprHandler({ - tokens: [wstETHArbitrum], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'ARBITRUM', -}); - -const stMaticPolygonAprHandler = new DefaultAprHandler({ - tokens: [stMATICPolygon], - url: 'https://polygon.lido.fi/api/stats', - path: 'apr', - network: 'POLYGON', -}); -const cbEthMainnetAprHandler = new DefaultAprHandler({ - tokens: [cbETHMainnet], - url: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', - path: 'apy', - scale: 1, - network: 'MAINNET', -}); -const sfrxEthMainnetAprHandler = new DefaultAprHandler({ - tokens: [sfrxETHMainnet], - url: 'https://api.frax.finance/v2/frxeth/summary/latest', - path: 'sfrxethApr', - network: 'MAINNET', -}); -const rETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [rETHMainnet], - url: 'https://drop-api.stafi.io/reth/v1/poolData', - path: 'data.stakeApr', - network: 'MAINNET', -}); -const USDRMainnetAprHandler = new DefaultAprHandler({ - tokens: [USDRMainnet], - url: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', - path: 'usdr', - network: 'MAINNET', -}); - -const MATICXPolygonAprHandler = new DefaultAprHandler({ - tokens: [MATICXPolygon], - url: 'https://universe.staderlabs.com/polygon/apy', - path: 'value', - network: 'POLYGON', -}); -const wbETHPolygonAprHandler = new DefaultAprHandler({ - tokens: [wbETHMainnet], - url: 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', - path: 'data.0.rewardRate', - scale: 1, - network: 'POLYGON', -}); - -const swETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [swETHMainnet], - url: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', - network: 'MAINNET', -}); -const wjAURAMainnetAprHandler = new DefaultAprHandler({ - tokens: [wjAURAMainnet], - url: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', - path: 'wjauraApy', - network: 'MAINNET', -}); - -export const defaultHandlers = [ - vETHMainnetAprHandler, - stETHMainnetAprHandler, - stETHPolygonAprHandler, - stETHZkEVMAprHandler, - stETHGnosisAprHandler, - stETHArbitrumAprHandler, - stMaticPolygonAprHandler, - cbEthMainnetAprHandler, - sfrxEthMainnetAprHandler, - rETHMainnetAprHandler, - USDRMainnetAprHandler, - MATICXPolygonAprHandler, - wbETHPolygonAprHandler, - swETHMainnetAprHandler, - wjAURAMainnetAprHandler, -]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts deleted file mode 100644 index d6cc43d72..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/euler-apr-handler.ts +++ /dev/null @@ -1,88 +0,0 @@ -import axios from 'axios'; -import { AprHandler } from '../ib-yield-apr-handlers'; - -class EulerAprHandler implements AprHandler { - tokens: { [key: string]: string }; - subgraphUrl: string; - networkPrismaId: string; - readonly group = 'EULER'; - - readonly query = ` - query getAssetsAPY($eTokenAddress_in: [String!]) { - assets( - where: { - eTokenAddress_in: $eTokenAddress_in - } - ) { - eTokenAddress - supplyAPY - } - } -`; - - constructor(aprHandlerConfig: EulerAprHandlerConfig) { - this.tokens = aprHandlerConfig.tokens; - this.subgraphUrl = aprHandlerConfig.subgraphUrl; - this.networkPrismaId = aprHandlerConfig.network; - } - - async getAprs() { - const requestQuery = { - operationName: 'getAssetsAPY', - query: this.query, - variables: { - eTokenAddress_in: Object.values(this.tokens), - }, - }; - - const { data } = await axios({ - url: this.subgraphUrl, - method: 'POST', - data: JSON.stringify(requestQuery), - }); - - const { - data: { assets }, - } = data as EulerResponse; - - const aprEntries = assets.map(({ eTokenAddress, supplyAPY }) => [ - eTokenAddress, - // supplyAPY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 - Number(supplyAPY.slice(0, 27)) / 1e27, - ]); - - return Object.fromEntries(aprEntries); - } -} - -export const eulerTokensMainnet = { - eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', - eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', - eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', - eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', -}; - -interface EulerResponse { - data: { - assets: [ - { - eTokenAddress: string; - supplyAPY: string; - }, - ]; - }; -} - -type EulerAprHandlerConfig = { - tokens: { [key: string]: string }; - subgraphUrl: string; - network: string; -}; - -const eulerMainnetAprHandler = new EulerAprHandler({ - tokens: eulerTokensMainnet, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet', - network: 'MAINNET', -}); - -export const eulerHandlers = [eulerMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts deleted file mode 100644 index ff5bab3b5..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/gearbox-apr-handler.ts +++ /dev/null @@ -1,52 +0,0 @@ -import axios from 'axios'; - -import { AprHandler } from '../ib-yield-apr-handlers'; - -class GearboxAprHandler implements AprHandler { - url: string; - tokens: { [key: string]: string }; - networkPrismaId: string; - readonly group = 'GEARBOX'; - - constructor(aprHandlerConfig: GearboxAprHandlerConfig) { - this.tokens = aprHandlerConfig.tokens; - this.url = aprHandlerConfig.url; - this.networkPrismaId = aprHandlerConfig.network; - } - - async getAprs() { - try { - const { data } = await axios.get(this.url); - const json = data as { data: { dieselToken: string; depositAPY_RAY: string }[] }; - - const aprEntries = json.data - .filter((t) => Object.values(this.tokens).includes(t.dieselToken.toLowerCase())) - .map(({ dieselToken, depositAPY_RAY }) => { - return [dieselToken, Number(depositAPY_RAY.slice(0, 27)) / 1e27]; - }); - return Object.fromEntries(aprEntries); - } catch (error) { - console.error('Failed to fetch Gearbox APR:', error); - return {}; - } - } -} - -type GearboxAprHandlerConfig = { - tokens: { [key: string]: string }; - url: string; - network: string; -}; - -export const gearboxTokensMainnet = { - dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', - dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', -}; - -const gearboxMainnetAprHandler = new GearboxAprHandler({ - tokens: gearboxTokensMainnet, - url: 'https://mainnet.gearbox.foundation/api/pools', - network: 'MAINNET', -}); - -export const gearboxHandlers = [gearboxMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts deleted file mode 100644 index 975497fe7..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/idle-apr-handler.ts +++ /dev/null @@ -1,77 +0,0 @@ -import axios from 'axios'; - -import { AprHandler } from '../ib-yield-apr-handlers'; - -class IdleAprHandler implements AprHandler { - wrappedIdleTokens: { [key: string]: string }; - idleTokens: { [key: string]: string }; - baseIdleApiUrl: string; - authorizationHeader: string; - networkPrismaId: string; - readonly group = 'IDLE'; - - constructor(aprHandlerConfig: IdleAprHandlerConfig) { - this.wrappedIdleTokens = aprHandlerConfig.wrappedIdleTokens; - this.idleTokens = aprHandlerConfig.idleTokens; - this.baseIdleApiUrl = aprHandlerConfig.baseIdleApiUrl; - this.authorizationHeader = aprHandlerConfig.authorizationHeader; - this.networkPrismaId = aprHandlerConfig.network; - } - - async getAprs() { - try { - const aprPromises = Object.entries(this.idleTokens).map(async ([tokenName, idleTokenAddress]) => { - const { data } = await axios.get( - [this.baseIdleApiUrl, idleTokenAddress, '?isRisk=false&order=desc&limit=1'].join(''), - { - headers: { - Authorization: this.authorizationHeader, - }, - }, - ); - const [json] = data as { idleRate: string }[]; - const value = Number(json.idleRate) / 1e20; - return [this.wrappedIdleTokens[tokenName], value]; - }); - const res = Array(Object.keys(this.idleTokens).length); - for (const [index, aprPromise] of aprPromises.entries()) { - res[index] = await aprPromise; - } - return Object.fromEntries(res); - } catch (error) { - console.error('Failed to fetch Idle APR:', error); - return {}; - } - } -} - -export const wrapped4626IdleTokensMainnet = { - idleDAI: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', - idleUSDC: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', - idleUSDT: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', -}; - -const idleTokensMainnet = { - idleDAI: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', - idleUSDC: '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', - idleUSDT: '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', -}; - -type IdleAprHandlerConfig = { - wrappedIdleTokens: { [key: string]: string }; - idleTokens: { [key: string]: string }; - baseIdleApiUrl: string; - authorizationHeader: string; - network: string; -}; - -const idleMainnetAprHandler = new IdleAprHandler({ - wrappedIdleTokens: wrapped4626IdleTokensMainnet, - idleTokens: idleTokensMainnet, - baseIdleApiUrl: 'https://api.idle.finance/junior-rates/', - authorizationHeader: - 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M', - network: 'MAINNET', -}); - -export const idleAprHandlers = [idleMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts deleted file mode 100644 index 64c64d88e..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/overnight-apr-handler.ts +++ /dev/null @@ -1,50 +0,0 @@ -import axios from 'axios'; - -import { AprHandler } from '../ib-yield-apr-handlers'; - -class OvernightAprHandler implements AprHandler { - overnightTokens: { [key: string]: string }; - url: string; - networkPrismaId: string; - readonly group = 'OVERNIGHT'; - - constructor(aprHandlerConfig: OvernightAprHandlerConfig) { - this.overnightTokens = aprHandlerConfig.tokens; - this.url = aprHandlerConfig.url; - this.networkPrismaId = aprHandlerConfig.network; - } - - async getAprs() { - try { - const { data } = await axios.get(this.url); - const rate = data as number; - - return Object.values(this.overnightTokens).reduce((acc, token) => { - acc[token] = rate; - return acc; - }, {} as { [key: string]: number }); - } catch (error) { - console.error(`Failed to fetch Overnight APRs in url:`, error); - return {}; - } - } -} - -export const overnightTokens = { - lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus - UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f', // UsdcUsdPlus -}; - -type OvernightAprHandlerConfig = { - tokens: { [key: string]: string }; - url: string; - network: string; -}; - -const overnightMainnetAprHandler = new OvernightAprHandler({ - tokens: overnightTokens, - url: 'https://app.overnight.fi/api/balancer/week/apr', - network: 'MAINNET', -}); - -export const overnightHandlers = [overnightMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts deleted file mode 100644 index b4a78b613..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/ovix-apr-handler.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { BigNumber, Contract } from 'ethers'; -import { abi } from './abis/oErc20'; -import { JsonRpcProvider } from '@ethersproject/providers'; - -import { AprHandler } from '../ib-yield-apr-handlers'; - -class OvixAprHandler implements AprHandler { - networkPrismaId: string; - provider: JsonRpcProvider; - yieldTokens: { [key: string]: `0x${string}` }; - wrappedTokens: { [key: string]: `0x${string}` }; - readonly group = 'OVIX'; - - constructor(aprHandlerConfig: OvixAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.networkPrismaId; - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); - this.yieldTokens = aprHandlerConfig.yieldTokens; - this.wrappedTokens = aprHandlerConfig.wrappedTokens; - } - - async getAprs() { - try { - const calls = Object.keys(this.yieldTokens).map(async (tokenName) => { - const contract = new Contract(this.yieldTokens[tokenName], abi, this.provider); - return contract.borrowRatePerTimestamp(); - }); - - const borrowRates = Array(Object.keys(this.yieldTokens).length); - for (const [index, aprPromise] of calls.entries()) { - borrowRates[index] = await aprPromise; - } - - const aprs = Object.keys(this.wrappedTokens).map((tokenName, i) => [ - this.wrappedTokens[tokenName], - Math.pow(1 + (borrowRates[i] as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1, - ]); - - return Object.fromEntries(aprs); - } catch (error) { - console.error('Failed to fetch Ovix APR:', error); - return {}; - } - } -} - -type OvixAprHandlerConfig = { - networkPrismaId: string; - networkChainId: number; - rpcUrl: string; - yieldTokens: { [key: string]: `0x${string}` }; - wrappedTokens: { - [key: string]: `0x${string}`; - }; -}; - -const ovixYieldTokensZkEvm = { - USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', - USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', -} as { [key: string]: `0x${string}` }; - -export const ovixWrappedTokensZkEvm = { - USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', - USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', -} as { [key: string]: `0x${string}` }; - -const ovixZkEVMAprHandler = new OvixAprHandler({ - networkPrismaId: 'ZKEVM', - networkChainId: 1101, - rpcUrl: 'https://zkevm-rpc.com', - yieldTokens: ovixYieldTokensZkEvm, - wrappedTokens: ovixWrappedTokensZkEvm, -}); - -export const ovixHandlers = [ovixZkEVMAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts deleted file mode 100644 index ad3cd4a7c..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/reaper-apr-handler.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { JsonRpcProvider } from '@ethersproject/providers'; -import { BigNumber, Contract } from 'ethers'; -import { abi } from './abis/reaperStrategy'; - -import { AprHandler } from '../ib-yield-apr-handlers'; - -class ReaperAprHandler implements AprHandler { - networkPrismaId: string; - provider: JsonRpcProvider; - yieldTokens: { [key: string]: `0x${string}` }; - strategiesMap: { [key: string]: `0x${string}` }; - readonly group = 'REAPER'; - - constructor(aprHandlerConfig: ReaperAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.networkPrismaId; - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); - this.yieldTokens = aprHandlerConfig.yieldTokens; - this.strategiesMap = aprHandlerConfig.strategiesMap; - } - - async getAprs() { - try { - const contractCalls = Object.keys(this.strategiesMap).map(async (tokenName) => { - const contract = new Contract(this.strategiesMap[tokenName], abi, this.provider); - return contract.averageAPRAcrossLastNHarvests(3); - }); - const callsAprResults: BigNumber[] = Array(Object.keys(this.yieldTokens).length); - for (const [index, aprPromise] of contractCalls.entries()) { - callsAprResults[index] = await aprPromise; - } - const aprs = Object.keys(this.strategiesMap).map((tokenName, i) => { - return [this.yieldTokens[tokenName], callsAprResults[i].toNumber() / 1e4]; - }); - - return Object.fromEntries(aprs); - } catch (error) { - console.error('Failed to fetch Reaper APR:', error); - return {}; - } - } -} - -type ReaperAprHandlerConfig = { - networkPrismaId: string; - networkChainId: number; - rpcUrl: string; - yieldTokens: { [key: string]: `0x${string}` }; - strategiesMap: { - [key: string]: `0x${string}`; - }; -}; - -export const reaperYieldTokensArbitrum = { - DAI: '0x12f256109e744081f633a827be80e06d97ff7447', - USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', - USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', -} as { [key: string]: `0x${string}` }; - -const reaperStrategiesMapArbitrum = { - DAI: '0xd4d5321b04e4832772a4d70e1eed6bcb7402d7ac', - USDT: '0x8a674ebbe33d6b03825626fa432e9ece888e13b5', - USDC: '0x6f6c0c5b7af2a326111ba6a9fa4926f7ca3adf44', -} as { [key: string]: `0x${string}` }; - -const reaperArbitrumAprHandler = new ReaperAprHandler({ - networkPrismaId: 'ARBITRUM', - networkChainId: 42161, - rpcUrl: 'https://arb1.arbitrum.io/rpc', - yieldTokens: reaperYieldTokensArbitrum, - strategiesMap: reaperStrategiesMapArbitrum, -}); - -export const reaperHandlers = [reaperArbitrumAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts deleted file mode 100644 index 3b9f8f4e0..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tessera-apr-handler.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Contract } from 'ethers'; -import { abi } from './abis/tesseraPool'; -import { JsonRpcProvider } from '@ethersproject/providers'; - -import { AprHandler } from '../ib-yield-apr-handlers'; - -class TesseraAprHandler implements AprHandler { - networkPrismaId: string; - provider: JsonRpcProvider; - yieldTokens: { [key: string]: `0x${string}` }; - stakingContractAddress: `0x${string}`; - readonly group = 'TESSERA'; - - constructor(aprHandlerConfig: TesseraAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.networkPrismaId; - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); - this.yieldTokens = aprHandlerConfig.yieldTokens; - this.stakingContractAddress = aprHandlerConfig.contractAddress; - } - - async getAprs() { - try { - let apr = 0; - try { - const contract = new Contract(this.stakingContractAddress, abi, this.provider); - const poolsUI = await contract.getPoolsUI(); - - const pool = poolsUI[0]; - const staked = BigInt(pool.stakedAmount); - const reward = BigInt(pool.currentTimeRange.rewardsPerHour) * BigInt(24 * 365); - apr = Number(reward.toString()) / Number(staked.toString()); - } catch (error) { - console.error('Failed to fetch Tessera Ape Coin APR:', error); - } - - return { - [this.yieldTokens.sApe]: apr, - }; - } catch (error) { - console.error('Failed to fetch Tessera APR:', error); - return {}; - } - } -} - -type TesseraAprHandlerConfig = { - networkPrismaId: string; - networkChainId: number; - rpcUrl: string; - yieldTokens: { [key: string]: `0x${string}` }; - contractAddress: `0x${string}`; -}; - -export const tesseraYieldTokensMainnet = { - sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', -} as { [key: string]: `0x${string}` }; - -const tesseraMainnetAprHandler = new TesseraAprHandler({ - networkPrismaId: 'MAINNET', - networkChainId: 1, - rpcUrl: 'https://rpc.ankr.com/eth', - yieldTokens: tesseraYieldTokensMainnet, - contractAddress: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9' /*ApeCoinStaking*/, -}); - -export const tesseraHandlers = [tesseraMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts deleted file mode 100644 index 34541ac8e..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tetu-apr-handler.ts +++ /dev/null @@ -1,53 +0,0 @@ -import axios from 'axios'; - -import { AprHandler } from '../ib-yield-apr-handlers'; - -class TetuAprHandler implements AprHandler { - networkPrismaId: string; - baseUrl: string; - networkName: string; - tetuTokens: string[]; - readonly group = 'TETU'; - - constructor(aprHandlerConfig: TetuAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.network; - this.baseUrl = aprHandlerConfig.baseUrl; - this.networkName = aprHandlerConfig.networkName; - this.tetuTokens = aprHandlerConfig.tetuTokens; - } - - async getAprs() { - try { - const { data } = await axios.get(`${this.baseUrl}?network=${this.networkName}`); - const json = data as { vault: string; apr: number }[]; - const aprs = json - .filter(({ vault }) => this.tetuTokens.includes(vault.toLowerCase())) - .map((t) => [t.vault, t.apr / 100]); - - return Object.fromEntries(aprs); - } catch (error) { - console.error('Failed to fetch Tetu APR:', error); - return {}; - } - } -} - -type TetuAprHandlerConfig = { - network: string; - baseUrl: string; - networkName: string; - tetuTokens: string[]; -}; - -export const tUSDCPolygon = '0x113f3d54c31ebc71510fd664c8303b34fbc2b355'; -export const tUSDTPolygon = '0x236975da9f0761e9cf3c2b0f705d705e22829886'; -export const tDAIPolygon = '0xace2ac58e1e5a7bfe274916c4d82914d490ed4a5'; -const tetuStQIPolygon = '0x4cd44ced63d9a6fef595f6ad3f7ced13fceac768'; - -const tetuPolygonAprHandler = new TetuAprHandler({ - network: 'POLYGON', - baseUrl: 'https://api.tetu.io/api/v1/reader/compoundAPRs', - networkName: 'MATIC', - tetuTokens: [tUSDCPolygon, tUSDTPolygon, tDAIPolygon, tetuStQIPolygon], -}); -export const tetuHandlers = [tetuPolygonAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts deleted file mode 100644 index fbe85c14a..000000000 --- a/modules/pool/lib/apr-data-sources/ib-yield-apr-handlers/sources/tranchess-apr-handler.ts +++ /dev/null @@ -1,47 +0,0 @@ -import axios from 'axios'; - -import { AprHandler } from '../ib-yield-apr-handlers'; - -export const qETHMainnet = '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d'; - -class TranchessAprHandler implements AprHandler { - networkPrismaId: string; - url: string; - token: string; - readonly group = 'TRANCHESS'; - - constructor(aprHandlerConfig: TranchessAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.network; - this.token = aprHandlerConfig.token; - this.url = aprHandlerConfig.url; - } - - async getAprs() { - try { - const { data } = await axios.get('https://tranchess.com/eth/api/v3/funds'); - const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[]; - // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. - const value = (365 * Number(weeklyAveragePnlPercentage)) / 1e18; - return { - [this.token]: value, - }; - } catch (error) { - console.error('Failed to fetch Tranchess APR:', error); - return {}; - } - } -} - -type TranchessAprHandlerConfig = { - network: string; - token: string; - url: string; -}; - -const tranchessMainnetAprHandler = new TranchessAprHandler({ - network: 'MAINNET', - token: qETHMainnet, - url: 'https://tranchess.com/eth/api/v3/funds', -}); - -export const tranchessHandlers = [tranchessMainnetAprHandler]; From 8c0431874cb740554bc43950451c0530d728f8a5 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Thu, 24 Aug 2023 03:02:55 -0300 Subject: [PATCH 22/42] Refactoring all code to be more scalable; Moving the apr config to network config; --- modules/network/arbitrum.ts | 58 ++++- modules/network/avalanche.ts | 68 +++++- modules/network/fantom.ts | 22 ++ modules/network/gnosis.ts | 18 +- modules/network/mainnet.ts | 212 +++++++++++++++++- modules/network/network-config-types.ts | 93 ++++++++ modules/network/optimism.ts | 34 +++ modules/network/polygon.ts | 122 +++++++++- modules/network/zkevm.ts | 31 ++- .../base-apr-handlers/base-apr-handlers.ts | 207 +++++++++++------ .../sources/aave-apr-handler.ts | 150 +++---------- .../sources/ankr-apr-handler.ts | 51 +++++ .../sources/ankr-eth-apr-handler.ts | 64 ------ .../sources/default-apr-handler.ts | 191 +--------------- .../sources/euler-apr-handler.ts | 21 +- .../sources/gearbox-apr-handler.ts | 23 +- .../sources/idle-apr-handler.ts | 71 +++--- .../sources/overnight-apr-handler.ts | 50 ----- .../sources/ovix-apr-handler.ts | 63 ++---- .../sources/tessera-apr-handler.ts | 66 +++--- .../sources/tetu-apr-handler.ts | 43 ++-- .../sources/tranchess-apr-handler.ts | 49 ++-- .../apr-data-sources/ib-tokens-apr.service.ts | 16 +- 23 files changed, 1008 insertions(+), 715 deletions(-) create mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-eth-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/sources/overnight-apr-handler.ts diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 7c977b0df..af49f0ec9 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -114,6 +114,57 @@ const arbitrumNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, + aprConfig: { + aave: { + v3: { + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum', + tokens: { + USDC: { + underlyingAssetAddress: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', + aTokenAddress: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', + wrappedTokens: { + waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', + stataArbUSDC: '0x3a301e7917689b8e8a19498b8a28fc912583490c', + stataArbUSDCn: '0xbde67e089886ec0e615d6f054bc6f746189a3d56', + }, + }, + USDT: { + underlyingAssetAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + aTokenAddress: '0x6ab707aca953edaefbc4fd23ba73294241490620', + wrappedTokens: { + waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', + stataArbUSDT: '0x8b5541b773dd781852940490b0c3dc1a8cdb6a87', + }, + }, + DAI: { + underlyingAssetAddress: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + aTokenAddress: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', + wrappedTokens: { + waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', + stataArbDAI: '0x426e8778bf7f54b0e4fc703dcca6f26a4e5b71de', + }, + }, + wETH: { + underlyingAssetAddress: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', + aTokenAddress: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', + wrappedTokens: { + waWETH: '0x18c100415988bef4354effad1188d1c22041b046', + stataArbWETH: '0x18468b6eba332285c6d9bb03fe7fb52e108c4596', + }, + }, + }, + }, + }, + defaultHandlers: { + stETH: { + tokens: { + wstETH: '0x5979d7b546e38e414f7e9822514be443a4800529', + }, + sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + }, + }, + }, yearn: { vaultsEndpoint: 'https://#/', }, @@ -161,7 +212,12 @@ export const arbitrumNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(arbitrumNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(arbitrumNetworkData.chain.prismaId, tokenService), + new IbTokensAprService( + arbitrumNetworkData.aprConfig, + arbitrumNetworkData.chain.prismaId, + arbitrumNetworkData.chain.id, + tokenService, + ), new WstethAprService(tokenService, arbitrumNetworkData.lido!.wstEthContract), new ReaperCryptAprService( arbitrumNetworkData.reaper.linearPoolFactories, diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index e8c658c18..7104b7764 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -15,7 +15,7 @@ import { GithubContentService } from '../content/github-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; -import { IbTokensAprService } from "../pool/lib/apr-data-sources/ib-tokens-apr.service"; +import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; const avalancheNetworkData: NetworkData = { chain: { @@ -105,6 +105,66 @@ const avalancheNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, + aprConfig: { + aave: { + v3: { + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-avalanche', + tokens: { + USDC: { + underlyingAssetAddress: '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', + aTokenAddress: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', + wrappedTokens: { + stataAvaUSDC: '0xe7839ea8ea8543c7f5d9c9d7269c661904729fe7', + }, + }, + USDT: { + underlyingAssetAddress: '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7', + aTokenAddress: '0x6ab707aca953edaefbc4fd23ba73294241490620', + wrappedTokens: { + stataAvaUSDT: '0x759a2e28d4c3ad394d3125d5ab75a6a5d6782fd9', + }, + }, + DAI: { + underlyingAssetAddress: '0xd586e7f844cea2f87f50152665bcbc2c279d8d70', + aTokenAddress: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', + wrappedTokens: { + stataAvaDAI: '0x234c4b76f749dfffd9c18ea7cc0972206b42d019', + }, + }, + wETH: { + underlyingAssetAddress: '0x49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab', + aTokenAddress: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', + wrappedTokens: { + stataAvaWETH: '0x41bafe0091d55378ed921af3784622923651fdd8', + }, + }, + wAVAX: { + underlyingAssetAddress: '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7', + aTokenAddress: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', + wrappedTokens: { + stataAvaWAVAX: '0xa291ae608d8854cdbf9838e28e9badcf10181669', + }, + }, + wBTC: { + underlyingAssetAddress: '0x50b7545627a5162f82a992c33b87adc75187b218', + aTokenAddress: '0x078f358208685046a11c85e8ad32895ded33a249', + wrappedTokens: { + stataAvaWBTC: '0xb516f74eb030cebd5f616b1a33f88e1213b93c2c', + }, + }, + }, + }, + }, + ankr: { + sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', + tokens: { + ankrAVAX: { + address: '0xc3344870d52688874b06d844e0c36cc39fc727f6', + serviceName: 'avax', + }, + }, + }, + }, yearn: { vaultsEndpoint: 'https://#/', }, @@ -148,6 +208,12 @@ export const avalancheNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(avalancheNetworkData.rpcUrl), poolAprServices: [ + new IbTokensAprService( + avalancheNetworkData.aprConfig, + avalancheNetworkData.chain.prismaId, + avalancheNetworkData.chain.id, + tokenService, + ), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(avalancheNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index 348894592..b6804cc8a 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -28,6 +28,7 @@ import { AnkrStakedFtmAprService } from '../pool/lib/apr-data-sources/fantom/ank import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { AnkrStakedEthAprService } from '../pool/lib/apr-data-sources/fantom/ankr-staked-eth-apr.service'; +import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; const fantomNetworkData: NetworkData = { chain: { @@ -152,6 +153,21 @@ const fantomNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, + aprConfig: { + ankr: { + sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', + tokens: { + ankrETH: { + address: '0x12d8ce035c5de3ce39b1fdd4c1d5a745eaba3b8c', + serviceName: 'eth', + }, + ankrFTM: { + address: '0xcfc785741dc0e98ad4c9f6394bb9d43cd1ef5179', + serviceName: 'ftm', + }, + }, + }, + }, yearn: { vaultsEndpoint: 'https://d28fcsszptni1s.cloudfront.net/v1/chains/250/vaults/all', }, @@ -222,6 +238,12 @@ export const fantomNetworkConfig: NetworkConfig = { contentService: new SanityContentService(), provider: new ethers.providers.JsonRpcProvider(fantomNetworkData.rpcUrl), poolAprServices: [ + new IbTokensAprService( + fantomNetworkData.aprConfig, + fantomNetworkData.chain.prismaId, + fantomNetworkData.chain.id, + tokenService, + ), // new SpookySwapAprService(tokenService, fantomNetworkData.spooky!.xBooContract), new YearnVaultAprService(tokenService), new StaderStakedFtmAprService(tokenService, fantomNetworkData.stader!.sFtmxContract), diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index 6e04c09d4..6d859ba41 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -105,6 +105,17 @@ const gnosisNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, + aprConfig: { + defaultHandlers: { + stETH: { + tokens: { + wstETH: '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6', + }, + sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + }, + }, + }, yearn: { vaultsEndpoint: 'https://#/', }, @@ -152,7 +163,12 @@ export const gnosisNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(gnosisNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(gnosisNetworkData.chain.prismaId, tokenService), + new IbTokensAprService( + gnosisNetworkData.aprConfig, + gnosisNetworkData.chain.prismaId, + gnosisNetworkData.chain.id, + tokenService, + ), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(gnosisNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 4be39a202..ca1ea17bb 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -116,6 +116,201 @@ const mainnetNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, + aprConfig: { + aave: { + v2: { + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2', + tokens: { + USDC: { + underlyingAssetAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + aTokenAddress: '0xbcca60bb61934080951369a648fb03df4f96263c', + wrappedTokens: { + waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', + }, + }, + USDT: { + underlyingAssetAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7', + aTokenAddress: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', + wrappedTokens: { + waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', + }, + }, + DAI: { + underlyingAssetAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', + aTokenAddress: '0x028171bca77440897b824ca71d1c56cac55b68a3', + wrappedTokens: { + waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', + }, + }, + }, + }, + v3: { + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3', + tokens: { + USDC: { + underlyingAssetAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + aTokenAddress: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', + wrappedTokens: { + waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', + stataEthUSDC: '0x02c2d189b45ce213a40097b62d311cf0dd16ec92', + }, + }, + USDT: { + underlyingAssetAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7', + aTokenAddress: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', + wrappedTokens: { + waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', + stataEthUSDT: '0x65799b9fd4206cdaa4a1db79254fcbc2fd2ffee6', + }, + }, + DAI: { + underlyingAssetAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', + aTokenAddress: '0x018008bfb33d285247a21d44e50697654f754e63', + wrappedTokens: { + waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', + stataEthDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', + }, + }, + wETH: { + underlyingAssetAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + aTokenAddress: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8', + wrappedTokens: { + waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', + stataEthWETH: '0x03928473f25bb2da6bc880b07ecbadc636822264', + }, + }, + }, + }, + }, + ankr: { + sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', + tokens: { + ankrETH: { + address: '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb', + serviceName: 'eth', + }, + }, + }, + euler: { + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet', + tokens: { + eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', + eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', + eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', + eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', + }, + }, + gearbox: { + sourceUrl: 'https://mainnet.gearbox.foundation/api/pools', + tokens: { + dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', + dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', + }, + }, + idle: { + sourceUrl: 'https://api.idle.finance/junior-rates/', + authorizationHeader: + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M', + tokens: { + idleDAI: { + address: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', + wrapped4626Address: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', + }, + idleUSDC: { + address: '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', + wrapped4626Address: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', + }, + idleUSDT: { + address: '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', + wrapped4626Address: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', + }, + }, + }, + tessera: { + rpcUrl: 'https://rpc.ankr.com/eth', + tokens: { + sAPE: { + tesseraPoolAddress: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9', + tokenAddress: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', + }, + }, + }, + tranchess: { + sourceUrl: 'https://tranchess.com/eth/api/v3/funds', + tokens: { + qETH: { + address: '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d', + underlyingAssetName: 'WETH', + }, + }, + }, + defaultHandlers: { + vETH: { + tokens: { + vETH: '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f', + }, + sourceUrl: 'https://apy.liebi.com/veth', + path: 'veth', + }, + stETH: { + tokens: { + stETH: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84', + wstETH: '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', + }, + sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + }, + cbETH: { + tokens: { + cbETH: '0xbe9895146f7af43049ca1c1ae358b0541ea49704', + }, + sourceUrl: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', + path: 'apy', + scale: 1, + }, + sfrxETH: { + tokens: { sfrxETH: '0xac3e018457b222d93114458476f3e3416abbe38f' }, + sourceUrl: 'https://api.frax.finance/v2/frxeth/summary/latest', + path: 'sfrxethApr', + }, + rETH: { + tokens: { + rETH: '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593', + }, + sourceUrl: 'https://drop-api.stafi.io/reth/v1/poolData', + path: 'data.stakeApr', + }, + USDR: { + tokens: { + USDR: '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b', + }, + sourceUrl: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', + path: 'usdr', + }, + swETH: { + tokens: { + swETH: '0xf951e335afb289353dc249e82926178eac7ded78', + }, + sourceUrl: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', + }, + wjAURA: { + tokens: { + wjAURA: '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f', + }, + sourceUrl: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', + path: 'wjauraApy', + }, + overnight: { + tokens: { + lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', + UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f', + }, + sourceUrl: 'https://app.overnight.fi/api/balancer/week/apr', + group: 'OVERNIGHT', + scale: 1, + }, + }, + }, yearn: { vaultsEndpoint: 'https://#/', }, @@ -163,7 +358,12 @@ export const mainnetNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(mainnetNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(mainnetNetworkData.chain.prismaId, tokenService), + new IbTokensAprService( + mainnetNetworkData.aprConfig, + mainnetNetworkData.chain.prismaId, + mainnetNetworkData.chain.id, + tokenService, + ), new WstethAprService(tokenService, mainnetNetworkData.lido!.wstEthContract), new PhantomStableAprService(), new BoostedPoolAprService(), @@ -182,12 +382,12 @@ export const mainnetNetworkConfig: NetworkConfig = { ], userStakedBalanceServices: [new UserSyncGaugeBalanceService()], /* - For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. - This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. +For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. +This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. - For every 1 days jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. - This is needed because the maximum alarm evaluation period is 1 day (period * evaluationPeriod). - */ +For every 1 days jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. +This is needed because the maximum alarm evaluation period is 1 day (period * evaluationPeriod). +*/ workerJobs: [ { name: 'update-token-prices', diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index ed57cffc4..3bbddcd35 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -100,6 +100,7 @@ export interface NetworkData { address: string; excludedFarmIds: string[]; }; + aprConfig: AprConfig; reliquary?: { address: string; excludedFarmIds: string[]; @@ -164,3 +165,95 @@ export interface NetworkData { }; }; } + +export interface AprConfig { + aave?: { + [version: string]: { + subgraphUrl: string; + tokens: { + [underlyingAssetName: string]: { + underlyingAssetAddress: string; + aTokenAddress: string; + wrappedTokens: { + [wrappedTokenName: string]: string; + }; + }; + }; + }; + }; + ankr?: { + sourceUrl: string; + tokens: { + [underlyingAssetName: string]: { + address: string; + serviceName: string; + }; + }; + }; + euler?: { + subgraphUrl: string; + tokens: { + [tokenName: string]: string; + }; + }; + gearbox?: { + sourceUrl: string; + tokens: { + [tokenName: string]: string; + }; + }; + idle?: { + sourceUrl: string; + authorizationHeader?: string; + tokens: { + [tokenName: string]: { + address: string; + wrapped4626Address: string; + }; + }; + }; + ovix?: { + rpcUrl: string; + tokens: { + [tokenName: string]: { + yieldAddress: string; + wrappedAddress: string; + }; + }; + }; + tessera?: { + rpcUrl: string; + tokens: { + [tokenName: string]: { + tesseraPoolAddress: string; + tokenAddress: string; + }; + }; + }; + tetu?: { + sourceUrl: string; + tokens: { + [tokenName: string]: string; + }; + }; + tranchess?: { + sourceUrl: string; + tokens: { + [tokenName: string]: { + address: string; + underlyingAssetName: string; + }; + }; + }; + defaultHandlers?: { + [tokenName: string]: { + sourceUrl: string; + tokens: { + [tokenName: string]: string; + }; + path?: string; + scale?: number; + group?: string; + }; + }; +} diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 00d7b4c83..d3d916229 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -21,6 +21,7 @@ import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { BeefyVaultAprService } from '../pool/lib/apr-data-sources/beefy-vault-apr.service copy'; +import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; const optimismNetworkData: NetworkData = { chain: { @@ -116,6 +117,33 @@ const optimismNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, + aprConfig: { + defaultHandlers: { + stEth: { + tokens: { + wstETH: '0x1f32b1c2345538c0c6f582fcb0227', + }, + sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + }, + overnightDAIPlus: { + tokens: { + DAIPlus: '0x0b8f31480249cc717081928b8af733f45f6915bb', + }, + sourceUrl: 'https://api.overnight.fi/optimism/dai+/fin-data/avg-apr/week', + path: 'value', + group: 'OVERNIGHT', + }, + overnightUSDPlus: { + tokens: { + USDPlus: '0xa348700745d249c3b49d2c2acac9a5ae8155f826', + }, + sourceUrl: 'https://api.overnight.fi/optimism/usd+/fin-data/avg-apr/week', + path: 'value', + group: 'OVERNIGHT', + }, + }, + }, yearn: { vaultsEndpoint: 'https://#/', }, @@ -183,6 +211,12 @@ export const optimismNetworkConfig: NetworkConfig = { contentService: new SanityContentService(), provider: new ethers.providers.JsonRpcProvider(optimismNetworkData.rpcUrl), poolAprServices: [ + new IbTokensAprService( + optimismNetworkData.aprConfig, + optimismNetworkData.chain.prismaId, + optimismNetworkData.chain.id, + tokenService, + ), new RocketPoolStakedEthAprService(tokenService, optimismNetworkData.rocket!.rEthContract), new WstethAprService(tokenService, optimismNetworkData.lido!.wstEthContract), new OvernightAprService(optimismNetworkData.overnight!.aprEndpoint, tokenService), diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index e2a0168c6..4e9a275e1 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -113,6 +113,121 @@ const polygonNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, + aprConfig: { + aave: { + v2: { + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic', + tokens: { + USDC: { + underlyingAssetAddress: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + aTokenAddress: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', + wrappedTokens: { + waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', + }, + }, + USDT: { + underlyingAssetAddress: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + aTokenAddress: '0x60d55f02a771d515e077c9c2403a1ef324885cec', + wrappedTokens: { + waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', + }, + }, + DAI: { + underlyingAssetAddress: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + aTokenAddress: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', + wrappedTokens: { + waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', + }, + }, + }, + }, + v3: { + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon', + tokens: { + USDC: { + underlyingAssetAddress: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + aTokenAddress: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', + wrappedTokens: { + waUSDC: '0xac69e38ed4298490906a3f8d84aefe883f3e86b5', + stataPolUSDC: '0xc04296aa4534f5a3bab2d948705bc89317b2f1ed', + }, + }, + USDT: { + underlyingAssetAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7', + aTokenAddress: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', + wrappedTokens: { + waUSDT: '0x715d73a88f2f0115d87cfe5e0f25d756b2f9679f', + stataPolUSDT: '0x31f5ac91804a4c0b54c0243789df5208993235a1', + }, + }, + DAI: { + underlyingAssetAddress: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + aTokenAddress: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', + wrappedTokens: { + waDAI: '0xdb6df721a6e7fdb97363079b01f107860ac156f9', + stataPolDAI: '0xfcf5d4b313e06bb3628eb4fe73320e94039dc4b7', + }, + }, + wETH: { + underlyingAssetAddress: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619', + aTokenAddress: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', + wrappedTokens: { + waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', + stataPolWETH: '0xd08b78b11df105d2861568959fca28e30c91cf68', + }, + }, + wMATIC: { + underlyingAssetAddress: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', + aTokenAddress: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', + wrappedTokens: { + waWMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', + stataPolWMATIC: '0x6f3913333f2d4b7b01d17bedbce1e4c758b94465', + }, + }, + }, + }, + }, + tetu: { + sourceUrl: 'https://api.tetu.io/api/v1/reader/compoundAPRs?network=MATIC', + tokens: { + tUSDC: '0x113f3d54c31ebc71510fd664c8303b34fbc2b355', + tUSDT: '0x236975da9f0761e9cf3c2b0f705d705e22829886', + tDAI: '0xace2ac58e1e5a7bfe274916c4d82914d490ed4a5', + tetuStQI: '0x4cd44ced63d9a6fef595f6ad3f7ced13fceac768', + }, + }, + defaultHandlers: { + stETH: { + tokens: { + wstETH: '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd', + }, + sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + }, + stMATIC: { + tokens: { + stMATIC: '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4', + }, + sourceUrl: 'https://polygon.lido.fi/api/stats', + path: 'apr', + }, + MATICX: { + tokens: { + MATICX: '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6', + }, + sourceUrl: 'https://universe.staderlabs.com/polygon/apy', + path: 'value', + }, + wbETH: { + tokens: { + wbETH: '0xa2e3356610840701bdf5611a53974510ae27e2e1', + }, + sourceUrl: + 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', + path: 'data.0.rewardRate', + }, + }, + }, yearn: { vaultsEndpoint: 'https://#/', }, @@ -156,7 +271,12 @@ export const polygonNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(polygonNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(polygonNetworkData.chain.prismaId, tokenService), + new IbTokensAprService( + polygonNetworkData.aprConfig, + polygonNetworkData.chain.prismaId, + polygonNetworkData.chain.id, + tokenService, + ), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(polygonNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index e55ec12b3..d3c6acca0 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -106,6 +106,30 @@ const zkevmNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, + aprConfig: { + ovix: { + rpcUrl: 'https://zkevm-rpc.com', + tokens: { + USDT: { + yieldAddress: '0xad41c77d99e282267c1492cdefe528d7d5044253', + wrappedAddress: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', + }, + USDC: { + yieldAddress: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', + wrappedAddress: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', + }, + }, + }, + defaultHandlers: { + stETH: { + tokens: { + wstETH: '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9', + }, + sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + }, + }, + }, yearn: { vaultsEndpoint: 'https://#/', }, @@ -153,7 +177,12 @@ export const zkevmNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider(zkevmNetworkData.rpcUrl), poolAprServices: [ - new IbTokensAprService(zkevmNetworkData.chain.prismaId, tokenService), + new IbTokensAprService( + zkevmNetworkData.aprConfig, + zkevmNetworkData.chain.prismaId, + zkevmNetworkData.chain.id, + tokenService, + ), new WstethAprService(tokenService, zkevmNetworkData.lido!.wstEthContract), new PhantomStableAprService(), new BoostedPoolAprService(), diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts index 3b6f133c5..7eaff9f5c 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts @@ -1,50 +1,117 @@ -import { - aaveHandlers, - wrappedAaveTokensV2Mainnet, - wrappedAaveTokensV2Polygon, - wrappedAaveTokensV3Arbitrum, - wrappedAaveTokensV3Mainnet, - wrappedAaveTokensV3Polygon, -} from './sources/aave-apr-handler'; -import { ankrEthMainnet, ankrEthHandlers, ankrEthFantom } from './sources/ankr-eth-apr-handler'; -import { - defaultHandlers, - overnightDaiPlusOptimism, - overnightLpUsdcUsdPlusMainnet, - overnightUsdcUsdPlusMainnet, - overnightUsdPlusOptimism, - rETHMainnet, - swETHMainnet, - USDRMainnet, - wjAURAMainnet, -} from './sources/default-apr-handler'; -import { eulerHandlers, eulerTokensMainnet } from './sources/euler-apr-handler'; -import { gearboxHandlers, gearboxTokensMainnet } from './sources/gearbox-apr-handler'; -import { idleAprHandlers, wrapped4626IdleTokensMainnet } from './sources/idle-apr-handler'; -import { ovixHandlers, ovixWrappedTokensZkEvm } from './sources/ovix-apr-handler'; -import { reaperHandlers, reaperYieldTokensArbitrum } from './sources/reaper-apr-handler'; -import { tesseraHandlers, tesseraYieldTokensMainnet } from './sources/tessera-apr-handler'; -import { tDAIPolygon, tetuHandlers, tUSDCPolygon, tUSDTPolygon } from './sources/tetu-apr-handler'; -import { qETHMainnet } from './sources/tranchess-apr-handler'; - -const aprHandlers: AprHandler[] = [ - ...aaveHandlers, - ...ankrEthHandlers, - ...defaultHandlers, - ...eulerHandlers, - ...gearboxHandlers, - ...idleAprHandlers, - ...ovixHandlers, - ...reaperHandlers, - ...tesseraHandlers, - ...tetuHandlers, -]; +import { AaveAprHandler } from './sources/aave-apr-handler'; +import { AnkrAprHandler } from './sources/ankr-apr-handler'; +import { DefaultAprHandler } from './sources/default-apr-handler'; +import { EulerAprHandler } from './sources/euler-apr-handler'; +import { GearboxAprHandler } from './sources/gearbox-apr-handler'; +import { IdleAprHandler } from './sources/idle-apr-handler'; +import { OvixAprHandler } from './sources/ovix-apr-handler'; +import { TesseraAprHandler } from './sources/tessera-apr-handler'; +import { TetuAprHandler } from './sources/tetu-apr-handler'; +import { TranchessAprHandler } from './sources/tranchess-apr-handler'; +import { AprConfig } from '../../../../network/network-config-types'; export class BaseAprHandlers { private handlers: AprHandler[] = []; - constructor(networkPrismaId: string) { - this.handlers = aprHandlers.filter((handler) => handler.networkPrismaId === networkPrismaId); + constructor(aprConfig: AprConfig, networkPrismaId: string, networkChainId: number) { + this.handlers = this.buildAprHandlers(aprConfig, networkPrismaId, networkChainId); + } + + buildAprHandlers(aprConfig: AprConfig, networkPrismaId: string, networkChainId: number) { + const handlers: AprHandler[] = []; + if (aprConfig.aave) { + for (const config of Object.values(aprConfig.aave)) { + const { tokens, subgraphUrl } = config; + const aaveHandler = new AaveAprHandler({ + tokens, + subgraphUrl, + networkPrismaId, + }); + handlers.push(aaveHandler); + } + } + if (aprConfig.ankr) { + const { sourceUrl, tokens } = aprConfig.ankr; + const ankrHandler = new AnkrAprHandler({ + sourceUrl, + tokens, + networkPrismaId, + }); + handlers.push(ankrHandler); + } + if (aprConfig.euler) { + const { subgraphUrl, tokens } = aprConfig.euler; + const eulerHandler = new EulerAprHandler({ + subgraphUrl, + tokens, + networkPrismaId, + }); + handlers.push(eulerHandler); + } + if (aprConfig.gearbox) { + const { sourceUrl, tokens } = aprConfig.gearbox; + const gearboxHandler = new GearboxAprHandler({ + sourceUrl, + tokens, + networkPrismaId, + }); + handlers.push(gearboxHandler); + } + if (aprConfig.idle) { + const { sourceUrl, tokens, authorizationHeader } = aprConfig.idle; + const idleHandler = new IdleAprHandler({ + sourceUrl, + tokens, + authorizationHeader: 'Bearer ' + authorizationHeader, + networkPrismaId, + }); + handlers.push(idleHandler); + } + if (aprConfig.ovix) { + const { rpcUrl, tokens } = aprConfig.ovix; + const ovixHandler = new OvixAprHandler({ + rpcUrl, + tokens, + networkPrismaId, + networkChainId, + }); + handlers.push(ovixHandler); + } + if (aprConfig.tessera) { + const { rpcUrl, tokens } = aprConfig.tessera; + const tesseraHandler = new TesseraAprHandler({ + rpcUrl, + tokens, + networkPrismaId, + networkChainId, + }); + handlers.push(tesseraHandler); + } + if (aprConfig.tetu) { + const { sourceUrl, tokens } = aprConfig.tetu; + const tetuHandler = new TetuAprHandler({ + sourceUrl, + tokens, + networkPrismaId, + }); + handlers.push(tetuHandler); + } + if (aprConfig.tranchess) { + const { sourceUrl, tokens } = aprConfig.tranchess; + const tranchessHandler = new TranchessAprHandler({ + sourceUrl, + tokens, + networkPrismaId, + }); + handlers.push(tranchessHandler); + } + if (aprConfig.defaultHandlers) { + for (const handlerConfig of Object.values(aprConfig.defaultHandlers)) { + const handler = new DefaultAprHandler({ ...handlerConfig, networkPrismaId }); + handlers.push(handler); + } + } + return handlers; } async fetchAprsFromAllHandlers(): Promise { @@ -76,30 +143,30 @@ export type TokenApr = { group?: string; }; -export const wrappedBoostedTokens = [ - ...Object.values(wrappedAaveTokensV2Mainnet), - ...Object.values(wrappedAaveTokensV2Polygon), - ...Object.values(wrappedAaveTokensV3Mainnet), - ...Object.values(wrappedAaveTokensV3Polygon), - ...Object.values(wrappedAaveTokensV3Arbitrum), - ankrEthMainnet, - ankrEthFantom, - rETHMainnet, - USDRMainnet, - swETHMainnet, - wjAURAMainnet, - ...Object.values(eulerTokensMainnet), - ...Object.values(gearboxTokensMainnet), - ...Object.values(wrapped4626IdleTokensMainnet), - ...Object.values(ovixWrappedTokensZkEvm), - ...Object.values(reaperYieldTokensArbitrum), - ...Object.values(tesseraYieldTokensMainnet), - tUSDTPolygon, - tUSDCPolygon, - tDAIPolygon, - qETHMainnet, - overnightLpUsdcUsdPlusMainnet, - overnightUsdcUsdPlusMainnet, - overnightUsdPlusOptimism, - overnightDaiPlusOptimism, -]; +// export const wrappedBoostedTokens = [ +// ...Object.values(wrappedAaveTokensV2Mainnet), +// ...Object.values(wrappedAaveTokensV2Polygon), +// ...Object.values(wrappedAaveTokensV3Mainnet), +// ...Object.values(wrappedAaveTokensV3Polygon), +// ...Object.values(wrappedAaveTokensV3Arbitrum), +// ankrEthMainnet, +// ankrEthFantom, +// rETHMainnet, +// USDRMainnet, +// swETHMainnet, +// wjAURAMainnet, +// ...Object.values(eulerTokensMainnet), +// ...Object.values(gearboxTokensMainnet), +// ...Object.values(wrapped4626IdleTokensMainnet), +// ...Object.values(ovixWrappedTokensZkEvm), +// ...Object.values(reaperYieldTokensArbitrum), +// ...Object.values(tesseraYieldTokensMainnet), +// tUSDTPolygon, +// tUSDCPolygon, +// tDAIPolygon, +// qETHMainnet, +// overnightLpUsdcUsdPlusMainnet, +// overnightUsdcUsdPlusMainnet, +// overnightUsdPlusOptimism, +// overnightDaiPlusOptimism, +// ]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts index 93b6e515e..6845183e7 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts @@ -1,10 +1,16 @@ import axios from 'axios'; import { AprHandler } from '../base-apr-handlers'; -class AaveAprHandler implements AprHandler { - wrappedTokens: { [key: string]: string }; - aaveTokens: { [key: string]: string }; - underlyingTokens: { [key: string]: string }; +export class AaveAprHandler implements AprHandler { + tokens: { + [assetName: string]: { + underlyingAssetAddress: string; + aTokenAddress: string; + wrappedTokens: { + [tokenName: string]: string; + }; + }; + }; subgraphUrl: string; networkPrismaId: string; @@ -25,11 +31,9 @@ class AaveAprHandler implements AprHandler { }`; constructor(aprHandlerConfig: AaveAprHandlerConfig) { - this.wrappedTokens = aprHandlerConfig.wrappedTokens; - this.aaveTokens = aprHandlerConfig.aaveTokens; - this.underlyingTokens = aprHandlerConfig.underlyingTokens; + this.tokens = aprHandlerConfig.tokens; this.subgraphUrl = aprHandlerConfig.subgraphUrl; - this.networkPrismaId = aprHandlerConfig.network; + this.networkPrismaId = aprHandlerConfig.networkPrismaId; } async getAprs() { @@ -38,8 +42,10 @@ class AaveAprHandler implements AprHandler { operationName: 'getReserves', query: this.query, variables: { - aTokens: Object.values(this.aaveTokens), - underlyingAssets: Object.values(this.underlyingTokens), + aTokens: Object.values(this.tokens).map(({ aTokenAddress }) => aTokenAddress), + underlyingAssets: Object.values(this.tokens).map( + ({ underlyingAssetAddress }) => underlyingAssetAddress, + ), }, }; const { data } = await axios({ @@ -59,16 +65,13 @@ class AaveAprHandler implements AprHandler { Number(r.liquidityRate.slice(0, 27)) / 1e27, ]), ); - const aprEntries = Object.fromEntries( - Object.values(this.underlyingTokens) - //Removing undefined aprs - .filter(([, address]) => !!aprsByUnderlyingAddress[address]) - //Mapping aprs by wrapped instead of underlying addresses - .map(([underlyingTokenName, underlyingTokenAddress]) => [ - this.wrappedTokens['wa' + underlyingTokenName] as string, - aprsByUnderlyingAddress[underlyingTokenAddress], - ]), - ); + const aprEntries = Object.values(this.tokens) + .map(({ wrappedTokens, underlyingAssetAddress }) => { + const apr = aprsByUnderlyingAddress[underlyingAssetAddress]; + return Object.values(wrappedTokens).map((wrappedTokenAddress) => ({ [wrappedTokenAddress]: apr })); + }) + .flat() + .reduce((acc, curr) => ({ ...acc, ...curr }), {}); return aprEntries; } catch (e) { console.error(`Failed to fetch Aave APR in subgraph ${this.subgraphUrl}:`, e); @@ -83,24 +86,12 @@ export const wrappedAaveTokensV2Mainnet = { waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', }; -const aaveTokensV2Mainnet = { - aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', - aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c', - aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3', -}; - export const wrappedAaveTokensV2Polygon = { waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', }; -const aaveTokensV2Polygon = { - aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', - aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', - aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', -}; - export const wrappedAaveTokensV3Mainnet = { waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', @@ -108,13 +99,6 @@ export const wrappedAaveTokensV3Mainnet = { waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', }; -const aaveTokensV3Mainnet = { - aUSDT: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', - aUSDC: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', - aDAI: '0x018008bfb33d285247a21d44e50697654f754e63', - aWETH: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8', -}; - export const wrappedAaveTokensV3Polygon = { waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', @@ -123,14 +107,6 @@ export const wrappedAaveTokensV3Polygon = { waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', }; -const aaveTokensV3Polygon = { - aMATIC: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', - aUSDT: '0x60d55f02a771d515e077c9c2403a1ef324885cec', - aUSDC: '0x1a13f4ca1d028320a707d99520abfefca3998b7f', - aDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', - aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', -}; - export const wrappedAaveTokensV3Arbitrum = { waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', @@ -138,35 +114,6 @@ export const wrappedAaveTokensV3Arbitrum = { waWETH: '0x18c100415988bef4354effad1188d1c22041b046', }; -const aaveTokensV3Arbitrum = { - aUSDT: '0x6ab707aca953edaefbc4fd23ba73294241490620', - aUSDC: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', - aDAI: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', - aWETH: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', -}; - -const underlyingTokensMainnet = { - USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', - USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', - WETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', -}; - -const underlyingTokensPolygon = { - MATIC: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', - USDT: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', - USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', - DAI: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', - WETH: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619', -}; - -const underlyingTokensArbitrum = { - USDT: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - USDC: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - DAI: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', - WETH: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', -}; - interface ReserveResponse { data: { reserves: [ @@ -179,54 +126,7 @@ interface ReserveResponse { } type AaveAprHandlerConfig = { - wrappedTokens: { [key: string]: string }; - aaveTokens: { [key: string]: string }; - underlyingTokens: { [key: string]: string }; + tokens: {}; subgraphUrl: string; - network: string; + networkPrismaId: string; }; - -const aaveV2MainnetAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV2Mainnet, - aaveTokens: aaveTokensV2Mainnet, - underlyingTokens: underlyingTokensMainnet, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2', - network: 'MAINNET', -}); - -const aaveV2PolygonAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV2Polygon, - aaveTokens: aaveTokensV2Polygon, - underlyingTokens: underlyingTokensPolygon, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic', - network: 'POLYGON', -}); -const aaveV3MainnetAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV3Mainnet, - aaveTokens: aaveTokensV3Mainnet, - underlyingTokens: underlyingTokensMainnet, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3', - network: 'MAINNET', -}); -const aaveV3PolygonAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV3Polygon, - aaveTokens: aaveTokensV3Polygon, - underlyingTokens: underlyingTokensPolygon, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-polygon', - network: 'POLYGON', -}); -const aaveV3ArbitrumAprHandler = new AaveAprHandler({ - wrappedTokens: wrappedAaveTokensV3Arbitrum, - aaveTokens: aaveTokensV3Arbitrum, - underlyingTokens: underlyingTokensArbitrum, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum', - network: 'ARBITRUM', -}); - -export const aaveHandlers = [ - aaveV2MainnetAprHandler, - aaveV2PolygonAprHandler, - aaveV3MainnetAprHandler, - aaveV3PolygonAprHandler, - aaveV3ArbitrumAprHandler, -]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-apr-handler.ts new file mode 100644 index 000000000..bb28bb264 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-apr-handler.ts @@ -0,0 +1,51 @@ +import axios from 'axios'; +import { AprHandler } from '../base-apr-handlers'; + +export class AnkrAprHandler implements AprHandler { + tokens: { + [underlyingAssetName: string]: { + address: string; + serviceName: string; + }; + }; + networkPrismaId: string; + url: string; + readonly group = 'ANKR'; + + constructor(aprHandlerConfig: AnkrAprHandlerConfig) { + this.tokens = aprHandlerConfig.tokens; + this.networkPrismaId = aprHandlerConfig.networkPrismaId; + this.url = aprHandlerConfig.sourceUrl; + } + + async getAprs() { + try { + const { data } = await axios.get(this.url); + const services = (data as { services: { serviceName: string; apy: string }[] }).services; + const aprs = Object.fromEntries( + Object.values(this.tokens).map(({ address, serviceName }) => { + const service = services.find((service) => service.serviceName === serviceName); + if (!service) { + return [address, 0]; + } + return [address, parseFloat(service.apy) / 1e2]; + }), + ); + return aprs; + } catch (error) { + console.error('Failed to fetch Ankr APR:', error); + return {}; + } + } +} + +type AnkrAprHandlerConfig = { + tokens: { + [underlyingAssetName: string]: { + address: string; + serviceName: string; + }; + }; + networkPrismaId: string; + sourceUrl: string; +}; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-eth-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-eth-apr-handler.ts deleted file mode 100644 index 9f01bcf0a..000000000 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-eth-apr-handler.ts +++ /dev/null @@ -1,64 +0,0 @@ -import axios from 'axios'; -import { AprHandler } from '../base-apr-handlers'; - -class AnkrAprHandler implements AprHandler { - serviceName: string; - tokenAddress: string; - networkPrismaId: string; - readonly url: string = 'https://api.staking.ankr.com/v1alpha/metrics'; - readonly group = 'ANKR'; - - constructor(aprHandlerConfig: AnkrAprHandlerConfig) { - this.serviceName = aprHandlerConfig.serviceName; - this.tokenAddress = aprHandlerConfig.tokenAddress; - this.networkPrismaId = aprHandlerConfig.network; - } - - async getAprs() { - try { - const { data } = await axios.get(this.url); - const json = data as { services: { serviceName: string; apy: string }[] }; - const service = json.services.find((service) => service.serviceName === this.serviceName); - if (!service) { - return {}; - } - const scaledValue = parseFloat(service.apy) / 1e2; - return { - [this.tokenAddress]: scaledValue, - }; - } catch (error) { - console.error('Failed to fetch Ankr APR:', error); - return {}; - } - } -} - -export const ankrEthMainnet = '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb'; -export const ankrEthFantom = '0x12d8ce035c5de3ce39b1fdd4c1d5a745eaba3b8c'; - -export const ankrFtmFantom = '0xcfc785741dc0e98ad4c9f6394bb9d43cd1ef5179'; - -type AnkrAprHandlerConfig = { - serviceName: string; - tokenAddress: string; - network: string; -}; - -const ankrEthMainnetAprHandler = new AnkrAprHandler({ - serviceName: 'eth', - tokenAddress: ankrEthMainnet, - network: 'MAINNET', -}); - -const ankrEthFantomAprHandler = new AnkrAprHandler({ - serviceName: 'eth', - tokenAddress: ankrEthFantom, - network: 'FANTOM', -}); - -const ankrFtmFantomAprHandler = new AnkrAprHandler({ - serviceName: 'ftm', - tokenAddress: ankrFtmFantom, - network: 'FANTOM', -}); -export const ankrEthHandlers = [ankrEthMainnetAprHandler, ankrEthFantomAprHandler, ankrFtmFantomAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts index 50b5e1c95..9cc9b26b7 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts @@ -2,8 +2,10 @@ import axios from 'axios'; import { AprHandler } from '../base-apr-handlers'; -class DefaultAprHandler implements AprHandler { - tokens: string[]; +export class DefaultAprHandler implements AprHandler { + tokens: { + [tokenName: string]: string; + }; url: string; path: string; scale: number; @@ -12,8 +14,8 @@ class DefaultAprHandler implements AprHandler { constructor(aprHandlerConfig: DefaultAprHandlerConfig) { this.tokens = aprHandlerConfig.tokens; - this.url = aprHandlerConfig.url; - this.networkPrismaId = aprHandlerConfig.network; + this.url = aprHandlerConfig.sourceUrl; + this.networkPrismaId = aprHandlerConfig.networkPrismaId; this.path = aprHandlerConfig.path ?? ''; this.scale = aprHandlerConfig.scale ?? 100; this.group = aprHandlerConfig.group ?? 'DEFAULT'; @@ -25,7 +27,7 @@ class DefaultAprHandler implements AprHandler { const value = this.path === '' ? data : this.getValueFromPath(data, this.path); const scaledValue = parseFloat(value) / this.scale; - return this.tokens.reduce((acc, token) => { + return Object.values(this.tokens).reduce((acc, token) => { acc[token] = scaledValue; return acc; }, {} as { [key: string]: number }); @@ -49,181 +51,12 @@ class DefaultAprHandler implements AprHandler { } export type DefaultAprHandlerConfig = { - tokens: string[]; - url: string; - network: string; + tokens: { + [tokenName: string]: string; + }; + sourceUrl: string; + networkPrismaId: string; scale?: number; path?: string; group?: string; }; - -export const vETHMainnet = '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f'; -const wstETHGnosis = '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6'; -const wstETHZkEVM = '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9'; -const stETHMainnet = '0xae7ab96520de3a18e5e111b5eaab095312d7fe84'; -const wstETHMainnet = '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0'; -const wstETHPolygon = '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd'; -const wstETHArbitrum = '0x5979d7b546e38e414f7e9822514be443a4800529'; -const wstETHOptimism = '0x1f32b1c2345538c0c6f582fcb0227;39c4a194ebb'; -const stMATICPolygon = '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4'; -export const cbETHMainnet = '0xbe9895146f7af43049ca1c1ae358b0541ea49704'; - -const sfrxETHMainnet = '0xac3e018457b222d93114458476f3e3416abbe38f'; -export const rETHMainnet = '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593'; -export const USDRMainnet = '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b'; -const MATICXPolygon = '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6'; -const wbETHMainnet = '0xa2e3356610840701bdf5611a53974510ae27e2e1'; -export const swETHMainnet = '0xf951e335afb289353dc249e82926178eac7ded78'; -export const wjAURAMainnet = '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f'; -export const overnightLpUsdcUsdPlusMainnet = '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425'; -export const overnightUsdcUsdPlusMainnet = '0x6933ec1ca55c06a894107860c92acdfd2dd8512f'; -export const overnightUsdPlusOptimism = '0xa348700745d249c3b49d2c2acac9a5ae8155f826'; -export const overnightDaiPlusOptimism = '0x0b8f31480249cc717081928b8af733f45f6915bb'; - -const vETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [vETHMainnet], - url: 'https://apy.liebi.com/veth', - path: 'veth', - network: 'MAINNET', -}); -const stETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [stETHMainnet, wstETHMainnet], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'MAINNET', -}); -const stETHPolygonAprHandler = new DefaultAprHandler({ - tokens: [wstETHPolygon], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'POLYGON', -}); -const stETHZkEVMAprHandler = new DefaultAprHandler({ - tokens: [wstETHZkEVM], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'ZKEVM', -}); -const stETHGnosisAprHandler = new DefaultAprHandler({ - tokens: [wstETHGnosis], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'GNOSIS', -}); -const stETHArbitrumAprHandler = new DefaultAprHandler({ - tokens: [wstETHArbitrum], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'ARBITRUM', -}); - -const stETHOptimismAprHandler = new DefaultAprHandler({ - tokens: [wstETHOptimism], - url: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', - network: 'OPTIMISM', -}); - -const stMaticPolygonAprHandler = new DefaultAprHandler({ - tokens: [stMATICPolygon], - url: 'https://polygon.lido.fi/api/stats', - path: 'apr', - network: 'POLYGON', -}); -const cbEthMainnetAprHandler = new DefaultAprHandler({ - tokens: [cbETHMainnet], - url: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', - path: 'apy', - scale: 1, - network: 'MAINNET', -}); -const sfrxEthMainnetAprHandler = new DefaultAprHandler({ - tokens: [sfrxETHMainnet], - url: 'https://api.frax.finance/v2/frxeth/summary/latest', - path: 'sfrxethApr', - network: 'MAINNET', -}); -const rETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [rETHMainnet], - url: 'https://drop-api.stafi.io/reth/v1/poolData', - path: 'data.stakeApr', - network: 'MAINNET', -}); -const USDRMainnetAprHandler = new DefaultAprHandler({ - tokens: [USDRMainnet], - url: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', - path: 'usdr', - network: 'MAINNET', -}); - -const MATICXPolygonAprHandler = new DefaultAprHandler({ - tokens: [MATICXPolygon], - url: 'https://universe.staderlabs.com/polygon/apy', - path: 'value', - network: 'POLYGON', -}); -const wbETHPolygonAprHandler = new DefaultAprHandler({ - tokens: [wbETHMainnet], - url: 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', - path: 'data.0.rewardRate', - scale: 1, - network: 'POLYGON', -}); - -const swETHMainnetAprHandler = new DefaultAprHandler({ - tokens: [swETHMainnet], - url: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', - network: 'MAINNET', -}); -const wjAURAMainnetAprHandler = new DefaultAprHandler({ - tokens: [wjAURAMainnet], - url: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', - path: 'wjauraApy', - network: 'MAINNET', -}); - -const overnightMainnetAprHandler = new DefaultAprHandler({ - tokens: [overnightLpUsdcUsdPlusMainnet, overnightUsdcUsdPlusMainnet], - url: 'https://app.overnight.fi/api/balancer/week/apr', - network: 'MAINNET', - scale: 1, - group: 'OVERNIGHT', -}); - -const overnightUsdPlusOptimismAprHandler = new DefaultAprHandler({ - tokens: [overnightUsdPlusOptimism], - url: 'https://api.overnight.fi/optimism/usd+/fin-data/avg-apr/week', - path: 'value', - network: 'OPTIMISM', - group: 'OVERNIGHT', -}); - -const overnightDaiPlusOptimismAprHandler = new DefaultAprHandler({ - tokens: [overnightDaiPlusOptimism], - url: 'https://api.overnight.fi/optimism/dai+/fin-data/avg-apr/week', - path: 'value', - network: 'OPTIMISM', - group: 'OVERNIGHT', -}); - -export const defaultHandlers = [ - vETHMainnetAprHandler, - stETHMainnetAprHandler, - stETHPolygonAprHandler, - stETHZkEVMAprHandler, - stETHGnosisAprHandler, - stETHArbitrumAprHandler, - stETHOptimismAprHandler, - stMaticPolygonAprHandler, - cbEthMainnetAprHandler, - sfrxEthMainnetAprHandler, - rETHMainnetAprHandler, - USDRMainnetAprHandler, - MATICXPolygonAprHandler, - wbETHPolygonAprHandler, - swETHMainnetAprHandler, - wjAURAMainnetAprHandler, - overnightMainnetAprHandler, - overnightUsdPlusOptimismAprHandler, - overnightDaiPlusOptimismAprHandler, -]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts index cafb7b3f1..3e90dc9e4 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts @@ -1,7 +1,7 @@ import axios from 'axios'; import { AprHandler } from '../base-apr-handlers'; -class EulerAprHandler implements AprHandler { +export class EulerAprHandler implements AprHandler { tokens: { [key: string]: string }; subgraphUrl: string; networkPrismaId: string; @@ -23,7 +23,7 @@ class EulerAprHandler implements AprHandler { constructor(aprHandlerConfig: EulerAprHandlerConfig) { this.tokens = aprHandlerConfig.tokens; this.subgraphUrl = aprHandlerConfig.subgraphUrl; - this.networkPrismaId = aprHandlerConfig.network; + this.networkPrismaId = aprHandlerConfig.networkPrismaId; } async getAprs() { @@ -55,13 +55,6 @@ class EulerAprHandler implements AprHandler { } } -export const eulerTokensMainnet = { - eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', - eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', - eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', - eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', -}; - interface EulerResponse { data: { assets: [ @@ -76,13 +69,5 @@ interface EulerResponse { type EulerAprHandlerConfig = { tokens: { [key: string]: string }; subgraphUrl: string; - network: string; + networkPrismaId: string; }; - -const eulerMainnetAprHandler = new EulerAprHandler({ - tokens: eulerTokensMainnet, - subgraphUrl: 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet', - network: 'MAINNET', -}); - -export const eulerHandlers = [eulerMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts index 803a2257f..f3cf9b72b 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { AprHandler } from '../base-apr-handlers'; -class GearboxAprHandler implements AprHandler { +export class GearboxAprHandler implements AprHandler { url: string; tokens: { [key: string]: string }; networkPrismaId: string; @@ -10,8 +10,8 @@ class GearboxAprHandler implements AprHandler { constructor(aprHandlerConfig: GearboxAprHandlerConfig) { this.tokens = aprHandlerConfig.tokens; - this.url = aprHandlerConfig.url; - this.networkPrismaId = aprHandlerConfig.network; + this.url = aprHandlerConfig.sourceUrl; + this.networkPrismaId = aprHandlerConfig.networkPrismaId; } async getAprs() { @@ -34,19 +34,6 @@ class GearboxAprHandler implements AprHandler { type GearboxAprHandlerConfig = { tokens: { [key: string]: string }; - url: string; - network: string; -}; - -export const gearboxTokensMainnet = { - dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', - dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', + sourceUrl: string; + networkPrismaId: string; }; - -const gearboxMainnetAprHandler = new GearboxAprHandler({ - tokens: gearboxTokensMainnet, - url: 'https://mainnet.gearbox.foundation/api/pools', - network: 'MAINNET', -}); - -export const gearboxHandlers = [gearboxMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts index 382cb7c2d..d2a23b59d 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts @@ -2,38 +2,38 @@ import axios from 'axios'; import { AprHandler } from '../base-apr-handlers'; -class IdleAprHandler implements AprHandler { - wrappedIdleTokens: { [key: string]: string }; - idleTokens: { [key: string]: string }; - baseIdleApiUrl: string; +export class IdleAprHandler implements AprHandler { + tokens: { + [tokenName: string]: { + address: string; + wrapped4626Address: string; + }; + }; + url: string; authorizationHeader: string; networkPrismaId: string; readonly group = 'IDLE'; constructor(aprHandlerConfig: IdleAprHandlerConfig) { - this.wrappedIdleTokens = aprHandlerConfig.wrappedIdleTokens; - this.idleTokens = aprHandlerConfig.idleTokens; - this.baseIdleApiUrl = aprHandlerConfig.baseIdleApiUrl; + this.tokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.sourceUrl; this.authorizationHeader = aprHandlerConfig.authorizationHeader; - this.networkPrismaId = aprHandlerConfig.network; + this.networkPrismaId = aprHandlerConfig.networkPrismaId; } async getAprs() { try { - const aprPromises = Object.entries(this.idleTokens).map(async ([tokenName, idleTokenAddress]) => { - const { data } = await axios.get( - [this.baseIdleApiUrl, idleTokenAddress, '?isRisk=false&order=desc&limit=1'].join(''), - { - headers: { - Authorization: this.authorizationHeader, - }, + const aprPromises = Object.values(this.tokens).map(async ({ address, wrapped4626Address }) => { + const { data } = await axios.get([this.url, address, '?isRisk=false&order=desc&limit=1'].join(''), { + headers: { + Authorization: this.authorizationHeader, }, - ); + }); const [json] = data as { idleRate: string }[]; const value = Number(json.idleRate) / 1e20; - return [this.wrappedIdleTokens[tokenName], value]; + return [wrapped4626Address, value]; }); - const res = Array(Object.keys(this.idleTokens).length); + const res = Array(Object.keys(this.tokens).length); for (const [index, aprPromise] of aprPromises.entries()) { res[index] = await aprPromise; } @@ -45,33 +45,14 @@ class IdleAprHandler implements AprHandler { } } -export const wrapped4626IdleTokensMainnet = { - idleDAI: '0x0c80f31b840c6564e6c5e18f386fad96b63514ca', - idleUSDC: '0xc3da79e0de523eef7ac1e4ca9abfe3aac9973133', - idleUSDT: '0x544897a3b944fdeb1f94a0ed973ea31a80ae18e1', -}; - -const idleTokensMainnet = { - idleDAI: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', - idleUSDC: '0xdc7777c771a6e4b3a82830781bdde4dbc78f320e', - idleUSDT: '0xfa3afc9a194babd56e743fa3b7aa2ccbed3eaaad', -}; - type IdleAprHandlerConfig = { - wrappedIdleTokens: { [key: string]: string }; - idleTokens: { [key: string]: string }; - baseIdleApiUrl: string; + tokens: { + [tokenName: string]: { + address: string; + wrapped4626Address: string; + }; + }; + sourceUrl: string; authorizationHeader: string; - network: string; + networkPrismaId: string; }; - -const idleMainnetAprHandler = new IdleAprHandler({ - wrappedIdleTokens: wrapped4626IdleTokensMainnet, - idleTokens: idleTokensMainnet, - baseIdleApiUrl: 'https://api.idle.finance/junior-rates/', - authorizationHeader: - 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M', - network: 'MAINNET', -}); - -export const idleAprHandlers = [idleMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/overnight-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/overnight-apr-handler.ts deleted file mode 100644 index 956fc2bad..000000000 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/overnight-apr-handler.ts +++ /dev/null @@ -1,50 +0,0 @@ -import axios from 'axios'; - -import { AprHandler } from '../base-apr-handlers'; - -class OvernightAprHandler implements AprHandler { - overnightTokens: { [key: string]: string }; - url: string; - networkPrismaId: string; - readonly group = 'OVERNIGHT'; - - constructor(aprHandlerConfig: OvernightAprHandlerConfig) { - this.overnightTokens = aprHandlerConfig.tokens; - this.url = aprHandlerConfig.url; - this.networkPrismaId = aprHandlerConfig.network; - } - - async getAprs() { - try { - const { data } = await axios.get(this.url); - const rate = data as number; - - return Object.values(this.overnightTokens).reduce((acc, token) => { - acc[token] = rate; - return acc; - }, {} as { [key: string]: number }); - } catch (error) { - console.error(`Failed to fetch Overnight APRs in url:`, error); - return {}; - } - } -} - -export const overnightTokensMainnet = { - lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', //lpUsdcUsdPlus - UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f', // UsdcUsdPlus -}; - -type OvernightAprHandlerConfig = { - tokens: { [key: string]: string }; - url: string; - network: string; -}; - -const overnightMainnetAprHandler = new OvernightAprHandler({ - tokens: overnightTokensMainnet, - url: 'https://app.overnight.fi/api/balancer/week/apr', - network: 'MAINNET', -}); - -export const overnightHandlers = [overnightMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts index 0ffbc4c25..73a033cdf 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts @@ -4,38 +4,35 @@ import { JsonRpcProvider } from '@ethersproject/providers'; import { AprHandler } from '../base-apr-handlers'; -class OvixAprHandler implements AprHandler { +export class OvixAprHandler implements AprHandler { networkPrismaId: string; provider: JsonRpcProvider; - yieldTokens: { [key: string]: `0x${string}` }; - wrappedTokens: { [key: string]: `0x${string}` }; + tokens: { + [tokenName: string]: { + yieldAddress: string; + wrappedAddress: string; + }; + }; readonly group = 'OVIX'; constructor(aprHandlerConfig: OvixAprHandlerConfig) { this.networkPrismaId = aprHandlerConfig.networkPrismaId; this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); - this.yieldTokens = aprHandlerConfig.yieldTokens; - this.wrappedTokens = aprHandlerConfig.wrappedTokens; + this.tokens = aprHandlerConfig.tokens; } async getAprs() { try { - const calls = Object.keys(this.yieldTokens).map(async (tokenName) => { - const contract = new Contract(this.yieldTokens[tokenName], abi, this.provider); - return contract.borrowRatePerTimestamp(); + const aprEntries = Object.values(this.tokens).map(async ({ yieldAddress, wrappedAddress }) => { + const contract = new Contract(yieldAddress, abi, this.provider); + const borrowRate = await contract.borrowRatePerTimestamp(); + return [ + wrappedAddress, + Math.pow(1 + (borrowRate as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1, + ]; }); - const borrowRates = Array(Object.keys(this.yieldTokens).length); - for (const [index, aprPromise] of calls.entries()) { - borrowRates[index] = await aprPromise; - } - - const aprs = Object.keys(this.wrappedTokens).map((tokenName, i) => [ - this.wrappedTokens[tokenName], - Math.pow(1 + (borrowRates[i] as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1, - ]); - - return Object.fromEntries(aprs); + return Object.fromEntries(await Promise.all(aprEntries)); } catch (error) { console.error('Failed to fetch Ovix APR:', error); return {}; @@ -47,28 +44,10 @@ type OvixAprHandlerConfig = { networkPrismaId: string; networkChainId: number; rpcUrl: string; - yieldTokens: { [key: string]: `0x${string}` }; - wrappedTokens: { - [key: string]: `0x${string}`; + tokens: { + [tokenName: string]: { + yieldAddress: string; + wrappedAddress: string; + }; }; }; - -const ovixYieldTokensZkEvm = { - USDT: '0xad41c77d99e282267c1492cdefe528d7d5044253', - USDC: '0x68d9baa40394da2e2c1ca05d30bf33f52823ee7b', -} as { [key: string]: `0x${string}` }; - -export const ovixWrappedTokensZkEvm = { - USDT: '0x550d3bb1f77f97e4debb45d4f817d7b9f9a1affb', - USDC: '0x3a6789fc7c05a83cfdff5d2f9428ad9868b4ff85', -} as { [key: string]: `0x${string}` }; - -const ovixZkEVMAprHandler = new OvixAprHandler({ - networkPrismaId: 'ZKEVM', - networkChainId: 1101, - rpcUrl: 'https://zkevm-rpc.com', - yieldTokens: ovixYieldTokensZkEvm, - wrappedTokens: ovixWrappedTokensZkEvm, -}); - -export const ovixHandlers = [ovixZkEVMAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts index a7acdf999..400177e14 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts @@ -4,38 +4,42 @@ import { JsonRpcProvider } from '@ethersproject/providers'; import { AprHandler } from '../base-apr-handlers'; -class TesseraAprHandler implements AprHandler { +export class TesseraAprHandler implements AprHandler { networkPrismaId: string; provider: JsonRpcProvider; - yieldTokens: { [key: string]: `0x${string}` }; - stakingContractAddress: `0x${string}`; + tokens: { + [tokenName: string]: { + tesseraPoolAddress: string; + tokenAddress: string; + }; + }; readonly group = 'TESSERA'; constructor(aprHandlerConfig: TesseraAprHandlerConfig) { this.networkPrismaId = aprHandlerConfig.networkPrismaId; this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); - this.yieldTokens = aprHandlerConfig.yieldTokens; - this.stakingContractAddress = aprHandlerConfig.contractAddress; + this.tokens = aprHandlerConfig.tokens; } async getAprs() { try { - let apr = 0; - try { - const contract = new Contract(this.stakingContractAddress, abi, this.provider); - const poolsUI = await contract.getPoolsUI(); - - const pool = poolsUI[0]; - const staked = BigInt(pool.stakedAmount); - const reward = BigInt(pool.currentTimeRange.rewardsPerHour) * BigInt(24 * 365); - apr = Number(reward.toString()) / Number(staked.toString()); - } catch (error) { - console.error('Failed to fetch Tessera Ape Coin APR:', error); + let aprEntries = []; + for (const { tesseraPoolAddress, tokenAddress } of Object.values(this.tokens)) { + try { + const contract = new Contract(tesseraPoolAddress, abi, this.provider); + const poolsUI = await contract.getPoolsUI(); + + const pool = poolsUI[0]; + const staked = BigInt(pool.stakedAmount); + const reward = BigInt(pool.currentTimeRange.rewardsPerHour) * BigInt(24 * 365); + const apr = Number(reward.toString()) / Number(staked.toString()); + aprEntries.push([tokenAddress, apr]); + } catch (error) { + console.error('Failed to fetch Tessera Ape Coin APR:', error); + aprEntries.push([tokenAddress, 0]); + } } - - return { - [this.yieldTokens.sApe]: apr, - }; + return Object.fromEntries(aprEntries); } catch (error) { console.error('Failed to fetch Tessera APR:', error); return {}; @@ -47,20 +51,10 @@ type TesseraAprHandlerConfig = { networkPrismaId: string; networkChainId: number; rpcUrl: string; - yieldTokens: { [key: string]: `0x${string}` }; - contractAddress: `0x${string}`; + tokens: { + [tokenName: string]: { + tesseraPoolAddress: string; + tokenAddress: string; + }; + }; }; - -export const tesseraYieldTokensMainnet = { - sApe: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', -} as { [key: string]: `0x${string}` }; - -const tesseraMainnetAprHandler = new TesseraAprHandler({ - networkPrismaId: 'MAINNET', - networkChainId: 1, - rpcUrl: 'https://rpc.ankr.com/eth', - yieldTokens: tesseraYieldTokensMainnet, - contractAddress: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9' /*ApeCoinStaking*/, -}); - -export const tesseraHandlers = [tesseraMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts index 9fd2c433d..c1bd98762 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts @@ -2,28 +2,27 @@ import axios from 'axios'; import { AprHandler } from '../base-apr-handlers'; -class TetuAprHandler implements AprHandler { +export class TetuAprHandler implements AprHandler { networkPrismaId: string; - baseUrl: string; - networkName: string; - tetuTokens: string[]; + sourceUrl: string; + tokens: { + [tokenName: string]: string; + }; readonly group = 'TETU'; constructor(aprHandlerConfig: TetuAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.network; - this.baseUrl = aprHandlerConfig.baseUrl; - this.networkName = aprHandlerConfig.networkName; - this.tetuTokens = aprHandlerConfig.tetuTokens; + this.networkPrismaId = aprHandlerConfig.networkPrismaId; + this.sourceUrl = aprHandlerConfig.sourceUrl; + this.tokens = aprHandlerConfig.tokens; } async getAprs() { try { - const { data } = await axios.get(`${this.baseUrl}?network=${this.networkName}`); + const { data } = await axios.get(this.sourceUrl); const json = data as { vault: string; apr: number }[]; const aprs = json - .filter(({ vault }) => this.tetuTokens.includes(vault.toLowerCase())) + .filter(({ vault }) => Object.values(this.tokens).includes(vault.toLowerCase())) .map((t) => [t.vault, t.apr / 100]); - return Object.fromEntries(aprs); } catch (error) { console.error('Failed to fetch Tetu APR:', error); @@ -33,21 +32,9 @@ class TetuAprHandler implements AprHandler { } type TetuAprHandlerConfig = { - network: string; - baseUrl: string; - networkName: string; - tetuTokens: string[]; + networkPrismaId: string; + sourceUrl: string; + tokens: { + [tokenName: string]: string; + }; }; - -export const tUSDCPolygon = '0x113f3d54c31ebc71510fd664c8303b34fbc2b355'; -export const tUSDTPolygon = '0x236975da9f0761e9cf3c2b0f705d705e22829886'; -export const tDAIPolygon = '0xace2ac58e1e5a7bfe274916c4d82914d490ed4a5'; -const tetuStQIPolygon = '0x4cd44ced63d9a6fef595f6ad3f7ced13fceac768'; - -const tetuPolygonAprHandler = new TetuAprHandler({ - network: 'POLYGON', - baseUrl: 'https://api.tetu.io/api/v1/reader/compoundAPRs', - networkName: 'MATIC', - tetuTokens: [tUSDCPolygon, tUSDTPolygon, tDAIPolygon, tetuStQIPolygon], -}); -export const tetuHandlers = [tetuPolygonAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts index bc00bd866..009c743c8 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts @@ -2,29 +2,35 @@ import axios from 'axios'; import { AprHandler } from '../base-apr-handlers'; -export const qETHMainnet = '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d'; - -class TranchessAprHandler implements AprHandler { +export class TranchessAprHandler implements AprHandler { networkPrismaId: string; url: string; - token: string; + tokens: { + [tokenName: string]: { + address: string; + underlyingAssetName: string; + }; + }; readonly group = 'TRANCHESS'; constructor(aprHandlerConfig: TranchessAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.network; - this.token = aprHandlerConfig.token; - this.url = aprHandlerConfig.url; + this.networkPrismaId = aprHandlerConfig.networkPrismaId; + this.tokens = aprHandlerConfig.tokens; + this.url = aprHandlerConfig.sourceUrl; } async getAprs() { try { const { data } = await axios.get('https://tranchess.com/eth/api/v3/funds'); - const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[]; + // const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[]; + const aprEntries = Object.values(this.tokens).map(({ address, underlyingAssetName }) => { + const weeklyAveragePnlPercentage = ( + data as { weeklyAveragePnlPercentage: string; name: string }[] + ).filter(({ name }) => name === underlyingAssetName)[0].weeklyAveragePnlPercentage; + return [address, (365 * Number(weeklyAveragePnlPercentage)) / 1e18]; + }); // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. - const value = (365 * Number(weeklyAveragePnlPercentage)) / 1e18; - return { - [this.token]: value, - }; + return Object.fromEntries(aprEntries); } catch (error) { console.error('Failed to fetch Tranchess APR:', error); return {}; @@ -33,15 +39,12 @@ class TranchessAprHandler implements AprHandler { } type TranchessAprHandlerConfig = { - network: string; - token: string; - url: string; + networkPrismaId: string; + tokens: { + [tokenName: string]: { + address: string; + underlyingAssetName: string; + }; + }; + sourceUrl: string; }; - -const tranchessMainnetAprHandler = new TranchessAprHandler({ - network: 'MAINNET', - token: qETHMainnet, - url: 'https://tranchess.com/eth/api/v3/funds', -}); - -export const tranchessHandlers = [tranchessMainnetAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index d51a20f3d..50b4c6bb7 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -4,15 +4,21 @@ import { prisma } from '../../../../prisma/prisma-client'; import { networkContext } from '../../../network/network-context.service'; import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; import { PrismaPoolAprItemGroup } from '@prisma/client'; -import { BaseAprHandlers, TokenApr, wrappedBoostedTokens } from './base-apr-handlers/base-apr-handlers'; +import { BaseAprHandlers, TokenApr } from './base-apr-handlers/base-apr-handlers'; import { TokenService } from '../../../token/token.service'; import { collectsYieldFee } from '../pool-utils'; +import { AprConfig } from '../../../network/network-config-types'; export class IbTokensAprService implements PoolAprService { private baseAprHandlers: BaseAprHandlers; - constructor(networkPrismaId: string, private readonly tokenService: TokenService) { - this.baseAprHandlers = new BaseAprHandlers(networkPrismaId); + constructor( + aprConfig: AprConfig, + networkPrismaId: string, + networkChainId: number, + private readonly tokenService: TokenService, + ) { + this.baseAprHandlers = new BaseAprHandlers(aprConfig, networkPrismaId, networkChainId); } getAprServiceName(): string { @@ -48,7 +54,6 @@ export class IbTokensAprService implements PoolAprService { : poolTokenApr * (1 - protocolYieldFeePercentage); const tokenSymbol = token.token.symbol; const itemId = `${pool.id}-${tokenSymbol}-yield-apr`; - const isBoosted = wrappedBoostedTokens.includes(token.address); operations.push( prisma.prismaPoolAprItem.upsert({ where: { id_chain: { id: itemId, chain: networkContext.chain } }, @@ -59,7 +64,7 @@ export class IbTokensAprService implements PoolAprService { title: `${tokenSymbol} APR`, apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, group: tokenApr.group as PrismaPoolAprItemGroup, - type: pool.type === 'LINEAR' && isBoosted ? 'LINEAR_BOOSTED' : 'IB_YIELD', + type: pool.type === 'LINEAR' ? 'LINEAR_BOOSTED' : 'IB_YIELD', }, update: { title: `${tokenSymbol} APR`, @@ -70,7 +75,6 @@ export class IbTokensAprService implements PoolAprService { } } } - await prismaBulkExecuteOperations(operations); } From 8f040cdcefbd415e6235fca26eaef09a9492aa31 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Thu, 24 Aug 2023 03:08:52 -0300 Subject: [PATCH 23/42] removing aave tokens unused; --- .../sources/aave-apr-handler.ts | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts index 6845183e7..1503c911d 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts @@ -80,40 +80,6 @@ export class AaveAprHandler implements AprHandler { } } -export const wrappedAaveTokensV2Mainnet = { - waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', - waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', - waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', -}; - -export const wrappedAaveTokensV2Polygon = { - waUSDT: '0x19c60a251e525fa88cd6f3768416a8024e98fc19', - waUSDC: '0x221836a597948dce8f3568e044ff123108acc42a', - waDAI: '0xee029120c72b0607344f35b17cdd90025e647b00', -}; - -export const wrappedAaveTokensV3Mainnet = { - waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', - waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', - waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', - waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', -}; - -export const wrappedAaveTokensV3Polygon = { - waMATIC: '0x0d6135b2cfbae3b1c58368a93b855fa54fa5aae1', - waUSDT: '0x7c76b6b3fe14831a39c0fec908da5f17180df677', - waUSDC: '0x9719d867a500ef117cc201206b8ab51e794d3f82', - waDAI: '0x27f8d03b3a2196956ed754badc28d73be8830a6e', - waWETH: '0xa5bbf0f46b9dc8a43147862ba35c8134eb45f1f5', -}; - -export const wrappedAaveTokensV3Arbitrum = { - waUSDT: '0x3c7680dfe7f732ca0279c39ff30fe2eafdae49db', - waUSDC: '0xe719aef17468c7e10c0c205be62c990754dff7e5', - waDAI: '0x345a864ac644c82c2d649491c905c71f240700b2', - waWETH: '0x18c100415988bef4354effad1188d1c22041b046', -}; - interface ReserveResponse { data: { reserves: [ From 85f76fdb115bb5f29983c470a757a15c3c0043c3 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Mon, 28 Aug 2023 23:59:34 -0300 Subject: [PATCH 24/42] Renaming aprConfig to IbAprConfig; Adding ReaperCrypt to Apr Handlers; Removing services already included in base-apr-handlers; --- modules/balancer/loadRestRoutes.ts | 21 + modules/network/arbitrum.ts | 25 +- modules/network/avalanche.ts | 13 +- modules/network/fantom.ts | 102 +-- modules/network/gnosis.ts | 13 +- modules/network/mainnet.ts | 38 +- modules/network/network-config-types.ts | 38 +- modules/network/optimism.ts | 77 +-- modules/network/polygon.ts | 13 +- modules/network/zkevm.ts | 13 +- .../base-apr-handlers/base-apr-handlers.ts | 172 ----- .../fantom/ankr-staked-eth-apr.service.ts | 56 -- .../fantom/ankr-staked-ftm-apr.service.ts | 59 -- .../fantom/tarot-vault-apr.service.ts | 0 .../fantom/yearn-vault-apr.service.ts | 59 -- .../ib-linear-apr-handlers.ts | 141 +++++ .../sources/aave-apr-handler.ts | 5 +- .../sources/abis/ReaperCrypt.json | 329 ++++++++++ .../sources/abis/ReaperCryptStrategy.json | 586 ++++++++++++++++++ .../sources/abis/oErc20.ts | 0 .../sources/abis/reaperStrategy.ts | 0 .../sources/abis/tesseraPool.ts | 0 .../sources/ankr-apr-handler.ts | 5 +- .../sources/default-apr-handler.ts | 9 +- .../sources/euler-apr-handler.ts | 5 +- .../sources/gearbox-apr-handler.ts | 5 +- .../sources/idle-apr-handler.ts | 5 +- .../sources/ovix-apr-handler.ts | 5 +- .../sources/reaper-apr-handler.ts | 2 +- .../sources/reaper-crypt-apr-handler.ts | 143 +++++ .../sources/tessera-apr-handler.ts | 5 +- .../sources/tetu-apr-handler.ts | 5 +- .../sources/tranchess-apr-handler.ts | 5 +- .../sources/yearn-apr-handler.ts | 26 + .../apr-data-sources/ib-tokens-apr.service.ts | 131 ++-- .../liquid-staked-base-apr.service.ts | 4 +- .../optimism/overnight-apr.service.ts | 74 --- 37 files changed, 1510 insertions(+), 679 deletions(-) delete mode 100644 modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts delete mode 100644 modules/pool/lib/apr-data-sources/fantom/ankr-staked-eth-apr.service.ts delete mode 100644 modules/pool/lib/apr-data-sources/fantom/ankr-staked-ftm-apr.service.ts delete mode 100644 modules/pool/lib/apr-data-sources/fantom/tarot-vault-apr.service.ts delete mode 100644 modules/pool/lib/apr-data-sources/fantom/yearn-vault-apr.service.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/aave-apr-handler.ts (94%) create mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCrypt.json create mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCryptStrategy.json rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/abis/oErc20.ts (100%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/abis/reaperStrategy.ts (100%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/abis/tesseraPool.ts (100%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/ankr-apr-handler.ts (88%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/default-apr-handler.ts (85%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/euler-apr-handler.ts (90%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/gearbox-apr-handler.ts (86%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/idle-apr-handler.ts (90%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/ovix-apr-handler.ts (89%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/reaper-apr-handler.ts (97%) create mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/tessera-apr-handler.ts (91%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/tetu-apr-handler.ts (85%) rename modules/pool/lib/apr-data-sources/{base-apr-handlers => ib-linear-apr-handlers}/sources/tranchess-apr-handler.ts (90%) create mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/optimism/overnight-apr.service.ts diff --git a/modules/balancer/loadRestRoutes.ts b/modules/balancer/loadRestRoutes.ts index aad0efca7..26894317d 100644 --- a/modules/balancer/loadRestRoutes.ts +++ b/modules/balancer/loadRestRoutes.ts @@ -1,5 +1,26 @@ import { Express } from 'express'; +import { prisma } from '../../prisma/prisma-client'; +import { prismaPoolWithExpandedNesting } from '../../prisma/prisma-types'; +import { networkContext } from '../network/network-context.service'; +import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; +import { tokenService } from '../token/token.service'; +import { mainnetNetworkData } from '../network/mainnet'; export function loadRestRoutesBalancer(app: Express) { app.use('/health', (req, res) => res.sendStatus(200)); + app.use('/test', async (req, res) => { + const pools = await prisma.prismaPool.findMany({ + ...prismaPoolWithExpandedNesting, + where: { chain: networkContext.chain }, + }); + const ibTokensAprService = new IbTokensAprService( + mainnetNetworkData.ibAprConfig, + mainnetNetworkData.chain.prismaId, + mainnetNetworkData.chain.id, + tokenService, + ); + await ibTokensAprService.updateAprForPools(pools); + + return res.sendStatus(200); + }); } diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index af49f0ec9..e449fd0d2 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -114,7 +114,7 @@ const arbitrumNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, - aprConfig: { + ibAprConfig: { aave: { v3: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum', @@ -165,22 +165,9 @@ const arbitrumNetworkData: NetworkData = { }, }, }, - yearn: { - vaultsEndpoint: 'https://#/', - }, - reaper: { - linearPoolFactories: ['0xC101dcA301a4011C1F925e9622e749e550a1B667'], - linearPoolIdsFromErc4626Factory: [], - averageAPRAcrossLastNHarvests: 2, - multistratAprSubgraphUrl: '', - }, beefy: { linearPools: [''], }, - lido: { - wstEthAprEndpoint: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - wstEthContract: '0x5979d7b546e38e414f7e9822514be443a4800529', - }, datastudio: { main: { user: 'datafeed-service@datastudio-366113.iam.gserviceaccount.com', @@ -213,19 +200,11 @@ export const arbitrumNetworkConfig: NetworkConfig = { provider: new ethers.providers.JsonRpcProvider(arbitrumNetworkData.rpcUrl), poolAprServices: [ new IbTokensAprService( - arbitrumNetworkData.aprConfig, + arbitrumNetworkData.ibAprConfig, arbitrumNetworkData.chain.prismaId, arbitrumNetworkData.chain.id, tokenService, ), - new WstethAprService(tokenService, arbitrumNetworkData.lido!.wstEthContract), - new ReaperCryptAprService( - arbitrumNetworkData.reaper.linearPoolFactories, - arbitrumNetworkData.reaper.linearPoolIdsFromErc4626Factory, - arbitrumNetworkData.reaper.averageAPRAcrossLastNHarvests, - arbitrumNetworkData.stader ? arbitrumNetworkData.stader.sFtmxContract : undefined, - arbitrumNetworkData.lido ? arbitrumNetworkData.lido.wstEthContract : undefined, - ), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(arbitrumNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index 7104b7764..0625cd2c3 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -105,7 +105,7 @@ const avalancheNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, - aprConfig: { + ibAprConfig: { aave: { v3: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-avalanche', @@ -165,15 +165,6 @@ const avalancheNetworkData: NetworkData = { }, }, }, - yearn: { - vaultsEndpoint: 'https://#/', - }, - reaper: { - linearPoolFactories: [], - linearPoolIdsFromErc4626Factory: [], - averageAPRAcrossLastNHarvests: 2, - multistratAprSubgraphUrl: '', - }, beefy: { linearPools: [''], }, @@ -209,7 +200,7 @@ export const avalancheNetworkConfig: NetworkConfig = { provider: new ethers.providers.JsonRpcProvider(avalancheNetworkData.rpcUrl), poolAprServices: [ new IbTokensAprService( - avalancheNetworkData.aprConfig, + avalancheNetworkData.ibAprConfig, avalancheNetworkData.chain.prismaId, avalancheNetworkData.chain.id, tokenService, diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index b6804cc8a..0ffb669ea 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -1,10 +1,7 @@ import { BigNumber, ethers } from 'ethers'; import { NetworkConfig, NetworkData } from './network-config-types'; -import { SpookySwapAprService } from '../pool/lib/apr-data-sources/fantom/spooky-swap-apr.service'; import { tokenService } from '../token/token.service'; -import { YearnVaultAprService } from '../pool/lib/apr-data-sources/fantom/yearn-vault-apr.service'; import { StaderStakedFtmAprService } from '../pool/lib/apr-data-sources/fantom/stader-staked-ftm-apr.service'; -import { ReaperCryptAprService } from '../pool/lib/apr-data-sources/reaper-crypt-apr.service'; import { PhantomStableAprService } from '../pool/lib/apr-data-sources/phantom-stable-apr.service'; import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool-apr.service'; import { SwapFeeAprService } from '../pool/lib/apr-data-sources/swap-fee-apr.service'; @@ -24,10 +21,8 @@ import { UserSyncMasterchefFarmBalanceService } from '../user/lib/user-sync-mast import { UserSyncReliquaryFarmBalanceService } from '../user/lib/user-sync-reliquary-farm-balance.service'; import { every } from '../../worker/intervals'; import { SanityContentService } from '../content/sanity-content.service'; -import { AnkrStakedFtmAprService } from '../pool/lib/apr-data-sources/fantom/ankr-staked-ftm-apr.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { coingeckoService } from '../coingecko/coingecko.service'; -import { AnkrStakedEthAprService } from '../pool/lib/apr-data-sources/fantom/ankr-staked-eth-apr.service'; import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; const fantomNetworkData: NetworkData = { @@ -153,7 +148,7 @@ const fantomNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, - aprConfig: { + ibAprConfig: { ankr: { sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', tokens: { @@ -167,33 +162,70 @@ const fantomNetworkData: NetworkData = { }, }, }, - }, - yearn: { - vaultsEndpoint: 'https://d28fcsszptni1s.cloudfront.net/v1/chains/250/vaults/all', + reaper: { + multiStrategy: { + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/byte-masons/multi-strategy-vaults-fantom', + tokens: { + rfwBTC: { + address: '0xfa985463b7fa975d06cde703ec72efccf293c605', + }, + rffUSDT: { + address: '0xaea55c0e84af6e5ef8c9b7042fb6ab682516214a', + }, + rfWFTM: { + address: '0x963ffcd14d471e279245ee1570ad64ca78d8e67e', + }, + rfWETH: { + address: '0xc052627bc73117d2cb3569f133419550156bdfa1', + }, + rfDAI: { + address: '0x16e4399fa9ba6e58f12bf2d2bc35f8bde8a9a4ab', + }, + rfUSDC: { + address: '0xd55c59da5872de866e39b1e3af2065330ea8acd6', + }, + rfUSDCCrypt: { + // Not named as Multi-Strategy in the contract, but is multi-strategy + address: '0x4455aef4b5d8ffe3436184e8a1ec99607f9a4340', + }, + rfWFTMCrypt: { + // Not named Multi-Strategy in the contract, but is multi-strategy + address: '0xe4a54b6a175cf3f6d7a5e8ab7544c3e6e364dbf9', + }, + rfWETHCrypt: { + // Not named Multi-Strategy in the contract, but is multi-strategy + address: '0x152d62dccc2c7c7930c4483cc2a24fefd23c24c2', + }, + rfDAICrypt: { + // Not named Multi-Strategy in the contract, but is multi-strategy + address: '0x5427f192137405e6a4143d1c3321359bab2dbd87', + }, + rfWBTCCrypt: { + // Not named Multi-Strategy in the contract, but is multi-strategy + address: '0x660c6ec76bd83f53263681f83cbeb35042dcd1cc', + }, + }, + }, + singleStrategy: { + averageAPRAcrossLastNHarvests: 5, + tokens: { + rfGrainSFTMX: { + address: '0xab30a4956c7d838234e24f1c3e50082c0607f35f', + isSftmX: true, + }, + rfGrainFTM: { + address: '0xc5b29d59d0b4717aa0dd8d11597d9fd3a05d86bb', + }, + }, + }, + }, + yearn: { + sourceUrl: 'https://d28fcsszptni1s.cloudfront.net/v1/chains/250/vaults/all', + }, }, copper: { proxyAddress: '0xbC8a71C75ffbd2807c021F4F81a8832392dEF93c', }, - reaper: { - linearPoolFactories: ['0xd448c4156b8de31e56fdfc071c8d96459bb28119'], - linearPoolIdsFromErc4626Factory: [ - '0x55e0499d268858a5e804d7864dc2a6b4ef194c630000000000000000000005b1', - '0xa9a1f2f7407ce27bcef35d04c47e079e7d6d399e0000000000000000000005b6', - '0xa8bcdca345e61bad9bb539933a4009f7a6f4b7ea0000000000000000000006eb', - '0x654def39262548cc958d07c82622e23c52411c820000000000000000000006ec', - '0xd3f155d7f421414dc4177e54e4308274dfa8b9680000000000000000000006ed', - '0xb8b0e5e9f8b740b557e7c26fcbc753523a718a870000000000000000000006ee', - '0xdc910e2647caae5f63a760b70a2308e1c90d88860000000000000000000006ef', - '0x92502cd8e00f5b8e737b2ba203fdd7cd27b23c8f000000000000000000000718', - '0xc385e76e575b2d71eb877c27dcc1608f77fada99000000000000000000000719', - '0x685056d3a4e574b163d0fa05a78f1b0b3aa04a8000000000000000000000071a', - '0x3c1420df122ac809b9d1ba77906f833764d6450100000000000000000000071b', - '0xa0051ab2c3eb7f17758428b02a07cf72eb0ef1a300000000000000000000071c', - '0x442988091cdc18acb8912cd3fe062cda9233f9dc00000000000000000000071d', - ], - averageAPRAcrossLastNHarvests: 5, - multistratAprSubgraphUrl: 'https://api.thegraph.com/subgraphs/name/byte-masons/multi-strategy-vaults-fantom', - }, beefy: { linearPools: [''], }, @@ -239,23 +271,13 @@ export const fantomNetworkConfig: NetworkConfig = { provider: new ethers.providers.JsonRpcProvider(fantomNetworkData.rpcUrl), poolAprServices: [ new IbTokensAprService( - fantomNetworkData.aprConfig, + fantomNetworkData.ibAprConfig, fantomNetworkData.chain.prismaId, fantomNetworkData.chain.id, tokenService, ), // new SpookySwapAprService(tokenService, fantomNetworkData.spooky!.xBooContract), - new YearnVaultAprService(tokenService), new StaderStakedFtmAprService(tokenService, fantomNetworkData.stader!.sFtmxContract), - new AnkrStakedFtmAprService(tokenService, fantomNetworkData.ankr!.ankrFtmContract), - new AnkrStakedEthAprService(tokenService, fantomNetworkData.ankr!.ankrEthContract), - new ReaperCryptAprService( - fantomNetworkData.reaper.linearPoolFactories, - fantomNetworkData.reaper.linearPoolIdsFromErc4626Factory, - fantomNetworkData.reaper.averageAPRAcrossLastNHarvests, - fantomNetworkData.stader ? fantomNetworkData.stader.sFtmxContract : undefined, - fantomNetworkData.lido ? fantomNetworkData.lido.wstEthContract : undefined, - ), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(fantomNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index 6d859ba41..ac1b51c57 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -105,7 +105,7 @@ const gnosisNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, - aprConfig: { + ibAprConfig: { defaultHandlers: { stETH: { tokens: { @@ -116,15 +116,6 @@ const gnosisNetworkData: NetworkData = { }, }, }, - yearn: { - vaultsEndpoint: 'https://#/', - }, - reaper: { - linearPoolFactories: [], - linearPoolIdsFromErc4626Factory: [], - averageAPRAcrossLastNHarvests: 2, - multistratAprSubgraphUrl: '', - }, lido: { wstEthAprEndpoint: '', wstEthContract: '', @@ -164,7 +155,7 @@ export const gnosisNetworkConfig: NetworkConfig = { provider: new ethers.providers.JsonRpcProvider(gnosisNetworkData.rpcUrl), poolAprServices: [ new IbTokensAprService( - gnosisNetworkData.aprConfig, + gnosisNetworkData.ibAprConfig, gnosisNetworkData.chain.prismaId, gnosisNetworkData.chain.id, tokenService, diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index ca1ea17bb..7ec504796 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -19,7 +19,14 @@ import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; -const mainnetNetworkData: NetworkData = { +const underlyingTokens = { + USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', + DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', + wETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', +}; + +export const mainnetNetworkData: NetworkData = { chain: { slug: 'ethereum', id: 1, @@ -116,27 +123,27 @@ const mainnetNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, - aprConfig: { + ibAprConfig: { aave: { v2: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2', tokens: { USDC: { - underlyingAssetAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + underlyingAssetAddress: underlyingTokens.USDC, aTokenAddress: '0xbcca60bb61934080951369a648fb03df4f96263c', wrappedTokens: { waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', }, }, USDT: { - underlyingAssetAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7', + underlyingAssetAddress: underlyingTokens.USDT, aTokenAddress: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', wrappedTokens: { waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', }, }, DAI: { - underlyingAssetAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', + underlyingAssetAddress: underlyingTokens.DAI, aTokenAddress: '0x028171bca77440897b824ca71d1c56cac55b68a3', wrappedTokens: { waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', @@ -148,7 +155,7 @@ const mainnetNetworkData: NetworkData = { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3', tokens: { USDC: { - underlyingAssetAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + underlyingAssetAddress: underlyingTokens.USDC, aTokenAddress: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', wrappedTokens: { waUSDC: '0x57d20c946a7a3812a7225b881cdcd8431d23431c', @@ -156,7 +163,7 @@ const mainnetNetworkData: NetworkData = { }, }, USDT: { - underlyingAssetAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7', + underlyingAssetAddress: underlyingTokens.USDT, aTokenAddress: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', wrappedTokens: { waUSDT: '0xa7e0e66f38b8ad8343cff67118c1f33e827d1455', @@ -164,7 +171,7 @@ const mainnetNetworkData: NetworkData = { }, }, DAI: { - underlyingAssetAddress: '0x6b175474e89094c44da98b954eedeac495271d0f', + underlyingAssetAddress: underlyingTokens.DAI, aTokenAddress: '0x018008bfb33d285247a21d44e50697654f754e63', wrappedTokens: { waDAI: '0x098256c06ab24f5655c5506a6488781bd711c14b', @@ -172,7 +179,7 @@ const mainnetNetworkData: NetworkData = { }, }, wETH: { - underlyingAssetAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + underlyingAssetAddress: underlyingTokens.wETH, aTokenAddress: '0x4d5f47fa6a74757f35c14fd3a6ef8e3c9bc514e8', wrappedTokens: { waWETH: '0x59463bb67ddd04fe58ed291ba36c26d99a39fbc6', @@ -210,7 +217,7 @@ const mainnetNetworkData: NetworkData = { idle: { sourceUrl: 'https://api.idle.finance/junior-rates/', authorizationHeader: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M', + 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IkFwcDciLCJpYXQiOjE2NzAyMzc1Mjd9.L12KJEt8fW1Cvy3o7Nl4OJ2wtEjzlObaAYJ9aC_CY6M', tokens: { idleDAI: { address: '0xec9482040e6483b7459cc0db05d51dfa3d3068e1', @@ -311,15 +318,6 @@ const mainnetNetworkData: NetworkData = { }, }, }, - yearn: { - vaultsEndpoint: 'https://#/', - }, - reaper: { - linearPoolFactories: [], - linearPoolIdsFromErc4626Factory: [], - averageAPRAcrossLastNHarvests: 2, - multistratAprSubgraphUrl: '', - }, beefy: { linearPools: [''], }, @@ -359,7 +357,7 @@ export const mainnetNetworkConfig: NetworkConfig = { provider: new ethers.providers.JsonRpcProvider(mainnetNetworkData.rpcUrl), poolAprServices: [ new IbTokensAprService( - mainnetNetworkData.aprConfig, + mainnetNetworkData.ibAprConfig, mainnetNetworkData.chain.prismaId, mainnetNetworkData.chain.id, tokenService, diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index 3bbddcd35..1e9d3093d 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -100,7 +100,7 @@ export interface NetworkData { address: string; excludedFarmIds: string[]; }; - aprConfig: AprConfig; + ibAprConfig: AprConfig; reliquary?: { address: string; excludedFarmIds: string[]; @@ -108,18 +108,9 @@ export interface NetworkData { copper?: { proxyAddress: string; }; - reaper: { - linearPoolFactories: string[]; - linearPoolIdsFromErc4626Factory: string[]; - averageAPRAcrossLastNHarvests: number; - multistratAprSubgraphUrl: string; - }; beefy: { linearPools: string[]; }; - yearn: { - vaultsEndpoint: string; - }; lido?: { wstEthContract: string; wstEthAprEndpoint: string; @@ -204,7 +195,7 @@ export interface AprConfig { }; idle?: { sourceUrl: string; - authorizationHeader?: string; + authorizationHeader: string; tokens: { [tokenName: string]: { address: string; @@ -221,6 +212,28 @@ export interface AprConfig { }; }; }; + reaper?: { + multiStrategy?: { + subgraphUrl: string; + tokens: { + [tokenName: string]: { + address: string; + isSftmX?: boolean; + isWstETH?: boolean; + }; + }; + }; + singleStrategy?: { + averageAPRAcrossLastNHarvests: number; + tokens: { + [tokenName: string]: { + address: string; + isSftmX?: boolean; + isWstETH?: boolean; + }; + }; + }; + }; tessera?: { rpcUrl: string; tokens: { @@ -245,6 +258,9 @@ export interface AprConfig { }; }; }; + yearn?: { + sourceUrl: string; + }; defaultHandlers?: { [tokenName: string]: { sourceUrl: string; diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index d3d916229..5d5280c0e 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -3,7 +3,6 @@ import { NetworkConfig, NetworkData } from './network-config-types'; import { RocketPoolStakedEthAprService } from '../pool/lib/apr-data-sources/optimism/rocket-pool-staked-eth-apr.service'; import { tokenService } from '../token/token.service'; import { WstethAprService } from '../pool/lib/apr-data-sources/optimism/wsteth-apr.service'; -import { OvernightAprService } from '../pool/lib/apr-data-sources/optimism/overnight-apr.service'; import { ReaperCryptAprService } from '../pool/lib/apr-data-sources/reaper-crypt-apr.service'; import { PhantomStableAprService } from '../pool/lib/apr-data-sources/phantom-stable-apr.service'; import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool-apr.service'; @@ -117,15 +116,51 @@ const optimismNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, - aprConfig: { + ibAprConfig: { + reaper: { + multiStrategy: { + subgraphUrl: 'https://api.thegraph.com/subgraphs/name/byte-masons/multi-strategy-vaults-optimism', + tokens: { + rfUSDT: { + address: '0x51868bb8b71fb423b87129908fa039b880c8612d', + }, + rfWETH: { + address: '0x1bad45e92dce078cf68c2141cd34f54a02c92806', + }, + rfOP: { + address: '0xcecd29559a84e4d4f6467b36bbd4b9c3e6b89771', + }, + rfwstETH: { + address: '0xb19f4d65882f6c103c332f0bc012354548e9ce0e', + isWstETH: true, + }, + rfWBTC: { + address: '0xf6533b6fcb3f42d2fc91da7c379858ae6ebc7448', + }, + rfDAI: { + address: '0xc0f5da4fb484ce6d8a6832819299f7cd0d15726e', + }, + rfUSDC: { + address: '0x508734b52ba7e04ba068a2d4f67720ac1f63df47', + }, + }, + }, + }, defaultHandlers: { stEth: { tokens: { - wstETH: '0x1f32b1c2345538c0c6f582fcb0227', + wstETH: '0x1f32b1c2345538c0c6f582fcb022739c4a194ebb', }, sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', }, + rETH: { + tokens: { + rETH: '0x9bcef72be871e61ed4fbbc7630889bee758eb81d', + }, + sourceUrl: 'https://drop-api.stafi.io/reth/v1/poolData', + path: 'data.stakeApr', + }, overnightDAIPlus: { tokens: { DAIPlus: '0x0b8f31480249cc717081928b8af733f45f6915bb', @@ -144,36 +179,12 @@ const optimismNetworkData: NetworkData = { }, }, }, - yearn: { - vaultsEndpoint: 'https://#/', - }, - reaper: { - linearPoolFactories: [ - '0x19968d4b7126904fd665ed25417599df9604df83', - '0xe4b88e745dce9084b9fc2439f85a9a4c5cd6f361', - ], - linearPoolIdsFromErc4626Factory: [ - '0x20715545c15c76461861cb0d6ba96929766d05a50000000000000000000000e8', - '0xf970659221bb9d01b615321b63a26e857ffc030b0000000000000000000000e9', - '0xa5d4802b4ce6b745b0c9e1b4a79c093d197869c80000000000000000000000ea', - '0x2e2b8b82123789d895fd79913f6dfa51f5b5a0e60000000000000000000000eb', - '0x48ace81c09382bfc08ed102e7eadd37e3b0497520000000000000000000000ec', - '0x8025586ac5fb265a23b9492e7414beccc2059ec30000000000000000000000ed', - '0x3e9cbffd270ae67abb09d28988e7e785498c73730000000000000000000000ee', - ], - averageAPRAcrossLastNHarvests: 2, - multistratAprSubgraphUrl: 'https://api.thegraph.com/subgraphs/name/byte-masons/multi-strategy-vaults-optimism', - }, beefy: { linearPools: [ '0x5bdd8c19b44c3e4a15305601a2c9841bde9366f00000000000000000000000ca', '0x72d6df381cac8c2283c0b13fe5262a1f5e8e8d1b0000000000000000000000cb', ], }, - lido: { - wstEthAprEndpoint: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - wstEthContract: '0x1f32b1c2345538c0c6f582fcb022739c4a194ebb', - }, rocket: { rEthContract: '0x9bcef72be871e61ed4fbbc7630889bee758eb81d', }, @@ -212,21 +223,11 @@ export const optimismNetworkConfig: NetworkConfig = { provider: new ethers.providers.JsonRpcProvider(optimismNetworkData.rpcUrl), poolAprServices: [ new IbTokensAprService( - optimismNetworkData.aprConfig, + optimismNetworkData.ibAprConfig, optimismNetworkData.chain.prismaId, optimismNetworkData.chain.id, tokenService, ), - new RocketPoolStakedEthAprService(tokenService, optimismNetworkData.rocket!.rEthContract), - new WstethAprService(tokenService, optimismNetworkData.lido!.wstEthContract), - new OvernightAprService(optimismNetworkData.overnight!.aprEndpoint, tokenService), - new ReaperCryptAprService( - optimismNetworkData.reaper.linearPoolFactories, - optimismNetworkData.reaper.linearPoolIdsFromErc4626Factory, - optimismNetworkData.reaper.averageAPRAcrossLastNHarvests, - optimismNetworkData.stader ? optimismNetworkData.stader.sFtmxContract : undefined, - optimismNetworkData.lido ? optimismNetworkData.lido.wstEthContract : undefined, - ), new BeefyVaultAprService(optimismNetworkData.beefy.linearPools, tokenService), new PhantomStableAprService(), new BoostedPoolAprService(), diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index 4e9a275e1..a3939ea19 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -113,7 +113,7 @@ const polygonNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, - aprConfig: { + ibAprConfig: { aave: { v2: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic', @@ -228,15 +228,6 @@ const polygonNetworkData: NetworkData = { }, }, }, - yearn: { - vaultsEndpoint: 'https://#/', - }, - reaper: { - linearPoolFactories: [], - linearPoolIdsFromErc4626Factory: [], - averageAPRAcrossLastNHarvests: 2, - multistratAprSubgraphUrl: '', - }, beefy: { linearPools: [''], }, @@ -272,7 +263,7 @@ export const polygonNetworkConfig: NetworkConfig = { provider: new ethers.providers.JsonRpcProvider(polygonNetworkData.rpcUrl), poolAprServices: [ new IbTokensAprService( - polygonNetworkData.aprConfig, + polygonNetworkData.ibAprConfig, polygonNetworkData.chain.prismaId, polygonNetworkData.chain.id, tokenService, diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index d3c6acca0..d471220b6 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -106,7 +106,7 @@ const zkevmNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, - aprConfig: { + ibAprConfig: { ovix: { rpcUrl: 'https://zkevm-rpc.com', tokens: { @@ -130,15 +130,6 @@ const zkevmNetworkData: NetworkData = { }, }, }, - yearn: { - vaultsEndpoint: 'https://#/', - }, - reaper: { - linearPoolFactories: [], - linearPoolIdsFromErc4626Factory: [], - averageAPRAcrossLastNHarvests: 2, - multistratAprSubgraphUrl: '', - }, beefy: { linearPools: [''], }, @@ -178,7 +169,7 @@ export const zkevmNetworkConfig: NetworkConfig = { provider: new ethers.providers.JsonRpcProvider(zkevmNetworkData.rpcUrl), poolAprServices: [ new IbTokensAprService( - zkevmNetworkData.aprConfig, + zkevmNetworkData.ibAprConfig, zkevmNetworkData.chain.prismaId, zkevmNetworkData.chain.id, tokenService, diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts b/modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts deleted file mode 100644 index 7eaff9f5c..000000000 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/base-apr-handlers.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { AaveAprHandler } from './sources/aave-apr-handler'; -import { AnkrAprHandler } from './sources/ankr-apr-handler'; -import { DefaultAprHandler } from './sources/default-apr-handler'; -import { EulerAprHandler } from './sources/euler-apr-handler'; -import { GearboxAprHandler } from './sources/gearbox-apr-handler'; -import { IdleAprHandler } from './sources/idle-apr-handler'; -import { OvixAprHandler } from './sources/ovix-apr-handler'; -import { TesseraAprHandler } from './sources/tessera-apr-handler'; -import { TetuAprHandler } from './sources/tetu-apr-handler'; -import { TranchessAprHandler } from './sources/tranchess-apr-handler'; -import { AprConfig } from '../../../../network/network-config-types'; - -export class BaseAprHandlers { - private handlers: AprHandler[] = []; - - constructor(aprConfig: AprConfig, networkPrismaId: string, networkChainId: number) { - this.handlers = this.buildAprHandlers(aprConfig, networkPrismaId, networkChainId); - } - - buildAprHandlers(aprConfig: AprConfig, networkPrismaId: string, networkChainId: number) { - const handlers: AprHandler[] = []; - if (aprConfig.aave) { - for (const config of Object.values(aprConfig.aave)) { - const { tokens, subgraphUrl } = config; - const aaveHandler = new AaveAprHandler({ - tokens, - subgraphUrl, - networkPrismaId, - }); - handlers.push(aaveHandler); - } - } - if (aprConfig.ankr) { - const { sourceUrl, tokens } = aprConfig.ankr; - const ankrHandler = new AnkrAprHandler({ - sourceUrl, - tokens, - networkPrismaId, - }); - handlers.push(ankrHandler); - } - if (aprConfig.euler) { - const { subgraphUrl, tokens } = aprConfig.euler; - const eulerHandler = new EulerAprHandler({ - subgraphUrl, - tokens, - networkPrismaId, - }); - handlers.push(eulerHandler); - } - if (aprConfig.gearbox) { - const { sourceUrl, tokens } = aprConfig.gearbox; - const gearboxHandler = new GearboxAprHandler({ - sourceUrl, - tokens, - networkPrismaId, - }); - handlers.push(gearboxHandler); - } - if (aprConfig.idle) { - const { sourceUrl, tokens, authorizationHeader } = aprConfig.idle; - const idleHandler = new IdleAprHandler({ - sourceUrl, - tokens, - authorizationHeader: 'Bearer ' + authorizationHeader, - networkPrismaId, - }); - handlers.push(idleHandler); - } - if (aprConfig.ovix) { - const { rpcUrl, tokens } = aprConfig.ovix; - const ovixHandler = new OvixAprHandler({ - rpcUrl, - tokens, - networkPrismaId, - networkChainId, - }); - handlers.push(ovixHandler); - } - if (aprConfig.tessera) { - const { rpcUrl, tokens } = aprConfig.tessera; - const tesseraHandler = new TesseraAprHandler({ - rpcUrl, - tokens, - networkPrismaId, - networkChainId, - }); - handlers.push(tesseraHandler); - } - if (aprConfig.tetu) { - const { sourceUrl, tokens } = aprConfig.tetu; - const tetuHandler = new TetuAprHandler({ - sourceUrl, - tokens, - networkPrismaId, - }); - handlers.push(tetuHandler); - } - if (aprConfig.tranchess) { - const { sourceUrl, tokens } = aprConfig.tranchess; - const tranchessHandler = new TranchessAprHandler({ - sourceUrl, - tokens, - networkPrismaId, - }); - handlers.push(tranchessHandler); - } - if (aprConfig.defaultHandlers) { - for (const handlerConfig of Object.values(aprConfig.defaultHandlers)) { - const handler = new DefaultAprHandler({ ...handlerConfig, networkPrismaId }); - handlers.push(handler); - } - } - return handlers; - } - - async fetchAprsFromAllHandlers(): Promise { - let aprs: { val: number; group: string; address: string }[] = []; - for (const handler of this.handlers) { - const fetchedResponse: { [key: string]: number } = await handler.getAprs(); - for (const [address, aprValue] of Object.entries(fetchedResponse)) { - aprs.push({ - val: aprValue, - group: handler.group, - address, - }); - } - } - return aprs; - } -} - -export interface AprHandler { - group: string; - networkPrismaId: string; - - getAprs(): Promise<{ [tokenAddress: string]: number }>; -} - -export type TokenApr = { - val: number; - address: string; - group?: string; -}; - -// export const wrappedBoostedTokens = [ -// ...Object.values(wrappedAaveTokensV2Mainnet), -// ...Object.values(wrappedAaveTokensV2Polygon), -// ...Object.values(wrappedAaveTokensV3Mainnet), -// ...Object.values(wrappedAaveTokensV3Polygon), -// ...Object.values(wrappedAaveTokensV3Arbitrum), -// ankrEthMainnet, -// ankrEthFantom, -// rETHMainnet, -// USDRMainnet, -// swETHMainnet, -// wjAURAMainnet, -// ...Object.values(eulerTokensMainnet), -// ...Object.values(gearboxTokensMainnet), -// ...Object.values(wrapped4626IdleTokensMainnet), -// ...Object.values(ovixWrappedTokensZkEvm), -// ...Object.values(reaperYieldTokensArbitrum), -// ...Object.values(tesseraYieldTokensMainnet), -// tUSDTPolygon, -// tUSDCPolygon, -// tDAIPolygon, -// qETHMainnet, -// overnightLpUsdcUsdPlusMainnet, -// overnightUsdcUsdPlusMainnet, -// overnightUsdPlusOptimism, -// overnightDaiPlusOptimism, -// ]; diff --git a/modules/pool/lib/apr-data-sources/fantom/ankr-staked-eth-apr.service.ts b/modules/pool/lib/apr-data-sources/fantom/ankr-staked-eth-apr.service.ts deleted file mode 100644 index ae9bc1d74..000000000 --- a/modules/pool/lib/apr-data-sources/fantom/ankr-staked-eth-apr.service.ts +++ /dev/null @@ -1,56 +0,0 @@ -import axios from 'axios'; -import { prisma } from '../../../../../prisma/prisma-client'; -import { PrismaPoolWithExpandedNesting } from '../../../../../prisma/prisma-types'; -import { TokenService } from '../../../../token/token.service'; -import { PoolAprService } from '../../../pool-types'; -import { collectsYieldFee } from '../../pool-utils'; -import { liquidStakedBaseAprService } from '../liquid-staked-base-apr.service'; -import { networkContext } from '../../../../network/network-context.service'; - -export class AnkrStakedEthAprService implements PoolAprService { - constructor(private readonly tokenService: TokenService, private readonly ankrEthAddress: string) {} - - public getAprServiceName(): string { - return 'AnkrStakedEthAprService'; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const tokenPrices = await this.tokenService.getTokenPrices(); - const ankrEthPrice = this.tokenService.getPriceForToken(tokenPrices, this.ankrEthAddress); - - const ankrEthBaseApr = await liquidStakedBaseAprService.getAnkrEthBaseApr(); - - let operations: any[] = []; - for (const pool of pools) { - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : networkContext.data.balancer.yieldProtocolFeePercentage; - const ankrEthToken = pool.tokens.find((token) => token.address === this.ankrEthAddress); - const ankrEthTokenBalance = ankrEthToken?.dynamicData?.balance; - if (ankrEthTokenBalance && pool.dynamicData) { - const ankrEthPercentage = - (parseFloat(ankrEthTokenBalance) * ankrEthPrice) / pool.dynamicData.totalLiquidity; - const poolAnkrEthApr = pool.dynamicData.totalLiquidity > 0 ? ankrEthBaseApr * ankrEthPercentage : 0; - const userApr = - pool.type === 'META_STABLE' - ? poolAnkrEthApr * (1 - networkContext.data.balancer.swapProtocolFeePercentage) - : poolAnkrEthApr * (1 - protocolYieldFeePercentage); - operations.push( - prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: `${pool.id}-ankreth-apr`, chain: networkContext.chain } }, - update: { apr: collectsYieldFee(pool) ? userApr : poolAnkrEthApr }, - create: { - id: `${pool.id}-ankreth-apr`, - chain: networkContext.chain, - poolId: pool.id, - apr: collectsYieldFee(pool) ? userApr : poolAnkrEthApr, - title: 'ankrETH APR', - type: 'IB_YIELD', - }, - }), - ); - } - } - await Promise.all(operations); - } -} diff --git a/modules/pool/lib/apr-data-sources/fantom/ankr-staked-ftm-apr.service.ts b/modules/pool/lib/apr-data-sources/fantom/ankr-staked-ftm-apr.service.ts deleted file mode 100644 index 38b54573b..000000000 --- a/modules/pool/lib/apr-data-sources/fantom/ankr-staked-ftm-apr.service.ts +++ /dev/null @@ -1,59 +0,0 @@ -import axios from 'axios'; -import { prisma } from '../../../../../prisma/prisma-client'; -import { PrismaPoolWithExpandedNesting } from '../../../../../prisma/prisma-types'; -import { networkContext } from '../../../../network/network-context.service'; -import { TokenService } from '../../../../token/token.service'; -import { PoolAprService } from '../../../pool-types'; -import { collectsYieldFee } from '../../pool-utils'; -import { liquidStakedBaseAprService } from '../liquid-staked-base-apr.service'; - -export class AnkrStakedFtmAprService implements PoolAprService { - constructor(private readonly tokenService: TokenService, private readonly ankrFtmAddress: string) {} - - public getAprServiceName(): string { - return 'AnkrStakedFtmAprService'; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const tokenPrices = await this.tokenService.getTokenPrices(); - const ankrFtmPrice = this.tokenService.getPriceForToken(tokenPrices, this.ankrFtmAddress); - - const ankrFtmBaseApr = await liquidStakedBaseAprService.getAnkrFtmBaseApr(); - - let operations: any[] = []; - for (const pool of pools) { - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : networkContext.data.balancer.yieldProtocolFeePercentage; - const ankrFtmToken = pool.tokens.find((token) => token.address === this.ankrFtmAddress); - const ankrFtmTokenBalance = ankrFtmToken?.dynamicData?.balance; - - if (ankrFtmTokenBalance && pool.dynamicData) { - const ankrFtmPercentage = - (parseFloat(ankrFtmTokenBalance) * ankrFtmPrice) / pool.dynamicData.totalLiquidity; - const poolAnkrFtmApr = pool.dynamicData.totalLiquidity > 0 ? ankrFtmBaseApr * ankrFtmPercentage : 0; - - const userApr = - pool.type === 'META_STABLE' - ? poolAnkrFtmApr * (1 - networkContext.data.balancer.swapProtocolFeePercentage) - : poolAnkrFtmApr * (1 - protocolYieldFeePercentage); - - operations.push( - prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: `${pool.id}-ankrftm-apr`, chain: networkContext.chain } }, - update: { apr: collectsYieldFee(pool) ? userApr : poolAnkrFtmApr }, - create: { - id: `${pool.id}-ankrftm-apr`, - chain: networkContext.chain, - poolId: pool.id, - apr: collectsYieldFee(pool) ? userApr : poolAnkrFtmApr, - title: 'ankrFTM APR', - type: 'IB_YIELD', - }, - }), - ); - } - } - await Promise.all(operations); - } -} diff --git a/modules/pool/lib/apr-data-sources/fantom/tarot-vault-apr.service.ts b/modules/pool/lib/apr-data-sources/fantom/tarot-vault-apr.service.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/modules/pool/lib/apr-data-sources/fantom/yearn-vault-apr.service.ts b/modules/pool/lib/apr-data-sources/fantom/yearn-vault-apr.service.ts deleted file mode 100644 index 8115ff842..000000000 --- a/modules/pool/lib/apr-data-sources/fantom/yearn-vault-apr.service.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { PoolAprService } from '../../../pool-types'; -import { PrismaPoolWithExpandedNesting } from '../../../../../prisma/prisma-types'; -import axios from 'axios'; -import { prisma } from '../../../../../prisma/prisma-client'; -import { TokenService } from '../../../../token/token.service'; -import { YearnVault } from '../apr-types'; -import { networkContext } from '../../../../network/network-context.service'; - -export class YearnVaultAprService implements PoolAprService { - constructor(private readonly tokenService: TokenService) {} - - public getAprServiceName(): string { - return 'YearnVaultAprService'; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const { data } = await axios.get(networkContext.data.yearn.vaultsEndpoint); - const tokenPrices = await this.tokenService.getTokenPrices(); - - for (const pool of pools) { - const itemId = `${pool.id}-yearn-vault`; - - if (!pool.linearData || !pool.dynamicData) { - continue; - } - - const linearData = pool.linearData; - const wrappedToken = pool.tokens[linearData.wrappedIndex]; - const mainToken = pool.tokens[linearData.mainIndex]; - - const vault = data.find((vault) => vault.address.toLowerCase() === wrappedToken.address.toLowerCase()); - - if (!vault) { - continue; - } - - const tokenPrice = this.tokenService.getPriceForToken(tokenPrices, mainToken.address); - const wrappedTokens = parseFloat(wrappedToken.dynamicData?.balance || '0'); - const priceRate = parseFloat(wrappedToken.dynamicData?.priceRate || '1.0'); - const poolWrappedLiquidity = wrappedTokens * priceRate * tokenPrice; - const totalLiquidity = pool.dynamicData.totalLiquidity; - const apr = totalLiquidity > 0 ? vault.apy.net_apy * (poolWrappedLiquidity / totalLiquidity) : 0; - - await prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `${vault.symbol} APR`, - apr, - group: 'YEARN', - type: 'LINEAR_BOOSTED', - }, - update: { apr, group: 'YEARN', type: 'LINEAR_BOOSTED' }, - }); - } - } -} diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts new file mode 100644 index 000000000..a0909fbd2 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts @@ -0,0 +1,141 @@ +import { AaveAprHandler } from './sources/aave-apr-handler'; +import { AnkrAprHandler } from './sources/ankr-apr-handler'; +import { DefaultAprHandler } from './sources/default-apr-handler'; +import { EulerAprHandler } from './sources/euler-apr-handler'; +import { GearboxAprHandler } from './sources/gearbox-apr-handler'; +import { IdleAprHandler } from './sources/idle-apr-handler'; +import { OvixAprHandler } from './sources/ovix-apr-handler'; +import { TesseraAprHandler } from './sources/tessera-apr-handler'; +import { TetuAprHandler } from './sources/tetu-apr-handler'; +import { TranchessAprHandler } from './sources/tranchess-apr-handler'; +import { AprConfig } from '../../../../network/network-config-types'; +import { YearnAprHandler } from './sources/yearn-apr-handler'; +import { ReaperCryptAprHandler } from './sources/reaper-crypt-apr-handler'; + +export class IbLinearAprHandlers { + private handlers: AprHandler[] = []; + //List of addresses of wrappedBoostedTokens, used to check what is LINEAR_BOOSTED APR and what is IB_YIELD APR + wrappedBoostedTokens: string[] = []; + + constructor(aprConfig: AprConfig, networkPrismaId: string, networkChainId: number) { + this.handlers = this.buildAprHandlers(aprConfig, networkPrismaId, networkChainId); + this.wrappedBoostedTokens = this.buildWrappedBoostedTokens(aprConfig); + } + + buildAprHandlers(aprConfig: AprConfig, networkPrismaId: string, networkChainId: number) { + const handlers: AprHandler[] = []; + if (aprConfig.aave) { + for (const config of Object.values(aprConfig.aave)) { + const aaveHandler = new AaveAprHandler(config); + handlers.push(aaveHandler); + } + } + if (aprConfig.ankr) { + const ankrHandler = new AnkrAprHandler(aprConfig.ankr); + handlers.push(ankrHandler); + } + if (aprConfig.euler) { + const eulerHandler = new EulerAprHandler(aprConfig.euler); + handlers.push(eulerHandler); + } + if (aprConfig.gearbox) { + const gearboxHandler = new GearboxAprHandler(aprConfig.gearbox); + handlers.push(gearboxHandler); + } + if (aprConfig.idle) { + const idleHandler = new IdleAprHandler(aprConfig.idle); + handlers.push(idleHandler); + } + if (aprConfig.ovix) { + const ovixHandler = new OvixAprHandler({ + ...aprConfig.ovix, + networkChainId, + }); + handlers.push(ovixHandler); + } + if (aprConfig.reaper) { + const reaperCryptHandler = new ReaperCryptAprHandler({ ...aprConfig.reaper, networkChainId }); + handlers.push(reaperCryptHandler); + } + if (aprConfig.tessera) { + const tesseraHandler = new TesseraAprHandler({ + ...aprConfig.tessera, + networkChainId, + }); + handlers.push(tesseraHandler); + } + if (aprConfig.tetu) { + const tetuHandler = new TetuAprHandler(aprConfig.tetu); + handlers.push(tetuHandler); + } + if (aprConfig.tranchess) { + const tranchessHandler = new TranchessAprHandler(aprConfig.tranchess); + handlers.push(tranchessHandler); + } + if (aprConfig.yearn) { + const yearnHandler = new YearnAprHandler(aprConfig.yearn); + handlers.push(yearnHandler); + } + if (aprConfig.defaultHandlers) { + for (const handlerConfig of Object.values(aprConfig.defaultHandlers)) { + const handler = new DefaultAprHandler(handlerConfig); + handlers.push(handler); + } + } + return handlers; + } + + buildWrappedBoostedTokens(aprConfig: AprConfig): string[] { + return [ + ...Object.values(aprConfig?.aave?.v2?.tokens?.USDC?.wrappedTokens || {}), + ...Object.values(aprConfig?.aave?.v3?.tokens?.USDC?.wrappedTokens || {}), + ...Object.values(aprConfig?.aave?.v2?.tokens?.USDT?.wrappedTokens || {}), + ...Object.values(aprConfig?.aave?.v3?.tokens?.USDT?.wrappedTokens || {}), + ...Object.values(aprConfig?.aave?.v2?.tokens?.DAI?.wrappedTokens || {}), + ...Object.values(aprConfig?.aave?.v3?.tokens?.DAI?.wrappedTokens || {}), + ...Object.values(aprConfig?.aave?.v3?.tokens?.wETH?.wrappedTokens || {}), + ...Object.values(aprConfig?.aave?.v3?.tokens?.wMATIC?.wrappedTokens || {}), + ...Object.values(aprConfig?.ankr?.tokens || {}).map(({ address }) => address), + ...Object.values(aprConfig?.euler?.tokens || {}), + ...Object.values(aprConfig?.gearbox?.tokens || {}), + ...Object.values(aprConfig?.idle?.tokens || {}).map(({ wrapped4626Address }) => wrapped4626Address), + ...Object.values(aprConfig?.ovix?.tokens || {}).map(({ wrappedAddress }) => wrappedAddress), + ...Object.values(aprConfig?.tessera?.tokens || {}).map(({ tokenAddress }) => tokenAddress), + ...Object.values(aprConfig?.tranchess?.tokens || {}).map(({ address }) => address), + ...Object.values(aprConfig?.tetu?.tokens || {}), + ...Object.values( + Object.entries(aprConfig?.defaultHandlers || {}) + //Filtering out handlers that are not LINEAR_BOOSTED + .filter(([key, _]) => ['rETH', 'USDR', 'swETH', 'wjAURA', 'qETH', 'overnight'].includes(key)) + .reduce((acc, [_, value]) => ({ ...acc, ...value.tokens }), {}) as { [p: string]: string }, + ), + ]; + } + + async fetchAprsFromAllHandlers(): Promise { + let aprs: TokenApr[] = []; + for (const handler of this.handlers) { + const fetchedResponse: { [key: string]: number } = await handler.getAprs(); + for (const [address, aprValue] of Object.entries(fetchedResponse)) { + aprs.push({ + val: aprValue, + group: handler.group, + address, + }); + } + } + console.log(aprs); + return aprs; + } +} + +export interface AprHandler { + group: string | undefined; + getAprs(): Promise<{ [tokenAddress: string]: number }>; +} + +export type TokenApr = { + val: number; + address: string; + group?: string; +}; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts similarity index 94% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts index 1503c911d..c16e0dda6 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; export class AaveAprHandler implements AprHandler { tokens: { @@ -12,7 +12,6 @@ export class AaveAprHandler implements AprHandler { }; }; subgraphUrl: string; - networkPrismaId: string; readonly group = 'AAVE'; @@ -33,7 +32,6 @@ export class AaveAprHandler implements AprHandler { constructor(aprHandlerConfig: AaveAprHandlerConfig) { this.tokens = aprHandlerConfig.tokens; this.subgraphUrl = aprHandlerConfig.subgraphUrl; - this.networkPrismaId = aprHandlerConfig.networkPrismaId; } async getAprs() { @@ -94,5 +92,4 @@ interface ReserveResponse { type AaveAprHandlerConfig = { tokens: {}; subgraphUrl: string; - networkPrismaId: string; }; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCrypt.json b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCrypt.json new file mode 100644 index 000000000..5ea0973e1 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCrypt.json @@ -0,0 +1,329 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "_token", "type": "address" }, + { "internalType": "string", "name": "_name", "type": "string" }, + { "internalType": "string", "name": "_symbol", "type": "string" }, + { "internalType": "uint256", "name": "_depositFee", "type": "uint256" }, + { "internalType": "uint256", "name": "_tvlCap", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "total", "type": "uint256" } + ], + "name": "DepositsIncremented", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "user", "type": "address" }], + "name": "TermsAccepted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "newTvlCap", "type": "uint256" }], + "name": "TvlCapUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "total", "type": "uint256" } + ], + "name": "WithdrawalsIncremented", + "type": "event" + }, + { + "inputs": [], + "name": "PERCENT_DIVISOR", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "agreeToTerms", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "available", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "balance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "constructionTime", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "cumulativeDeposits", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "cumulativeWithdrawals", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "subtractedValue", "type": "uint256" } + ], + "name": "decreaseAllowance", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_amount", "type": "uint256" }], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { "inputs": [], "name": "depositAll", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "depositFee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "earn", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "getPricePerFullShare", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "hasReadAndAcceptedTerms", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_token", "type": "address" }], + "name": "inCaseTokensGetStuck", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "addedValue", "type": "uint256" } + ], + "name": "increaseAllowance", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_strategy", "type": "address" }], + "name": "initialize", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "initialized", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "removeTvlCap", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "strategy", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token", + "outputs": [{ "internalType": "contract IERC20", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "recipient", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sender", "type": "address" }, + { "internalType": "address", "name": "recipient", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "tvlCap", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "fee", "type": "uint256" }], + "name": "updateDepositFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_newTvlCap", "type": "uint256" }], + "name": "updateTvlCap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_shares", "type": "uint256" }], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { "inputs": [], "name": "withdrawAll", "outputs": [], "stateMutability": "nonpayable", "type": "function" } +] diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCryptStrategy.json b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCryptStrategy.json new file mode 100644 index 000000000..2a29a1f41 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCryptStrategy.json @@ -0,0 +1,586 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "_vault", "type": "address" }, + { "internalType": "address[]", "name": "_feeRemitters", "type": "address[]" }, + { "internalType": "address[]", "name": "_strategists", "type": "address[]" }, + { "internalType": "address[]", "name": "_multisigRoles", "type": "address[]" }, + { "internalType": "contract IAToken", "name": "_aWant", "type": "address" }, + { "internalType": "address[]", "name": "_opToWantPath", "type": "address[]" }, + { "internalType": "uint256", "name": "_targetLtv", "type": "uint256" }, + { "internalType": "uint256", "name": "_maxLtv", "type": "uint256" }, + { "internalType": "uint8", "name": "_eModeCategory", "type": "uint8" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "newCallFee", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newTreasuryFee", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newStrategistFee", "type": "uint256" } + ], + "name": "FeesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "account", "type": "address" }], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "indexed": true, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32" }, + { "indexed": true, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32" } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "indexed": true, "internalType": "address", "name": "account", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "sender", "type": "address" } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "indexed": true, "internalType": "address", "name": "account", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "sender", "type": "address" } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": true, "internalType": "address", "name": "harvester", "type": "address" }], + "name": "StratHarvest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "newStrategistRemitter", "type": "address" }], + "name": "StrategistRemitterUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "newFee", "type": "uint256" }], + "name": "TotalFeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "account", "type": "address" }], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "AAVE_ADDRESSES_PROVIDER", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "AAVE_DATA_PROVIDER", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "AAVE_REWARDS_CONTROLLER", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ADDRESSES_PROVIDER", + "outputs": [{ "internalType": "contract IPoolAddressesProvider", "name": "", "type": "address" }], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "ADMIN", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GUARDIAN", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "KEEPER", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_FEE", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ONE_YEAR", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OP", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PERCENT_DIVISOR", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "POOL", + "outputs": [{ "internalType": "contract IPool", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STRATEGIST", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "STRATEGIST_MAX_FEE", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "USDC", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VELO_ROUTER", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "aWant", + "outputs": [{ "internalType": "contract IAToken", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_amount", "type": "uint256" }], + "name": "authorizedDelever", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_amount", "type": "uint256" }], + "name": "authorizedSendToVault", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_amount", "type": "uint256" }], + "name": "authorizedWithdrawUnderlying", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "int256", "name": "_n", "type": "int256" }], + "name": "averageAPRAcrossLastNHarvests", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_startIndex", "type": "uint256" }, + { "internalType": "uint256", "name": "_endIndex", "type": "uint256" } + ], + "name": "calculateAPRUsingLogs", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "callFee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "deposit", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "address[]", "name": "", "type": "address[]" }, + { "internalType": "uint256[]", "name": "", "type": "uint256[]" }, + { "internalType": "uint256[]", "name": "", "type": "uint256[]" }, + { "internalType": "address", "name": "initiator", "type": "address" }, + { "internalType": "bytes", "name": "", "type": "bytes" } + ], + "name": "executeOperation", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }], + "name": "getRoleAdmin", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "uint256", "name": "index", "type": "uint256" } + ], + "name": "getRoleMember", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }], + "name": "getRoleMemberCount", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getSupplyAndBorrow", + "outputs": [ + { "internalType": "uint256", "name": "supply", "type": "uint256" }, + { "internalType": "uint256", "name": "borrow", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "harvest", + "outputs": [{ "internalType": "uint256", "name": "callerFee", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "harvestLog", + "outputs": [ + { "internalType": "uint256", "name": "timestamp", "type": "uint256" }, + { "internalType": "uint256", "name": "vaultSharePrice", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "harvestLogCadence", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "harvestLogLength", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "hasRole", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastHarvestTimestamp", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxLtv", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minLeverageAmount", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "opToUsdcPath", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "opToWantPath", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "panic", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { "inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "paused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "rewardClaimingTokens", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_newTargetLtv", "type": "uint256" }, + { "internalType": "uint256", "name": "_newMaxLtv", "type": "uint256" } + ], + "name": "setLTVs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_newWithdrawSlippageTolerance", "type": "uint256" }, + { "internalType": "uint256", "name": "_newMinLeverageAmount", "type": "uint256" } + ], + "name": "setLeverageParams", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address[]", "name": "_path", "type": "address[]" }], + "name": "setOpToUsdcPath", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address[]", "name": "_path", "type": "address[]" }], + "name": "setOpToWantPath", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "strategistFee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "strategistRemitter", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "targetLtv", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalFee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "treasury", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "treasuryFee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "uint256", "name": "_callFee", "type": "uint256" }, + { "internalType": "uint256", "name": "_treasuryFee", "type": "uint256" }, + { "internalType": "uint256", "name": "_strategistFee", "type": "uint256" } + ], + "name": "updateFees", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_newCadenceInSeconds", "type": "uint256" }], + "name": "updateHarvestLogCadence", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_newStrategistRemitter", "type": "address" }], + "name": "updateStrategistRemitter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_totalFee", "type": "uint256" }], + "name": "updateTotalFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newTreasury", "type": "address" }], + "name": "updateTreasury", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vault", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "want", + "outputs": [{ "internalType": "contract IERC20", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_amount", "type": "uint256" }], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawSlippageTolerance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/oErc20.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/oErc20.ts similarity index 100% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/oErc20.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/oErc20.ts diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/reaperStrategy.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/reaperStrategy.ts similarity index 100% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/reaperStrategy.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/reaperStrategy.ts diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/tesseraPool.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/tesseraPool.ts similarity index 100% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/abis/tesseraPool.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/tesseraPool.ts diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts similarity index 88% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts index bb28bb264..1dee03ec8 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ankr-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; export class AnkrAprHandler implements AprHandler { tokens: { @@ -8,13 +8,11 @@ export class AnkrAprHandler implements AprHandler { serviceName: string; }; }; - networkPrismaId: string; url: string; readonly group = 'ANKR'; constructor(aprHandlerConfig: AnkrAprHandlerConfig) { this.tokens = aprHandlerConfig.tokens; - this.networkPrismaId = aprHandlerConfig.networkPrismaId; this.url = aprHandlerConfig.sourceUrl; } @@ -46,6 +44,5 @@ type AnkrAprHandlerConfig = { serviceName: string; }; }; - networkPrismaId: string; sourceUrl: string; }; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts similarity index 85% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts index 9cc9b26b7..2109e9180 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts @@ -1,6 +1,6 @@ import axios from 'axios'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; export class DefaultAprHandler implements AprHandler { tokens: { @@ -9,16 +9,14 @@ export class DefaultAprHandler implements AprHandler { url: string; path: string; scale: number; - networkPrismaId: string; - group = 'DEFAULT'; + group: string | undefined = undefined; constructor(aprHandlerConfig: DefaultAprHandlerConfig) { this.tokens = aprHandlerConfig.tokens; this.url = aprHandlerConfig.sourceUrl; - this.networkPrismaId = aprHandlerConfig.networkPrismaId; this.path = aprHandlerConfig.path ?? ''; this.scale = aprHandlerConfig.scale ?? 100; - this.group = aprHandlerConfig.group ?? 'DEFAULT'; + this.group = aprHandlerConfig.group; } async getAprs() { @@ -55,7 +53,6 @@ export type DefaultAprHandlerConfig = { [tokenName: string]: string; }; sourceUrl: string; - networkPrismaId: string; scale?: number; path?: string; group?: string; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts similarity index 90% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts index 3e90dc9e4..fa15ade47 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/euler-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts @@ -1,10 +1,9 @@ import axios from 'axios'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; export class EulerAprHandler implements AprHandler { tokens: { [key: string]: string }; subgraphUrl: string; - networkPrismaId: string; readonly group = 'EULER'; readonly query = ` @@ -23,7 +22,6 @@ export class EulerAprHandler implements AprHandler { constructor(aprHandlerConfig: EulerAprHandlerConfig) { this.tokens = aprHandlerConfig.tokens; this.subgraphUrl = aprHandlerConfig.subgraphUrl; - this.networkPrismaId = aprHandlerConfig.networkPrismaId; } async getAprs() { @@ -69,5 +67,4 @@ interface EulerResponse { type EulerAprHandlerConfig = { tokens: { [key: string]: string }; subgraphUrl: string; - networkPrismaId: string; }; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts similarity index 86% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts index f3cf9b72b..0a373d3be 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/gearbox-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts @@ -1,17 +1,15 @@ import axios from 'axios'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; export class GearboxAprHandler implements AprHandler { url: string; tokens: { [key: string]: string }; - networkPrismaId: string; readonly group = 'GEARBOX'; constructor(aprHandlerConfig: GearboxAprHandlerConfig) { this.tokens = aprHandlerConfig.tokens; this.url = aprHandlerConfig.sourceUrl; - this.networkPrismaId = aprHandlerConfig.networkPrismaId; } async getAprs() { @@ -35,5 +33,4 @@ export class GearboxAprHandler implements AprHandler { type GearboxAprHandlerConfig = { tokens: { [key: string]: string }; sourceUrl: string; - networkPrismaId: string; }; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts similarity index 90% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts index d2a23b59d..b4281f145 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/idle-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts @@ -1,6 +1,6 @@ import axios from 'axios'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; export class IdleAprHandler implements AprHandler { tokens: { @@ -11,14 +11,12 @@ export class IdleAprHandler implements AprHandler { }; url: string; authorizationHeader: string; - networkPrismaId: string; readonly group = 'IDLE'; constructor(aprHandlerConfig: IdleAprHandlerConfig) { this.tokens = aprHandlerConfig.tokens; this.url = aprHandlerConfig.sourceUrl; this.authorizationHeader = aprHandlerConfig.authorizationHeader; - this.networkPrismaId = aprHandlerConfig.networkPrismaId; } async getAprs() { @@ -54,5 +52,4 @@ type IdleAprHandlerConfig = { }; sourceUrl: string; authorizationHeader: string; - networkPrismaId: string; }; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts similarity index 89% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts index 73a033cdf..7fafd98de 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/ovix-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts @@ -2,10 +2,9 @@ import { BigNumber, Contract } from 'ethers'; import { abi } from './abis/oErc20'; import { JsonRpcProvider } from '@ethersproject/providers'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; export class OvixAprHandler implements AprHandler { - networkPrismaId: string; provider: JsonRpcProvider; tokens: { [tokenName: string]: { @@ -16,7 +15,6 @@ export class OvixAprHandler implements AprHandler { readonly group = 'OVIX'; constructor(aprHandlerConfig: OvixAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.networkPrismaId; this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); this.tokens = aprHandlerConfig.tokens; } @@ -41,7 +39,6 @@ export class OvixAprHandler implements AprHandler { } type OvixAprHandlerConfig = { - networkPrismaId: string; networkChainId: number; rpcUrl: string; tokens: { diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/reaper-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-apr-handler.ts similarity index 97% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/reaper-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-apr-handler.ts index da0aca61f..4dba7f291 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/reaper-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-apr-handler.ts @@ -2,7 +2,7 @@ import { JsonRpcProvider } from '@ethersproject/providers'; import { BigNumber, Contract } from 'ethers'; import { abi } from './abis/reaperStrategy'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; class ReaperAprHandler implements AprHandler { networkPrismaId: string; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts new file mode 100644 index 000000000..abb0ecb04 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts @@ -0,0 +1,143 @@ +import { AprHandler } from '../ib-linear-apr-handlers'; +import { getContractAt } from '../../../../../web3/contract'; +import ReaperCryptStrategyAbi from './abis/ReaperCryptStrategy.json'; +import axios from 'axios'; +import ReaperCryptAbi from './abis/ReaperCrypt.json'; +import { networkContext } from '../../../../../network/network-context.service'; + +const APR_PERCENT_DIVISOR = 10_000; + +const sFTMxBaseApr = 0.046; +export class ReaperCryptAprHandler implements AprHandler { + multiStrategyTokens?: { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean } }; + singleStrategyTokens?: { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean } }; + subgraphUrl?: string; + averageAPRAcrossLastNHarvests?: number; + wstETHBaseApr: number = 0; + + readonly query = `query getVaults($ids: [ID!]) { + vaults(where:{id_in: $ids}){ + id + apr + } + }`; + readonly group = 'REAPER'; + constructor(aprConfig: ReaperCryptAprHandlerConfig) { + this.multiStrategyTokens = aprConfig.multiStrategy?.tokens; + this.singleStrategyTokens = aprConfig.singleStrategy?.tokens; + this.subgraphUrl = aprConfig.multiStrategy?.subgraphUrl; + this.averageAPRAcrossLastNHarvests = aprConfig.singleStrategy?.averageAPRAcrossLastNHarvests; + } + + async getAprs(): Promise<{ [p: string]: number }> { + let multiStrategyAprs = {}; + let singleStrategyAprs = {}; + this.wstETHBaseApr = await this.getWstEthBaseApr(); + if (this.multiStrategyTokens !== undefined) { + multiStrategyAprs = await this.getMultiStrategyAprFromSubgraph(this.multiStrategyTokens); + } + if (this.singleStrategyTokens !== undefined) { + singleStrategyAprs = await this.getSingleStrategyCryptApr(this.singleStrategyTokens); + } + return { ...multiStrategyAprs, ...singleStrategyAprs }; + } + + private async getSingleStrategyCryptApr(tokens: { + [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean }; + }): Promise<{ [tokenAddress: string]: number }> { + const aprs: { [tokenAddress: string]: number } = {}; + console.log(networkContext.provider); + for (const { address, isSftmX, isWstETH } of Object.values(tokens)) { + const tokenContract = getContractAt(address, ReaperCryptAbi); + const strategyAddress = await tokenContract.strategy(); + const strategyContract = getContractAt(strategyAddress, ReaperCryptStrategyAbi); + let avgAprAcrossXHarvests = 0; + + avgAprAcrossXHarvests = + (await strategyContract.averageAPRAcrossLastNHarvests(this.averageAPRAcrossLastNHarvests)) / + APR_PERCENT_DIVISOR; + if (isSftmX) { + avgAprAcrossXHarvests = avgAprAcrossXHarvests * (1 + sFTMxBaseApr); + } + if (isWstETH) { + avgAprAcrossXHarvests = avgAprAcrossXHarvests * (1 + this.wstETHBaseApr); + } + aprs[address] = avgAprAcrossXHarvests; + } + + return aprs; + } + + private async getMultiStrategyAprFromSubgraph(tokens: { + [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean }; + }): Promise<{ [tokenAddress: string]: number }> { + const requestQuery = { + operationName: 'getVaults', + query: this.query, + variables: { + ids: Object.values(tokens).map(({ address }) => address), + }, + }; + const { + data: { data }, + }: { data: { data: MultiStratResponse } } = await axios({ + method: 'post', + url: this.subgraphUrl, + data: JSON.stringify(requestQuery), + }); + return data.vaults.reduce((acc, { id, apr }) => { + console.log(id); + const token = Object.values(tokens).find((token) => token.address.toLowerCase() === id.toLowerCase()); + if (!token) { + return acc; + } + let tokenApr = parseFloat(apr) / APR_PERCENT_DIVISOR; + if (token.isSftmX) { + tokenApr = tokenApr * (1 + sFTMxBaseApr); + } + if (token.isWstETH) { + tokenApr = tokenApr * (1 + this.wstETHBaseApr); + } + return { + ...acc, + [id]: tokenApr, + }; + }, {}); + } + + private async getWstEthBaseApr(): Promise { + const { data } = await axios.get<{ + data: { aprs: [{ timeUnix: number; apr: number }]; smaApr: number }; + }>('https://eth-api.lido.fi/v1/protocol/steth/apr/sma'); + return data.data.smaApr / 100; + } +} +type MultiStratResponse = { + vaults: { + id: string; + apr: string; + }[]; +}; +interface ReaperCryptAprHandlerConfig { + networkChainId: number; + multiStrategy?: { + subgraphUrl: string; + tokens: { + [tokenName: string]: { + address: string; + isSftmX?: boolean; + isWstETH?: boolean; + }; + }; + }; + singleStrategy?: { + averageAPRAcrossLastNHarvests: number; + tokens: { + [tokenName: string]: { + address: string; + isSftmX?: boolean; + isWstETH?: boolean; + }; + }; + }; +} diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts similarity index 91% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts index 400177e14..edb501a2c 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tessera-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts @@ -2,10 +2,9 @@ import { Contract } from 'ethers'; import { abi } from './abis/tesseraPool'; import { JsonRpcProvider } from '@ethersproject/providers'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; export class TesseraAprHandler implements AprHandler { - networkPrismaId: string; provider: JsonRpcProvider; tokens: { [tokenName: string]: { @@ -16,7 +15,6 @@ export class TesseraAprHandler implements AprHandler { readonly group = 'TESSERA'; constructor(aprHandlerConfig: TesseraAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.networkPrismaId; this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); this.tokens = aprHandlerConfig.tokens; } @@ -48,7 +46,6 @@ export class TesseraAprHandler implements AprHandler { } type TesseraAprHandlerConfig = { - networkPrismaId: string; networkChainId: number; rpcUrl: string; tokens: { diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts similarity index 85% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts index c1bd98762..9651f34d7 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tetu-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts @@ -1,9 +1,8 @@ import axios from 'axios'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; export class TetuAprHandler implements AprHandler { - networkPrismaId: string; sourceUrl: string; tokens: { [tokenName: string]: string; @@ -11,7 +10,6 @@ export class TetuAprHandler implements AprHandler { readonly group = 'TETU'; constructor(aprHandlerConfig: TetuAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.networkPrismaId; this.sourceUrl = aprHandlerConfig.sourceUrl; this.tokens = aprHandlerConfig.tokens; } @@ -32,7 +30,6 @@ export class TetuAprHandler implements AprHandler { } type TetuAprHandlerConfig = { - networkPrismaId: string; sourceUrl: string; tokens: { [tokenName: string]: string; diff --git a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts similarity index 90% rename from modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts rename to modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts index 009c743c8..42e87e3a9 100644 --- a/modules/pool/lib/apr-data-sources/base-apr-handlers/sources/tranchess-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts @@ -1,9 +1,8 @@ import axios from 'axios'; -import { AprHandler } from '../base-apr-handlers'; +import { AprHandler } from '../ib-linear-apr-handlers'; export class TranchessAprHandler implements AprHandler { - networkPrismaId: string; url: string; tokens: { [tokenName: string]: { @@ -14,7 +13,6 @@ export class TranchessAprHandler implements AprHandler { readonly group = 'TRANCHESS'; constructor(aprHandlerConfig: TranchessAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.networkPrismaId; this.tokens = aprHandlerConfig.tokens; this.url = aprHandlerConfig.sourceUrl; } @@ -39,7 +37,6 @@ export class TranchessAprHandler implements AprHandler { } type TranchessAprHandlerConfig = { - networkPrismaId: string; tokens: { [tokenName: string]: { address: string; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts new file mode 100644 index 000000000..ef4d53eda --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts @@ -0,0 +1,26 @@ +import { AprHandler } from '../ib-linear-apr-handlers'; +import axios from 'axios'; +import { YearnVault } from '../../apr-types'; +import { networkContext } from '../../../../../network/network-context.service'; + +export class YearnAprHandler implements AprHandler { + sourceUrl: string; + group: string = 'YEARN'; + + constructor(aprHandlerConfig: YearnAprHandlerConfig) { + this.sourceUrl = aprHandlerConfig.sourceUrl; + } + async getAprs(): Promise<{ [p: string]: number }> { + const { data } = await axios.get(this.sourceUrl); + const aprs = Object.fromEntries( + data.map(({ address, apy: { net_apy } }) => { + return [address.toLowerCase(), net_apy]; + }), + ); + return aprs; + } +} + +interface YearnAprHandlerConfig { + sourceUrl: string; +} diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 50b4c6bb7..b0f833dcb 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -3,14 +3,14 @@ import { PrismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; import { prisma } from '../../../../prisma/prisma-client'; import { networkContext } from '../../../network/network-context.service'; import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; -import { PrismaPoolAprItemGroup } from '@prisma/client'; -import { BaseAprHandlers, TokenApr } from './base-apr-handlers/base-apr-handlers'; +import { PrismaPoolAprItemGroup, PrismaPoolLinearData } from '@prisma/client'; +import { IbLinearAprHandlers, TokenApr } from './ib-linear-apr-handlers/ib-linear-apr-handlers'; import { TokenService } from '../../../token/token.service'; import { collectsYieldFee } from '../pool-utils'; import { AprConfig } from '../../../network/network-config-types'; export class IbTokensAprService implements PoolAprService { - private baseAprHandlers: BaseAprHandlers; + private baseAprHandlers: IbLinearAprHandlers; constructor( aprConfig: AprConfig, @@ -18,7 +18,7 @@ export class IbTokensAprService implements PoolAprService { networkChainId: number, private readonly tokenService: TokenService, ) { - this.baseAprHandlers = new BaseAprHandlers(aprConfig, networkPrismaId, networkChainId); + this.baseAprHandlers = new IbLinearAprHandlers(aprConfig, networkPrismaId, networkChainId); } getAprServiceName(): string { @@ -37,41 +37,96 @@ export class IbTokensAprService implements PoolAprService { }); }); for (const pool of tokenYieldPools) { + if (!pool.dynamicData) { + continue; + } const totalLiquidity = pool.dynamicData?.totalLiquidity; - for (const token of pool.tokens) { - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : networkContext.data.balancer.yieldProtocolFeePercentage; - const tokenPrice = this.tokenService.getPriceForToken(tokenPrices, token.address); - const tokenBalance = token.dynamicData?.balance; - const tokenApr = aprs.get(token.address); - if (tokenPrice && tokenBalance && totalLiquidity !== undefined && tokenApr !== undefined) { - const tokenPercentage = (parseFloat(tokenBalance) * tokenPrice) / totalLiquidity; - const poolTokenApr = totalLiquidity > 0 ? tokenApr.val * tokenPercentage : 0; - const aprAfterFees = - pool.type === 'META_STABLE' - ? poolTokenApr * (1 - networkContext.data.balancer.swapProtocolFeePercentage) - : poolTokenApr * (1 - protocolYieldFeePercentage); - const tokenSymbol = token.token.symbol; - const itemId = `${pool.id}-${tokenSymbol}-yield-apr`; - operations.push( - prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `${tokenSymbol} APR`, - apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, - group: tokenApr.group as PrismaPoolAprItemGroup, - type: pool.type === 'LINEAR' ? 'LINEAR_BOOSTED' : 'IB_YIELD', - }, - update: { - title: `${tokenSymbol} APR`, - apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, - }, - }), - ); + if (!totalLiquidity) { + continue; + } + const isLinear = pool.type === 'LINEAR' && pool.linearData !== null; + if (!isLinear) { + // TODO: In theory, we should check whether the token has a rate provider set, but we don't store this information yet + for (const token of pool.tokens) { + const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee + ? parseFloat(pool.dynamicData.protocolYieldFee) + : networkContext.data.balancer.yieldProtocolFeePercentage; + const tokenPrice = this.tokenService.getPriceForToken(tokenPrices, token.address); + const tokenBalance = token.dynamicData?.balance; + const tokenApr = aprs.get(token.address); + if (tokenPrice && tokenBalance && tokenApr !== undefined) { + const tokenPercentage = (parseFloat(tokenBalance) * tokenPrice) / totalLiquidity; + const poolTokenApr = totalLiquidity > 0 ? tokenApr.val * tokenPercentage : 0; + const aprAfterFees = + pool.type === 'META_STABLE' + ? poolTokenApr * (1 - networkContext.data.balancer.swapProtocolFeePercentage) + : poolTokenApr * (1 - protocolYieldFeePercentage); + const tokenSymbol = token.token.symbol; + const itemId = `${pool.id}-${tokenSymbol}-yield-apr`; + operations.push( + prisma.prismaPoolAprItem.upsert({ + where: { id_chain: { id: itemId, chain: networkContext.chain } }, + create: { + id: itemId, + chain: networkContext.chain, + poolId: pool.id, + title: `${tokenSymbol} APR`, + apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, + group: tokenApr.group as PrismaPoolAprItemGroup, + type: 'IB_YIELD', + }, + update: { + title: `${tokenSymbol} APR`, + apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, + }, + }), + ); + } + } + } else { + // If pool is Linear + if (!isLinear) { + continue; + } + const linearData = pool.linearData as PrismaPoolLinearData; + const wrappedToken = pool.tokens[linearData.wrappedIndex]; + const mainToken = pool.tokens[linearData.mainIndex]; + for (const token of pool.tokens) { + const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee + ? parseFloat(pool.dynamicData.protocolYieldFee) + : networkContext.data.balancer.yieldProtocolFeePercentage; + const tokenPrice = this.tokenService.getPriceForToken(tokenPrices, mainToken.address); + const wrappedTokenBalance = parseFloat(wrappedToken.dynamicData?.balance || '0'); + const wrappedTokenPriceRate = parseFloat(wrappedToken.dynamicData?.priceRate || '1.0'); + const poolWrappedLiquidity = wrappedTokenBalance * wrappedTokenPriceRate * tokenPrice; + const totalLiquidity = pool.dynamicData.totalLiquidity; + const tokenApr = aprs.get(wrappedToken.address); + if (tokenPrice && wrappedTokenBalance && totalLiquidity !== undefined && tokenApr !== undefined) { + const tokenPercentage = poolWrappedLiquidity / totalLiquidity; + const poolTokenApr = totalLiquidity > 0 ? tokenApr.val * tokenPercentage : 0; + const aprAfterFees = poolTokenApr * (1 - protocolYieldFeePercentage); + const tokenSymbol = token.token.symbol; + const isBoosted = this.baseAprHandlers.wrappedBoostedTokens.includes(wrappedToken.address); + const itemId = `${pool.id}-${tokenSymbol}-${isBoosted ? 'boosted' : 'yield'}-apr`; + operations.push( + prisma.prismaPoolAprItem.upsert({ + where: { id_chain: { id: itemId, chain: networkContext.chain } }, + create: { + id: itemId, + chain: networkContext.chain, + poolId: pool.id, + title: `${tokenSymbol} APR`, + apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, + group: tokenApr.group as PrismaPoolAprItemGroup, + type: isBoosted ? 'LINEAR_BOOSTED' : 'IB_YIELD', + }, + update: { + title: `${tokenSymbol} APR`, + apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, + }, + }), + ); + } } } } diff --git a/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts b/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts index 80197b5dc..1d2acc199 100644 --- a/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts @@ -13,7 +13,7 @@ export class LiquidStakedBaseAprService { return 0.046; } - //TODO - Remove this, since it's already in base-apr-handlers + //TODO - Remove this, since it's already in ib-linear-apr-handlers public async getAnkrFtmBaseApr(): Promise { const { data } = await axios.get<{ services: { serviceName: string; apy: string }[] }>( 'https://api.staking.ankr.com/v1alpha/metrics', @@ -23,7 +23,7 @@ export class LiquidStakedBaseAprService { const ankrFtmApy = data.services.find((service) => service.serviceName === 'ftm'); return parseFloat(ankrFtmApy?.apy || '0') / 100; } - //TODO - Remove this, since it's already in base-apr-handlers + //TODO - Remove this, since it's already in ib-linear-apr-handlers public async getAnkrEthBaseApr(): Promise { const { data } = await axios.get<{ services: { serviceName: string; apy: string }[] }>( 'https://api.staking.ankr.com/v1alpha/metrics', diff --git a/modules/pool/lib/apr-data-sources/optimism/overnight-apr.service.ts b/modules/pool/lib/apr-data-sources/optimism/overnight-apr.service.ts deleted file mode 100644 index dea9486e3..000000000 --- a/modules/pool/lib/apr-data-sources/optimism/overnight-apr.service.ts +++ /dev/null @@ -1,74 +0,0 @@ -import axios from 'axios'; -import { prisma } from '../../../../../prisma/prisma-client'; -import { PrismaPoolWithExpandedNesting } from '../../../../../prisma/prisma-types'; -import { TokenService } from '../../../../token/token.service'; -import { PoolAprService } from '../../../pool-types'; -import { networkContext } from '../../../../network/network-context.service'; - -type OvernightApr = { - value: number; - date: string; -}; - -export class OvernightAprService implements PoolAprService { - private readonly overnightTokens: Record = { - //these should always be stored in all lowercase - '0xa348700745d249c3b49d2c2acac9a5ae8155f826': 'usd+', - '0x0b8f31480249cc717081928b8af733f45f6915bb': 'dai+', - }; - private readonly wrappedTokenAddresses = Object.keys(this.overnightTokens); - - constructor(private readonly overnightAprEndpoint: string, private readonly tokenService: TokenService) {} - - public getAprServiceName(): string { - return 'OvernightAprService'; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const tokenPrices = await this.tokenService.getTokenPrices(); - const overnightLinearPools = pools.filter( - (pool) => - pool.type === 'LINEAR' && - pool.tokens.some((token) => this.wrappedTokenAddresses.includes(token.address)), - ); - - for (const pool of overnightLinearPools) { - if (!pool.linearData || !pool.dynamicData) { - continue; - } - - const itemId = `${pool.id}-overnight`; - - const linearData = pool.linearData; - const wrappedToken = pool.tokens[linearData.wrappedIndex]; - const apiQuerySlug = this.overnightTokens[wrappedToken.token.address]; - - const { data: aprData } = await axios.get( - `${this.overnightAprEndpoint}/${apiQuerySlug}/fin-data/avg-apr/week`, - ); - - const mainToken = pool.tokens[linearData.mainIndex]; - - const mainTokenPrice = this.tokenService.getPriceForToken(tokenPrices, mainToken.address); - const wrappedTokens = parseFloat(wrappedToken.dynamicData?.balance || '0'); - const priceRate = parseFloat(wrappedToken.dynamicData?.priceRate || '1.0'); - const poolWrappedLiquidity = wrappedTokens * priceRate * mainTokenPrice; - const totalLiquidity = pool.dynamicData.totalLiquidity; - const apr = totalLiquidity > 0 ? (aprData.value / 100) * (poolWrappedLiquidity / totalLiquidity) : 0; - - await prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `${wrappedToken.token.symbol} APR`, - apr, - group: 'OVERNIGHT', - type: 'LINEAR_BOOSTED', - }, - update: { apr, group: 'OVERNIGHT', type: 'LINEAR_BOOSTED', title: `${wrappedToken.token.symbol} APR` }, - }); - } - } -} From c509044e6c5267eee7f4c8196fb012008f870d73 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 29 Aug 2023 00:00:48 -0300 Subject: [PATCH 25/42] Removing Reaper Crypt Apr Service; --- modules/network/arbitrum.ts | 2 - modules/network/mainnet.ts | 1 - modules/network/optimism.ts | 3 - .../reaper-crypt-apr.service.ts | 182 ------------------ 4 files changed, 188 deletions(-) delete mode 100644 modules/pool/lib/apr-data-sources/reaper-crypt-apr.service.ts diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index e449fd0d2..3df191451 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -1,8 +1,6 @@ import { BigNumber, ethers } from 'ethers'; import { NetworkConfig, NetworkData } from './network-config-types'; import { tokenService } from '../token/token.service'; -import { WstethAprService } from '../pool/lib/apr-data-sources/optimism/wsteth-apr.service'; -import { ReaperCryptAprService } from '../pool/lib/apr-data-sources/reaper-crypt-apr.service'; import { PhantomStableAprService } from '../pool/lib/apr-data-sources/phantom-stable-apr.service'; import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool-apr.service'; import { SwapFeeAprService } from '../pool/lib/apr-data-sources/swap-fee-apr.service'; diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 7ec504796..e7280bbe8 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -2,7 +2,6 @@ import { BigNumber, ethers } from 'ethers'; import { NetworkConfig, NetworkData } from './network-config-types'; import { tokenService } from '../token/token.service'; import { WstethAprService } from '../pool/lib/apr-data-sources/optimism/wsteth-apr.service'; -import { ReaperCryptAprService } from '../pool/lib/apr-data-sources/reaper-crypt-apr.service'; import { PhantomStableAprService } from '../pool/lib/apr-data-sources/phantom-stable-apr.service'; import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool-apr.service'; import { SwapFeeAprService } from '../pool/lib/apr-data-sources/swap-fee-apr.service'; diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 5d5280c0e..3aeb06ec6 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -1,9 +1,6 @@ import { BigNumber, ethers } from 'ethers'; import { NetworkConfig, NetworkData } from './network-config-types'; -import { RocketPoolStakedEthAprService } from '../pool/lib/apr-data-sources/optimism/rocket-pool-staked-eth-apr.service'; import { tokenService } from '../token/token.service'; -import { WstethAprService } from '../pool/lib/apr-data-sources/optimism/wsteth-apr.service'; -import { ReaperCryptAprService } from '../pool/lib/apr-data-sources/reaper-crypt-apr.service'; import { PhantomStableAprService } from '../pool/lib/apr-data-sources/phantom-stable-apr.service'; import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool-apr.service'; import { SwapFeeAprService } from '../pool/lib/apr-data-sources/swap-fee-apr.service'; diff --git a/modules/pool/lib/apr-data-sources/reaper-crypt-apr.service.ts b/modules/pool/lib/apr-data-sources/reaper-crypt-apr.service.ts deleted file mode 100644 index 492496222..000000000 --- a/modules/pool/lib/apr-data-sources/reaper-crypt-apr.service.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { isSameAddress } from '@balancer-labs/sdk'; -import * as Sentry from '@sentry/node'; -import { prisma } from '../../../../prisma/prisma-client'; -import { PrismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; -import { tokenService } from '../../../token/token.service'; -import { getContractAt } from '../../../web3/contract'; -import { PoolAprService } from '../../pool-types'; -import ReaperCryptAbi from './abi/ReaperCrypt.json'; -import ReaperCryptStrategyAbi from './abi/ReaperCryptStrategy.json'; -import { networkContext } from '../../../network/network-context.service'; -import { liquidStakedBaseAprService } from './liquid-staked-base-apr.service'; -import axios from 'axios'; -import { Contract } from 'ethers'; - -type MultiStratQueryResponse = { - data: { - vault: { - apr: string; - }; - }; -}; - -export class ReaperCryptAprService implements PoolAprService { - private readonly APR_PERCENT_DIVISOR = 10_000; - - constructor( - private readonly linearPoolFactories: string[], - private readonly linearPoolsFromErc4626Factory: string[], - private readonly averageAPRAcrossLastNHarvests: number, - private readonly sFtmXAddress: string | undefined, - private readonly wstEthAddress: string | undefined, - ) {} - - public getAprServiceName(): string { - return 'ReaperCryptAprService'; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const tokenPrices = await tokenService.getTokenPrices(); - - for (const pool of pools) { - if ( - (!this.linearPoolFactories.includes(pool.factory || '') && - !this.linearPoolsFromErc4626Factory.includes(pool.id)) || - !pool.linearData || - !pool.dynamicData - ) { - continue; - } - const linearData = pool.linearData; - const wrappedToken = pool.tokens[linearData.wrappedIndex]; - const mainToken = pool.tokens[linearData.mainIndex]; - - const cryptContract = getContractAt(wrappedToken.address, ReaperCryptAbi); - - const cryptName = await cryptContract.name(); - - let cryptApr = 0; - let itemId = ''; - - if (cryptName.includes('Multi-Strategy')) { - cryptApr = await this.getMultiStrategyAprFromSubgraph(wrappedToken.address); - itemId = `${pool.id}-reaper-mutlistrat`; - } else { - try { - cryptApr = await this.getSingleStrategyCryptApr(cryptContract); - itemId = `${pool.id}-reaper-crypt`; - } catch (e) { - Sentry.captureException(e, { - tags: { - poolId: pool.id, - poolName: pool.name, - cryptContract: wrappedToken.address, - }, - }); - continue; - } - } - - const tokenPrice = tokenService.getPriceForToken(tokenPrices, mainToken.address); - const wrappedTokens = parseFloat(wrappedToken.dynamicData?.balance || '0'); - const priceRate = parseFloat(wrappedToken.dynamicData?.priceRate || '1.0'); - const poolWrappedLiquidity = wrappedTokens * priceRate * tokenPrice; - const totalLiquidity = pool.dynamicData!.totalLiquidity; - let apr = totalLiquidity > 0 ? cryptApr * (poolWrappedLiquidity / totalLiquidity) : 0; - - await prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `${wrappedToken.token.symbol} APR`, - apr: apr, - group: 'REAPER', - type: 'LINEAR_BOOSTED', - }, - update: { title: `${wrappedToken.token.symbol} APR`, apr: apr }, - }); - - // if we have sftmx as the main token in this linear pool, we want to take the linear APR top level and - // we also need to adapt the APR since the vault APR is denominated in sFTMx, so we need to apply the growth rate - // and add the sftmx base apr to the unwrapped portion - if (this.sFtmXAddress && isSameAddress(mainToken.address, this.sFtmXAddress)) { - const baseApr = await liquidStakedBaseAprService.getSftmxBaseApr(); - if (baseApr > 0) { - const boostedVaultApr = this.getBoostedVaultApr( - totalLiquidity, - cryptApr, - baseApr, - poolWrappedLiquidity, - ); - - await prisma.prismaPoolAprItem.update({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - data: { - apr: boostedVaultApr, - }, - }); - } - } - - if (this.wstEthAddress && isSameAddress(mainToken.address, this.wstEthAddress)) { - const baseApr = await liquidStakedBaseAprService.getWstEthBaseApr(); - if (baseApr > 0) { - const boostedVaultApr = this.getBoostedVaultApr( - totalLiquidity, - cryptApr, - baseApr, - poolWrappedLiquidity, - ); - - await prisma.prismaPoolAprItem.update({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - data: { apr: boostedVaultApr }, - }); - } - } - } - } - - private async getSingleStrategyCryptApr(cryptContract: Contract): Promise { - const cryptStrategyAddress = await cryptContract.strategy(); - - const strategyContract = getContractAt(cryptStrategyAddress, ReaperCryptStrategyAbi); - let avgAprAcrossXHarvests = 0; - - avgAprAcrossXHarvests = - (await strategyContract.averageAPRAcrossLastNHarvests(this.averageAPRAcrossLastNHarvests)) / - this.APR_PERCENT_DIVISOR; - - return avgAprAcrossXHarvests; - } - - private async getMultiStrategyAprFromSubgraph(address: string): Promise { - const baseUrl = networkContext.data.reaper.multistratAprSubgraphUrl; - - const { data } = await axios.post(baseUrl, { - query: `query { - vault(id: "${address}"){ - apr - } - }`, - }); - - if (data.data.vault && data.data.vault.apr) { - return parseFloat(data.data.vault.apr); - } - return 0; - } - - private getBoostedVaultApr( - totalLiquidity: number, - vaultHarvestApr: number, - IbBaseApr: number, - poolWrappedLiquidity: number, - ) { - return totalLiquidity > 0 - ? ((1 + vaultHarvestApr) * (1 + IbBaseApr) - 1) * (poolWrappedLiquidity / totalLiquidity) - : 0; - } -} From 3d568ca0ba3dcfc29f064ea32a24677a3922d470 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 29 Aug 2023 19:29:13 -0300 Subject: [PATCH 26/42] Removing services that are already in the ib-yield service; Adding fixed apr tokens; Removing logs --- modules/balancer/loadRestRoutes.ts | 7 ++- modules/network/fantom.ts | 8 ++- modules/network/mainnet.ts | 6 -- modules/network/network-config-types.ts | 18 ++++++ modules/network/optimism.ts | 17 +++++- modules/network/zkevm.ts | 6 -- .../fantom/stader-staked-ftm-apr.service.ts | 57 ------------------ .../ib-linear-apr-handlers.ts | 17 +++++- .../sources/beefy-apr-handler.ts | 50 ++++++++++++++++ .../sources/reaper-crypt-apr-handler.ts | 2 - .../rocket-pool-staked-eth-apr.service.ts | 54 ----------------- .../optimism/wsteth-apr.service.ts | 59 ------------------- 12 files changed, 110 insertions(+), 191 deletions(-) delete mode 100644 modules/pool/lib/apr-data-sources/fantom/stader-staked-ftm-apr.service.ts create mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/optimism/rocket-pool-staked-eth-apr.service.ts delete mode 100644 modules/pool/lib/apr-data-sources/optimism/wsteth-apr.service.ts diff --git a/modules/balancer/loadRestRoutes.ts b/modules/balancer/loadRestRoutes.ts index 26894317d..b4da58c46 100644 --- a/modules/balancer/loadRestRoutes.ts +++ b/modules/balancer/loadRestRoutes.ts @@ -5,6 +5,7 @@ import { networkContext } from '../network/network-context.service'; import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; import { tokenService } from '../token/token.service'; import { mainnetNetworkData } from '../network/mainnet'; +import { optimismNetworkData } from '../network/optimism'; export function loadRestRoutesBalancer(app: Express) { app.use('/health', (req, res) => res.sendStatus(200)); @@ -14,9 +15,9 @@ export function loadRestRoutesBalancer(app: Express) { where: { chain: networkContext.chain }, }); const ibTokensAprService = new IbTokensAprService( - mainnetNetworkData.ibAprConfig, - mainnetNetworkData.chain.prismaId, - mainnetNetworkData.chain.id, + optimismNetworkData.ibAprConfig, + optimismNetworkData.chain.prismaId, + optimismNetworkData.chain.id, tokenService, ); await ibTokensAprService.updateAprForPools(pools); diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index 0ffb669ea..3b389dbb8 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -1,7 +1,6 @@ import { BigNumber, ethers } from 'ethers'; import { NetworkConfig, NetworkData } from './network-config-types'; import { tokenService } from '../token/token.service'; -import { StaderStakedFtmAprService } from '../pool/lib/apr-data-sources/fantom/stader-staked-ftm-apr.service'; import { PhantomStableAprService } from '../pool/lib/apr-data-sources/phantom-stable-apr.service'; import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool-apr.service'; import { SwapFeeAprService } from '../pool/lib/apr-data-sources/swap-fee-apr.service'; @@ -222,6 +221,12 @@ const fantomNetworkData: NetworkData = { yearn: { sourceUrl: 'https://d28fcsszptni1s.cloudfront.net/v1/chains/250/vaults/all', }, + fixedAprTokens: { + sFTMx: { + address: '0xd7028092c830b5c8fce061af2e593413ebbc1fc1', + value: 0.046, + }, + }, }, copper: { proxyAddress: '0xbC8a71C75ffbd2807c021F4F81a8832392dEF93c', @@ -277,7 +282,6 @@ export const fantomNetworkConfig: NetworkConfig = { tokenService, ), // new SpookySwapAprService(tokenService, fantomNetworkData.spooky!.xBooContract), - new StaderStakedFtmAprService(tokenService, fantomNetworkData.stader!.sFtmxContract), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(fantomNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index e7280bbe8..a667c09aa 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -1,7 +1,6 @@ import { BigNumber, ethers } from 'ethers'; import { NetworkConfig, NetworkData } from './network-config-types'; import { tokenService } from '../token/token.service'; -import { WstethAprService } from '../pool/lib/apr-data-sources/optimism/wsteth-apr.service'; import { PhantomStableAprService } from '../pool/lib/apr-data-sources/phantom-stable-apr.service'; import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool-apr.service'; import { SwapFeeAprService } from '../pool/lib/apr-data-sources/swap-fee-apr.service'; @@ -320,10 +319,6 @@ export const mainnetNetworkData: NetworkData = { beefy: { linearPools: [''], }, - lido: { - wstEthAprEndpoint: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - wstEthContract: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', - }, datastudio: { main: { user: 'datafeed-service@datastudio-366113.iam.gserviceaccount.com', @@ -361,7 +356,6 @@ export const mainnetNetworkConfig: NetworkConfig = { mainnetNetworkData.chain.id, tokenService, ), - new WstethAprService(tokenService, mainnetNetworkData.lido!.wstEthContract), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(mainnetNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index 1e9d3093d..af69df74f 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -181,6 +181,17 @@ export interface AprConfig { }; }; }; + beefy?: { + sourceUrl: string; + tokens: { + [tokenName: string]: { + address: string; + // To get the vaultId, get the vault address from the token contract(token.vault()), + // and search for the vault address in the link: https://api.beefy.finance/vaults + vaultId: string; + }; + }; + }; euler?: { subgraphUrl: string; tokens: { @@ -272,4 +283,11 @@ export interface AprConfig { group?: string; }; }; + fixedAprTokens?: { + [tokenName: string]: { + address: string; + value: number; + group?: string; + }; + }; } diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 3aeb06ec6..16cfedf3c 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -19,7 +19,7 @@ import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/ import { BeefyVaultAprService } from '../pool/lib/apr-data-sources/beefy-vault-apr.service copy'; import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; -const optimismNetworkData: NetworkData = { +export const optimismNetworkData: NetworkData = { chain: { slug: 'optimism', id: 10, @@ -114,6 +114,21 @@ const optimismNetworkData: NetworkData = { }, }, ibAprConfig: { + beefy: { + sourceUrl: 'https://api.beefy.finance/apy/breakdown?_=', + tokens: { + wmooExactlySupplyUSDC: { + address: '0xe5e9168b45a90c1e5730da6184cc5901c6e4353f', + vaultId: 'exactly-supply-usdc', + }, + wmooExactlySupplyETH: { + address: '0x44b1cea4f597f493e2fd0833a9c04dfb1e479ef0', + vaultId: 'exactly-supply-eth', + }, + // To get the vaultId, get the vault address from the token contract(token.vault()), + // and search for the vault address in the link: https://api.beefy.finance/vaults + }, + }, reaper: { multiStrategy: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/byte-masons/multi-strategy-vaults-optimism', diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index d471220b6..f2429d84d 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -1,7 +1,6 @@ import { BigNumber, ethers } from 'ethers'; import { NetworkConfig, NetworkData } from './network-config-types'; import { tokenService } from '../token/token.service'; -import { WstethAprService } from '../pool/lib/apr-data-sources/optimism/wsteth-apr.service'; import { PhantomStableAprService } from '../pool/lib/apr-data-sources/phantom-stable-apr.service'; import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool-apr.service'; import { SwapFeeAprService } from '../pool/lib/apr-data-sources/swap-fee-apr.service'; @@ -133,10 +132,6 @@ const zkevmNetworkData: NetworkData = { beefy: { linearPools: [''], }, - lido: { - wstEthAprEndpoint: '', - wstEthContract: '', - }, datastudio: { main: { user: 'datafeed-service@datastudio-366113.iam.gserviceaccount.com', @@ -174,7 +169,6 @@ export const zkevmNetworkConfig: NetworkConfig = { zkevmNetworkData.chain.id, tokenService, ), - new WstethAprService(tokenService, zkevmNetworkData.lido!.wstEthContract), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(zkevmNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/pool/lib/apr-data-sources/fantom/stader-staked-ftm-apr.service.ts b/modules/pool/lib/apr-data-sources/fantom/stader-staked-ftm-apr.service.ts deleted file mode 100644 index c1f2905f4..000000000 --- a/modules/pool/lib/apr-data-sources/fantom/stader-staked-ftm-apr.service.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { prisma } from '../../../../../prisma/prisma-client'; -import { PrismaPoolWithExpandedNesting } from '../../../../../prisma/prisma-types'; -import { TokenService } from '../../../../token/token.service'; -import { PoolAprService } from '../../../pool-types'; -import { networkContext } from '../../../../network/network-context.service'; -import { collectsYieldFee } from '../../pool-utils'; -import { liquidStakedBaseAprService } from '../liquid-staked-base-apr.service'; - -export class StaderStakedFtmAprService implements PoolAprService { - constructor(private readonly tokenService: TokenService, private readonly sftmxAddress: string) {} - - public getAprServiceName(): string { - return 'StaderStakedFtmAprService'; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const tokenPrices = await this.tokenService.getTokenPrices(); - const sftmxPrice = this.tokenService.getPriceForToken(tokenPrices, this.sftmxAddress); - const sftmxBaseApr = await liquidStakedBaseAprService.getSftmxBaseApr(); - - let operations: any[] = []; - - for (const pool of pools) { - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : networkContext.data.balancer.yieldProtocolFeePercentage; - const sftmxToken = pool.tokens.find((token) => token.address === this.sftmxAddress); - const sftmxTokenBalance = sftmxToken?.dynamicData?.balance; - - if (sftmxTokenBalance && pool.dynamicData) { - const sftmxPercentage = (parseFloat(sftmxTokenBalance) * sftmxPrice) / pool.dynamicData.totalLiquidity; - const sftmxApr = pool.dynamicData.totalLiquidity > 0 ? sftmxBaseApr * sftmxPercentage : 0; - - const userApr = - pool.type === 'META_STABLE' - ? sftmxApr * (1 - networkContext.data.balancer.swapProtocolFeePercentage) - : sftmxApr * (1 - protocolYieldFeePercentage); - - operations.push( - prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: `${pool.id}-sftmx-apr`, chain: networkContext.chain } }, - update: { apr: collectsYieldFee(pool) ? userApr : sftmxApr }, - create: { - id: `${pool.id}-sftmx-apr`, - chain: networkContext.chain, - poolId: pool.id, - apr: collectsYieldFee(pool) ? userApr : sftmxApr, - title: 'sFTMx APR', - type: 'IB_YIELD', - }, - }), - ); - } - } - await Promise.all(operations); - } -} diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts index a0909fbd2..8012e3073 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts @@ -11,15 +11,18 @@ import { TranchessAprHandler } from './sources/tranchess-apr-handler'; import { AprConfig } from '../../../../network/network-config-types'; import { YearnAprHandler } from './sources/yearn-apr-handler'; import { ReaperCryptAprHandler } from './sources/reaper-crypt-apr-handler'; +import { BeefyAprHandler } from './sources/beefy-apr-handler'; export class IbLinearAprHandlers { private handlers: AprHandler[] = []; //List of addresses of wrappedBoostedTokens, used to check what is LINEAR_BOOSTED APR and what is IB_YIELD APR wrappedBoostedTokens: string[] = []; + fixedAprTokens?: { [tokenName: string]: { address: string; value: number; group?: string } }; constructor(aprConfig: AprConfig, networkPrismaId: string, networkChainId: number) { this.handlers = this.buildAprHandlers(aprConfig, networkPrismaId, networkChainId); this.wrappedBoostedTokens = this.buildWrappedBoostedTokens(aprConfig); + this.fixedAprTokens = aprConfig.fixedAprTokens; } buildAprHandlers(aprConfig: AprConfig, networkPrismaId: string, networkChainId: number) { @@ -34,6 +37,10 @@ export class IbLinearAprHandlers { const ankrHandler = new AnkrAprHandler(aprConfig.ankr); handlers.push(ankrHandler); } + if (aprConfig.beefy) { + const beefyHandler = new BeefyAprHandler(aprConfig.beefy); + handlers.push(beefyHandler); + } if (aprConfig.euler) { const eulerHandler = new EulerAprHandler(aprConfig.euler); handlers.push(eulerHandler); @@ -124,7 +131,15 @@ export class IbLinearAprHandlers { }); } } - console.log(aprs); + if (this.fixedAprTokens) { + for (const { address, value, group } of Object.values(this.fixedAprTokens)) { + aprs.push({ + val: value, + group, + address, + }); + } + } return aprs; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts new file mode 100644 index 000000000..e6934fd7a --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts @@ -0,0 +1,50 @@ +import { AprHandler } from '../ib-linear-apr-handlers'; +import axios from 'axios'; + +export class BeefyAprHandler implements AprHandler { + tokens: { + [tokenName: string]: { + address: string; + vaultId: string; + }; + }; + sourceUrl: string; + group: string | undefined = 'BEEFY'; + + constructor(aprConfig: BeefyAprHandlerConfig) { + this.tokens = aprConfig.tokens; + this.sourceUrl = aprConfig.sourceUrl; + } + + async getAprs(): Promise<{ [p: string]: number }> { + const { data: aprData } = await axios.get(this.sourceUrl); + const aprs: { [tokenAddress: string]: number } = {}; + for (const { address, vaultId } of Object.values(this.tokens)) { + aprs[address] = aprData[vaultId].vaultApr; + } + return aprs; + } +} + +interface BeefyAprHandlerConfig { + tokens: { + [tokenName: string]: { + address: string; + vaultId: string; + }; + }; + sourceUrl: string; +} + +type VaultApr = Record< + string, + { + vaultApr: number; + compoundingsPerYear: number; + beefyPerformanceFee: number; + vaultApy: number; + lpFee: number; + tradingApr: number; + totalApy: number; + } +>; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts index abb0ecb04..292e25b57 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts @@ -46,7 +46,6 @@ export class ReaperCryptAprHandler implements AprHandler { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean }; }): Promise<{ [tokenAddress: string]: number }> { const aprs: { [tokenAddress: string]: number } = {}; - console.log(networkContext.provider); for (const { address, isSftmX, isWstETH } of Object.values(tokens)) { const tokenContract = getContractAt(address, ReaperCryptAbi); const strategyAddress = await tokenContract.strategy(); @@ -86,7 +85,6 @@ export class ReaperCryptAprHandler implements AprHandler { data: JSON.stringify(requestQuery), }); return data.vaults.reduce((acc, { id, apr }) => { - console.log(id); const token = Object.values(tokens).find((token) => token.address.toLowerCase() === id.toLowerCase()); if (!token) { return acc; diff --git a/modules/pool/lib/apr-data-sources/optimism/rocket-pool-staked-eth-apr.service.ts b/modules/pool/lib/apr-data-sources/optimism/rocket-pool-staked-eth-apr.service.ts deleted file mode 100644 index 5027385d3..000000000 --- a/modules/pool/lib/apr-data-sources/optimism/rocket-pool-staked-eth-apr.service.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { prisma } from '../../../../../prisma/prisma-client'; -import { PrismaPoolWithExpandedNesting } from '../../../../../prisma/prisma-types'; -import { TokenService } from '../../../../token/token.service'; -import { PoolAprService } from '../../../pool-types'; -import { collectsYieldFee } from '../../pool-utils'; -import { networkContext } from '../../../../network/network-context.service'; -import { liquidStakedBaseAprService } from '../liquid-staked-base-apr.service'; - -export class RocketPoolStakedEthAprService implements PoolAprService { - constructor(private readonly tokenService: TokenService, private readonly rethAddress: string) {} - - public getAprServiceName(): string { - return 'RocketPoolStakedEthAprService'; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const tokenPrices = await this.tokenService.getTokenPrices(); - const rethPrice = this.tokenService.getPriceForToken(tokenPrices, this.rethAddress); - const rethBaseApr = await liquidStakedBaseAprService.getREthBaseApr(); - - let operations: any[] = []; - for (const pool of pools) { - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : networkContext.data.balancer.yieldProtocolFeePercentage; - const rethToken = pool.tokens.find((token) => token.address === this.rethAddress); - const rethTokenBalance = rethToken?.dynamicData?.balance; - if (rethTokenBalance && pool.dynamicData) { - const rethPercentage = (parseFloat(rethTokenBalance) * rethPrice) / pool.dynamicData.totalLiquidity; - const rethApr = pool.dynamicData.totalLiquidity > 0 ? rethBaseApr * rethPercentage : 0; - const userApr = - pool.type === 'META_STABLE' - ? rethApr * (1 - networkContext.data.balancer.swapProtocolFeePercentage) - : rethApr * (1 - protocolYieldFeePercentage); - - operations.push( - prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: `${pool.id}-reth-apr`, chain: networkContext.chain } }, - update: { apr: collectsYieldFee(pool) ? userApr : rethApr }, - create: { - id: `${pool.id}-reth-apr`, - chain: networkContext.chain, - poolId: pool.id, - apr: collectsYieldFee(pool) ? userApr : rethApr, - title: 'rETH APR', - type: 'IB_YIELD', - }, - }), - ); - } - } - await Promise.all(operations); - } -} diff --git a/modules/pool/lib/apr-data-sources/optimism/wsteth-apr.service.ts b/modules/pool/lib/apr-data-sources/optimism/wsteth-apr.service.ts deleted file mode 100644 index ec306e15d..000000000 --- a/modules/pool/lib/apr-data-sources/optimism/wsteth-apr.service.ts +++ /dev/null @@ -1,59 +0,0 @@ -import axios from 'axios'; -import { prisma } from '../../../../../prisma/prisma-client'; -import { PrismaPoolWithExpandedNesting } from '../../../../../prisma/prisma-types'; -import { TokenService } from '../../../../token/token.service'; -import { PoolAprService } from '../../../pool-types'; -import { collectsYieldFee } from '../../pool-utils'; -import { networkContext } from '../../../../network/network-context.service'; -import { liquidStakedBaseAprService } from '../liquid-staked-base-apr.service'; - -export class WstethAprService implements PoolAprService { - constructor(private readonly tokenService: TokenService, private readonly wstethContractAddress: string) {} - - public getAprServiceName(): string { - return 'WstethAprService'; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const tokenPrices = await this.tokenService.getTokenPrices(); - const wstethPrice = this.tokenService.getPriceForToken(tokenPrices, this.wstethContractAddress); - - let wstethBaseApr: number | undefined; - for (const pool of pools) { - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : networkContext.data.balancer.yieldProtocolFeePercentage; - const itemId = `${pool.id}-lido-wsteth`; - - const wstethToken = pool.tokens.find((token) => token.address === this.wstethContractAddress.toLowerCase()); - const wstethTokenBalance = wstethToken?.dynamicData?.balance; - - if (wstethTokenBalance && pool.dynamicData) { - if (!wstethBaseApr) { - wstethBaseApr = await liquidStakedBaseAprService.getWstEthBaseApr(); - } - - const wstethPercentage = - (parseFloat(wstethTokenBalance) * wstethPrice) / pool.dynamicData.totalLiquidity; - const wstethApr = pool.dynamicData.totalLiquidity > 0 ? wstethBaseApr * wstethPercentage : 0; - const userApr = - pool.type === 'META_STABLE' - ? wstethApr * (1 - networkContext.data.balancer.swapProtocolFeePercentage) - : wstethApr * (1 - protocolYieldFeePercentage); - - await prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `stETH APR`, - apr: collectsYieldFee(pool) ? userApr : wstethApr, - type: 'IB_YIELD', - }, - update: { apr: collectsYieldFee(pool) ? userApr : wstethApr, title: `stETH APR` }, - }); - } - } - } -} From ae0d54cc91495f9270fba9ae71d254fc185528f2 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 29 Aug 2023 19:29:57 -0300 Subject: [PATCH 27/42] Removing test route; --- modules/balancer/loadRestRoutes.ts | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/modules/balancer/loadRestRoutes.ts b/modules/balancer/loadRestRoutes.ts index b4da58c46..aad0efca7 100644 --- a/modules/balancer/loadRestRoutes.ts +++ b/modules/balancer/loadRestRoutes.ts @@ -1,27 +1,5 @@ import { Express } from 'express'; -import { prisma } from '../../prisma/prisma-client'; -import { prismaPoolWithExpandedNesting } from '../../prisma/prisma-types'; -import { networkContext } from '../network/network-context.service'; -import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; -import { tokenService } from '../token/token.service'; -import { mainnetNetworkData } from '../network/mainnet'; -import { optimismNetworkData } from '../network/optimism'; export function loadRestRoutesBalancer(app: Express) { app.use('/health', (req, res) => res.sendStatus(200)); - app.use('/test', async (req, res) => { - const pools = await prisma.prismaPool.findMany({ - ...prismaPoolWithExpandedNesting, - where: { chain: networkContext.chain }, - }); - const ibTokensAprService = new IbTokensAprService( - optimismNetworkData.ibAprConfig, - optimismNetworkData.chain.prismaId, - optimismNetworkData.chain.id, - tokenService, - ); - await ibTokensAprService.updateAprForPools(pools); - - return res.sendStatus(200); - }); } From 98e9df61df3256f253193e3d0f0cea93c7e6a5fa Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 29 Aug 2023 20:15:24 -0300 Subject: [PATCH 28/42] fixing base network incompatibilities; --- modules/network/base.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/modules/network/base.ts b/modules/network/base.ts index ec4eea965..48fb7bcba 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -1,9 +1,6 @@ import { BigNumber, ethers } from 'ethers'; import { DeploymentEnv, NetworkConfig, NetworkData } from './network-config-types'; import { tokenService } from '../token/token.service'; -import { WstethAprService } from '../pool/lib/apr-data-sources/optimism/wsteth-apr.service'; -import { ReaperCryptAprService } from '../pool/lib/apr-data-sources/reaper-crypt-apr.service'; -import { PhantomStableAprService } from '../pool/lib/apr-data-sources/phantom-stable-apr.service'; import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool-apr.service'; import { SwapFeeAprService } from '../pool/lib/apr-data-sources/swap-fee-apr.service'; import { GaugeAprService } from '../pool/lib/apr-data-sources/ve-bal-gauge-apr.service'; @@ -77,6 +74,17 @@ const baseNetworkData: NetworkData = { yieldProtocolFeePercentage: 0.5, poolDataQueryContract: '0x67af5D428d38C5176a286a2371Df691cDD914Fb8', }, + ibAprConfig: { + defaultHandlers: { + stETH: { + tokens: { + wstETH: '', + }, + sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + }, + }, + }, multicall: '0xca11bde05977b3631167028862be2a173976ca11', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', avgBlockSpeed: 2, @@ -115,7 +123,6 @@ export const baseNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: baseNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new WstethAprService(tokenService, baseNetworkData.lido!.wstEthContract), new BoostedPoolAprService(), new SwapFeeAprService(baseNetworkData.balancer.swapProtocolFeePercentage), new GaugeAprService(gaugeSubgraphService, tokenService, [baseNetworkData.bal!.address]), From fd7f1365e1c421e403a6013232b11320a2650f24 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 29 Aug 2023 20:40:06 -0300 Subject: [PATCH 29/42] fixing optional beefy property in network config; --- modules/network/network-config-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index 7e860e0f9..04f9b5987 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -114,7 +114,7 @@ export interface NetworkData { copper?: { proxyAddress: string; }; - beefy: { + beefy?: { linearPools: string[]; }; lido?: { From a836720f1f6c4e43947b6569539f51d1b681aa0f Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 29 Aug 2023 20:41:35 -0300 Subject: [PATCH 30/42] Removing all unused functions of liquid staked base apr, left just xBoo, because idk what to do with the spooky apr service yet; --- .../liquid-staked-base-apr.service.ts | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts b/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts index 1d2acc199..90bccafb8 100644 --- a/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/liquid-staked-base-apr.service.ts @@ -1,47 +1,10 @@ import axios from 'axios'; export class LiquidStakedBaseAprService { - //TODO - remove this, i - public async getWstEthBaseApr(): Promise { - const { data } = await axios.get<{ - data: { aprs: [{ timeUnix: number; apr: number }]; smaApr: number }; - }>('https://eth-api.lido.fi/v1/protocol/steth/apr/sma'); - return data.data.smaApr / 100; - } - - public getSftmxBaseApr(): number { - return 0.046; - } - - //TODO - Remove this, since it's already in ib-linear-apr-handlers - public async getAnkrFtmBaseApr(): Promise { - const { data } = await axios.get<{ services: { serviceName: string; apy: string }[] }>( - 'https://api.staking.ankr.com/v1alpha/metrics', - {}, - ); - - const ankrFtmApy = data.services.find((service) => service.serviceName === 'ftm'); - return parseFloat(ankrFtmApy?.apy || '0') / 100; - } - //TODO - Remove this, since it's already in ib-linear-apr-handlers - public async getAnkrEthBaseApr(): Promise { - const { data } = await axios.get<{ services: { serviceName: string; apy: string }[] }>( - 'https://api.staking.ankr.com/v1alpha/metrics', - {}, - ); - - const ankrEthApy = data.services.find((service) => service.serviceName === 'eth'); - return parseFloat(ankrEthApy?.apy || '0') / 100; - } - public async getXBooBaseApr(): Promise { const { data } = await axios.get('https://api.spooky.fi/api/xboo', {}); return parseFloat(data) / 100; } - - public getREthBaseApr(): number { - return 0.0425; - } } export const liquidStakedBaseAprService = new LiquidStakedBaseAprService(); From 114386dedb7e94af4d3af3bb5303f83a986a6687 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Tue, 29 Aug 2023 20:42:31 -0300 Subject: [PATCH 31/42] Renaming AprConfig to IbAprConfig; --- modules/network/network-config-types.ts | 4 ++-- .../ib-linear-apr-handlers/ib-linear-apr-handlers.ts | 8 ++++---- .../pool/lib/apr-data-sources/ib-tokens-apr.service.ts | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index 04f9b5987..37d7eca5c 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -106,7 +106,7 @@ export interface NetworkData { address: string; excludedFarmIds: string[]; }; - ibAprConfig: AprConfig; + ibAprConfig: IbAprConfig; reliquary?: { address: string; excludedFarmIds: string[]; @@ -163,7 +163,7 @@ export interface NetworkData { }; } -export interface AprConfig { +export interface IbAprConfig { aave?: { [version: string]: { subgraphUrl: string; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts index 8012e3073..5ff411210 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts @@ -8,7 +8,7 @@ import { OvixAprHandler } from './sources/ovix-apr-handler'; import { TesseraAprHandler } from './sources/tessera-apr-handler'; import { TetuAprHandler } from './sources/tetu-apr-handler'; import { TranchessAprHandler } from './sources/tranchess-apr-handler'; -import { AprConfig } from '../../../../network/network-config-types'; +import { IbAprConfig } from '../../../../network/network-config-types'; import { YearnAprHandler } from './sources/yearn-apr-handler'; import { ReaperCryptAprHandler } from './sources/reaper-crypt-apr-handler'; import { BeefyAprHandler } from './sources/beefy-apr-handler'; @@ -19,13 +19,13 @@ export class IbLinearAprHandlers { wrappedBoostedTokens: string[] = []; fixedAprTokens?: { [tokenName: string]: { address: string; value: number; group?: string } }; - constructor(aprConfig: AprConfig, networkPrismaId: string, networkChainId: number) { + constructor(aprConfig: IbAprConfig, networkPrismaId: string, networkChainId: number) { this.handlers = this.buildAprHandlers(aprConfig, networkPrismaId, networkChainId); this.wrappedBoostedTokens = this.buildWrappedBoostedTokens(aprConfig); this.fixedAprTokens = aprConfig.fixedAprTokens; } - buildAprHandlers(aprConfig: AprConfig, networkPrismaId: string, networkChainId: number) { + buildAprHandlers(aprConfig: IbAprConfig, networkPrismaId: string, networkChainId: number) { const handlers: AprHandler[] = []; if (aprConfig.aave) { for (const config of Object.values(aprConfig.aave)) { @@ -92,7 +92,7 @@ export class IbLinearAprHandlers { return handlers; } - buildWrappedBoostedTokens(aprConfig: AprConfig): string[] { + buildWrappedBoostedTokens(aprConfig: IbAprConfig): string[] { return [ ...Object.values(aprConfig?.aave?.v2?.tokens?.USDC?.wrappedTokens || {}), ...Object.values(aprConfig?.aave?.v3?.tokens?.USDC?.wrappedTokens || {}), diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index b0f833dcb..3e4b7b3c4 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -7,13 +7,13 @@ import { PrismaPoolAprItemGroup, PrismaPoolLinearData } from '@prisma/client'; import { IbLinearAprHandlers, TokenApr } from './ib-linear-apr-handlers/ib-linear-apr-handlers'; import { TokenService } from '../../../token/token.service'; import { collectsYieldFee } from '../pool-utils'; -import { AprConfig } from '../../../network/network-config-types'; +import { IbAprConfig } from '../../../network/network-config-types'; export class IbTokensAprService implements PoolAprService { private baseAprHandlers: IbLinearAprHandlers; constructor( - aprConfig: AprConfig, + aprConfig: IbAprConfig, networkPrismaId: string, networkChainId: number, private readonly tokenService: TokenService, From 9ac7a10c612387b61660e66176b299188d99ea01 Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 1 Sep 2023 11:57:32 +0200 Subject: [PATCH 32/42] clean up types --- modules/network/apr-config-types.ts | 162 ++++++++++++++++++ modules/network/arbitrum.ts | 7 +- modules/network/avalanche.ts | 7 +- modules/network/fantom.ts | 13 +- modules/network/gnosis.ts | 7 +- modules/network/mainnet.ts | 7 +- modules/network/network-config-types.ts | 136 +-------------- modules/network/optimism.ts | 29 +++- modules/network/polygon.ts | 7 +- modules/network/zkevm.ts | 7 +- .../fantom/yearn-vault-apr.service.ts | 0 .../ib-linear-apr-handlers.ts | 14 +- .../sources/aave-apr-handler.ts | 18 +- .../sources/ankr-apr-handler.ts | 13 +- .../sources/beefy-apr-handler.ts | 13 +- .../sources/default-apr-handler.ts | 20 +-- .../sources/euler-apr-handler.ts | 8 +- .../sources/gearbox-apr-handler.ts | 8 +- .../sources/idle-apr-handler.ts | 14 +- .../sources/ovix-apr-handler.ts | 20 +-- .../sources/reaper-apr-handler.ts | 73 -------- .../sources/reaper-crypt-apr-handler.ts | 27 +-- .../sources/tessera-apr-handler.ts | 20 +-- .../sources/tetu-apr-handler.ts | 10 +- .../sources/tranchess-apr-handler.ts | 13 +- .../sources/yearn-apr-handler.ts | 8 +- .../apr-data-sources/ib-tokens-apr.service.ts | 23 +-- 27 files changed, 267 insertions(+), 417 deletions(-) create mode 100644 modules/network/apr-config-types.ts delete mode 100644 modules/pool/lib/apr-data-sources/fantom/yearn-vault-apr.service.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-apr-handler.ts diff --git a/modules/network/apr-config-types.ts b/modules/network/apr-config-types.ts new file mode 100644 index 000000000..5ecffc7a2 --- /dev/null +++ b/modules/network/apr-config-types.ts @@ -0,0 +1,162 @@ +export interface IbAprConfig { + aave?: AaveAprConfig; + ankr?: AnkrAprConfig; + beefy?: BeefyAprConfig; + euler?: EulerAprConfig; + gearbox?: GearBoxAprConfig; + idle?: IdleAprConfig; + ovix?: OvixAprConfig; + reaper?: ReaperAprConfig; + tessera?: TesseraAprConfig; + tetu?: TetuAprConfig; + tranchess?: TranchessAprConfig; + yearn?: YearnAprConfig; + defaultHandlers?: DefaultHandlerAprConfig; + fixed?: FixedAprConfig; +} + +export interface AaveAprConfig { + [version: string]: { + subgraphUrl: string; + tokens: { + [underlyingAssetName: string]: { + underlyingAssetAddress: string; + aTokenAddress: string; + wrappedTokens: { + [wrappedTokenName: string]: string; + }; + }; + }; + }; +} + +export interface AnkrAprConfig { + sourceUrl: string; + tokens: { + [underlyingAssetName: string]: { + address: string; + serviceName: string; + }; + }; +} + +export interface BeefyAprConfig { + sourceUrl: string; + tokens: { + [tokenName: string]: { + address: string; + // To get the vaultId, get the vault address from the token contract(token.vault()), + // and search for the vault address in the link: https://api.beefy.finance/vaults + vaultId: string; + }; + }; +} + +export interface EulerAprConfig { + subgraphUrl: string; + tokens: { + [tokenName: string]: string; + }; +} + +export interface GearBoxAprConfig { + sourceUrl: string; + tokens: { + [tokenName: string]: string; + }; +} + +export interface IdleAprConfig { + sourceUrl: string; + authorizationHeader: string; + tokens: { + [tokenName: string]: { + address: string; + wrapped4626Address: string; + }; + }; +} + +export interface OvixAprConfig { + rpcUrl: string; + tokens: { + [tokenName: string]: { + yieldAddress: string; + wrappedAddress: string; + }; + }; +} + +export interface ReaperAprConfig { + subgraphSource?: { + subgraphUrl: string; + tokens: { + [tokenName: string]: { + address: string; + isSftmX?: boolean; + isWstETH?: boolean; + }; + }; + }; + onchainSource?: { + averageAPRAcrossLastNHarvests: number; + tokens: { + [tokenName: string]: { + address: string; + isSftmX?: boolean; + isWstETH?: boolean; + }; + }; + }; +} + +export interface TesseraAprConfig { + rpcUrl: string; + tokens: { + [tokenName: string]: { + tesseraPoolAddress: string; + tokenAddress: string; + }; + }; +} + +export interface TetuAprConfig { + sourceUrl: string; + tokens: { + [tokenName: string]: string; + }; +} + +export interface TranchessAprConfig { + sourceUrl: string; + tokens: { + [tokenName: string]: { + address: string; + underlyingAssetName: string; + }; + }; +} + +export interface YearnAprConfig { + sourceUrl: string; +} + +export interface DefaultHandlerAprConfig { + [tokenName: string]: { + sourceUrl: string; + tokens: { + [tokenName: string]: string; + }; + path?: string; + scale?: number; + group?: string; + }; +} + +export interface FixedAprConfig { + [tokenName: string]: { + address: string; + value: number; + group?: string; + }; +} diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 0a00abf7f..9ad99ce46 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -192,12 +192,7 @@ export const arbitrumNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: arbitrumNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - arbitrumNetworkData.ibAprConfig, - arbitrumNetworkData.chain.prismaId, - arbitrumNetworkData.chain.id, - tokenService, - ), + new IbTokensAprService(arbitrumNetworkData.ibAprConfig, tokenService), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(arbitrumNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index f32d483a1..5d71e2fb6 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -190,12 +190,7 @@ export const avalancheNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: avalancheNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - avalancheNetworkData.ibAprConfig, - avalancheNetworkData.chain.prismaId, - avalancheNetworkData.chain.id, - tokenService, - ), + new IbTokensAprService(avalancheNetworkData.ibAprConfig, tokenService), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(avalancheNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index 980cb6629..d9b455711 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -183,7 +183,7 @@ const fantomNetworkData: NetworkData = { }, }, reaper: { - multiStrategy: { + subgraphSource: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/byte-masons/multi-strategy-vaults-fantom', tokens: { rfwBTC: { @@ -226,7 +226,7 @@ const fantomNetworkData: NetworkData = { }, }, }, - singleStrategy: { + onchainSource: { averageAPRAcrossLastNHarvests: 5, tokens: { rfGrainSFTMX: { @@ -242,7 +242,7 @@ const fantomNetworkData: NetworkData = { yearn: { sourceUrl: 'https://d28fcsszptni1s.cloudfront.net/v1/chains/250/vaults/all', }, - fixedAprTokens: { + fixed: { sFTMx: { address: '0xd7028092c830b5c8fce061af2e593413ebbc1fc1', value: 0.046, @@ -296,12 +296,7 @@ export const fantomNetworkConfig: NetworkConfig = { contentService: new SanityContentService(), provider: new ethers.providers.JsonRpcProvider({ url: fantomNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - fantomNetworkData.ibAprConfig, - fantomNetworkData.chain.prismaId, - fantomNetworkData.chain.id, - tokenService, - ), + new IbTokensAprService(fantomNetworkData.ibAprConfig, tokenService), // new SpookySwapAprService(tokenService, fantomNetworkData.spooky!.xBooContract), new PhantomStableAprService(), new BoostedPoolAprService(), diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index 432e58fc4..af2822b0c 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -143,12 +143,7 @@ export const gnosisNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: gnosisNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - gnosisNetworkData.ibAprConfig, - gnosisNetworkData.chain.prismaId, - gnosisNetworkData.chain.id, - tokenService, - ), + new IbTokensAprService(gnosisNetworkData.ibAprConfig, tokenService), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(gnosisNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index ffdb3adb5..843ed1c5a 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -340,12 +340,7 @@ export const mainnetNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: mainnetNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - mainnetNetworkData.ibAprConfig, - mainnetNetworkData.chain.prismaId, - mainnetNetworkData.chain.id, - tokenService, - ), + new IbTokensAprService(mainnetNetworkData.ibAprConfig, tokenService), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(mainnetNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index 37d7eca5c..05921180a 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -6,6 +6,7 @@ import { TokenPriceHandler } from '../token/token-types'; import { BaseProvider } from '@ethersproject/providers'; import { GqlChain } from '../../schema'; import { ContentService } from '../content/content-types'; +import { AaveAprConfig, IbAprConfig } from './apr-config-types'; export interface NetworkConfig { data: NetworkData; @@ -162,138 +163,3 @@ export interface NetworkData { }; }; } - -export interface IbAprConfig { - aave?: { - [version: string]: { - subgraphUrl: string; - tokens: { - [underlyingAssetName: string]: { - underlyingAssetAddress: string; - aTokenAddress: string; - wrappedTokens: { - [wrappedTokenName: string]: string; - }; - }; - }; - }; - }; - ankr?: { - sourceUrl: string; - tokens: { - [underlyingAssetName: string]: { - address: string; - serviceName: string; - }; - }; - }; - beefy?: { - sourceUrl: string; - tokens: { - [tokenName: string]: { - address: string; - // To get the vaultId, get the vault address from the token contract(token.vault()), - // and search for the vault address in the link: https://api.beefy.finance/vaults - vaultId: string; - }; - }; - }; - euler?: { - subgraphUrl: string; - tokens: { - [tokenName: string]: string; - }; - }; - gearbox?: { - sourceUrl: string; - tokens: { - [tokenName: string]: string; - }; - }; - idle?: { - sourceUrl: string; - authorizationHeader: string; - tokens: { - [tokenName: string]: { - address: string; - wrapped4626Address: string; - }; - }; - }; - ovix?: { - rpcUrl: string; - tokens: { - [tokenName: string]: { - yieldAddress: string; - wrappedAddress: string; - }; - }; - }; - reaper?: { - multiStrategy?: { - subgraphUrl: string; - tokens: { - [tokenName: string]: { - address: string; - isSftmX?: boolean; - isWstETH?: boolean; - }; - }; - }; - singleStrategy?: { - averageAPRAcrossLastNHarvests: number; - tokens: { - [tokenName: string]: { - address: string; - isSftmX?: boolean; - isWstETH?: boolean; - }; - }; - }; - }; - tessera?: { - rpcUrl: string; - tokens: { - [tokenName: string]: { - tesseraPoolAddress: string; - tokenAddress: string; - }; - }; - }; - tetu?: { - sourceUrl: string; - tokens: { - [tokenName: string]: string; - }; - }; - tranchess?: { - sourceUrl: string; - tokens: { - [tokenName: string]: { - address: string; - underlyingAssetName: string; - }; - }; - }; - yearn?: { - sourceUrl: string; - }; - defaultHandlers?: { - [tokenName: string]: { - sourceUrl: string; - tokens: { - [tokenName: string]: string; - }; - path?: string; - scale?: number; - group?: string; - }; - }; - fixedAprTokens?: { - [tokenName: string]: { - address: string; - value: number; - group?: string; - }; - }; -} diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 80d48c927..16fa076f9 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -133,7 +133,7 @@ const optimismNetworkData: NetworkData = { }, }, reaper: { - multiStrategy: { + subgraphSource: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/byte-masons/multi-strategy-vaults-optimism', tokens: { rfUSDT: { @@ -160,6 +160,26 @@ const optimismNetworkData: NetworkData = { }, }, }, + onchainSource: { + averageAPRAcrossLastNHarvests: 2, + tokens: { + rfsoUSDC: { + address: '0x875456b73cbc58aa1be98dfe3b0459e0c0bf7b0e', + }, + rfsoUSDT: { + address: '0x1e1bf73db9b278a95c9fe9205759956edea8b6ae', + }, + rfsoDAI: { + address: '0x19ca00d242e96a30a1cad12f08c375caa989628f', + }, + rfsoWBTC: { + address: '0x73e51b0368ef8bd0070b12dd992c54aa53bcb5f4', + }, + rfsoWSTETH: { + address: '0x3573de618ae4a740fb24215d93f4483436fbb2b6', + }, + }, + }, }, defaultHandlers: { stEth: { @@ -237,12 +257,7 @@ export const optimismNetworkConfig: NetworkConfig = { contentService: new SanityContentService(), provider: new ethers.providers.JsonRpcProvider({ url: optimismNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - optimismNetworkData.ibAprConfig, - optimismNetworkData.chain.prismaId, - optimismNetworkData.chain.id, - tokenService, - ), + new IbTokensAprService(optimismNetworkData.ibAprConfig, tokenService), new BeefyVaultAprService(optimismNetworkData.beefy!.linearPools, tokenService), new PhantomStableAprService(), new BoostedPoolAprService(), diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index 7cf669c20..886dd4bc5 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -253,12 +253,7 @@ export const polygonNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: polygonNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - polygonNetworkData.ibAprConfig, - polygonNetworkData.chain.prismaId, - polygonNetworkData.chain.id, - tokenService, - ), + new IbTokensAprService(polygonNetworkData.ibAprConfig, tokenService), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(polygonNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index 4c14e9f2d..c3b2cf6ff 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -156,12 +156,7 @@ export const zkevmNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: zkevmNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - zkevmNetworkData.ibAprConfig, - zkevmNetworkData.chain.prismaId, - zkevmNetworkData.chain.id, - tokenService, - ), + new IbTokensAprService(zkevmNetworkData.ibAprConfig, tokenService), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(zkevmNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/pool/lib/apr-data-sources/fantom/yearn-vault-apr.service.ts b/modules/pool/lib/apr-data-sources/fantom/yearn-vault-apr.service.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts index 5ff411210..3f81771f6 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts @@ -8,10 +8,10 @@ import { OvixAprHandler } from './sources/ovix-apr-handler'; import { TesseraAprHandler } from './sources/tessera-apr-handler'; import { TetuAprHandler } from './sources/tetu-apr-handler'; import { TranchessAprHandler } from './sources/tranchess-apr-handler'; -import { IbAprConfig } from '../../../../network/network-config-types'; import { YearnAprHandler } from './sources/yearn-apr-handler'; import { ReaperCryptAprHandler } from './sources/reaper-crypt-apr-handler'; import { BeefyAprHandler } from './sources/beefy-apr-handler'; +import { IbAprConfig } from '../../../../network/apr-config-types'; export class IbLinearAprHandlers { private handlers: AprHandler[] = []; @@ -19,13 +19,13 @@ export class IbLinearAprHandlers { wrappedBoostedTokens: string[] = []; fixedAprTokens?: { [tokenName: string]: { address: string; value: number; group?: string } }; - constructor(aprConfig: IbAprConfig, networkPrismaId: string, networkChainId: number) { - this.handlers = this.buildAprHandlers(aprConfig, networkPrismaId, networkChainId); + constructor(aprConfig: IbAprConfig) { + this.handlers = this.buildAprHandlers(aprConfig); this.wrappedBoostedTokens = this.buildWrappedBoostedTokens(aprConfig); - this.fixedAprTokens = aprConfig.fixedAprTokens; + this.fixedAprTokens = aprConfig.fixed; } - buildAprHandlers(aprConfig: IbAprConfig, networkPrismaId: string, networkChainId: number) { + buildAprHandlers(aprConfig: IbAprConfig) { const handlers: AprHandler[] = []; if (aprConfig.aave) { for (const config of Object.values(aprConfig.aave)) { @@ -56,18 +56,16 @@ export class IbLinearAprHandlers { if (aprConfig.ovix) { const ovixHandler = new OvixAprHandler({ ...aprConfig.ovix, - networkChainId, }); handlers.push(ovixHandler); } if (aprConfig.reaper) { - const reaperCryptHandler = new ReaperCryptAprHandler({ ...aprConfig.reaper, networkChainId }); + const reaperCryptHandler = new ReaperCryptAprHandler({ ...aprConfig.reaper }); handlers.push(reaperCryptHandler); } if (aprConfig.tessera) { const tesseraHandler = new TesseraAprHandler({ ...aprConfig.tessera, - networkChainId, }); handlers.push(tesseraHandler); } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts index c16e0dda6..4692bb63f 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts @@ -29,7 +29,18 @@ export class AaveAprHandler implements AprHandler { } }`; - constructor(aprHandlerConfig: AaveAprHandlerConfig) { + constructor(aprHandlerConfig: { + subgraphUrl: string; + tokens: { + [underlyingAssetName: string]: { + underlyingAssetAddress: string; + aTokenAddress: string; + wrappedTokens: { + [wrappedTokenName: string]: string; + }; + }; + }; + }) { this.tokens = aprHandlerConfig.tokens; this.subgraphUrl = aprHandlerConfig.subgraphUrl; } @@ -88,8 +99,3 @@ interface ReserveResponse { ]; }; } - -type AaveAprHandlerConfig = { - tokens: {}; - subgraphUrl: string; -}; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts index 1dee03ec8..c134c76ba 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts @@ -1,5 +1,6 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; +import { AnkrAprConfig } from '../../../../../network/apr-config-types'; export class AnkrAprHandler implements AprHandler { tokens: { @@ -11,7 +12,7 @@ export class AnkrAprHandler implements AprHandler { url: string; readonly group = 'ANKR'; - constructor(aprHandlerConfig: AnkrAprHandlerConfig) { + constructor(aprHandlerConfig: AnkrAprConfig) { this.tokens = aprHandlerConfig.tokens; this.url = aprHandlerConfig.sourceUrl; } @@ -36,13 +37,3 @@ export class AnkrAprHandler implements AprHandler { } } } - -type AnkrAprHandlerConfig = { - tokens: { - [underlyingAssetName: string]: { - address: string; - serviceName: string; - }; - }; - sourceUrl: string; -}; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts index e6934fd7a..03bf2052c 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts @@ -1,3 +1,4 @@ +import { BeefyAprConfig } from '../../../../../network/apr-config-types'; import { AprHandler } from '../ib-linear-apr-handlers'; import axios from 'axios'; @@ -11,7 +12,7 @@ export class BeefyAprHandler implements AprHandler { sourceUrl: string; group: string | undefined = 'BEEFY'; - constructor(aprConfig: BeefyAprHandlerConfig) { + constructor(aprConfig: BeefyAprConfig) { this.tokens = aprConfig.tokens; this.sourceUrl = aprConfig.sourceUrl; } @@ -26,16 +27,6 @@ export class BeefyAprHandler implements AprHandler { } } -interface BeefyAprHandlerConfig { - tokens: { - [tokenName: string]: { - address: string; - vaultId: string; - }; - }; - sourceUrl: string; -} - type VaultApr = Record< string, { diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts index 2109e9180..37572a52e 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts @@ -11,7 +11,15 @@ export class DefaultAprHandler implements AprHandler { scale: number; group: string | undefined = undefined; - constructor(aprHandlerConfig: DefaultAprHandlerConfig) { + constructor(aprHandlerConfig: { + sourceUrl: string; + tokens: { + [tokenName: string]: string; + }; + path?: string; + scale?: number; + group?: string; + }) { this.tokens = aprHandlerConfig.tokens; this.url = aprHandlerConfig.sourceUrl; this.path = aprHandlerConfig.path ?? ''; @@ -47,13 +55,3 @@ export class DefaultAprHandler implements AprHandler { return value; } } - -export type DefaultAprHandlerConfig = { - tokens: { - [tokenName: string]: string; - }; - sourceUrl: string; - scale?: number; - path?: string; - group?: string; -}; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts index fa15ade47..d912b301b 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts @@ -1,5 +1,6 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; +import { EulerAprConfig } from '../../../../../network/apr-config-types'; export class EulerAprHandler implements AprHandler { tokens: { [key: string]: string }; @@ -19,7 +20,7 @@ export class EulerAprHandler implements AprHandler { } `; - constructor(aprHandlerConfig: EulerAprHandlerConfig) { + constructor(aprHandlerConfig: EulerAprConfig) { this.tokens = aprHandlerConfig.tokens; this.subgraphUrl = aprHandlerConfig.subgraphUrl; } @@ -63,8 +64,3 @@ interface EulerResponse { ]; }; } - -type EulerAprHandlerConfig = { - tokens: { [key: string]: string }; - subgraphUrl: string; -}; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts index 0a373d3be..f5dc888ba 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts @@ -1,13 +1,14 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; +import { GearBoxAprConfig } from '../../../../../network/apr-config-types'; export class GearboxAprHandler implements AprHandler { url: string; tokens: { [key: string]: string }; readonly group = 'GEARBOX'; - constructor(aprHandlerConfig: GearboxAprHandlerConfig) { + constructor(aprHandlerConfig: GearBoxAprConfig) { this.tokens = aprHandlerConfig.tokens; this.url = aprHandlerConfig.sourceUrl; } @@ -29,8 +30,3 @@ export class GearboxAprHandler implements AprHandler { } } } - -type GearboxAprHandlerConfig = { - tokens: { [key: string]: string }; - sourceUrl: string; -}; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts index b4281f145..ce654f6b1 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts @@ -1,6 +1,7 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; +import { IdleAprConfig } from '../../../../../network/apr-config-types'; export class IdleAprHandler implements AprHandler { tokens: { @@ -13,7 +14,7 @@ export class IdleAprHandler implements AprHandler { authorizationHeader: string; readonly group = 'IDLE'; - constructor(aprHandlerConfig: IdleAprHandlerConfig) { + constructor(aprHandlerConfig: IdleAprConfig) { this.tokens = aprHandlerConfig.tokens; this.url = aprHandlerConfig.sourceUrl; this.authorizationHeader = aprHandlerConfig.authorizationHeader; @@ -42,14 +43,3 @@ export class IdleAprHandler implements AprHandler { } } } - -type IdleAprHandlerConfig = { - tokens: { - [tokenName: string]: { - address: string; - wrapped4626Address: string; - }; - }; - sourceUrl: string; - authorizationHeader: string; -}; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts index 7fafd98de..97a6108ae 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts @@ -1,11 +1,11 @@ import { BigNumber, Contract } from 'ethers'; import { abi } from './abis/oErc20'; -import { JsonRpcProvider } from '@ethersproject/providers'; import { AprHandler } from '../ib-linear-apr-handlers'; +import { networkContext } from '../../../../../network/network-context.service'; +import { OvixAprConfig } from '../../../../../network/apr-config-types'; export class OvixAprHandler implements AprHandler { - provider: JsonRpcProvider; tokens: { [tokenName: string]: { yieldAddress: string; @@ -14,15 +14,14 @@ export class OvixAprHandler implements AprHandler { }; readonly group = 'OVIX'; - constructor(aprHandlerConfig: OvixAprHandlerConfig) { - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); + constructor(aprHandlerConfig: OvixAprConfig) { this.tokens = aprHandlerConfig.tokens; } async getAprs() { try { const aprEntries = Object.values(this.tokens).map(async ({ yieldAddress, wrappedAddress }) => { - const contract = new Contract(yieldAddress, abi, this.provider); + const contract = new Contract(yieldAddress, abi, networkContext.provider); const borrowRate = await contract.borrowRatePerTimestamp(); return [ wrappedAddress, @@ -37,14 +36,3 @@ export class OvixAprHandler implements AprHandler { } } } - -type OvixAprHandlerConfig = { - networkChainId: number; - rpcUrl: string; - tokens: { - [tokenName: string]: { - yieldAddress: string; - wrappedAddress: string; - }; - }; -}; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-apr-handler.ts deleted file mode 100644 index 4dba7f291..000000000 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-apr-handler.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { JsonRpcProvider } from '@ethersproject/providers'; -import { BigNumber, Contract } from 'ethers'; -import { abi } from './abis/reaperStrategy'; - -import { AprHandler } from '../ib-linear-apr-handlers'; - -class ReaperAprHandler implements AprHandler { - networkPrismaId: string; - provider: JsonRpcProvider; - yieldTokens: { [key: string]: `0x${string}` }; - strategiesMap: { [key: string]: `0x${string}` }; - readonly group = 'REAPER'; - - constructor(aprHandlerConfig: ReaperAprHandlerConfig) { - this.networkPrismaId = aprHandlerConfig.networkPrismaId; - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); - this.yieldTokens = aprHandlerConfig.yieldTokens; - this.strategiesMap = aprHandlerConfig.strategiesMap; - } - - async getAprs() { - try { - const contractCalls = Object.keys(this.strategiesMap).map(async (tokenName) => { - const contract = new Contract(this.strategiesMap[tokenName], abi, this.provider); - return contract.averageAPRAcrossLastNHarvests(3); - }); - const callsAprResults: BigNumber[] = Array(Object.keys(this.yieldTokens).length); - for (const [index, aprPromise] of contractCalls.entries()) { - callsAprResults[index] = await aprPromise; - } - const aprs = Object.keys(this.strategiesMap).map((tokenName, i) => { - return [this.yieldTokens[tokenName], callsAprResults[i].toNumber() / 1e4]; - }); - - return Object.fromEntries(aprs); - } catch (error) { - console.error('Failed to fetch Reaper APR:', error); - return {}; - } - } -} - -type ReaperAprHandlerConfig = { - networkPrismaId: string; - networkChainId: number; - rpcUrl: string; - yieldTokens: { [key: string]: `0x${string}` }; - strategiesMap: { - [key: string]: `0x${string}`; - }; -}; - -export const reaperYieldTokensArbitrum = { - DAI: '0x12f256109e744081f633a827be80e06d97ff7447', - USDT: '0x0179bac7493a92ac812730a4c64a0b41b7ea0ecf', - USDC: '0xaeacf641a0342330ec681b57c0a6af0b71d5cbff', -} as { [key: string]: `0x${string}` }; - -const reaperStrategiesMapArbitrum = { - DAI: '0xd4d5321b04e4832772a4d70e1eed6bcb7402d7ac', - USDT: '0x8a674ebbe33d6b03825626fa432e9ece888e13b5', - USDC: '0x6f6c0c5b7af2a326111ba6a9fa4926f7ca3adf44', -} as { [key: string]: `0x${string}` }; - -const reaperArbitrumAprHandler = new ReaperAprHandler({ - networkPrismaId: 'ARBITRUM', - networkChainId: 42161, - rpcUrl: 'https://arb1.arbitrum.io/rpc', - yieldTokens: reaperYieldTokensArbitrum, - strategiesMap: reaperStrategiesMapArbitrum, -}); - -export const reaperHandlers = [reaperArbitrumAprHandler]; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts index 292e25b57..7cd58482b 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts @@ -3,14 +3,14 @@ import { getContractAt } from '../../../../../web3/contract'; import ReaperCryptStrategyAbi from './abis/ReaperCryptStrategy.json'; import axios from 'axios'; import ReaperCryptAbi from './abis/ReaperCrypt.json'; -import { networkContext } from '../../../../../network/network-context.service'; +import { ReaperAprConfig } from '../../../../../network/apr-config-types'; const APR_PERCENT_DIVISOR = 10_000; const sFTMxBaseApr = 0.046; export class ReaperCryptAprHandler implements AprHandler { - multiStrategyTokens?: { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean } }; - singleStrategyTokens?: { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean } }; + tokensWithSubgraphSource?: { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean } }; + tokensWithOnChainSource?: { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean } }; subgraphUrl?: string; averageAPRAcrossLastNHarvests?: number; wstETHBaseApr: number = 0; @@ -22,22 +22,23 @@ export class ReaperCryptAprHandler implements AprHandler { } }`; readonly group = 'REAPER'; - constructor(aprConfig: ReaperCryptAprHandlerConfig) { - this.multiStrategyTokens = aprConfig.multiStrategy?.tokens; - this.singleStrategyTokens = aprConfig.singleStrategy?.tokens; - this.subgraphUrl = aprConfig.multiStrategy?.subgraphUrl; - this.averageAPRAcrossLastNHarvests = aprConfig.singleStrategy?.averageAPRAcrossLastNHarvests; + + constructor(aprConfig: ReaperAprConfig) { + this.tokensWithSubgraphSource = aprConfig.subgraphSource?.tokens; + this.tokensWithOnChainSource = aprConfig.onchainSource?.tokens; + this.subgraphUrl = aprConfig.subgraphSource?.subgraphUrl; + this.averageAPRAcrossLastNHarvests = aprConfig.onchainSource?.averageAPRAcrossLastNHarvests; } async getAprs(): Promise<{ [p: string]: number }> { let multiStrategyAprs = {}; let singleStrategyAprs = {}; this.wstETHBaseApr = await this.getWstEthBaseApr(); - if (this.multiStrategyTokens !== undefined) { - multiStrategyAprs = await this.getMultiStrategyAprFromSubgraph(this.multiStrategyTokens); + if (this.tokensWithSubgraphSource !== undefined) { + multiStrategyAprs = await this.getMultiStrategyAprFromSubgraph(this.tokensWithSubgraphSource); } - if (this.singleStrategyTokens !== undefined) { - singleStrategyAprs = await this.getSingleStrategyCryptApr(this.singleStrategyTokens); + if (this.tokensWithOnChainSource !== undefined) { + singleStrategyAprs = await this.getSingleStrategyCryptApr(this.tokensWithOnChainSource); } return { ...multiStrategyAprs, ...singleStrategyAprs }; } @@ -55,6 +56,7 @@ export class ReaperCryptAprHandler implements AprHandler { avgAprAcrossXHarvests = (await strategyContract.averageAPRAcrossLastNHarvests(this.averageAPRAcrossLastNHarvests)) / APR_PERCENT_DIVISOR; + // TODO hanlde this outside if (isSftmX) { avgAprAcrossXHarvests = avgAprAcrossXHarvests * (1 + sFTMxBaseApr); } @@ -117,7 +119,6 @@ type MultiStratResponse = { }[]; }; interface ReaperCryptAprHandlerConfig { - networkChainId: number; multiStrategy?: { subgraphUrl: string; tokens: { diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts index edb501a2c..c4c8ef4f4 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts @@ -1,11 +1,11 @@ import { Contract } from 'ethers'; import { abi } from './abis/tesseraPool'; -import { JsonRpcProvider } from '@ethersproject/providers'; import { AprHandler } from '../ib-linear-apr-handlers'; +import { networkContext } from '../../../../../network/network-context.service'; +import { TesseraAprConfig } from '../../../../../network/apr-config-types'; export class TesseraAprHandler implements AprHandler { - provider: JsonRpcProvider; tokens: { [tokenName: string]: { tesseraPoolAddress: string; @@ -14,8 +14,7 @@ export class TesseraAprHandler implements AprHandler { }; readonly group = 'TESSERA'; - constructor(aprHandlerConfig: TesseraAprHandlerConfig) { - this.provider = new JsonRpcProvider(aprHandlerConfig.rpcUrl, aprHandlerConfig.networkChainId); + constructor(aprHandlerConfig: TesseraAprConfig) { this.tokens = aprHandlerConfig.tokens; } @@ -24,7 +23,7 @@ export class TesseraAprHandler implements AprHandler { let aprEntries = []; for (const { tesseraPoolAddress, tokenAddress } of Object.values(this.tokens)) { try { - const contract = new Contract(tesseraPoolAddress, abi, this.provider); + const contract = new Contract(tesseraPoolAddress, abi, networkContext.provider); const poolsUI = await contract.getPoolsUI(); const pool = poolsUI[0]; @@ -44,14 +43,3 @@ export class TesseraAprHandler implements AprHandler { } } } - -type TesseraAprHandlerConfig = { - networkChainId: number; - rpcUrl: string; - tokens: { - [tokenName: string]: { - tesseraPoolAddress: string; - tokenAddress: string; - }; - }; -}; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts index 9651f34d7..b695166fb 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts @@ -1,6 +1,7 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; +import { TetuAprConfig } from '../../../../../network/apr-config-types'; export class TetuAprHandler implements AprHandler { sourceUrl: string; @@ -9,7 +10,7 @@ export class TetuAprHandler implements AprHandler { }; readonly group = 'TETU'; - constructor(aprHandlerConfig: TetuAprHandlerConfig) { + constructor(aprHandlerConfig: TetuAprConfig) { this.sourceUrl = aprHandlerConfig.sourceUrl; this.tokens = aprHandlerConfig.tokens; } @@ -28,10 +29,3 @@ export class TetuAprHandler implements AprHandler { } } } - -type TetuAprHandlerConfig = { - sourceUrl: string; - tokens: { - [tokenName: string]: string; - }; -}; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts index 42e87e3a9..7f064d7fd 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts @@ -1,6 +1,7 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; +import { TranchessAprConfig } from '../../../../../network/apr-config-types'; export class TranchessAprHandler implements AprHandler { url: string; @@ -12,7 +13,7 @@ export class TranchessAprHandler implements AprHandler { }; readonly group = 'TRANCHESS'; - constructor(aprHandlerConfig: TranchessAprHandlerConfig) { + constructor(aprHandlerConfig: TranchessAprConfig) { this.tokens = aprHandlerConfig.tokens; this.url = aprHandlerConfig.sourceUrl; } @@ -35,13 +36,3 @@ export class TranchessAprHandler implements AprHandler { } } } - -type TranchessAprHandlerConfig = { - tokens: { - [tokenName: string]: { - address: string; - underlyingAssetName: string; - }; - }; - sourceUrl: string; -}; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts index ef4d53eda..31a45defa 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts @@ -1,13 +1,13 @@ import { AprHandler } from '../ib-linear-apr-handlers'; import axios from 'axios'; import { YearnVault } from '../../apr-types'; -import { networkContext } from '../../../../../network/network-context.service'; +import { YearnAprConfig } from '../../../../../network/apr-config-types'; export class YearnAprHandler implements AprHandler { sourceUrl: string; group: string = 'YEARN'; - constructor(aprHandlerConfig: YearnAprHandlerConfig) { + constructor(aprHandlerConfig: YearnAprConfig) { this.sourceUrl = aprHandlerConfig.sourceUrl; } async getAprs(): Promise<{ [p: string]: number }> { @@ -20,7 +20,3 @@ export class YearnAprHandler implements AprHandler { return aprs; } } - -interface YearnAprHandlerConfig { - sourceUrl: string; -} diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 3e4b7b3c4..5e3d9d0e2 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -4,21 +4,16 @@ import { prisma } from '../../../../prisma/prisma-client'; import { networkContext } from '../../../network/network-context.service'; import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; import { PrismaPoolAprItemGroup, PrismaPoolLinearData } from '@prisma/client'; -import { IbLinearAprHandlers, TokenApr } from './ib-linear-apr-handlers/ib-linear-apr-handlers'; +import { IbLinearAprHandlers as IbTokensAprHandlers, TokenApr } from './ib-linear-apr-handlers/ib-linear-apr-handlers'; import { TokenService } from '../../../token/token.service'; import { collectsYieldFee } from '../pool-utils'; -import { IbAprConfig } from '../../../network/network-config-types'; +import { IbAprConfig } from '../../../network/apr-config-types'; export class IbTokensAprService implements PoolAprService { - private baseAprHandlers: IbLinearAprHandlers; + private ibTokensAprHandlers: IbTokensAprHandlers; - constructor( - aprConfig: IbAprConfig, - networkPrismaId: string, - networkChainId: number, - private readonly tokenService: TokenService, - ) { - this.baseAprHandlers = new IbLinearAprHandlers(aprConfig, networkPrismaId, networkChainId); + constructor(aprConfig: IbAprConfig, private readonly tokenService: TokenService) { + this.ibTokensAprHandlers = new IbTokensAprHandlers(aprConfig); } getAprServiceName(): string { @@ -84,10 +79,6 @@ export class IbTokensAprService implements PoolAprService { } } } else { - // If pool is Linear - if (!isLinear) { - continue; - } const linearData = pool.linearData as PrismaPoolLinearData; const wrappedToken = pool.tokens[linearData.wrappedIndex]; const mainToken = pool.tokens[linearData.mainIndex]; @@ -106,7 +97,7 @@ export class IbTokensAprService implements PoolAprService { const poolTokenApr = totalLiquidity > 0 ? tokenApr.val * tokenPercentage : 0; const aprAfterFees = poolTokenApr * (1 - protocolYieldFeePercentage); const tokenSymbol = token.token.symbol; - const isBoosted = this.baseAprHandlers.wrappedBoostedTokens.includes(wrappedToken.address); + const isBoosted = this.ibTokensAprHandlers.wrappedBoostedTokens.includes(wrappedToken.address); const itemId = `${pool.id}-${tokenSymbol}-${isBoosted ? 'boosted' : 'yield'}-apr`; operations.push( prisma.prismaPoolAprItem.upsert({ @@ -134,7 +125,7 @@ export class IbTokensAprService implements PoolAprService { } private async fetchYieldTokensApr(): Promise> { - const data = await this.baseAprHandlers.fetchAprsFromAllHandlers(); + const data = await this.ibTokensAprHandlers.fetchAprsFromAllHandlers(); return new Map(data.filter((apr) => !isNaN(apr.val)).map((apr) => [apr.address, apr])); } } From a5ca109e5b6900e71aa2d290694335cee7f0bd74 Mon Sep 17 00:00:00 2001 From: franz Date: Fri, 1 Sep 2023 17:47:15 +0200 Subject: [PATCH 33/42] simplify ib-tokens-apr service --- .../ib-linear-apr-handlers.ts | 10 +- .../apr-data-sources/ib-tokens-apr.service.ts | 135 ++++++++---------- 2 files changed, 63 insertions(+), 82 deletions(-) diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts index 3f81771f6..9d89a1721 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts @@ -16,12 +16,13 @@ import { IbAprConfig } from '../../../../network/apr-config-types'; export class IbLinearAprHandlers { private handlers: AprHandler[] = []; //List of addresses of wrappedBoostedTokens, used to check what is LINEAR_BOOSTED APR and what is IB_YIELD APR - wrappedBoostedTokens: string[] = []; + wrappedLinearTokens: string[] = []; + fixedAprTokens?: { [tokenName: string]: { address: string; value: number; group?: string } }; constructor(aprConfig: IbAprConfig) { this.handlers = this.buildAprHandlers(aprConfig); - this.wrappedBoostedTokens = this.buildWrappedBoostedTokens(aprConfig); + this.wrappedLinearTokens = this.buildWrappedLinearTokens(aprConfig); this.fixedAprTokens = aprConfig.fixed; } @@ -90,7 +91,8 @@ export class IbLinearAprHandlers { return handlers; } - buildWrappedBoostedTokens(aprConfig: IbAprConfig): string[] { + // TODO rethink that one + buildWrappedLinearTokens(aprConfig: IbAprConfig): string[] { return [ ...Object.values(aprConfig?.aave?.v2?.tokens?.USDC?.wrappedTokens || {}), ...Object.values(aprConfig?.aave?.v3?.tokens?.USDC?.wrappedTokens || {}), @@ -111,7 +113,7 @@ export class IbLinearAprHandlers { ...Object.values( Object.entries(aprConfig?.defaultHandlers || {}) //Filtering out handlers that are not LINEAR_BOOSTED - .filter(([key, _]) => ['rETH', 'USDR', 'swETH', 'wjAURA', 'qETH', 'overnight'].includes(key)) + .filter(([key, _]) => ['rETH', 'USDR', 'swETH', 'wjAURA', 'qETH'].includes(key)) .reduce((acc, [_, value]) => ({ ...acc, ...value.tokens }), {}) as { [p: string]: string }, ), ]; diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 5e3d9d0e2..85bbf1ad9 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -3,7 +3,7 @@ import { PrismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; import { prisma } from '../../../../prisma/prisma-client'; import { networkContext } from '../../../network/network-context.service'; import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; -import { PrismaPoolAprItemGroup, PrismaPoolLinearData } from '@prisma/client'; +import { PrismaPoolAprItemGroup, PrismaPoolAprType, PrismaPoolLinearData } from '@prisma/client'; import { IbLinearAprHandlers as IbTokensAprHandlers, TokenApr } from './ib-linear-apr-handlers/ib-linear-apr-handlers'; import { TokenService } from '../../../token/token.service'; import { collectsYieldFee } from '../pool-utils'; @@ -24,14 +24,14 @@ export class IbTokensAprService implements PoolAprService { const operations: any[] = []; const tokenPrices = await this.tokenService.getTokenPrices(); const aprs = await this.fetchYieldTokensApr(); - const tokenYieldPools = pools.filter((pool) => { + const poolsWithIbTokens = pools.filter((pool) => { return pool.tokens.find((token) => { return Array.from(aprs.keys()) .map((key) => key.toLowerCase()) .includes(token.address.toLowerCase()); }); }); - for (const pool of tokenYieldPools) { + for (const pool of poolsWithIbTokens) { if (!pool.dynamicData) { continue; } @@ -39,86 +39,65 @@ export class IbTokensAprService implements PoolAprService { if (!totalLiquidity) { continue; } - const isLinear = pool.type === 'LINEAR' && pool.linearData !== null; - if (!isLinear) { - // TODO: In theory, we should check whether the token has a rate provider set, but we don't store this information yet - for (const token of pool.tokens) { - const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee - ? parseFloat(pool.dynamicData.protocolYieldFee) - : networkContext.data.balancer.yieldProtocolFeePercentage; - const tokenPrice = this.tokenService.getPriceForToken(tokenPrices, token.address); - const tokenBalance = token.dynamicData?.balance; - const tokenApr = aprs.get(token.address); - if (tokenPrice && tokenBalance && tokenApr !== undefined) { - const tokenPercentage = (parseFloat(tokenBalance) * tokenPrice) / totalLiquidity; - const poolTokenApr = totalLiquidity > 0 ? tokenApr.val * tokenPercentage : 0; - const aprAfterFees = - pool.type === 'META_STABLE' - ? poolTokenApr * (1 - networkContext.data.balancer.swapProtocolFeePercentage) - : poolTokenApr * (1 - protocolYieldFeePercentage); - const tokenSymbol = token.token.symbol; - const itemId = `${pool.id}-${tokenSymbol}-yield-apr`; - operations.push( - prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `${tokenSymbol} APR`, - apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, - group: tokenApr.group as PrismaPoolAprItemGroup, - type: 'IB_YIELD', - }, - update: { - title: `${tokenSymbol} APR`, - apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, - }, - }), - ); - } + + // TODO: We should check whether the token has a rate provider set, but we don't store this information yet + + for (const token of pool.tokens) { + const tokenApr = aprs.get(token.address); + if (!tokenApr) { + continue; + } + + const tokenPrice = this.tokenService.getPriceForToken(tokenPrices, token.address); + const tokenBalance = token.dynamicData?.balance; + + const tokenLiquidity = tokenPrice * parseFloat(tokenBalance || '0'); + const tokenPercentageInPool = tokenLiquidity / totalLiquidity; + + if (!tokenApr || !tokenPercentageInPool) { + continue; } - } else { - const linearData = pool.linearData as PrismaPoolLinearData; - const wrappedToken = pool.tokens[linearData.wrappedIndex]; - const mainToken = pool.tokens[linearData.mainIndex]; - for (const token of pool.tokens) { + + let aprAfterFees = tokenApr.val; + + if (collectsYieldFee(pool)) { const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee ? parseFloat(pool.dynamicData.protocolYieldFee) : networkContext.data.balancer.yieldProtocolFeePercentage; - const tokenPrice = this.tokenService.getPriceForToken(tokenPrices, mainToken.address); - const wrappedTokenBalance = parseFloat(wrappedToken.dynamicData?.balance || '0'); - const wrappedTokenPriceRate = parseFloat(wrappedToken.dynamicData?.priceRate || '1.0'); - const poolWrappedLiquidity = wrappedTokenBalance * wrappedTokenPriceRate * tokenPrice; - const totalLiquidity = pool.dynamicData.totalLiquidity; - const tokenApr = aprs.get(wrappedToken.address); - if (tokenPrice && wrappedTokenBalance && totalLiquidity !== undefined && tokenApr !== undefined) { - const tokenPercentage = poolWrappedLiquidity / totalLiquidity; - const poolTokenApr = totalLiquidity > 0 ? tokenApr.val * tokenPercentage : 0; - const aprAfterFees = poolTokenApr * (1 - protocolYieldFeePercentage); - const tokenSymbol = token.token.symbol; - const isBoosted = this.ibTokensAprHandlers.wrappedBoostedTokens.includes(wrappedToken.address); - const itemId = `${pool.id}-${tokenSymbol}-${isBoosted ? 'boosted' : 'yield'}-apr`; - operations.push( - prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `${tokenSymbol} APR`, - apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, - group: tokenApr.group as PrismaPoolAprItemGroup, - type: isBoosted ? 'LINEAR_BOOSTED' : 'IB_YIELD', - }, - update: { - title: `${tokenSymbol} APR`, - apr: collectsYieldFee(pool) ? aprAfterFees : poolTokenApr, - }, - }), - ); - } + aprAfterFees = + pool.type === 'META_STABLE' + ? aprAfterFees * (1 - networkContext.data.balancer.swapProtocolFeePercentage) + : aprAfterFees * (1 - protocolYieldFeePercentage); } + + // yieldType is LINEAR_BOOSTED if its in the wrappedLinearTokens list + const yieldType: PrismaPoolAprType = this.ibTokensAprHandlers.wrappedLinearTokens.includes( + token.address, + ) + ? 'LINEAR_BOOSTED' + : 'IB_YIELD'; + + const itemId = `${pool.id}-${token.token.symbol}-yield-apr`; + + operations.push( + prisma.prismaPoolAprItem.upsert({ + where: { id_chain: { id: itemId, chain: networkContext.chain } }, + create: { + id: itemId, + chain: networkContext.chain, + poolId: pool.id, + title: `${token.token.symbol} APR`, + apr: aprAfterFees, + group: tokenApr.group as PrismaPoolAprItemGroup, + type: yieldType, + }, + update: { + title: `${token.token.symbol} APR`, + group: tokenApr.group as PrismaPoolAprItemGroup, + apr: aprAfterFees, + }, + }), + ); } } await prismaBulkExecuteOperations(operations); From 97a795f3ce0314fe0c7993dd030ef404e0e3d3a4 Mon Sep 17 00:00:00 2001 From: franz Date: Mon, 4 Sep 2023 10:55:37 +0200 Subject: [PATCH 34/42] change default handler, adapt token lists --- modules/network/apr-config-types.ts | 8 +-- modules/network/arbitrum.ts | 6 +- modules/network/base.ts | 15 ++--- modules/network/fantom.ts | 2 +- modules/network/gnosis.ts | 10 +--- modules/network/mainnet.ts | 46 +++++---------- modules/network/optimism.ts | 18 ++---- modules/network/polygon.ts | 18 ++---- modules/network/zkevm.ts | 7 +-- .../ib-linear-apr-handlers.ts | 57 ++++++++++--------- .../sources/default-apr-handler.ts | 17 ++---- .../apr-data-sources/ib-tokens-apr.service.ts | 10 ++-- 12 files changed, 77 insertions(+), 137 deletions(-) diff --git a/modules/network/apr-config-types.ts b/modules/network/apr-config-types.ts index 5ecffc7a2..1eb0cda37 100644 --- a/modules/network/apr-config-types.ts +++ b/modules/network/apr-config-types.ts @@ -12,7 +12,7 @@ export interface IbAprConfig { tranchess?: TranchessAprConfig; yearn?: YearnAprConfig; defaultHandlers?: DefaultHandlerAprConfig; - fixed?: FixedAprConfig; + fixedAprHandler?: FixedAprConfig; } export interface AaveAprConfig { @@ -78,7 +78,6 @@ export interface IdleAprConfig { } export interface OvixAprConfig { - rpcUrl: string; tokens: { [tokenName: string]: { yieldAddress: string; @@ -111,7 +110,6 @@ export interface ReaperAprConfig { } export interface TesseraAprConfig { - rpcUrl: string; tokens: { [tokenName: string]: { tesseraPoolAddress: string; @@ -144,9 +142,7 @@ export interface YearnAprConfig { export interface DefaultHandlerAprConfig { [tokenName: string]: { sourceUrl: string; - tokens: { - [tokenName: string]: string; - }; + tokenAddress: string; path?: string; scale?: number; group?: string; diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 9ad99ce46..4f1a4f7f5 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -145,10 +145,8 @@ const arbitrumNetworkData: NetworkData = { }, }, defaultHandlers: { - stETH: { - tokens: { - wstETH: '0x5979d7b546e38e414f7e9822514be443a4800529', - }, + wstETH: { + tokenAddress: '0x5979d7b546e38e414f7e9822514be443a4800529', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', }, diff --git a/modules/network/base.ts b/modules/network/base.ts index 48fb7bcba..b91f13b55 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -76,12 +76,11 @@ const baseNetworkData: NetworkData = { }, ibAprConfig: { defaultHandlers: { - stETH: { - tokens: { - wstETH: '', - }, - sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - path: 'data.smaApr', + cbETH: { + tokenAddress: '0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22', + sourceUrl: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', + path: 'apy', + scale: 1, }, }, }, @@ -104,10 +103,6 @@ const baseNetworkData: NetworkData = { swapGas: BigNumber.from('1000000'), }, }, - lido: { - wstEthAprEndpoint: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', - wstEthContract: '', - }, monitoring: { main: { alarmTopicArn: 'arn:aws:sns:ca-central-1:118697801881:api_alarms', diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index d9b455711..2932a25a8 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -242,7 +242,7 @@ const fantomNetworkData: NetworkData = { yearn: { sourceUrl: 'https://d28fcsszptni1s.cloudfront.net/v1/chains/250/vaults/all', }, - fixed: { + fixedAprHandler: { sFTMx: { address: '0xd7028092c830b5c8fce061af2e593413ebbc1fc1', value: 0.046, diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index af2822b0c..6e35252b9 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -96,19 +96,13 @@ const gnosisNetworkData: NetworkData = { }, ibAprConfig: { defaultHandlers: { - stETH: { - tokens: { - wstETH: '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6', - }, + wstETH: { + tokenAddress: '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', }, }, }, - lido: { - wstEthAprEndpoint: '', - wstEthContract: '', - }, datastudio: { main: { user: 'datafeed-service@datastudio-366113.iam.gserviceaccount.com', diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 843ed1c5a..62db6239d 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -222,7 +222,6 @@ export const mainnetNetworkData: NetworkData = { }, }, tessera: { - rpcUrl: 'https://rpc.ankr.com/eth', tokens: { sAPE: { tesseraPoolAddress: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9', @@ -241,69 +240,50 @@ export const mainnetNetworkData: NetworkData = { }, defaultHandlers: { vETH: { - tokens: { - vETH: '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f', - }, + tokenAddress: '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f', sourceUrl: 'https://apy.liebi.com/veth', path: 'veth', }, stETH: { - tokens: { - stETH: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84', - wstETH: '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', - }, + tokenAddress: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84', + sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', + path: 'data.smaApr', + }, + wstETH: { + tokenAddress: '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', }, cbETH: { - tokens: { - cbETH: '0xbe9895146f7af43049ca1c1ae358b0541ea49704', - }, + tokenAddress: '0xbe9895146f7af43049ca1c1ae358b0541ea49704', sourceUrl: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', path: 'apy', scale: 1, }, sfrxETH: { - tokens: { sfrxETH: '0xac3e018457b222d93114458476f3e3416abbe38f' }, + tokenAddress: '0xac3e018457b222d93114458476f3e3416abbe38f', sourceUrl: 'https://api.frax.finance/v2/frxeth/summary/latest', path: 'sfrxethApr', }, rETH: { - tokens: { - rETH: '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593', - }, + tokenAddress: '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593', sourceUrl: 'https://drop-api.stafi.io/reth/v1/poolData', path: 'data.stakeApr', }, USDR: { - tokens: { - USDR: '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b', - }, + tokenAddress: '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b', sourceUrl: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', path: 'usdr', }, swETH: { - tokens: { - swETH: '0xf951e335afb289353dc249e82926178eac7ded78', - }, + tokenAddress: '0xf951e335afb289353dc249e82926178eac7ded78', sourceUrl: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', }, wjAURA: { - tokens: { - wjAURA: '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f', - }, + tokenAddress: '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f', sourceUrl: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', path: 'wjauraApy', }, - overnight: { - tokens: { - lpUsdcUsdPlus: '0x1aafc31091d93c3ff003cff5d2d8f7ba2e728425', - UsdcUsdPlus: '0x6933ec1ca55c06a894107860c92acdfd2dd8512f', - }, - sourceUrl: 'https://app.overnight.fi/api/balancer/week/apr', - group: 'OVERNIGHT', - scale: 1, - }, }, }, beefy: { diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 16fa076f9..f60cd7612 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -182,32 +182,24 @@ const optimismNetworkData: NetworkData = { }, }, defaultHandlers: { - stEth: { - tokens: { - wstETH: '0x1f32b1c2345538c0c6f582fcb022739c4a194ebb', - }, + wstEth: { + tokenAddress: '0x1f32b1c2345538c0c6f582fcb022739c4a194ebb', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', }, rETH: { - tokens: { - rETH: '0x9bcef72be871e61ed4fbbc7630889bee758eb81d', - }, + tokenAddress: '0x9bcef72be871e61ed4fbbc7630889bee758eb81d', sourceUrl: 'https://drop-api.stafi.io/reth/v1/poolData', path: 'data.stakeApr', }, overnightDAIPlus: { - tokens: { - DAIPlus: '0x0b8f31480249cc717081928b8af733f45f6915bb', - }, + tokenAddress: '0x0b8f31480249cc717081928b8af733f45f6915bb', sourceUrl: 'https://api.overnight.fi/optimism/dai+/fin-data/avg-apr/week', path: 'value', group: 'OVERNIGHT', }, overnightUSDPlus: { - tokens: { - USDPlus: '0xa348700745d249c3b49d2c2acac9a5ae8155f826', - }, + tokenAddress: '0xa348700745d249c3b49d2c2acac9a5ae8155f826', sourceUrl: 'https://api.overnight.fi/optimism/usd+/fin-data/avg-apr/week', path: 'value', group: 'OVERNIGHT', diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index 886dd4bc5..1c082d130 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -188,31 +188,23 @@ const polygonNetworkData: NetworkData = { }, }, defaultHandlers: { - stETH: { - tokens: { - wstETH: '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd', - }, + wstETH: { + tokenAddress: '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', }, stMATIC: { - tokens: { - stMATIC: '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4', - }, + tokenAddress: '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4', sourceUrl: 'https://polygon.lido.fi/api/stats', path: 'apr', }, MATICX: { - tokens: { - MATICX: '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6', - }, + tokenAddress: '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6', sourceUrl: 'https://universe.staderlabs.com/polygon/apy', path: 'value', }, wbETH: { - tokens: { - wbETH: '0xa2e3356610840701bdf5611a53974510ae27e2e1', - }, + tokenAddress: '0xa2e3356610840701bdf5611a53974510ae27e2e1', sourceUrl: 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', path: 'data.0.rewardRate', diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index c3b2cf6ff..2496fcdf5 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -100,7 +100,6 @@ const zkevmNetworkData: NetworkData = { }, ibAprConfig: { ovix: { - rpcUrl: 'https://zkevm-rpc.com', tokens: { USDT: { yieldAddress: '0xad41c77d99e282267c1492cdefe528d7d5044253', @@ -113,10 +112,8 @@ const zkevmNetworkData: NetworkData = { }, }, defaultHandlers: { - stETH: { - tokens: { - wstETH: '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9', - }, + wstETH: { + tokenAddress: '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', }, diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts index 9d89a1721..73f7d6ddc 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts @@ -15,15 +15,15 @@ import { IbAprConfig } from '../../../../network/apr-config-types'; export class IbLinearAprHandlers { private handlers: AprHandler[] = []; - //List of addresses of wrappedBoostedTokens, used to check what is LINEAR_BOOSTED APR and what is IB_YIELD APR - wrappedLinearTokens: string[] = []; + //List of addresses of any IB Yield tokens (such as reth, wsteth), used to check what is LINEAR_BOOSTED APR and what is IB_YIELD APR + ibYieledTokens: string[] = []; fixedAprTokens?: { [tokenName: string]: { address: string; value: number; group?: string } }; constructor(aprConfig: IbAprConfig) { this.handlers = this.buildAprHandlers(aprConfig); - this.wrappedLinearTokens = this.buildWrappedLinearTokens(aprConfig); - this.fixedAprTokens = aprConfig.fixed; + this.ibYieledTokens = this.buildIbYieldTokens(aprConfig); + this.fixedAprTokens = aprConfig.fixedAprHandler; } buildAprHandlers(aprConfig: IbAprConfig) { @@ -91,30 +91,33 @@ export class IbLinearAprHandlers { return handlers; } - // TODO rethink that one - buildWrappedLinearTokens(aprConfig: IbAprConfig): string[] { + // Any IB Yield tokens (such as rETH, wstETH) need to be added here. Linear Wrapped Tokens must NOT be added here. + buildIbYieldTokens(aprConfig: IbAprConfig): string[] { + const ibYieldTokenNamesForDefaultHandler = [ + 'rEth', + 'stETH', + 'wstETH', + 'cbETH', + 'sfrxETH', + 'USDR', + 'swETH', + 'wjAURA', + 'qETH', + 'ankrETH', + 'ankrFTM', + 'sFTMx', + 'stMATIC', + 'MATICX', + 'wbETH', + ].map((token) => token.toLowerCase()); + return [ - ...Object.values(aprConfig?.aave?.v2?.tokens?.USDC?.wrappedTokens || {}), - ...Object.values(aprConfig?.aave?.v3?.tokens?.USDC?.wrappedTokens || {}), - ...Object.values(aprConfig?.aave?.v2?.tokens?.USDT?.wrappedTokens || {}), - ...Object.values(aprConfig?.aave?.v3?.tokens?.USDT?.wrappedTokens || {}), - ...Object.values(aprConfig?.aave?.v2?.tokens?.DAI?.wrappedTokens || {}), - ...Object.values(aprConfig?.aave?.v3?.tokens?.DAI?.wrappedTokens || {}), - ...Object.values(aprConfig?.aave?.v3?.tokens?.wETH?.wrappedTokens || {}), - ...Object.values(aprConfig?.aave?.v3?.tokens?.wMATIC?.wrappedTokens || {}), - ...Object.values(aprConfig?.ankr?.tokens || {}).map(({ address }) => address), - ...Object.values(aprConfig?.euler?.tokens || {}), - ...Object.values(aprConfig?.gearbox?.tokens || {}), - ...Object.values(aprConfig?.idle?.tokens || {}).map(({ wrapped4626Address }) => wrapped4626Address), - ...Object.values(aprConfig?.ovix?.tokens || {}).map(({ wrappedAddress }) => wrappedAddress), - ...Object.values(aprConfig?.tessera?.tokens || {}).map(({ tokenAddress }) => tokenAddress), - ...Object.values(aprConfig?.tranchess?.tokens || {}).map(({ address }) => address), - ...Object.values(aprConfig?.tetu?.tokens || {}), - ...Object.values( - Object.entries(aprConfig?.defaultHandlers || {}) - //Filtering out handlers that are not LINEAR_BOOSTED - .filter(([key, _]) => ['rETH', 'USDR', 'swETH', 'wjAURA', 'qETH'].includes(key)) - .reduce((acc, [_, value]) => ({ ...acc, ...value.tokens }), {}) as { [p: string]: string }, + ...Object.values(aprConfig?.ankr?.tokens || {}).map((token) => token.address), + ...Object.keys(aprConfig?.defaultHandlers || {}).filter((handler) => + ibYieldTokenNamesForDefaultHandler.includes(handler.toLowerCase()), + ), + ...Object.keys(aprConfig?.fixedAprHandler || {}).filter((handler) => + ibYieldTokenNamesForDefaultHandler.includes(handler.toLowerCase()), ), ]; } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts index 37572a52e..b2b5bd9e2 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts @@ -1,11 +1,10 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; +import * as Sentry from '@sentry/node'; export class DefaultAprHandler implements AprHandler { - tokens: { - [tokenName: string]: string; - }; + tokenAddress: string; url: string; path: string; scale: number; @@ -13,14 +12,12 @@ export class DefaultAprHandler implements AprHandler { constructor(aprHandlerConfig: { sourceUrl: string; - tokens: { - [tokenName: string]: string; - }; + tokenAddress: string; path?: string; scale?: number; group?: string; }) { - this.tokens = aprHandlerConfig.tokens; + this.tokenAddress = aprHandlerConfig.tokenAddress; this.url = aprHandlerConfig.sourceUrl; this.path = aprHandlerConfig.path ?? ''; this.scale = aprHandlerConfig.scale ?? 100; @@ -33,12 +30,10 @@ export class DefaultAprHandler implements AprHandler { const value = this.path === '' ? data : this.getValueFromPath(data, this.path); const scaledValue = parseFloat(value) / this.scale; - return Object.values(this.tokens).reduce((acc, token) => { - acc[token] = scaledValue; - return acc; - }, {} as { [key: string]: number }); + return [this.tokenAddress, scaledValue]; } catch (error) { console.error(`Failed to fetch APRs in url ${this.url}:`, error); + Sentry.captureException(`Failed to fetch APRs in url ${this.url}: ${error}`); return {}; } } diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 85bbf1ad9..3cd1698a3 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -70,12 +70,10 @@ export class IbTokensAprService implements PoolAprService { : aprAfterFees * (1 - protocolYieldFeePercentage); } - // yieldType is LINEAR_BOOSTED if its in the wrappedLinearTokens list - const yieldType: PrismaPoolAprType = this.ibTokensAprHandlers.wrappedLinearTokens.includes( - token.address, - ) - ? 'LINEAR_BOOSTED' - : 'IB_YIELD'; + // yieldType is IB_YIELD if its in the ibYieledTokens list + const yieldType: PrismaPoolAprType = this.ibTokensAprHandlers.ibYieledTokens.includes(token.address) + ? 'IB_YIELD' + : 'LINEAR_BOOSTED'; const itemId = `${pool.id}-${token.token.symbol}-yield-apr`; From ea595772596027f822c11f3454276533fb491a32 Mon Sep 17 00:00:00 2001 From: franz Date: Mon, 4 Sep 2023 12:50:50 +0200 Subject: [PATCH 35/42] fix percentage --- modules/network/arbitrum.ts | 2 +- modules/network/avalanche.ts | 2 +- modules/network/base.ts | 2 + modules/network/fantom.ts | 2 +- modules/network/gnosis.ts | 2 +- modules/network/mainnet.ts | 2 +- modules/network/optimism.ts | 3 +- modules/network/polygon.ts | 2 +- modules/network/zkevm.ts | 2 +- .../apr-data-sources/ib-tokens-apr.service.ts | 42 +++++++++---------- 10 files changed, 30 insertions(+), 31 deletions(-) diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 4f1a4f7f5..2d7dd2b7b 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -190,7 +190,7 @@ export const arbitrumNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: arbitrumNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService(arbitrumNetworkData.ibAprConfig, tokenService), + new IbTokensAprService(arbitrumNetworkData.ibAprConfig), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(arbitrumNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index 5d71e2fb6..ee759b8ad 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -190,7 +190,7 @@ export const avalancheNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: avalancheNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService(avalancheNetworkData.ibAprConfig, tokenService), + new IbTokensAprService(avalancheNetworkData.ibAprConfig), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(avalancheNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/base.ts b/modules/network/base.ts index b91f13b55..e21118367 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -15,6 +15,7 @@ import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { env } from '../../app/env'; +import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; const baseNetworkData: NetworkData = { chain: { @@ -118,6 +119,7 @@ export const baseNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: baseNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ + new IbTokensAprService(baseNetworkData.ibAprConfig), new BoostedPoolAprService(), new SwapFeeAprService(baseNetworkData.balancer.swapProtocolFeePercentage), new GaugeAprService(gaugeSubgraphService, tokenService, [baseNetworkData.bal!.address]), diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index 2932a25a8..1bbd63e8a 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -296,7 +296,7 @@ export const fantomNetworkConfig: NetworkConfig = { contentService: new SanityContentService(), provider: new ethers.providers.JsonRpcProvider({ url: fantomNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService(fantomNetworkData.ibAprConfig, tokenService), + new IbTokensAprService(fantomNetworkData.ibAprConfig), // new SpookySwapAprService(tokenService, fantomNetworkData.spooky!.xBooContract), new PhantomStableAprService(), new BoostedPoolAprService(), diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index 6e35252b9..52f0726ec 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -137,7 +137,7 @@ export const gnosisNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: gnosisNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService(gnosisNetworkData.ibAprConfig, tokenService), + new IbTokensAprService(gnosisNetworkData.ibAprConfig), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(gnosisNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 62db6239d..92081b0f0 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -320,7 +320,7 @@ export const mainnetNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: mainnetNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService(mainnetNetworkData.ibAprConfig, tokenService), + new IbTokensAprService(mainnetNetworkData.ibAprConfig), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(mainnetNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index f60cd7612..40e05bd65 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -249,8 +249,7 @@ export const optimismNetworkConfig: NetworkConfig = { contentService: new SanityContentService(), provider: new ethers.providers.JsonRpcProvider({ url: optimismNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService(optimismNetworkData.ibAprConfig, tokenService), - new BeefyVaultAprService(optimismNetworkData.beefy!.linearPools, tokenService), + new IbTokensAprService(optimismNetworkData.ibAprConfig), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(optimismNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index 1c082d130..04064d192 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -245,7 +245,7 @@ export const polygonNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: polygonNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService(polygonNetworkData.ibAprConfig, tokenService), + new IbTokensAprService(polygonNetworkData.ibAprConfig), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(polygonNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index 2496fcdf5..0af16504b 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -153,7 +153,7 @@ export const zkevmNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: zkevmNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService(zkevmNetworkData.ibAprConfig, tokenService), + new IbTokensAprService(zkevmNetworkData.ibAprConfig), new PhantomStableAprService(), new BoostedPoolAprService(), new SwapFeeAprService(zkevmNetworkData.balancer.swapProtocolFeePercentage), diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index 3cd1698a3..f1b614530 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -5,14 +5,14 @@ import { networkContext } from '../../../network/network-context.service'; import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; import { PrismaPoolAprItemGroup, PrismaPoolAprType, PrismaPoolLinearData } from '@prisma/client'; import { IbLinearAprHandlers as IbTokensAprHandlers, TokenApr } from './ib-linear-apr-handlers/ib-linear-apr-handlers'; -import { TokenService } from '../../../token/token.service'; +import { tokenService } from '../../../token/token.service'; import { collectsYieldFee } from '../pool-utils'; import { IbAprConfig } from '../../../network/apr-config-types'; export class IbTokensAprService implements PoolAprService { private ibTokensAprHandlers: IbTokensAprHandlers; - constructor(aprConfig: IbAprConfig, private readonly tokenService: TokenService) { + constructor(aprConfig: IbAprConfig) { this.ibTokensAprHandlers = new IbTokensAprHandlers(aprConfig); } @@ -22,7 +22,7 @@ export class IbTokensAprService implements PoolAprService { public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { const operations: any[] = []; - const tokenPrices = await this.tokenService.getTokenPrices(); + const tokenPrices = await tokenService.getTokenPrices(); const aprs = await this.fetchYieldTokensApr(); const poolsWithIbTokens = pools.filter((pool) => { return pool.tokens.find((token) => { @@ -48,7 +48,7 @@ export class IbTokensAprService implements PoolAprService { continue; } - const tokenPrice = this.tokenService.getPriceForToken(tokenPrices, token.address); + const tokenPrice = tokenService.getPriceForToken(tokenPrices, token.address); const tokenBalance = token.dynamicData?.balance; const tokenLiquidity = tokenPrice * parseFloat(tokenBalance || '0'); @@ -58,16 +58,16 @@ export class IbTokensAprService implements PoolAprService { continue; } - let aprAfterFees = tokenApr.val; + let aprInPoolAfterFees = tokenApr.val * tokenPercentageInPool; if (collectsYieldFee(pool)) { const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee ? parseFloat(pool.dynamicData.protocolYieldFee) : networkContext.data.balancer.yieldProtocolFeePercentage; - aprAfterFees = + aprInPoolAfterFees = pool.type === 'META_STABLE' - ? aprAfterFees * (1 - networkContext.data.balancer.swapProtocolFeePercentage) - : aprAfterFees * (1 - protocolYieldFeePercentage); + ? aprInPoolAfterFees * (1 - networkContext.data.balancer.swapProtocolFeePercentage) + : aprInPoolAfterFees * (1 - protocolYieldFeePercentage); } // yieldType is IB_YIELD if its in the ibYieledTokens list @@ -77,23 +77,21 @@ export class IbTokensAprService implements PoolAprService { const itemId = `${pool.id}-${token.token.symbol}-yield-apr`; + const data = { + id: itemId, + chain: networkContext.chain, + poolId: pool.id, + title: `${token.token.symbol} APR`, + apr: aprInPoolAfterFees, + group: tokenApr.group as PrismaPoolAprItemGroup, + type: yieldType, + }; + operations.push( prisma.prismaPoolAprItem.upsert({ where: { id_chain: { id: itemId, chain: networkContext.chain } }, - create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `${token.token.symbol} APR`, - apr: aprAfterFees, - group: tokenApr.group as PrismaPoolAprItemGroup, - type: yieldType, - }, - update: { - title: `${token.token.symbol} APR`, - group: tokenApr.group as PrismaPoolAprItemGroup, - apr: aprAfterFees, - }, + create: data, + update: data, }), ); } From 1a9352e212d0627a229bf449c0388390f374894d Mon Sep 17 00:00:00 2001 From: franz Date: Mon, 4 Sep 2023 13:25:22 +0200 Subject: [PATCH 36/42] add try catch --- .../sources/aave-apr-handler.ts | 2 + .../sources/ankr-apr-handler.ts | 4 +- .../sources/beefy-apr-handler.ts | 17 ++- .../sources/default-apr-handler.ts | 2 +- .../sources/euler-apr-handler.ts | 48 ++++---- .../sources/gearbox-apr-handler.ts | 2 + .../sources/idle-apr-handler.ts | 2 + .../sources/ovix-apr-handler.ts | 2 + .../sources/reaper-crypt-apr-handler.ts | 109 ++++++++++-------- .../sources/tessera-apr-handler.ts | 2 + .../sources/tetu-apr-handler.ts | 2 + .../sources/tranchess-apr-handler.ts | 2 + .../sources/yearn-apr-handler.ts | 21 ++-- 13 files changed, 132 insertions(+), 83 deletions(-) diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts index 4692bb63f..ffb0f7d06 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts @@ -1,4 +1,5 @@ import axios from 'axios'; +import * as Sentry from '@sentry/node'; import { AprHandler } from '../ib-linear-apr-handlers'; export class AaveAprHandler implements AprHandler { @@ -84,6 +85,7 @@ export class AaveAprHandler implements AprHandler { return aprEntries; } catch (e) { console.error(`Failed to fetch Aave APR in subgraph ${this.subgraphUrl}:`, e); + Sentry.captureException(`Aave IB APR handler failed: ${e}`); return {}; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts index c134c76ba..9b5710336 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts @@ -1,4 +1,5 @@ import axios from 'axios'; +import * as Sentry from '@sentry/node'; import { AprHandler } from '../ib-linear-apr-handlers'; import { AnkrAprConfig } from '../../../../../network/apr-config-types'; @@ -10,7 +11,7 @@ export class AnkrAprHandler implements AprHandler { }; }; url: string; - readonly group = 'ANKR'; + readonly group = undefined; constructor(aprHandlerConfig: AnkrAprConfig) { this.tokens = aprHandlerConfig.tokens; @@ -33,6 +34,7 @@ export class AnkrAprHandler implements AprHandler { return aprs; } catch (error) { console.error('Failed to fetch Ankr APR:', error); + Sentry.captureException(`Ankr IB APR handler failed: ${error}`); return {}; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts index 03bf2052c..7dd0d48fa 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts @@ -1,6 +1,7 @@ import { BeefyAprConfig } from '../../../../../network/apr-config-types'; import { AprHandler } from '../ib-linear-apr-handlers'; import axios from 'axios'; +import * as Sentry from '@sentry/node'; export class BeefyAprHandler implements AprHandler { tokens: { @@ -18,12 +19,18 @@ export class BeefyAprHandler implements AprHandler { } async getAprs(): Promise<{ [p: string]: number }> { - const { data: aprData } = await axios.get(this.sourceUrl); - const aprs: { [tokenAddress: string]: number } = {}; - for (const { address, vaultId } of Object.values(this.tokens)) { - aprs[address] = aprData[vaultId].vaultApr; + try { + const { data: aprData } = await axios.get(this.sourceUrl); + const aprs: { [tokenAddress: string]: number } = {}; + for (const { address, vaultId } of Object.values(this.tokens)) { + aprs[address] = aprData[vaultId].vaultApr; + } + return aprs; + } catch (error) { + console.error(`Beefy IB APR hanlder failed: `, error); + Sentry.captureException(`Beefy IB APR handler failed: ${error}`); + return {}; } - return aprs; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts index b2b5bd9e2..3594eafb9 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts @@ -33,7 +33,7 @@ export class DefaultAprHandler implements AprHandler { return [this.tokenAddress, scaledValue]; } catch (error) { console.error(`Failed to fetch APRs in url ${this.url}:`, error); - Sentry.captureException(`Failed to fetch APRs in url ${this.url}: ${error}`); + Sentry.captureException(`Failed to fetch default IB APRs in url ${this.url}: ${error}`); return {}; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts index d912b301b..cb1c08aae 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts @@ -1,6 +1,7 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; import { EulerAprConfig } from '../../../../../network/apr-config-types'; +import * as Sentry from '@sentry/node'; export class EulerAprHandler implements AprHandler { tokens: { [key: string]: string }; @@ -26,31 +27,36 @@ export class EulerAprHandler implements AprHandler { } async getAprs() { - const requestQuery = { - operationName: 'getAssetsAPY', - query: this.query, - variables: { - eTokenAddress_in: Object.values(this.tokens), - }, - }; + try { + const requestQuery = { + operationName: 'getAssetsAPY', + query: this.query, + variables: { + eTokenAddress_in: Object.values(this.tokens), + }, + }; - const { data } = await axios({ - url: this.subgraphUrl, - method: 'POST', - data: JSON.stringify(requestQuery), - }); + const { data } = await axios({ + url: this.subgraphUrl, + method: 'POST', + data: JSON.stringify(requestQuery), + }); - const { - data: { assets }, - } = data as EulerResponse; + const { + data: { assets }, + } = data as EulerResponse; - const aprEntries = assets.map(({ eTokenAddress, supplyAPY }) => [ - eTokenAddress, - // supplyAPY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 - Number(supplyAPY.slice(0, 27)) / 1e27, - ]); + const aprEntries = assets.map(({ eTokenAddress, supplyAPY }) => [ + eTokenAddress, + // supplyAPY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 + Number(supplyAPY.slice(0, 27)) / 1e27, + ]); - return Object.fromEntries(aprEntries); + return Object.fromEntries(aprEntries); + } catch (error) { + console.error(`Euler IB APR handler failed: `, error); + Sentry.captureException(`Euler IB APR handler failed: ${error}`); + } } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts index f5dc888ba..953f41354 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts @@ -1,4 +1,5 @@ import axios from 'axios'; +import * as Sentry from '@sentry/node'; import { AprHandler } from '../ib-linear-apr-handlers'; import { GearBoxAprConfig } from '../../../../../network/apr-config-types'; @@ -26,6 +27,7 @@ export class GearboxAprHandler implements AprHandler { return Object.fromEntries(aprEntries); } catch (error) { console.error('Failed to fetch Gearbox APR:', error); + Sentry.captureException(`Gearbox IB APR handler failed: ${error}`); return {}; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts index ce654f6b1..996167152 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts @@ -2,6 +2,7 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; import { IdleAprConfig } from '../../../../../network/apr-config-types'; +import * as Sentry from '@sentry/node'; export class IdleAprHandler implements AprHandler { tokens: { @@ -39,6 +40,7 @@ export class IdleAprHandler implements AprHandler { return Object.fromEntries(res); } catch (error) { console.error('Failed to fetch Idle APR:', error); + Sentry.captureException(`Idle IB APR handler failed: ${error}`); return {}; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts index 97a6108ae..eea6df113 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts @@ -1,5 +1,6 @@ import { BigNumber, Contract } from 'ethers'; import { abi } from './abis/oErc20'; +import * as Sentry from '@sentry/node'; import { AprHandler } from '../ib-linear-apr-handlers'; import { networkContext } from '../../../../../network/network-context.service'; @@ -32,6 +33,7 @@ export class OvixAprHandler implements AprHandler { return Object.fromEntries(await Promise.all(aprEntries)); } catch (error) { console.error('Failed to fetch Ovix APR:', error); + Sentry.captureException(`Ovix IB APR handler failed: ${error}`); return {}; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts index 7cd58482b..4d9b6311a 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts @@ -4,6 +4,7 @@ import ReaperCryptStrategyAbi from './abis/ReaperCryptStrategy.json'; import axios from 'axios'; import ReaperCryptAbi from './abis/ReaperCrypt.json'; import { ReaperAprConfig } from '../../../../../network/apr-config-types'; +import * as Sentry from '@sentry/node'; const APR_PERCENT_DIVISOR = 10_000; @@ -35,74 +36,86 @@ export class ReaperCryptAprHandler implements AprHandler { let singleStrategyAprs = {}; this.wstETHBaseApr = await this.getWstEthBaseApr(); if (this.tokensWithSubgraphSource !== undefined) { - multiStrategyAprs = await this.getMultiStrategyAprFromSubgraph(this.tokensWithSubgraphSource); + multiStrategyAprs = await this.getAprFromSubgraph(this.tokensWithSubgraphSource); } if (this.tokensWithOnChainSource !== undefined) { - singleStrategyAprs = await this.getSingleStrategyCryptApr(this.tokensWithOnChainSource); + singleStrategyAprs = await this.getOnChainCryptApr(this.tokensWithOnChainSource); } return { ...multiStrategyAprs, ...singleStrategyAprs }; } - private async getSingleStrategyCryptApr(tokens: { + private async getOnChainCryptApr(tokens: { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean }; }): Promise<{ [tokenAddress: string]: number }> { const aprs: { [tokenAddress: string]: number } = {}; for (const { address, isSftmX, isWstETH } of Object.values(tokens)) { - const tokenContract = getContractAt(address, ReaperCryptAbi); - const strategyAddress = await tokenContract.strategy(); - const strategyContract = getContractAt(strategyAddress, ReaperCryptStrategyAbi); - let avgAprAcrossXHarvests = 0; + try { + const tokenContract = getContractAt(address, ReaperCryptAbi); + const strategyAddress = await tokenContract.strategy(); + const strategyContract = getContractAt(strategyAddress, ReaperCryptStrategyAbi); + let avgAprAcrossXHarvests = 0; - avgAprAcrossXHarvests = - (await strategyContract.averageAPRAcrossLastNHarvests(this.averageAPRAcrossLastNHarvests)) / - APR_PERCENT_DIVISOR; - // TODO hanlde this outside - if (isSftmX) { - avgAprAcrossXHarvests = avgAprAcrossXHarvests * (1 + sFTMxBaseApr); + avgAprAcrossXHarvests = + (await strategyContract.averageAPRAcrossLastNHarvests(this.averageAPRAcrossLastNHarvests)) / + APR_PERCENT_DIVISOR; + // TODO hanlde this outside + if (isSftmX) { + avgAprAcrossXHarvests = avgAprAcrossXHarvests * (1 + sFTMxBaseApr); + } + if (isWstETH) { + avgAprAcrossXHarvests = avgAprAcrossXHarvests * (1 + this.wstETHBaseApr); + } + aprs[address] = avgAprAcrossXHarvests; + } catch (error) { + console.error(`Reaper IB APR handler failed for onChain source: `, error); + Sentry.captureException(`Reaper IB APR handler failed for onChain source: ${error}`); + return {}; } - if (isWstETH) { - avgAprAcrossXHarvests = avgAprAcrossXHarvests * (1 + this.wstETHBaseApr); - } - aprs[address] = avgAprAcrossXHarvests; } return aprs; } - private async getMultiStrategyAprFromSubgraph(tokens: { + private async getAprFromSubgraph(tokens: { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean }; }): Promise<{ [tokenAddress: string]: number }> { - const requestQuery = { - operationName: 'getVaults', - query: this.query, - variables: { - ids: Object.values(tokens).map(({ address }) => address), - }, - }; - const { - data: { data }, - }: { data: { data: MultiStratResponse } } = await axios({ - method: 'post', - url: this.subgraphUrl, - data: JSON.stringify(requestQuery), - }); - return data.vaults.reduce((acc, { id, apr }) => { - const token = Object.values(tokens).find((token) => token.address.toLowerCase() === id.toLowerCase()); - if (!token) { - return acc; - } - let tokenApr = parseFloat(apr) / APR_PERCENT_DIVISOR; - if (token.isSftmX) { - tokenApr = tokenApr * (1 + sFTMxBaseApr); - } - if (token.isWstETH) { - tokenApr = tokenApr * (1 + this.wstETHBaseApr); - } - return { - ...acc, - [id]: tokenApr, + try { + const requestQuery = { + operationName: 'getVaults', + query: this.query, + variables: { + ids: Object.values(tokens).map(({ address }) => address), + }, }; - }, {}); + const { + data: { data }, + }: { data: { data: MultiStratResponse } } = await axios({ + method: 'post', + url: this.subgraphUrl, + data: JSON.stringify(requestQuery), + }); + return data.vaults.reduce((acc, { id, apr }) => { + const token = Object.values(tokens).find((token) => token.address.toLowerCase() === id.toLowerCase()); + if (!token) { + return acc; + } + let tokenApr = parseFloat(apr) / APR_PERCENT_DIVISOR; + if (token.isSftmX) { + tokenApr = tokenApr * (1 + sFTMxBaseApr); + } + if (token.isWstETH) { + tokenApr = tokenApr * (1 + this.wstETHBaseApr); + } + return { + ...acc, + [id]: tokenApr, + }; + }, {}); + } catch (error) { + console.error(`Reaper IB APR handler failed for subgraph source: `, error); + Sentry.captureException(`Reaper IB APR handler failed for subgraph source: ${error}`); + return {}; + } } private async getWstEthBaseApr(): Promise { diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts index c4c8ef4f4..8ab8df9b5 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts @@ -4,6 +4,7 @@ import { abi } from './abis/tesseraPool'; import { AprHandler } from '../ib-linear-apr-handlers'; import { networkContext } from '../../../../../network/network-context.service'; import { TesseraAprConfig } from '../../../../../network/apr-config-types'; +import * as Sentry from '@sentry/node'; export class TesseraAprHandler implements AprHandler { tokens: { @@ -39,6 +40,7 @@ export class TesseraAprHandler implements AprHandler { return Object.fromEntries(aprEntries); } catch (error) { console.error('Failed to fetch Tessera APR:', error); + Sentry.captureException(`Tessera IB APR handler failed: ${error}`); return {}; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts index b695166fb..858e29dee 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts @@ -2,6 +2,7 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; import { TetuAprConfig } from '../../../../../network/apr-config-types'; +import * as Sentry from '@sentry/node'; export class TetuAprHandler implements AprHandler { sourceUrl: string; @@ -25,6 +26,7 @@ export class TetuAprHandler implements AprHandler { return Object.fromEntries(aprs); } catch (error) { console.error('Failed to fetch Tetu APR:', error); + Sentry.captureException(`Tetu IB APR handler failed: ${error}`); return {}; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts index 7f064d7fd..ec375ab1d 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts @@ -2,6 +2,7 @@ import axios from 'axios'; import { AprHandler } from '../ib-linear-apr-handlers'; import { TranchessAprConfig } from '../../../../../network/apr-config-types'; +import * as Sentry from '@sentry/node'; export class TranchessAprHandler implements AprHandler { url: string; @@ -32,6 +33,7 @@ export class TranchessAprHandler implements AprHandler { return Object.fromEntries(aprEntries); } catch (error) { console.error('Failed to fetch Tranchess APR:', error); + Sentry.captureException(`Tranchess IB APR handler failed: ${error}`); return {}; } } diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts index 31a45defa..08be9193e 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts @@ -2,6 +2,7 @@ import { AprHandler } from '../ib-linear-apr-handlers'; import axios from 'axios'; import { YearnVault } from '../../apr-types'; import { YearnAprConfig } from '../../../../../network/apr-config-types'; +import * as Sentry from '@sentry/node'; export class YearnAprHandler implements AprHandler { sourceUrl: string; @@ -11,12 +12,18 @@ export class YearnAprHandler implements AprHandler { this.sourceUrl = aprHandlerConfig.sourceUrl; } async getAprs(): Promise<{ [p: string]: number }> { - const { data } = await axios.get(this.sourceUrl); - const aprs = Object.fromEntries( - data.map(({ address, apy: { net_apy } }) => { - return [address.toLowerCase(), net_apy]; - }), - ); - return aprs; + try { + const { data } = await axios.get(this.sourceUrl); + const aprs = Object.fromEntries( + data.map(({ address, apy: { net_apy } }) => { + return [address.toLowerCase(), net_apy]; + }), + ); + return aprs; + } catch (error) { + console.error(`Yearn IB APR handler failed: `, error); + Sentry.captureException(`Yearn IB APR handler failed: ${error}`); + return {}; + } } } From c174806feb5da6966a981eb1168ba0d715b3fd81 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Abou Hatem De Liz Date: Mon, 4 Sep 2023 17:13:38 -0300 Subject: [PATCH 37/42] Changing the ib yield filter to network config; Fixing default apr handler error; testing on all networks; --- modules/network/apr-config-types.ts | 29 ++++++++-- modules/network/arbitrum.ts | 1 + modules/network/avalanche.ts | 1 + modules/network/base.ts | 1 + modules/network/fantom.ts | 4 +- modules/network/gnosis.ts | 1 + modules/network/mainnet.ts | 18 ++++-- modules/network/optimism.ts | 3 +- modules/network/polygon.ts | 13 +++-- modules/network/zkevm.ts | 1 + .../ib-linear-apr-handlers.ts | 23 ++++---- .../sources/aave-apr-handler.ts | 8 ++- .../sources/ankr-apr-handler.ts | 7 ++- .../sources/beefy-apr-handler.ts | 9 +-- .../sources/default-apr-handler.ts | 5 +- .../sources/euler-apr-handler.ts | 19 +++++-- .../sources/gearbox-apr-handler.ts | 16 +++++- .../sources/idle-apr-handler.ts | 5 +- .../sources/ovix-apr-handler.ts | 8 ++- .../sources/reaper-crypt-apr-handler.ts | 56 ++++++++----------- .../sources/tessera-apr-handler.ts | 7 ++- .../sources/tetu-apr-handler.ts | 20 ++++++- .../sources/tranchess-apr-handler.ts | 8 ++- .../sources/yearn-apr-handler.ts | 6 +- .../apr-data-sources/ib-tokens-apr.service.ts | 16 ++++-- 25 files changed, 187 insertions(+), 98 deletions(-) diff --git a/modules/network/apr-config-types.ts b/modules/network/apr-config-types.ts index 1eb0cda37..3b344bf80 100644 --- a/modules/network/apr-config-types.ts +++ b/modules/network/apr-config-types.ts @@ -25,6 +25,7 @@ export interface AaveAprConfig { wrappedTokens: { [wrappedTokenName: string]: string; }; + isIbYield?: boolean; }; }; }; @@ -36,6 +37,7 @@ export interface AnkrAprConfig { [underlyingAssetName: string]: { address: string; serviceName: string; + isIbYield?: boolean; }; }; } @@ -48,6 +50,7 @@ export interface BeefyAprConfig { // To get the vaultId, get the vault address from the token contract(token.vault()), // and search for the vault address in the link: https://api.beefy.finance/vaults vaultId: string; + isIbYield?: boolean; }; }; } @@ -55,14 +58,20 @@ export interface BeefyAprConfig { export interface EulerAprConfig { subgraphUrl: string; tokens: { - [tokenName: string]: string; + [tokenName: string]: { + address: string; + isIbYield?: boolean; + }; }; } export interface GearBoxAprConfig { sourceUrl: string; tokens: { - [tokenName: string]: string; + [tokenName: string]: { + address: string; + isIbYield?: boolean; + }; }; } @@ -73,6 +82,7 @@ export interface IdleAprConfig { [tokenName: string]: { address: string; wrapped4626Address: string; + isIbYield?: boolean; }; }; } @@ -82,6 +92,7 @@ export interface OvixAprConfig { [tokenName: string]: { yieldAddress: string; wrappedAddress: string; + isIbYield?: boolean; }; }; } @@ -94,6 +105,7 @@ export interface ReaperAprConfig { address: string; isSftmX?: boolean; isWstETH?: boolean; + isIbYield?: boolean; }; }; }; @@ -104,6 +116,7 @@ export interface ReaperAprConfig { address: string; isSftmX?: boolean; isWstETH?: boolean; + isIbYield?: boolean; }; }; }; @@ -114,6 +127,7 @@ export interface TesseraAprConfig { [tokenName: string]: { tesseraPoolAddress: string; tokenAddress: string; + isIbYield?: boolean; }; }; } @@ -121,7 +135,10 @@ export interface TesseraAprConfig { export interface TetuAprConfig { sourceUrl: string; tokens: { - [tokenName: string]: string; + [tokenName: string]: { + address: string; + isIbYield?: boolean; + }; }; } @@ -131,12 +148,14 @@ export interface TranchessAprConfig { [tokenName: string]: { address: string; underlyingAssetName: string; + isIbYield?: boolean; }; }; } export interface YearnAprConfig { sourceUrl: string; + isIbYield?: boolean; } export interface DefaultHandlerAprConfig { @@ -146,13 +165,15 @@ export interface DefaultHandlerAprConfig { path?: string; scale?: number; group?: string; + isIbYield?: boolean; }; } export interface FixedAprConfig { [tokenName: string]: { address: string; - value: number; + apr: number; group?: string; + isIbYield?: boolean; }; } diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 2d7dd2b7b..4505eb26c 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -149,6 +149,7 @@ const arbitrumNetworkData: NetworkData = { tokenAddress: '0x5979d7b546e38e414f7e9822514be443a4800529', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', + isIbYield: true, }, }, }, diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index ee759b8ad..8bedd5714 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -152,6 +152,7 @@ const avalancheNetworkData: NetworkData = { ankrAVAX: { address: '0xc3344870d52688874b06d844e0c36cc39fc727f6', serviceName: 'avax', + isIbYield: true, }, }, }, diff --git a/modules/network/base.ts b/modules/network/base.ts index e21118367..cf5304fff 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -82,6 +82,7 @@ const baseNetworkData: NetworkData = { sourceUrl: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', path: 'apy', scale: 1, + isIbYield: true, }, }, }, diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index 1bbd63e8a..04c692cb9 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -175,10 +175,12 @@ const fantomNetworkData: NetworkData = { ankrETH: { address: '0x12d8ce035c5de3ce39b1fdd4c1d5a745eaba3b8c', serviceName: 'eth', + isIbYield: true, }, ankrFTM: { address: '0xcfc785741dc0e98ad4c9f6394bb9d43cd1ef5179', serviceName: 'ftm', + isIbYield: true, }, }, }, @@ -245,7 +247,7 @@ const fantomNetworkData: NetworkData = { fixedAprHandler: { sFTMx: { address: '0xd7028092c830b5c8fce061af2e593413ebbc1fc1', - value: 0.046, + apr: 0.046, }, }, }, diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index 52f0726ec..a0e4c7d05 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -100,6 +100,7 @@ const gnosisNetworkData: NetworkData = { tokenAddress: '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', + isIbYield: true, }, }, }, diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 92081b0f0..f027521b5 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -189,17 +189,17 @@ export const mainnetNetworkData: NetworkData = { euler: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/euler-xyz/euler-mainnet', tokens: { - eUSDC: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716', - eDAI: '0xe025e3ca2be02316033184551d4d3aa22024d9dc', - eUSDT: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2', - eFRAX: '0x5484451a88a35cd0878a1be177435ca8a0e4054e', + eUSDC: { address: '0xeb91861f8a4e1c12333f42dce8fb0ecdc28da716' }, + eDAI: { address: '0xe025e3ca2be02316033184551d4d3aa22024d9dc' }, + eUSDT: { address: '0x4d19f33948b99800b6113ff3e83bec9b537c85d2' }, + eFRAX: { address: '0x5484451a88a35cd0878a1be177435ca8a0e4054e' }, }, }, gearbox: { sourceUrl: 'https://mainnet.gearbox.foundation/api/pools', tokens: { - dDAI: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba', - dUSDC: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3', + dDAI: { address: '0x6cfaf95457d7688022fc53e7abe052ef8dfbbdba' }, + dUSDC: { address: '0xc411db5f5eb3f7d552f9b8454b2d74097ccde6e3' }, }, }, idle: { @@ -248,17 +248,20 @@ export const mainnetNetworkData: NetworkData = { tokenAddress: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', + isIbYield: true, }, wstETH: { tokenAddress: '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', + isIbYield: true, }, cbETH: { tokenAddress: '0xbe9895146f7af43049ca1c1ae358b0541ea49704', sourceUrl: 'https://api.exchange.coinbase.com/wrapped-assets/CBETH/', path: 'apy', scale: 1, + isIbYield: true, }, sfrxETH: { tokenAddress: '0xac3e018457b222d93114458476f3e3416abbe38f', @@ -269,15 +272,18 @@ export const mainnetNetworkData: NetworkData = { tokenAddress: '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593', sourceUrl: 'https://drop-api.stafi.io/reth/v1/poolData', path: 'data.stakeApr', + isIbYield: true, }, USDR: { tokenAddress: '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b', sourceUrl: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', path: 'usdr', + isIbYield: true, }, swETH: { tokenAddress: '0xf951e335afb289353dc249e82926178eac7ded78', sourceUrl: 'https://v3.svc.swellnetwork.io/api/tokens/sweth/apr', + isIbYield: true, }, wjAURA: { tokenAddress: '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f', diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 40e05bd65..824b35919 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -16,7 +16,6 @@ import { SanityContentService } from '../content/sanity-content.service'; import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { coingeckoService } from '../coingecko/coingecko.service'; import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/coingecko-price-handler.service'; -import { BeefyVaultAprService } from '../pool/lib/apr-data-sources/beefy-vault-apr.service copy'; import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; import { env } from '../../app/env'; @@ -186,11 +185,13 @@ const optimismNetworkData: NetworkData = { tokenAddress: '0x1f32b1c2345538c0c6f582fcb022739c4a194ebb', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', + isIbYield: true, }, rETH: { tokenAddress: '0x9bcef72be871e61ed4fbbc7630889bee758eb81d', sourceUrl: 'https://drop-api.stafi.io/reth/v1/poolData', path: 'data.stakeApr', + isIbYield: true, }, overnightDAIPlus: { tokenAddress: '0x0b8f31480249cc717081928b8af733f45f6915bb', diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index 04064d192..f8300a160 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -6,7 +6,6 @@ import { BoostedPoolAprService } from '../pool/lib/apr-data-sources/boosted-pool import { SwapFeeAprService } from '../pool/lib/apr-data-sources/swap-fee-apr.service'; import { GaugeAprService } from '../pool/lib/apr-data-sources/ve-bal-gauge-apr.service'; import { GaugeStakingService } from '../pool/lib/staking/gauge-staking.service'; -import { BeetsPriceHandlerService } from '../token/lib/token-price-handlers/beets-price-handler.service'; import { BptPriceHandlerService } from '../token/lib/token-price-handlers/bpt-price-handler.service'; import { LinearWrappedTokenPriceHandlerService } from '../token/lib/token-price-handlers/linear-wrapped-token-price-handler.service'; import { SwapsPriceHandlerService } from '../token/lib/token-price-handlers/swaps-price-handler.service'; @@ -181,10 +180,10 @@ const polygonNetworkData: NetworkData = { tetu: { sourceUrl: 'https://api.tetu.io/api/v1/reader/compoundAPRs?network=MATIC', tokens: { - tUSDC: '0x113f3d54c31ebc71510fd664c8303b34fbc2b355', - tUSDT: '0x236975da9f0761e9cf3c2b0f705d705e22829886', - tDAI: '0xace2ac58e1e5a7bfe274916c4d82914d490ed4a5', - tetuStQI: '0x4cd44ced63d9a6fef595f6ad3f7ced13fceac768', + tUSDC: { address: '0x113f3d54c31ebc71510fd664c8303b34fbc2b355' }, + tUSDT: { address: '0x236975da9f0761e9cf3c2b0f705d705e22829886' }, + tDAI: { address: '0xace2ac58e1e5a7bfe274916c4d82914d490ed4a5' }, + tetuStQI: { address: '0x4cd44ced63d9a6fef595f6ad3f7ced13fceac768' }, }, }, defaultHandlers: { @@ -192,22 +191,26 @@ const polygonNetworkData: NetworkData = { tokenAddress: '0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', + isIbYield: true, }, stMATIC: { tokenAddress: '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4', sourceUrl: 'https://polygon.lido.fi/api/stats', path: 'apr', + isIbYield: true, }, MATICX: { tokenAddress: '0xfa68fb4628dff1028cfec22b4162fccd0d45efb6', sourceUrl: 'https://universe.staderlabs.com/polygon/apy', path: 'value', + isIbYield: true, }, wbETH: { tokenAddress: '0xa2e3356610840701bdf5611a53974510ae27e2e1', sourceUrl: 'https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/rewardRateList?projectId=BETH', path: 'data.0.rewardRate', + isIbYield: true, }, }, }, diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index 0af16504b..cb393d347 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -116,6 +116,7 @@ const zkevmNetworkData: NetworkData = { tokenAddress: '0x5d8cff95d7a57c0bf50b30b43c7cc0d52825d4a9', sourceUrl: 'https://eth-api.lido.fi/v1/protocol/steth/apr/sma', path: 'data.smaApr', + isIbYield: true, }, }, }, diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts index 73f7d6ddc..0bf9305eb 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts @@ -15,14 +15,10 @@ import { IbAprConfig } from '../../../../network/apr-config-types'; export class IbLinearAprHandlers { private handlers: AprHandler[] = []; - //List of addresses of any IB Yield tokens (such as reth, wsteth), used to check what is LINEAR_BOOSTED APR and what is IB_YIELD APR - ibYieledTokens: string[] = []; - - fixedAprTokens?: { [tokenName: string]: { address: string; value: number; group?: string } }; + fixedAprTokens?: { [tokenName: string]: { address: string; apr: number; group?: string; isIbYield?: boolean } }; constructor(aprConfig: IbAprConfig) { this.handlers = this.buildAprHandlers(aprConfig); - this.ibYieledTokens = this.buildIbYieldTokens(aprConfig); this.fixedAprTokens = aprConfig.fixedAprHandler; } @@ -125,19 +121,21 @@ export class IbLinearAprHandlers { async fetchAprsFromAllHandlers(): Promise { let aprs: TokenApr[] = []; for (const handler of this.handlers) { - const fetchedResponse: { [key: string]: number } = await handler.getAprs(); - for (const [address, aprValue] of Object.entries(fetchedResponse)) { + const fetchedResponse: { [key: string]: { apr: number; isIbYield: boolean } } = await handler.getAprs(); + for (const [address, { apr, isIbYield }] of Object.entries(fetchedResponse)) { aprs.push({ - val: aprValue, + apr, + isIbYield, group: handler.group, address, }); } } if (this.fixedAprTokens) { - for (const { address, value, group } of Object.values(this.fixedAprTokens)) { + for (const { address, apr, isIbYield, group } of Object.values(this.fixedAprTokens)) { aprs.push({ - val: value, + apr, + isIbYield: isIbYield ?? false, group, address, }); @@ -149,11 +147,12 @@ export class IbLinearAprHandlers { export interface AprHandler { group: string | undefined; - getAprs(): Promise<{ [tokenAddress: string]: number }>; + getAprs(): Promise<{ [tokenAddress: string]: { apr: number; isIbYield: boolean } }>; } export type TokenApr = { - val: number; + apr: number; address: string; group?: string; + isIbYield: boolean; }; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts index ffb0f7d06..f2b72156b 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts @@ -10,6 +10,7 @@ export class AaveAprHandler implements AprHandler { wrappedTokens: { [tokenName: string]: string; }; + isIbYield?: boolean; }; }; subgraphUrl: string; @@ -39,6 +40,7 @@ export class AaveAprHandler implements AprHandler { wrappedTokens: { [wrappedTokenName: string]: string; }; + isIbYield?: boolean; }; }; }) { @@ -76,9 +78,11 @@ export class AaveAprHandler implements AprHandler { ]), ); const aprEntries = Object.values(this.tokens) - .map(({ wrappedTokens, underlyingAssetAddress }) => { + .map(({ wrappedTokens, underlyingAssetAddress, isIbYield }) => { const apr = aprsByUnderlyingAddress[underlyingAssetAddress]; - return Object.values(wrappedTokens).map((wrappedTokenAddress) => ({ [wrappedTokenAddress]: apr })); + return Object.values(wrappedTokens).map((wrappedTokenAddress) => ({ + [wrappedTokenAddress]: { apr, isIbYield: isIbYield ?? false }, + })); }) .flat() .reduce((acc, curr) => ({ ...acc, ...curr }), {}); diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts index 9b5710336..2f89875ed 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts @@ -8,6 +8,7 @@ export class AnkrAprHandler implements AprHandler { [underlyingAssetName: string]: { address: string; serviceName: string; + isIbYield?: boolean; }; }; url: string; @@ -18,17 +19,17 @@ export class AnkrAprHandler implements AprHandler { this.url = aprHandlerConfig.sourceUrl; } - async getAprs() { + async getAprs(): Promise<{ [tokenAddress: string]: { apr: number; isIbYield: boolean } }> { try { const { data } = await axios.get(this.url); const services = (data as { services: { serviceName: string; apy: string }[] }).services; const aprs = Object.fromEntries( - Object.values(this.tokens).map(({ address, serviceName }) => { + Object.values(this.tokens).map(({ address, serviceName, isIbYield }) => { const service = services.find((service) => service.serviceName === serviceName); if (!service) { return [address, 0]; } - return [address, parseFloat(service.apy) / 1e2]; + return [address, { apr: parseFloat(service.apy) / 1e2, isIbYield: isIbYield ?? false }]; }), ); return aprs; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts index 7dd0d48fa..1a6e50fef 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts @@ -8,6 +8,7 @@ export class BeefyAprHandler implements AprHandler { [tokenName: string]: { address: string; vaultId: string; + isIbYield?: boolean; }; }; sourceUrl: string; @@ -18,12 +19,12 @@ export class BeefyAprHandler implements AprHandler { this.sourceUrl = aprConfig.sourceUrl; } - async getAprs(): Promise<{ [p: string]: number }> { + async getAprs(): Promise<{ [p: string]: { apr: number; isIbYield: boolean } }> { try { const { data: aprData } = await axios.get(this.sourceUrl); - const aprs: { [tokenAddress: string]: number } = {}; - for (const { address, vaultId } of Object.values(this.tokens)) { - aprs[address] = aprData[vaultId].vaultApr; + const aprs: { [tokenAddress: string]: { apr: number; isIbYield: boolean } } = {}; + for (const { address, vaultId, isIbYield } of Object.values(this.tokens)) { + aprs[address] = { apr: aprData[vaultId].vaultApr, isIbYield: isIbYield ?? false }; } return aprs; } catch (error) { diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts index 3594eafb9..e48dc0b4e 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts @@ -9,6 +9,7 @@ export class DefaultAprHandler implements AprHandler { path: string; scale: number; group: string | undefined = undefined; + isIbYield: boolean | undefined; constructor(aprHandlerConfig: { sourceUrl: string; @@ -16,12 +17,14 @@ export class DefaultAprHandler implements AprHandler { path?: string; scale?: number; group?: string; + isIbYield?: boolean; }) { this.tokenAddress = aprHandlerConfig.tokenAddress; this.url = aprHandlerConfig.sourceUrl; this.path = aprHandlerConfig.path ?? ''; this.scale = aprHandlerConfig.scale ?? 100; this.group = aprHandlerConfig.group; + this.isIbYield = aprHandlerConfig.isIbYield; } async getAprs() { @@ -30,7 +33,7 @@ export class DefaultAprHandler implements AprHandler { const value = this.path === '' ? data : this.getValueFromPath(data, this.path); const scaledValue = parseFloat(value) / this.scale; - return [this.tokenAddress, scaledValue]; + return { [this.tokenAddress]: { apr: scaledValue, isIbYield: this.isIbYield ?? false } }; } catch (error) { console.error(`Failed to fetch APRs in url ${this.url}:`, error); Sentry.captureException(`Failed to fetch default IB APRs in url ${this.url}: ${error}`); diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts index cb1c08aae..f6edc5479 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts @@ -4,7 +4,12 @@ import { EulerAprConfig } from '../../../../../network/apr-config-types'; import * as Sentry from '@sentry/node'; export class EulerAprHandler implements AprHandler { - tokens: { [key: string]: string }; + tokens: { + [key: string]: { + address: string; + isIbYield?: boolean; + }; + }; subgraphUrl: string; readonly group = 'EULER'; @@ -32,7 +37,7 @@ export class EulerAprHandler implements AprHandler { operationName: 'getAssetsAPY', query: this.query, variables: { - eTokenAddress_in: Object.values(this.tokens), + eTokenAddress_in: Object.values(this.tokens).map(({ address }) => address), }, }; @@ -47,9 +52,15 @@ export class EulerAprHandler implements AprHandler { } = data as EulerResponse; const aprEntries = assets.map(({ eTokenAddress, supplyAPY }) => [ - eTokenAddress, + eTokenAddress.toLowerCase(), // supplyAPY is 1e27 and apr is in bps (1e4), so all we need is to format to 1e23 - Number(supplyAPY.slice(0, 27)) / 1e27, + { + apr: Number(supplyAPY.slice(0, 27)) / 1e27, + isIbYield: + Object.values(this.tokens).find( + ({ address }) => address.toLowerCase() === eTokenAddress.toLowerCase(), + )?.isIbYield ?? false, + }, ]); return Object.fromEntries(aprEntries); diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts index 953f41354..96e77624d 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts @@ -6,7 +6,7 @@ import { GearBoxAprConfig } from '../../../../../network/apr-config-types'; export class GearboxAprHandler implements AprHandler { url: string; - tokens: { [key: string]: string }; + tokens: { [key: string]: { address: string; isIbYield?: boolean } }; readonly group = 'GEARBOX'; constructor(aprHandlerConfig: GearBoxAprConfig) { @@ -20,9 +20,19 @@ export class GearboxAprHandler implements AprHandler { const json = data as { data: { dieselToken: string; depositAPY_RAY: string }[] }; const aprEntries = json.data - .filter((t) => Object.values(this.tokens).includes(t.dieselToken.toLowerCase())) + .filter((t) => + Object.values(this.tokens) + .map(({ address }) => address) + .includes(t.dieselToken.toLowerCase()), + ) .map(({ dieselToken, depositAPY_RAY }) => { - return [dieselToken, Number(depositAPY_RAY.slice(0, 27)) / 1e27]; + const tokenObj = Object.values(this.tokens).find( + ({ address }) => address === dieselToken.toLowerCase(), + ); + return [ + dieselToken, + { apr: Number(depositAPY_RAY.slice(0, 27)) / 1e27, isIbYield: tokenObj?.isIbYield ?? false }, + ]; }); return Object.fromEntries(aprEntries); } catch (error) { diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts index 996167152..3782bf6e4 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts @@ -9,6 +9,7 @@ export class IdleAprHandler implements AprHandler { [tokenName: string]: { address: string; wrapped4626Address: string; + isIbYield?: boolean; }; }; url: string; @@ -23,7 +24,7 @@ export class IdleAprHandler implements AprHandler { async getAprs() { try { - const aprPromises = Object.values(this.tokens).map(async ({ address, wrapped4626Address }) => { + const aprPromises = Object.values(this.tokens).map(async ({ address, wrapped4626Address, isIbYield }) => { const { data } = await axios.get([this.url, address, '?isRisk=false&order=desc&limit=1'].join(''), { headers: { Authorization: this.authorizationHeader, @@ -31,7 +32,7 @@ export class IdleAprHandler implements AprHandler { }); const [json] = data as { idleRate: string }[]; const value = Number(json.idleRate) / 1e20; - return [wrapped4626Address, value]; + return [wrapped4626Address, { apr: value, isIbYield: isIbYield ?? false }]; }); const res = Array(Object.keys(this.tokens).length); for (const [index, aprPromise] of aprPromises.entries()) { diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts index eea6df113..3f3d0a7e1 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts @@ -11,6 +11,7 @@ export class OvixAprHandler implements AprHandler { [tokenName: string]: { yieldAddress: string; wrappedAddress: string; + isIbYield?: boolean; }; }; readonly group = 'OVIX'; @@ -21,12 +22,15 @@ export class OvixAprHandler implements AprHandler { async getAprs() { try { - const aprEntries = Object.values(this.tokens).map(async ({ yieldAddress, wrappedAddress }) => { + const aprEntries = Object.values(this.tokens).map(async ({ yieldAddress, wrappedAddress, isIbYield }) => { const contract = new Contract(yieldAddress, abi, networkContext.provider); const borrowRate = await contract.borrowRatePerTimestamp(); return [ wrappedAddress, - Math.pow(1 + (borrowRate as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1, + { + apr: Math.pow(1 + (borrowRate as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1, + isIbYield: isIbYield ?? false, + }, ]; }); diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts index 4d9b6311a..a9d0196d7 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts @@ -10,8 +10,22 @@ const APR_PERCENT_DIVISOR = 10_000; const sFTMxBaseApr = 0.046; export class ReaperCryptAprHandler implements AprHandler { - tokensWithSubgraphSource?: { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean } }; - tokensWithOnChainSource?: { [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean } }; + tokensWithSubgraphSource?: { + [tokenName: string]: { + address: string; + isSftmX?: boolean; + isWstETH?: boolean; + isIbYield?: boolean; + }; + }; + tokensWithOnChainSource?: { + [tokenName: string]: { + address: string; + isSftmX?: boolean; + isWstETH?: boolean; + isIbYield?: boolean; + }; + }; subgraphUrl?: string; averageAPRAcrossLastNHarvests?: number; wstETHBaseApr: number = 0; @@ -31,7 +45,7 @@ export class ReaperCryptAprHandler implements AprHandler { this.averageAPRAcrossLastNHarvests = aprConfig.onchainSource?.averageAPRAcrossLastNHarvests; } - async getAprs(): Promise<{ [p: string]: number }> { + async getAprs(): Promise<{ [p: string]: { apr: number; isIbYield: boolean } }> { let multiStrategyAprs = {}; let singleStrategyAprs = {}; this.wstETHBaseApr = await this.getWstEthBaseApr(); @@ -45,10 +59,10 @@ export class ReaperCryptAprHandler implements AprHandler { } private async getOnChainCryptApr(tokens: { - [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean }; - }): Promise<{ [tokenAddress: string]: number }> { - const aprs: { [tokenAddress: string]: number } = {}; - for (const { address, isSftmX, isWstETH } of Object.values(tokens)) { + [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean; isIbYield?: boolean }; + }): Promise<{ [tokenAddress: string]: { apr: number; isIbYield: boolean } }> { + const aprs: { [tokenAddress: string]: { apr: number; isIbYield: boolean } } = {}; + for (const { address, isSftmX, isWstETH, isIbYield } of Object.values(tokens)) { try { const tokenContract = getContractAt(address, ReaperCryptAbi); const strategyAddress = await tokenContract.strategy(); @@ -65,7 +79,7 @@ export class ReaperCryptAprHandler implements AprHandler { if (isWstETH) { avgAprAcrossXHarvests = avgAprAcrossXHarvests * (1 + this.wstETHBaseApr); } - aprs[address] = avgAprAcrossXHarvests; + aprs[address] = { apr: avgAprAcrossXHarvests, isIbYield: isIbYield ?? false }; } catch (error) { console.error(`Reaper IB APR handler failed for onChain source: `, error); Sentry.captureException(`Reaper IB APR handler failed for onChain source: ${error}`); @@ -77,7 +91,7 @@ export class ReaperCryptAprHandler implements AprHandler { } private async getAprFromSubgraph(tokens: { - [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean }; + [tokenName: string]: { address: string; isSftmX?: boolean; isWstETH?: boolean; isIbYield?: boolean }; }): Promise<{ [tokenAddress: string]: number }> { try { const requestQuery = { @@ -108,7 +122,7 @@ export class ReaperCryptAprHandler implements AprHandler { } return { ...acc, - [id]: tokenApr, + [id]: { apr: tokenApr, isIbYield: token.isIbYield ?? false }, }; }, {}); } catch (error) { @@ -131,25 +145,3 @@ type MultiStratResponse = { apr: string; }[]; }; -interface ReaperCryptAprHandlerConfig { - multiStrategy?: { - subgraphUrl: string; - tokens: { - [tokenName: string]: { - address: string; - isSftmX?: boolean; - isWstETH?: boolean; - }; - }; - }; - singleStrategy?: { - averageAPRAcrossLastNHarvests: number; - tokens: { - [tokenName: string]: { - address: string; - isSftmX?: boolean; - isWstETH?: boolean; - }; - }; - }; -} diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts index 8ab8df9b5..644e3662a 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts @@ -11,6 +11,7 @@ export class TesseraAprHandler implements AprHandler { [tokenName: string]: { tesseraPoolAddress: string; tokenAddress: string; + isIbYield?: boolean; }; }; readonly group = 'TESSERA'; @@ -22,7 +23,7 @@ export class TesseraAprHandler implements AprHandler { async getAprs() { try { let aprEntries = []; - for (const { tesseraPoolAddress, tokenAddress } of Object.values(this.tokens)) { + for (const { tesseraPoolAddress, tokenAddress, isIbYield } of Object.values(this.tokens)) { try { const contract = new Contract(tesseraPoolAddress, abi, networkContext.provider); const poolsUI = await contract.getPoolsUI(); @@ -31,10 +32,10 @@ export class TesseraAprHandler implements AprHandler { const staked = BigInt(pool.stakedAmount); const reward = BigInt(pool.currentTimeRange.rewardsPerHour) * BigInt(24 * 365); const apr = Number(reward.toString()) / Number(staked.toString()); - aprEntries.push([tokenAddress, apr]); + aprEntries.push([tokenAddress, { apr, isIbYield: isIbYield ?? false }]); } catch (error) { console.error('Failed to fetch Tessera Ape Coin APR:', error); - aprEntries.push([tokenAddress, 0]); + aprEntries.push([tokenAddress, { apr: 0, isIbYield: isIbYield ?? false }]); } } return Object.fromEntries(aprEntries); diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts index 858e29dee..2db4746f9 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts @@ -7,7 +7,10 @@ import * as Sentry from '@sentry/node'; export class TetuAprHandler implements AprHandler { sourceUrl: string; tokens: { - [tokenName: string]: string; + [tokenName: string]: { + address: string; + isIbYield?: boolean; + }; }; readonly group = 'TETU'; @@ -21,8 +24,19 @@ export class TetuAprHandler implements AprHandler { const { data } = await axios.get(this.sourceUrl); const json = data as { vault: string; apr: number }[]; const aprs = json - .filter(({ vault }) => Object.values(this.tokens).includes(vault.toLowerCase())) - .map((t) => [t.vault, t.apr / 100]); + .filter(({ vault }) => + Object.values(this.tokens) + .map(({ address }) => address) + .includes(vault.toLowerCase()), + ) + .map((t) => [ + t.vault, + { + apr: t.apr / 100, + isIbYield: + Object.values(this.tokens).find(({ address }) => address === t.vault)?.isIbYield ?? false, + }, + ]); return Object.fromEntries(aprs); } catch (error) { console.error('Failed to fetch Tetu APR:', error); diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts index ec375ab1d..37bea641d 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts @@ -10,6 +10,7 @@ export class TranchessAprHandler implements AprHandler { [tokenName: string]: { address: string; underlyingAssetName: string; + isIbYield?: boolean; }; }; readonly group = 'TRANCHESS'; @@ -23,11 +24,14 @@ export class TranchessAprHandler implements AprHandler { try { const { data } = await axios.get('https://tranchess.com/eth/api/v3/funds'); // const [{ weeklyAveragePnlPercentage }] = data as { weeklyAveragePnlPercentage: string }[]; - const aprEntries = Object.values(this.tokens).map(({ address, underlyingAssetName }) => { + const aprEntries = Object.values(this.tokens).map(({ address, underlyingAssetName, isIbYield }) => { const weeklyAveragePnlPercentage = ( data as { weeklyAveragePnlPercentage: string; name: string }[] ).filter(({ name }) => name === underlyingAssetName)[0].weeklyAveragePnlPercentage; - return [address, (365 * Number(weeklyAveragePnlPercentage)) / 1e18]; + return [ + address, + { apr: (365 * Number(weeklyAveragePnlPercentage)) / 1e18, isIbYield: isIbYield ?? false }, + ]; }); // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. return Object.fromEntries(aprEntries); diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts index 08be9193e..4eda3232a 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts @@ -6,17 +6,19 @@ import * as Sentry from '@sentry/node'; export class YearnAprHandler implements AprHandler { sourceUrl: string; + isIbYield?: boolean; group: string = 'YEARN'; constructor(aprHandlerConfig: YearnAprConfig) { this.sourceUrl = aprHandlerConfig.sourceUrl; + this.isIbYield = aprHandlerConfig.isIbYield; } - async getAprs(): Promise<{ [p: string]: number }> { + async getAprs(): Promise<{ [p: string]: { apr: number; isIbYield: boolean } }> { try { const { data } = await axios.get(this.sourceUrl); const aprs = Object.fromEntries( data.map(({ address, apy: { net_apy } }) => { - return [address.toLowerCase(), net_apy]; + return [address.toLowerCase(), { apr: net_apy, isIbYield: this.isIbYield ?? false }]; }), ); return aprs; diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index f1b614530..e76664a36 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -58,7 +58,7 @@ export class IbTokensAprService implements PoolAprService { continue; } - let aprInPoolAfterFees = tokenApr.val * tokenPercentageInPool; + let aprInPoolAfterFees = tokenApr.apr * tokenPercentageInPool; if (collectsYieldFee(pool)) { const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee @@ -70,10 +70,8 @@ export class IbTokensAprService implements PoolAprService { : aprInPoolAfterFees * (1 - protocolYieldFeePercentage); } - // yieldType is IB_YIELD if its in the ibYieledTokens list - const yieldType: PrismaPoolAprType = this.ibTokensAprHandlers.ibYieledTokens.includes(token.address) - ? 'IB_YIELD' - : 'LINEAR_BOOSTED'; + const yieldType: PrismaPoolAprType = + tokenApr.isIbYield || pool.type !== 'LINEAR' ? 'IB_YIELD' : 'LINEAR_BOOSTED'; const itemId = `${pool.id}-${token.token.symbol}-yield-apr`; @@ -101,6 +99,12 @@ export class IbTokensAprService implements PoolAprService { private async fetchYieldTokensApr(): Promise> { const data = await this.ibTokensAprHandlers.fetchAprsFromAllHandlers(); - return new Map(data.filter((apr) => !isNaN(apr.val)).map((apr) => [apr.address, apr])); + return new Map( + data + .filter((tokenApr) => { + return !isNaN(tokenApr.apr); + }) + .map((apr) => [apr.address, apr]), + ); } } From b00f57ddb21e949ebe48d1a817192938a6179de8 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 5 Sep 2023 10:56:13 +0200 Subject: [PATCH 38/42] ibyield flag --- modules/network/fantom.ts | 1 + modules/network/mainnet.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index 04c692cb9..c8142e65b 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -248,6 +248,7 @@ const fantomNetworkData: NetworkData = { sFTMx: { address: '0xd7028092c830b5c8fce061af2e593413ebbc1fc1', apr: 0.046, + isIbYield: true, }, }, }, diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index f027521b5..db21b5ef5 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -183,6 +183,7 @@ export const mainnetNetworkData: NetworkData = { ankrETH: { address: '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb', serviceName: 'eth', + isIbYield: true, }, }, }, @@ -267,6 +268,7 @@ export const mainnetNetworkData: NetworkData = { tokenAddress: '0xac3e018457b222d93114458476f3e3416abbe38f', sourceUrl: 'https://api.frax.finance/v2/frxeth/summary/latest', path: 'sfrxethApr', + isIbYield: true, }, rETH: { tokenAddress: '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593', @@ -289,6 +291,7 @@ export const mainnetNetworkData: NetworkData = { tokenAddress: '0x198d7387fa97a73f05b8578cdeff8f2a1f34cd1f', sourceUrl: 'https://data.jonesdao.io/api/v1/jones/apy-wjaura', path: 'wjauraApy', + isIbYield: true, }, }, }, From 21cd9ae85e1d083dfe9ea2a248b49bc938002ef5 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 5 Sep 2023 13:33:41 +0200 Subject: [PATCH 39/42] cleanup --- .../pool/lib/apr-data-sources/apr-types.ts | 73 ----------- .../beefy-vault-apr.service copy.ts | 115 ------------------ .../sources/yearn-apr-handler.ts | 12 +- .../reaper-crypt-apr.service.ts | 0 4 files changed, 11 insertions(+), 189 deletions(-) delete mode 100644 modules/pool/lib/apr-data-sources/apr-types.ts delete mode 100644 modules/pool/lib/apr-data-sources/beefy-vault-apr.service copy.ts delete mode 100644 modules/pool/lib/apr-data-sources/reaper-crypt-apr.service.ts diff --git a/modules/pool/lib/apr-data-sources/apr-types.ts b/modules/pool/lib/apr-data-sources/apr-types.ts deleted file mode 100644 index 7c5b8ba31..000000000 --- a/modules/pool/lib/apr-data-sources/apr-types.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Dictionary } from 'lodash' - -export interface YearnVault { - inception: number; - address: string; - symbol: string; - name: string; - display_name: string; - icon: string; - token: YearnVaultToken; - tvl: YearnVaultTvl; - apy: YearnVaultApy; - strategies: YearnStrategy[]; - endorsed: boolean; - version: string; - decimals: number; - type: YearnVaultType; - emergency_shutdown: boolean; - updated: number; - migration: YearnVaultMigration; -} - -interface YearnVaultApy { - type: YearnVaultApyType; - gross_apr: number; - net_apy: number; - fees: YearnFees; - points: YearnPoints; - composite: null; -} - -interface YearnFees { - performance: number; - withdrawal: number | null; - management: number | null; - keep_crv: null; - cvx_keep_crv: null; -} - -interface YearnPoints { - week_ago: number; - month_ago: number; - inception: number; -} - -type YearnVaultApyType = 'error' | 'v2:averaged'; - -interface YearnVaultMigration { - available: boolean; - address: string; -} - -interface YearnStrategy { - address: string; - name: string; -} - -interface YearnVaultToken { - name: string; - symbol: string; - address: string; - decimals: number; - display_name: string; - icon: string; -} - -interface YearnVaultTvl { - total_assets: number; - price: number | null; - tvl: number | null; -} - -type YearnVaultType = 'v2'; diff --git a/modules/pool/lib/apr-data-sources/beefy-vault-apr.service copy.ts b/modules/pool/lib/apr-data-sources/beefy-vault-apr.service copy.ts deleted file mode 100644 index a9aacf123..000000000 --- a/modules/pool/lib/apr-data-sources/beefy-vault-apr.service copy.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { isSameAddress } from '@balancer-labs/sdk'; -import * as Sentry from '@sentry/node'; -import { prisma } from '../../../../prisma/prisma-client'; -import { PrismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; -import { TokenService } from '../../../token/token.service'; -import { getContractAt } from '../../../web3/contract'; -import { PoolAprService } from '../../pool-types'; -import BeefyWrapper from './abi/BeefyWrapper.json'; -import axios from 'axios'; -import moment from 'moment-timezone'; -import { networkContext } from '../../../network/network-context.service'; - -interface VaultInformation { - id: string; - name: string; - token: string; - tokenAddress: string; - tokenDecimals: number; - earnedToken: string; - earnedTokenAddress: string; - earnContractAddress: string; - oracle: string; - oracleId: string; - status: string; - platformId: string; - assets: string[]; - risks: string[]; - strategyTypeId: string; - buyTokenUrl: string; - network: string; - createdAt: number; - chain: string; - strategy: string; - lastHarvest: number; - pricePerFullShare: string; -} - -type VaultApr = Record< - string, - { - vaultApr: number; - compoundingsPerYear: number; - beefyPerformanceFee: number; - vaultApy: number; - lpFee: number; - tradingApr: number; - totalApy: number; - } ->; - -export class BeefyVaultAprService implements PoolAprService { - constructor(private readonly beefyLinearPools: string[], private readonly tokenService: TokenService) {} - - public getAprServiceName(): string { - return 'BeefyVaultAprService'; - } - - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const tokenPrices = await this.tokenService.getTokenPrices(); - - for (const pool of pools) { - if (!this.beefyLinearPools.includes(pool.id || '') || !pool.linearData || !pool.dynamicData) { - continue; - } - - const itemId = `${pool.id}-beefy-vault`; - - const linearData = pool.linearData; - const wrappedToken = pool.tokens[linearData.wrappedIndex]; - const mainToken = pool.tokens[linearData.mainIndex]; - - const beefyWrapper = getContractAt(wrappedToken.address, BeefyWrapper); - const beefyVaultAddress: string = await beefyWrapper.vault(); - - const beefyVaultBaseApr = await this.getBeefyVaultBaseApr(beefyVaultAddress); - - const tokenPrice = this.tokenService.getPriceForToken(tokenPrices, mainToken.address); - const wrappedTokens = parseFloat(wrappedToken.dynamicData?.balance || '0'); - const priceRate = parseFloat(wrappedToken.dynamicData?.priceRate || '1.0'); - const poolWrappedLiquidity = wrappedTokens * priceRate * tokenPrice; - const totalLiquidity = pool.dynamicData.totalLiquidity; - let apr = totalLiquidity > 0 ? beefyVaultBaseApr * (poolWrappedLiquidity / totalLiquidity) : 0; - - await prisma.prismaPoolAprItem.upsert({ - where: { id_chain: { id: itemId, chain: networkContext.chain } }, - create: { - id: itemId, - chain: networkContext.chain, - poolId: pool.id, - title: `${wrappedToken.token.symbol} APR`, - apr: apr, - group: 'BEEFY', - type: 'LINEAR_BOOSTED', - }, - update: { title: `${wrappedToken.token.symbol} APR`, apr: apr }, - }); - } - } - - private async getBeefyVaultBaseApr(beefyVaultAddress: string): Promise { - const vaultEndpoint = 'https://api.beefy.finance/vaults?_='; - const aprEndpoint = 'https://api.beefy.finance/apy/breakdown?_='; - - const now = moment().startOf('minute').unix(); - - const { data: vaultData } = await axios.get(vaultEndpoint + `${now}`); - const beefyVault = vaultData.find((vault) => isSameAddress(vault.earnContractAddress, beefyVaultAddress)); - - if (beefyVault?.id) { - const { data: aprData } = await axios.get(aprEndpoint + `${now}`); - return aprData[beefyVault.id].vaultApr; - } - return 0; - } -} diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts index 4eda3232a..1451b2f3d 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts @@ -1,6 +1,5 @@ import { AprHandler } from '../ib-linear-apr-handlers'; import axios from 'axios'; -import { YearnVault } from '../../apr-types'; import { YearnAprConfig } from '../../../../../network/apr-config-types'; import * as Sentry from '@sentry/node'; @@ -29,3 +28,14 @@ export class YearnAprHandler implements AprHandler { } } } + +import { Dictionary } from 'lodash'; + +interface YearnVault { + address: string; + apy: YearnVaultApy; +} + +interface YearnVaultApy { + net_apy: number; +} diff --git a/modules/pool/lib/apr-data-sources/reaper-crypt-apr.service.ts b/modules/pool/lib/apr-data-sources/reaper-crypt-apr.service.ts deleted file mode 100644 index e69de29bb..000000000 From 1261ec6c158f3f88dba5d44a9316b50a109befec Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 5 Sep 2023 13:34:00 +0200 Subject: [PATCH 40/42] dont use nested query for apr --- .../boosted-pool-apr.service.ts | 43 +++++++++++++++---- .../apr-data-sources/ib-tokens-apr.service.ts | 21 +++++++-- .../phantom-stable-apr.service.ts | 11 +++-- .../apr-data-sources/swap-fee-apr.service.ts | 13 ++++-- .../ve-bal-gauge-apr.service.ts | 23 ++++++++-- modules/pool/lib/pool-apr-updater.service.ts | 4 +- modules/pool/pool-types.ts | 4 +- prisma/prisma-types.ts | 2 +- 8 files changed, 96 insertions(+), 25 deletions(-) diff --git a/modules/pool/lib/apr-data-sources/boosted-pool-apr.service.ts b/modules/pool/lib/apr-data-sources/boosted-pool-apr.service.ts index 29e97a906..fecb8d601 100644 --- a/modules/pool/lib/apr-data-sources/boosted-pool-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/boosted-pool-apr.service.ts @@ -1,5 +1,5 @@ import { PoolAprService } from '../../pool-types'; -import { PrismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; +import { PrismaPoolWithTokens, prismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; import { prisma } from '../../../../prisma/prisma-client'; import { collectsYieldFee } from '../pool-utils'; import { networkContext } from '../../../network/network-context.service'; @@ -9,14 +9,41 @@ export class BoostedPoolAprService implements PoolAprService { return 'BoostedPoolAprService'; } - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { - const boostedPools = pools.filter( - (pool) => - (pool.type === 'PHANTOM_STABLE' || pool.type === 'WEIGHTED') && - pool.tokens.find((token) => token.nestedPool), + public async updateAprForPools(pools: PrismaPoolWithTokens[]): Promise { + // need to do multiple queries otherwise the nesting is too deep for many pools. Error: stack depth limit exceeded + const boostedPools = pools.filter((pool) => pool.type === 'PHANTOM_STABLE' || pool.type === 'WEIGHTED'); + + const boostedPoolsWithNestedPool = await prisma.prismaPool.findMany({ + where: { chain: networkContext.chain, id: { in: boostedPools.map((pool) => pool.id) } }, + include: { + tokens: { + orderBy: { index: 'asc' }, + include: { + nestedPool: true, + }, + }, + }, + }); + + const filteredBoostedPools = boostedPoolsWithNestedPool.filter((pool) => + pool.tokens.find((token) => token.nestedPool), ); - for (const pool of boostedPools) { + const filteredBoostedPoolsExpanded = await prisma.prismaPool.findMany({ + where: { chain: networkContext.chain, id: { in: filteredBoostedPools.map((pool) => pool.id) } }, + include: { + dynamicData: true, + tokens: { + orderBy: { index: 'asc' }, + include: { + dynamicData: true, + nestedPool: true, + }, + }, + }, + }); + + for (const pool of filteredBoostedPoolsExpanded) { const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee ? parseFloat(pool.dynamicData.protocolYieldFee) : networkContext.data.balancer.yieldProtocolFeePercentage; @@ -51,7 +78,7 @@ export class BoostedPoolAprService implements PoolAprService { !pool.dynamicData || !token.dynamicData || !token.nestedPool || - !token.nestedPool.dynamicData || + !token.nestedPool.type || token.dynamicData.balanceUSD === 0 ) { continue; diff --git a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts index e76664a36..a2f2db527 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts @@ -1,5 +1,5 @@ import { PoolAprService } from '../../pool-types'; -import { PrismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; +import { PrismaPoolWithTokens } from '../../../../prisma/prisma-types'; import { prisma } from '../../../../prisma/prisma-client'; import { networkContext } from '../../../network/network-context.service'; import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; @@ -20,7 +20,7 @@ export class IbTokensAprService implements PoolAprService { return 'IbTokensAprService'; } - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { + public async updateAprForPools(pools: PrismaPoolWithTokens[]): Promise { const operations: any[] = []; const tokenPrices = await tokenService.getTokenPrices(); const aprs = await this.fetchYieldTokensApr(); @@ -31,7 +31,22 @@ export class IbTokensAprService implements PoolAprService { .includes(token.address.toLowerCase()); }); }); - for (const pool of poolsWithIbTokens) { + + const poolsWithIbTokensExpanded = await prisma.prismaPool.findMany({ + where: { chain: networkContext.chain, id: { in: poolsWithIbTokens.map((pool) => pool.id) } }, + include: { + dynamicData: true, + tokens: { + orderBy: { index: 'asc' }, + include: { + token: true, + dynamicData: true, + }, + }, + }, + }); + + for (const pool of poolsWithIbTokensExpanded) { if (!pool.dynamicData) { continue; } diff --git a/modules/pool/lib/apr-data-sources/phantom-stable-apr.service.ts b/modules/pool/lib/apr-data-sources/phantom-stable-apr.service.ts index c7e0c7f00..06f738c6b 100644 --- a/modules/pool/lib/apr-data-sources/phantom-stable-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/phantom-stable-apr.service.ts @@ -1,5 +1,5 @@ import { PoolAprService } from '../../pool-types'; -import { PrismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; +import { PrismaPoolWithTokens, prismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; import { prisma } from '../../../../prisma/prisma-client'; import { collectsYieldFee } from '../pool-utils'; import { networkContext } from '../../../network/network-context.service'; @@ -9,10 +9,15 @@ export class PhantomStableAprService implements PoolAprService { return 'PhantomStableAprService'; } - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { + public async updateAprForPools(pools: PrismaPoolWithTokens[]): Promise { const phantomStablePools = pools.filter((pool) => pool.type === 'PHANTOM_STABLE'); - for (const pool of phantomStablePools) { + const phantomStablePoolsExpanded = await prisma.prismaPool.findMany({ + ...prismaPoolWithExpandedNesting, + where: { chain: networkContext.chain, id: { in: phantomStablePools.map((pool) => pool.id) } }, + }); + + for (const pool of phantomStablePoolsExpanded) { const protocolYieldFeePercentage = pool.dynamicData?.protocolYieldFee ? parseFloat(pool.dynamicData.protocolYieldFee) : networkContext.data.balancer.yieldProtocolFeePercentage; diff --git a/modules/pool/lib/apr-data-sources/swap-fee-apr.service.ts b/modules/pool/lib/apr-data-sources/swap-fee-apr.service.ts index 3c032ffa1..e7a0bf07b 100644 --- a/modules/pool/lib/apr-data-sources/swap-fee-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/swap-fee-apr.service.ts @@ -1,5 +1,5 @@ import { PoolAprService } from '../../pool-types'; -import { PrismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; +import { PrismaPoolWithTokens } from '../../../../prisma/prisma-types'; import { prisma } from '../../../../prisma/prisma-client'; import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; import { networkContext } from '../../../network/network-context.service'; @@ -12,10 +12,17 @@ export class SwapFeeAprService implements PoolAprService { return 'SwapFeeAprService'; } - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { + public async updateAprForPools(pools: PrismaPoolWithTokens[]): Promise { const operations: any[] = []; - for (const pool of pools) { + const poolsExpanded = await prisma.prismaPool.findMany({ + where: { chain: networkContext.chain, id: { in: pools.map((pool) => pool.id) } }, + include: { + dynamicData: true, + }, + }); + + for (const pool of poolsExpanded) { if (pool.dynamicData) { const apr = pool.dynamicData.totalLiquidity > 0 diff --git a/modules/pool/lib/apr-data-sources/ve-bal-gauge-apr.service.ts b/modules/pool/lib/apr-data-sources/ve-bal-gauge-apr.service.ts index a8a79fd46..aabeb1d68 100644 --- a/modules/pool/lib/apr-data-sources/ve-bal-gauge-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/ve-bal-gauge-apr.service.ts @@ -1,4 +1,4 @@ -import { PrismaPoolWithExpandedNesting } from '../../../../prisma/prisma-types'; +import { PrismaPoolWithTokens } from '../../../../prisma/prisma-types'; import { PoolAprService } from '../../pool-types'; import { TokenService } from '../../../token/token.service'; import { secondsPerYear } from '../../../common/time'; @@ -21,11 +21,28 @@ export class GaugeAprService implements PoolAprService { return 'GaugeAprService'; } - public async updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise { + public async updateAprForPools(pools: PrismaPoolWithTokens[]): Promise { const operations: any[] = []; const gauges = await this.gaugeSubgraphService.getAllGaugesWithStatus(); const tokenPrices = await this.tokenService.getTokenPrices(); - for (const pool of pools) { + + const poolsExpanded = await prisma.prismaPool.findMany({ + where: { chain: networkContext.chain, id: { in: pools.map((pool) => pool.id) } }, + include: { + dynamicData: true, + staking: { + include: { + gauge: { + include: { + rewards: true, + }, + }, + }, + }, + }, + }); + + for (const pool of poolsExpanded) { let gauge; let preferredStaking; for (const stake of pool.staking) { diff --git a/modules/pool/lib/pool-apr-updater.service.ts b/modules/pool/lib/pool-apr-updater.service.ts index be99509d9..863a14242 100644 --- a/modules/pool/lib/pool-apr-updater.service.ts +++ b/modules/pool/lib/pool-apr-updater.service.ts @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/node'; import { prisma } from '../../../prisma/prisma-client'; -import { prismaPoolWithExpandedNesting } from '../../../prisma/prisma-types'; +import { poolWithTokens } from '../../../prisma/prisma-types'; import { PoolAprService } from '../pool-types'; import _ from 'lodash'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; @@ -15,7 +15,7 @@ export class PoolAprUpdaterService { public async updatePoolAprs() { const pools = await prisma.prismaPool.findMany({ - ...prismaPoolWithExpandedNesting, + ...poolWithTokens, where: { chain: networkContext.chain }, }); diff --git a/modules/pool/pool-types.ts b/modules/pool/pool-types.ts index db6c2c42d..091dc2087 100644 --- a/modules/pool/pool-types.ts +++ b/modules/pool/pool-types.ts @@ -1,8 +1,8 @@ import { PrismaPoolStakingType } from '@prisma/client'; -import { PrismaPoolWithExpandedNesting } from '../../prisma/prisma-types'; +import { PrismaPoolWithTokens } from '../../prisma/prisma-types'; export interface PoolAprService { - updateAprForPools(pools: PrismaPoolWithExpandedNesting[]): Promise; + updateAprForPools(pools: PrismaPoolWithTokens[]): Promise; getAprServiceName(): string; } diff --git a/prisma/prisma-types.ts b/prisma/prisma-types.ts index 1ed3b790a..d986de64e 100644 --- a/prisma/prisma-types.ts +++ b/prisma/prisma-types.ts @@ -1,6 +1,6 @@ import { Prisma, PrismaToken, PrismaTokenPrice, PrismaTokenTypeOption } from '@prisma/client'; -const poolWithTokens = Prisma.validator()({ +export const poolWithTokens = Prisma.validator()({ include: { tokens: true }, }); From e68f06a36ecee65e77b41f83157b90c08f117105 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 5 Sep 2023 18:23:12 +0200 Subject: [PATCH 41/42] lower case all addresses in configs --- modules/network/arbitrum.ts | 24 ++++++++++++------------ modules/network/avalanche.ts | 12 ++++++------ modules/network/base.ts | 8 ++++---- modules/network/fantom.ts | 32 ++++++++++++++++---------------- modules/network/gnosis.ts | 12 ++++++------ modules/network/mainnet.ts | 28 ++++++++++++++-------------- modules/network/optimism.ts | 20 ++++++++++---------- modules/network/polygon.ts | 24 ++++++++++++------------ modules/network/zkevm.ts | 12 ++++++------ 9 files changed, 86 insertions(+), 86 deletions(-) diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index f74c4c230..e6d64345d 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -23,7 +23,7 @@ const arbitrumNetworkData: NetworkData = { slug: 'arbitrum', id: 42161, nativeAssetAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - wrappedNativeAssetAddress: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', + wrappedNativeAssetAddress: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', prismaId: 'ARBITRUM', gqlId: 'ARBITRUM', }, @@ -67,24 +67,24 @@ const arbitrumNetworkData: NetworkData = { delegationProxy: '0x81cfae226343b24ba12ec6521db2c79e7aeeb310', }, balancer: { - vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', composableStablePoolFactories: [ - '0xaEb406b0E430BF5Ea2Dc0B9Fe62E4E53f74B3a33', - '0x85a80afee867aDf27B50BdB7b76DA70f1E853062', - '0x1c99324EDC771c82A0DCCB780CC7DDA0045E50e7', - '0x2498A2B0d6462d2260EAC50aE1C3e03F4829BA95', - '0xA8920455934Da4D853faac1f94Fe7bEf72943eF1', + '0xaeb406b0e430bf5ea2dc0b9fe62e4e53f74b3a33', + '0x85a80afee867adf27b50bdb7b76da70f1e853062', + '0x1c99324edc771c82a0dccb780cc7dda0045e50e7', + '0x2498a2b0d6462d2260eac50ae1c3e03f4829ba95', + '0xa8920455934da4d853faac1f94fe7bef72943ef1', ], weightedPoolV2Factories: [ - '0x8df6EfEc5547e31B0eb7d1291B511FF8a2bf987c', - '0xf1665E19bc105BE4EDD3739F88315cC699cc5b65', - '0xc7E5ED1054A24Ef31D827E6F86caA58B3Bc168d7', + '0x8df6efec5547e31b0eb7d1291b511ff8a2bf987c', + '0xf1665e19bc105be4edd3739f88315cc699cc5b65', + '0xc7e5ed1054a24ef31d827e6f86caa58b3bc168d7', ], swapProtocolFeePercentage: 0.5, yieldProtocolFeePercentage: 0.5, - poolDataQueryContract: '0x7Ba29fE8E83dd6097A7298075C4AFfdBda3121cC', + poolDataQueryContract: '0x7ba29fe8e83dd6097a7298075c4affdbda3121cc', }, - multicall: '0x80C7DD17B01855a6D2347444a0FCC36136a314de', + multicall: '0x80c7dd17b01855a6d2347444a0fcc36136a314de', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', avgBlockSpeed: 1, sor: { diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index 048ec1f15..2b55d31a8 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -23,7 +23,7 @@ const avalancheNetworkData: NetworkData = { slug: 'avalanche', id: 43114, nativeAssetAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - wrappedNativeAssetAddress: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', + wrappedNativeAssetAddress: '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7', prismaId: 'AVALANCHE', gqlId: 'AVALANCHE', }, @@ -67,15 +67,15 @@ const avalancheNetworkData: NetworkData = { delegationProxy: '', }, balancer: { - vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', composableStablePoolFactories: [ - '0x3B1eb8EB7b43882b385aB30533D9A2BeF9052a98', - '0xE42FFA682A26EF8F25891db4882932711D42e467', + '0x3b1eb8eb7b43882b385ab30533d9a2bef9052a98', + '0xe42ffa682a26ef8f25891db4882932711d42e467', ], - weightedPoolV2Factories: ['0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a'], + weightedPoolV2Factories: ['0x230a59f4d9adc147480f03b0d3fffecd56c3289a'], swapProtocolFeePercentage: 0.5, yieldProtocolFeePercentage: 0.5, - poolDataQueryContract: '0x67af5D428d38C5176a286a2371Df691cDD914Fb8', + poolDataQueryContract: '0x67af5d428d38c5176a286a2371df691cdd914fb8', }, multicall: '0xca11bde05977b3631167028862be2a173976ca11', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/network/base.ts b/modules/network/base.ts index 5609142de..11547301d 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -68,12 +68,12 @@ const baseNetworkData: NetworkData = { delegationProxy: '0xd87f44df0159dc78029ab9ca7d7e57e7249f5acd', }, balancer: { - vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', - composableStablePoolFactories: ['0x8df317a729fcaA260306d7de28888932cb579b88'], - weightedPoolV2Factories: ['0x4C32a8a8fDa4E24139B51b456B42290f51d6A1c4'], + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', + composableStablePoolFactories: ['0x8df317a729fcaa260306d7de28888932cb579b88'], + weightedPoolV2Factories: ['0x4c32a8a8fda4e24139b51b456b42290f51d6a1c4'], swapProtocolFeePercentage: 0.5, yieldProtocolFeePercentage: 0.5, - poolDataQueryContract: '0x67af5D428d38C5176a286a2371Df691cDD914Fb8', + poolDataQueryContract: '0x67af5d428d38c5176a286a2371df691cdd914fb8', }, ibAprConfig: { defaultHandlers: { diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index c8142e65b..99c103d39 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -109,25 +109,25 @@ const fantomNetworkData: NetworkData = { poolAddress: '0xcde5a11a4acb4ee4c805352cec57e236bdbc3837', }, balancer: { - vault: '0x20dd72Ed959b6147912C2e529F0a0C651c33c9ce', + vault: '0x20dd72ed959b6147912c2e529f0a0c651c33c9ce', composableStablePoolFactories: [ - '0x5AdAF6509BCEc3219455348AC45d6D3261b1A990', - '0xB384A86F2Fd7788720db42f9daa60fc07EcBeA06', - '0x44814E3A603bb7F1198617995c5696C232F6e8Ed', - '0x911566c808bF00acB200B418564440A2Af177548', - '0x5c3094982cF3c97A06b7d62A6f7669F14a199B19', - '0x23F03a4fb344d8B98833d2ACe093cc305E03474f', + '0x5adaf6509bcec3219455348ac45d6d3261b1a990', + '0xb384a86f2fd7788720db42f9daa60fc07ecbea06', + '0x44814e3a603bb7f1198617995c5696c232f6e8ed', + '0x911566c808bf00acb200b418564440a2af177548', + '0x5c3094982cf3c97a06b7d62a6f7669f14a199b19', + '0x23f03a4fb344d8b98833d2ace093cc305e03474f', ], weightedPoolV2Factories: [ - '0xB2ED595Afc445b47Db7043bEC25e772bf0FA1fbb', - '0x8ea1c497c16726E097f62C8C9FBD944143F27090', - '0xea87F3dFfc679035653C0FBa70e7bfe46E3FB733', - '0xd678b6Acd834Cc969Bb19Ce82727f2a541fb7941', - '0xb841Df73861E65E6D61a80F503F095a91ce75e15', + '0xb2ed595afc445b47db7043bec25e772bf0fa1fbb', + '0x8ea1c497c16726e097f62c8c9fbd944143f27090', + '0xea87f3dffc679035653c0fba70e7bfe46e3fb733', + '0xd678b6acd834cc969bb19ce82727f2a541fb7941', + '0xb841df73861e65e6d61a80f503f095a91ce75e15', ], swapProtocolFeePercentage: 0.25, yieldProtocolFeePercentage: 0.25, - poolDataQueryContract: '0x9642Dbba0753B1518022d7617Be079f0d7EFD165', + poolDataQueryContract: '0x9642dbba0753b1518022d7617be079f0d7efd165', factoriesWithpoolSpecificProtocolFeePercentagesProvider: [ '0xb841df73861e65e6d61a80f503f095a91ce75e15', '0x5c3094982cf3c97a06b7d62a6f7669f14a199b19', @@ -136,7 +136,7 @@ const fantomNetworkData: NetworkData = { multicall: '0x66335d7ad8011f6aa3f48aadcb523b62b38ed961', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', masterchef: { - address: '0x8166994d9ebBe5829EC86Bd81258149B87faCfd3', + address: '0x8166994d9ebbe5829ec86bd81258149b87facfd3', excludedFarmIds: [ '34', //OHM bonding farm '28', //OHM bonding farm @@ -145,7 +145,7 @@ const fantomNetworkData: NetworkData = { ], }, reliquary: { - address: '0x1ed6411670c709F4e163854654BD52c74E66D7eC', + address: '0x1ed6411670c709f4e163854654bd52c74e66d7ec', excludedFarmIds: [ '0', // test with dummy token '1', // test with fresh beets pool BPT @@ -253,7 +253,7 @@ const fantomNetworkData: NetworkData = { }, }, copper: { - proxyAddress: '0xbC8a71C75ffbd2807c021F4F81a8832392dEF93c', + proxyAddress: '0xbc8a71c75ffbd2807c021f4f81a8832392def93c', }, beefy: { linearPools: [''], diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index 1a2e09250..70a4d5c9b 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -23,7 +23,7 @@ const gnosisNetworkData: NetworkData = { slug: 'gnosis', id: 100, nativeAssetAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - wrappedNativeAssetAddress: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', + wrappedNativeAssetAddress: '0xe91d153e0b41518a2ce8dd3d7944fa863463a97d', prismaId: 'GNOSIS', gqlId: 'GNOSIS', }, @@ -65,15 +65,15 @@ const gnosisNetworkData: NetworkData = { delegationProxy: '0x7a2535f5fb47b8e44c02ef5d9990588313fe8f05', }, balancer: { - vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', composableStablePoolFactories: [ - '0xf23b4DB826DbA14c0e857029dfF076b1c0264843', - '0x4bdCc2fb18AEb9e2d281b0278D946445070EAda7', + '0xf23b4db826dba14c0e857029dff076b1c0264843', + '0x4bdcc2fb18aeb9e2d281b0278d946445070eada7', ], - weightedPoolV2Factories: ['0x6CaD2ea22BFA7F4C14Aae92E47F510Cd5C509bc7'], + weightedPoolV2Factories: ['0x6cad2ea22bfa7f4c14aae92e47f510cd5c509bc7'], swapProtocolFeePercentage: 0.5, yieldProtocolFeePercentage: 0.5, - poolDataQueryContract: '0x3f170631ed9821Ca51A59D996aB095162438DC10', + poolDataQueryContract: '0x3f170631ed9821ca51a59d996ab095162438dc10', }, multicall: '0xbb6fab6b627947dae0a75808250d8b2652952cb5', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index d3cca872f..e4a62d2f9 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -30,7 +30,7 @@ export const mainnetNetworkData: NetworkData = { slug: 'ethereum', id: 1, nativeAssetAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - wrappedNativeAssetAddress: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + wrappedNativeAssetAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', prismaId: 'MAINNET', gqlId: 'MAINNET', }, @@ -71,25 +71,25 @@ export const mainnetNetworkData: NetworkData = { address: '0xc128a9954e6c874ea3d62ce62b468ba073093f25', delegationProxy: '0x0000000000000000000000000000000000000000', }, - gaugeControllerAddress: '0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD', - gaugeControllerHelperAddress: '0x8E5698dC4897DC12243c8642e77B4f21349Db97C', + gaugeControllerAddress: '0xc128468b7ce63ea702c1f104d55a2566b13d3abd', + gaugeControllerHelperAddress: '0x8e5698dc4897dc12243c8642e77b4f21349db97c', balancer: { - vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', composableStablePoolFactories: [ - '0xf9ac7B9dF2b3454E841110CcE5550bD5AC6f875F', - '0x85a80afee867aDf27B50BdB7b76DA70f1E853062', - '0xdba127fBc23fb20F5929C546af220A991b5C6e01', - '0xfADa0f4547AB2de89D1304A668C39B3E09Aa7c76', - '0xDB8d758BCb971e482B2C45f7F8a7740283A1bd3A', + '0xf9ac7b9df2b3454e841110cce5550bd5ac6f875f', + '0x85a80afee867adf27b50bdb7b76da70f1e853062', + '0xdba127fbc23fb20f5929c546af220a991b5c6e01', + '0xfada0f4547ab2de89d1304a668c39b3e09aa7c76', + '0xdb8d758bcb971e482b2c45f7f8a7740283a1bd3a', ], weightedPoolV2Factories: [ - '0xcC508a455F5b0073973107Db6a878DdBDab957bC', - '0x5Dd94Da3644DDD055fcf6B3E1aa310Bb7801EB8b', - '0x897888115Ada5773E02aA29F775430BFB5F34c51', + '0xcc508a455f5b0073973107db6a878ddbdab957bc', + '0x5dd94da3644ddd055fcf6b3e1aa310bb7801eb8b', + '0x897888115ada5773e02aa29f775430bfb5f34c51', ], swapProtocolFeePercentage: 0.5, yieldProtocolFeePercentage: 0.5, - poolDataQueryContract: '0xf5CDdF6feD9C589f1Be04899F48f9738531daD59', + poolDataQueryContract: '0xf5cddf6fed9c589f1be04899f48f9738531dad59', excludedPoolDataQueryPoolIds: ['0xf71d0774b214c4cf51e33eb3d30ef98132e4dbaa00000000000000000000046e'], }, multicall: '0x5ba1e12693dc8f9c48aad8770482f4739beed696', @@ -225,7 +225,7 @@ export const mainnetNetworkData: NetworkData = { tessera: { tokens: { sAPE: { - tesseraPoolAddress: '0x5954aB967Bc958940b7EB73ee84797Dc8a2AFbb9', + tesseraPoolAddress: '0x5954ab967bc958940b7eb73ee84797dc8a2afbb9', tokenAddress: '0x7966c5bae631294d7cffcea5430b78c2f76db6fa', }, }, diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 824b35919..e3fbb64c0 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -76,23 +76,23 @@ const optimismNetworkData: NetworkData = { delegationProxy: '0x9da18982a33fd0c7051b19f0d7c76f2d5e7e017c', }, balancer: { - vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', composableStablePoolFactories: [ - '0xf145caFB67081895EE80eB7c04A30Cf87f07b745', - '0xe2E901AB09f37884BA31622dF3Ca7FC19AA443Be', - '0x1802953277FD955f9a254B80Aa0582f193cF1d77', - '0x043A2daD730d585C44FB79D2614F295D2d625412', + '0xf145cafb67081895ee80eb7c04a30cf87f07b745', + '0xe2e901ab09f37884ba31622df3ca7fc19aa443be', + '0x1802953277fd955f9a254b80aa0582f193cf1d77', + '0x043a2dad730d585c44fb79d2614f295d2d625412', ], weightedPoolV2Factories: [ - '0xad901309d9e9DbC5Df19c84f729f429F0189a633', - '0xA0DAbEBAAd1b243BBb243f933013d560819eB66f', - '0x230a59F4d9ADc147480f03B0D3fFfeCd56c3289a', + '0xad901309d9e9dbc5df19c84f729f429f0189a633', + '0xa0dabebaad1b243bbb243f933013d560819eb66f', + '0x230a59f4d9adc147480f03b0d3fffecd56c3289a', ], swapProtocolFeePercentage: 0.5, yieldProtocolFeePercentage: 0.5, - poolDataQueryContract: '0x6B5dA774890Db7B7b96C6f44e6a4b0F657399E2e', + poolDataQueryContract: '0x6b5da774890db7b7b96c6f44e6a4b0f657399e2e', }, - multicall: '0x2DC0E2aa608532Da689e89e237dF582B783E552C', + multicall: '0x2dc0e2aa608532da689e89e237df582b783e552c', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', masterchef: { address: '0x0000000000000000000000000000000000000000', diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index a3da1e9cc..242c311ff 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -23,7 +23,7 @@ const polygonNetworkData: NetworkData = { slug: 'polygon', id: 137, nativeAssetAddress: '0x0000000000000000000000000000000000001010', - wrappedNativeAssetAddress: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', + wrappedNativeAssetAddress: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270', prismaId: 'POLYGON', gqlId: 'POLYGON', }, @@ -67,24 +67,24 @@ const polygonNetworkData: NetworkData = { delegationProxy: '0x0f08eef2c785aa5e7539684af04755dec1347b7c', }, balancer: { - vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', composableStablePoolFactories: [ - '0x136FD06Fa01eCF624C7F2B3CB15742c1339dC2c4', - '0x85a80afee867aDf27B50BdB7b76DA70f1E853062', - '0x7bc6C0E73EDAa66eF3F6E2f27b0EE8661834c6C9', - '0x6Ab5549bBd766A43aFb687776ad8466F8b42f777', - '0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b', + '0x136fd06fa01ecf624c7f2b3cb15742c1339dc2c4', + '0x85a80afee867adf27b50bdb7b76da70f1e853062', + '0x7bc6c0e73edaa66ef3f6e2f27b0ee8661834c6c9', + '0x6ab5549bbd766a43afb687776ad8466f8b42f777', + '0xe2fa4e1d17725e72dcdafe943ecf45df4b9e285b', ], weightedPoolV2Factories: [ - '0x0e39C3D9b2ec765eFd9c5c70BB290B1fCD8536E3', - '0x82e4cFaef85b1B6299935340c964C942280327f4', - '0xFc8a407Bba312ac761D8BFe04CE1201904842B76', + '0x0e39c3d9b2ec765efd9c5c70bb290b1fcd8536e3', + '0x82e4cfaef85b1b6299935340c964c942280327f4', + '0xfc8a407bba312ac761d8bfe04ce1201904842b76', ], swapProtocolFeePercentage: 0.5, yieldProtocolFeePercentage: 0.5, - poolDataQueryContract: '0x84813aA3e079A665C0B80F944427eE83cBA63617', + poolDataQueryContract: '0x84813aa3e079a665c0b80f944427ee83cba63617', }, - multicall: '0x275617327c958bD06b5D6b871E7f491D76113dd8', + multicall: '0x275617327c958bd06b5d6b871e7f491d76113dd8', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', avgBlockSpeed: 1, sor: { diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index e3af40bda..293569ba1 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -23,7 +23,7 @@ const zkevmNetworkData: NetworkData = { slug: 'zkevm', id: 1101, nativeAssetAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', - wrappedNativeAssetAddress: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', + wrappedNativeAssetAddress: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', prismaId: 'ZKEVM', gqlId: 'ZKEVM', }, @@ -67,15 +67,15 @@ const zkevmNetworkData: NetworkData = { delegationProxy: '0xc7e5ed1054a24ef31d827e6f86caa58b3bc168d7', }, balancer: { - vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', + vault: '0xba12222222228d8ba445958a75a0704d566bf2c8', composableStablePoolFactories: [ - '0x8eA89804145c007e7D226001A96955ad53836087', - '0x956CCab09898C0AF2aCa5e6C229c3aD4E93d9288', + '0x8ea89804145c007e7d226001a96955ad53836087', + '0x956ccab09898c0af2aca5e6c229c3ad4e93d9288', ], - weightedPoolV2Factories: ['0x03F3Fb107e74F2EAC9358862E91ad3c692712054'], + weightedPoolV2Factories: ['0x03f3fb107e74f2eac9358862e91ad3c692712054'], swapProtocolFeePercentage: 0.5, yieldProtocolFeePercentage: 0.5, - poolDataQueryContract: '0xF24917fB88261a37Cc57F686eBC831a5c0B9fD39', + poolDataQueryContract: '0xf24917fb88261a37cc57f686ebc831a5c0b9fd39', }, multicall: '0xca11bde05977b3631167028862be2a173976ca11', multicall3: '0xca11bde05977b3631167028862be2a173976ca11', From 57099bf33f94c8e3952a0cb92ee3f9c30bafdd2d Mon Sep 17 00:00:00 2001 From: franz Date: Wed, 6 Sep 2023 13:45:14 +0200 Subject: [PATCH 42/42] adding rocket eth apr --- modules/network/mainnet.ts | 8 +++++++- modules/network/optimism.ts | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index c912c66a7..e95c15113 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -269,12 +269,18 @@ export const mainnetNetworkData: NetworkData = { path: 'sfrxethApr', isIbYield: true, }, - rETH: { + StaFirETH: { tokenAddress: '0x9559aaa82d9649c7a7b220e7c461d2e74c9a3593', sourceUrl: 'https://drop-api.stafi.io/reth/v1/poolData', path: 'data.stakeApr', isIbYield: true, }, + rETH: { + tokenAddress: '0xae78736cd615f374d3085123a210448e74fc6393', + sourceUrl: 'https://rocketpool.net/api/mainnet/payload', + path: 'rethAPR', + isIbYield: true, + }, USDR: { tokenAddress: '0xaf0d9d65fc54de245cda37af3d18cbec860a4d4b', sourceUrl: 'http://usdr-api.us-east-1.elasticbeanstalk.com/usdr/apy', diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 7beae2db7..8cb437ad8 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -188,8 +188,8 @@ const optimismNetworkData: NetworkData = { }, rETH: { tokenAddress: '0x9bcef72be871e61ed4fbbc7630889bee758eb81d', - sourceUrl: 'https://drop-api.stafi.io/reth/v1/poolData', - path: 'data.stakeApr', + sourceUrl: 'https://rocketpool.net/api/mainnet/payload', + path: 'rethAPR', isIbYield: true, }, overnightDAIPlus: {