From 9992890db43d1c6e9db7f08374bb94d93b063c0c Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Thu, 12 Oct 2023 21:00:47 +0200 Subject: [PATCH 1/2] simplified yb tokens apr handler --- .../ib-linear-apr-handlers.ts | 222 +++++++----------- .../sources/aave-apr-handler.ts | 9 +- .../sources/ankr-apr-handler.ts | 14 +- .../sources/beefy-apr-handler.ts | 25 +- .../sources/bloom-apr-handler.ts | 16 +- .../sources/default-apr-handler.ts | 12 +- .../sources/euler-apr-handler.ts | 1 + .../sources/gearbox-apr-handler.ts | 6 +- .../sources/idle-apr-handler.ts | 6 +- .../ib-linear-apr-handlers/sources/index.ts | 16 ++ .../sources/maker-apr-handler.ts | 12 +- .../sources/ovix-apr-handler.ts | 1 + .../sources/reaper-crypt-apr-handler.ts | 8 +- .../sources/tessera-apr-handler.ts | 6 +- .../sources/tetu-apr-handler.ts | 1 + .../sources/tranchess-apr-handler.ts | 6 +- .../sources/yearn-apr-handler.ts | 8 +- .../apr-data-sources/ib-tokens-apr.service.ts | 2 +- 18 files changed, 192 insertions(+), 179 deletions(-) create mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/index.ts 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 6b3ae0816..4f399d649 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 @@ -1,169 +1,113 @@ -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 { YearnAprHandler } from './sources/yearn-apr-handler'; -import { ReaperCryptAprHandler } from './sources/reaper-crypt-apr-handler'; -import { BeefyAprHandler } from './sources/beefy-apr-handler'; +import * as sources from './sources'; import { IbAprConfig } from '../../../../network/apr-config-types'; -import { MakerAprHandler } from './sources/maker-apr-handler'; -import { BloomAprHandler } from './sources/bloom-apr-handler'; +import { Chain } from '@prisma/client'; + +const sourceToHandler = { + aave: sources.AaveAprHandler, + ankr: sources.AnkrAprHandler, + beefy: sources.BeefyAprHandler, + bloom: sources.BloomAprHandler, + euler: sources.EulerAprHandler, + gearbox: sources.GearboxAprHandler, + idle: sources.IdleAprHandler, + maker: sources.MakerAprHandler, + ovix: sources.OvixAprHandler, + reaper: sources.ReaperCryptAprHandler, + tessera: sources.TesseraAprHandler, + tetu: sources.TetuAprHandler, + tranchess: sources.TranchessAprHandler, + yearn: sources.YearnAprHandler, + defaultHandlers: sources.DefaultAprHandler, +} export class IbLinearAprHandlers { private handlers: AprHandler[] = []; fixedAprTokens?: { [tokenName: string]: { address: string; apr: number; group?: string; isIbYield?: boolean } }; - constructor(aprConfig: IbAprConfig) { - this.handlers = this.buildAprHandlers(aprConfig); - this.fixedAprTokens = aprConfig.fixedAprHandler; + constructor(aprConfig: IbAprConfig, private chain?: Chain) { + const { fixedAprHandler, ...config } = aprConfig; + this.handlers = this.buildAprHandlers(config); + this.fixedAprTokens = fixedAprHandler; } - buildAprHandlers(aprConfig: IbAprConfig) { + private buildAprHandlers(aprConfig: IbAprConfig) { 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.beefy) { - const beefyHandler = new BeefyAprHandler(aprConfig.beefy); - handlers.push(beefyHandler); - } - if (aprConfig.bloom) { - const bloomAprHandler = new BloomAprHandler(aprConfig.bloom); - handlers.push(bloomAprHandler); - } - 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.maker) { - const makerHandler = new MakerAprHandler(aprConfig.maker); - handlers.push(makerHandler); - } - if (aprConfig.ovix) { - const ovixHandler = new OvixAprHandler({ - ...aprConfig.ovix, - }); - handlers.push(ovixHandler); - } - if (aprConfig.reaper) { - const reaperCryptHandler = new ReaperCryptAprHandler({ ...aprConfig.reaper }); - handlers.push(reaperCryptHandler); - } - if (aprConfig.tessera) { - const tesseraHandler = new TesseraAprHandler({ - ...aprConfig.tessera, - }); - 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); + + // Add handlers from global configuration + for (const [source, config] of Object.entries(aprConfig)) { + const Handler = sourceToHandler[source as keyof typeof sourceToHandler]; + + // Handle nested configs + if (source === 'aave' || source === 'defaultHandlers') { + for (const nestedConfig of Object.values(config)) { + handlers.push(new Handler(nestedConfig as any)); + } + } else { + handlers.push(new Handler(config)); } } - return handlers; - } - // 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', - 'ETHx', - ].map((token) => token.toLowerCase()); + // Add handlers from self-configured sources + Object.values(sources as unknown as any[]) + .filter((source): source is { chains: Chain[], Handler: AprHandlerConstructor } => 'chains' in source) + .filter((source) => this.chain && source.chains.includes(this.chain)) + .forEach((source) => { + handlers.push(new source.Handler()); + }); - return [ - ...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()), - ), - ]; + return handlers; } async fetchAprsFromAllHandlers(): Promise { - let aprs: TokenApr[] = []; - for (const handler of this.handlers) { - const fetchedResponse: { [key: string]: { apr: number; isIbYield: boolean } } = await handler.getAprs(); - for (const [address, { apr, isIbYield }] of Object.entries(fetchedResponse)) { - aprs.push({ - apr, - isIbYield, - group: handler.group, - address, - }); - } - } - if (this.fixedAprTokens) { - for (const { address, apr, isIbYield, group } of Object.values(this.fixedAprTokens)) { - aprs.push({ - apr, - isIbYield: isIbYield ?? false, - group, - address, - }); + let aprs: TokenApr[] = this.fixedAprTokens + ? Object.values(this.fixedAprTokens).map(({ address, apr, isIbYield, group }) => ({ + apr, + address, + isIbYield: isIbYield ?? false, + group + })) + : []; + + const results = await Promise.allSettled(this.handlers.map((handler) => handler.getAprs(this.chain))); + + for (const result of results) { + if (result.status === 'fulfilled') { + aprs = aprs.concat( + Object.entries(result.value).map(([address, { apr, isIbYield, group }]) => ({ + apr, + address, + isIbYield, + group + })), + ); + } else { + console.error('Failed to fetch APRs from handler', result.reason); } } + return aprs; } } +interface AprHandlerConstructor { + new (config?: any): AprHandler; +} + export interface AprHandler { - group: string | undefined; - getAprs(): Promise<{ [tokenAddress: string]: { apr: number; isIbYield: boolean } }>; + group?: string; + getAprs(chain?: Chain): Promise<{ + [tokenAddress: string]: { + /** Defined as float, eg: 0.01 is 1% */ + apr: number; + isIbYield: boolean + group?: string; + } + }>; } export type TokenApr = { apr: number; address: string; - group?: string; isIbYield: boolean; + group?: string; }; 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 f2b72156b..5312b1985 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 @@ -14,8 +14,7 @@ export class AaveAprHandler implements AprHandler { }; }; subgraphUrl: string; - - readonly group = 'AAVE'; + group = 'AAVE'; readonly query = `query getReserves($aTokens: [String!], $underlyingAssets: [Bytes!]) { reserves( @@ -81,7 +80,11 @@ export class AaveAprHandler implements AprHandler { .map(({ wrappedTokens, underlyingAssetAddress, isIbYield }) => { const apr = aprsByUnderlyingAddress[underlyingAssetAddress]; return Object.values(wrappedTokens).map((wrappedTokenAddress) => ({ - [wrappedTokenAddress]: { apr, isIbYield: isIbYield ?? false }, + [wrappedTokenAddress]: { + apr, + isIbYield: isIbYield ?? false, + group: this.group, + }, })); }) .flat() 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 2f89875ed..86c4e446d 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 @@ -12,14 +12,13 @@ export class AnkrAprHandler implements AprHandler { }; }; url: string; - readonly group = undefined; - constructor(aprHandlerConfig: AnkrAprConfig) { - this.tokens = aprHandlerConfig.tokens; - this.url = aprHandlerConfig.sourceUrl; + constructor(config: AnkrAprConfig) { + this.tokens = config.tokens; + this.url = config.sourceUrl; } - async getAprs(): Promise<{ [tokenAddress: string]: { apr: number; isIbYield: boolean } }> { + async getAprs() { try { const { data } = await axios.get(this.url); const services = (data as { services: { serviceName: string; apy: string }[] }).services; @@ -29,7 +28,10 @@ export class AnkrAprHandler implements AprHandler { if (!service) { return [address, 0]; } - return [address, { apr: parseFloat(service.apy) / 1e2, isIbYield: isIbYield ?? false }]; + 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 1a6e50fef..98e44bea3 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 @@ -12,20 +12,27 @@ export class BeefyAprHandler implements AprHandler { }; }; sourceUrl: string; - group: string | undefined = 'BEEFY'; + group = 'BEEFY'; - constructor(aprConfig: BeefyAprConfig) { - this.tokens = aprConfig.tokens; - this.sourceUrl = aprConfig.sourceUrl; + constructor(config: BeefyAprConfig) { + this.tokens = config.tokens; + this.sourceUrl = config.sourceUrl; } - async getAprs(): Promise<{ [p: string]: { apr: number; isIbYield: boolean } }> { + async getAprs() { try { const { data: aprData } = await axios.get(this.sourceUrl); - 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 }; - } + const aprs = Object.values(this.tokens).map(({ address, vaultId, isIbYield }) => { + const apr = aprData[vaultId]?.vaultApr ?? 0; + return { + [address]: { + apr, + isIbYield: isIbYield ?? false, + group: this.group + } + }; + }); + return aprs; } catch (error) { console.error(`Beefy IB APR hanlder failed: `, error); diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/bloom-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/bloom-apr-handler.ts index fed2cc55c..3f7e352ed 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/bloom-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/bloom-apr-handler.ts @@ -5,16 +5,16 @@ import { abi as bloomBpsFeed } from './abis/bloom-bps-feed'; import * as Sentry from '@sentry/node'; export class BloomAprHandler implements AprHandler { - group: string | undefined; + group = "BLOOM"; tokens: BloomAprConfig['tokens']; - constructor(aprConfig: BloomAprConfig) { - this.tokens = aprConfig.tokens; + constructor(config: BloomAprConfig) { + this.tokens = config.tokens; } - async getAprs(): Promise<{ [p: string]: { apr: number; isIbYield: boolean } }> { - const aprs: { [p: string]: { apr: number; isIbYield: boolean } } = {}; + async getAprs() { + const aprs: { [p: string]: { apr: number; isIbYield: boolean, group?: string } } = {}; for (const { address, feedAddress, isIbYield } of Object.values(this.tokens)) { try { const feedContract = getContractAt(feedAddress, bloomBpsFeed); @@ -23,7 +23,11 @@ export class BloomAprHandler implements AprHandler { continue; } const tokenApr = (Number(currentRate) - 10000) / 10000; - aprs[address] = { apr: tokenApr, isIbYield: isIbYield ?? false }; + aprs[address] = { + apr: tokenApr, + isIbYield: isIbYield ?? false, + group: this.group + }; } catch (error) { console.error(`Bloom APR Failed for token ${address}: `, error); Sentry.captureException(`Bloom APR Failed for token ${address}: ${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 e48dc0b4e..3e393f780 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 @@ -8,8 +8,8 @@ export class DefaultAprHandler implements AprHandler { url: string; path: string; scale: number; - group: string | undefined = undefined; - isIbYield: boolean | undefined; + group?: string; + isIbYield?: boolean; constructor(aprHandlerConfig: { sourceUrl: string; @@ -33,7 +33,13 @@ export class DefaultAprHandler implements AprHandler { const value = this.path === '' ? data : this.getValueFromPath(data, this.path); const scaledValue = parseFloat(value) / this.scale; - return { [this.tokenAddress]: { apr: scaledValue, isIbYield: this.isIbYield ?? false } }; + return { + [this.tokenAddress]: { + apr: scaledValue, + isIbYield: this.isIbYield ?? false, + group: this.group + } + }; } 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 f6edc5479..960954f78 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 @@ -60,6 +60,7 @@ export class EulerAprHandler implements AprHandler { Object.values(this.tokens).find( ({ address }) => address.toLowerCase() === eTokenAddress.toLowerCase(), )?.isIbYield ?? false, + group: this.group, }, ]); 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 96e77624d..490d6f441 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 @@ -31,7 +31,11 @@ export class GearboxAprHandler implements AprHandler { ); return [ dieselToken, - { apr: Number(depositAPY_RAY.slice(0, 27)) / 1e27, isIbYield: tokenObj?.isIbYield ?? false }, + { + apr: Number(depositAPY_RAY.slice(0, 27)) / 1e27, + isIbYield: tokenObj?.isIbYield ?? false, + group: this.group, + }, ]; }); return Object.fromEntries(aprEntries); 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 3782bf6e4..24857b410 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 @@ -32,7 +32,11 @@ export class IdleAprHandler implements AprHandler { }); const [json] = data as { idleRate: string }[]; const value = Number(json.idleRate) / 1e20; - return [wrapped4626Address, { apr: value, isIbYield: isIbYield ?? false }]; + return [wrapped4626Address, { + apr: value, + isIbYield: isIbYield ?? false, + group: this.group, + }]; }); 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/index.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/index.ts new file mode 100644 index 000000000..94a5dff90 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/index.ts @@ -0,0 +1,16 @@ +export * from './aave-apr-handler'; +export * from './ankr-apr-handler'; +export * from './default-apr-handler'; +export * from './euler-apr-handler'; +export * from './gearbox-apr-handler'; +export * from './idle-apr-handler'; +export * from './ovix-apr-handler'; +export * from './tessera-apr-handler'; +export * from './tetu-apr-handler'; +export * from './tranchess-apr-handler'; +export * from './yearn-apr-handler'; +export * from './reaper-crypt-apr-handler'; +export * from './beefy-apr-handler'; +export * from './maker-apr-handler'; +export * as MakerGnosis from './maker-gnosis-apr-handler'; +export * from './bloom-apr-handler'; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-apr-handler.ts index 20220f187..0b47bf9be 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-apr-handler.ts @@ -5,7 +5,7 @@ import { abi as makerPotAbi } from './abis/maker-pot'; import * as Sentry from '@sentry/node'; export class MakerAprHandler implements AprHandler { - group: string | undefined; + group = 'MAKER'; tokens: { [tokenName: string]: { address: string; @@ -18,8 +18,8 @@ export class MakerAprHandler implements AprHandler { this.tokens = aprConfig.tokens; } - async getAprs(): Promise<{ [p: string]: { apr: number; isIbYield: boolean } }> { - const aprs: { [p: string]: { apr: number; isIbYield: boolean } } = {}; + async getAprs() { + const aprs: { [p: string]: { apr: number; isIbYield: boolean, group: string } } = {}; for (const { address, potAddress, isIbYield } of Object.values(this.tokens)) { try { const potContract = getContractAt(potAddress, makerPotAbi); @@ -28,7 +28,11 @@ export class MakerAprHandler implements AprHandler { continue; } const tokenApr = (Number(dsr) * 10 ** -27 - 1) * 365 * 24 * 60 * 60; - aprs[address] = { apr: tokenApr, isIbYield: isIbYield ?? false }; + aprs[address] = { + apr: tokenApr, + isIbYield: isIbYield ?? false, + group: this.group + }; } catch (error) { console.error(`Maker APR Failed for token ${address}: `, error); Sentry.captureException(`Maker APR Failed for token ${address}: ${error}`); 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 3f3d0a7e1..a8206b52d 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 @@ -30,6 +30,7 @@ export class OvixAprHandler implements AprHandler { { apr: Math.pow(1 + (borrowRate as BigNumber).toNumber() / 1e18, 365 * 24 * 60 * 60) - 1, isIbYield: isIbYield ?? false, + group: this.group, }, ]; }); 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 a9d0196d7..6acf75005 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 @@ -45,7 +45,7 @@ export class ReaperCryptAprHandler implements AprHandler { this.averageAPRAcrossLastNHarvests = aprConfig.onchainSource?.averageAPRAcrossLastNHarvests; } - async getAprs(): Promise<{ [p: string]: { apr: number; isIbYield: boolean } }> { + async getAprs() { let multiStrategyAprs = {}; let singleStrategyAprs = {}; this.wstETHBaseApr = await this.getWstEthBaseApr(); @@ -122,7 +122,11 @@ export class ReaperCryptAprHandler implements AprHandler { } return { ...acc, - [id]: { apr: tokenApr, isIbYield: token.isIbYield ?? false }, + [id]: { + apr: tokenApr, + isIbYield: token.isIbYield ?? false, + group: this.group, + }, }; }, {}); } catch (error) { 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 ccdce1f15..f1d67f18f 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 @@ -31,7 +31,11 @@ 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, isIbYield: isIbYield ?? false }]); + aprEntries.push([tokenAddress, { + apr, + isIbYield: isIbYield ?? false, + group: this.group + }]); } catch (error) { console.error('Failed to fetch Tessera Ape Coin APR:', error); Sentry.captureException(`Tessera IB APR handler failed: ${error}`); 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 2db4746f9..d42480aac 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 @@ -35,6 +35,7 @@ export class TetuAprHandler implements AprHandler { apr: t.apr / 100, isIbYield: Object.values(this.tokens).find(({ address }) => address === t.vault)?.isIbYield ?? false, + group: this.group, }, ]); return Object.fromEntries(aprs); 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 37bea641d..aec8047ee 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 @@ -30,7 +30,11 @@ export class TranchessAprHandler implements AprHandler { ).filter(({ name }) => name === underlyingAssetName)[0].weeklyAveragePnlPercentage; return [ address, - { apr: (365 * Number(weeklyAveragePnlPercentage)) / 1e18, isIbYield: isIbYield ?? false }, + { + apr: (365 * Number(weeklyAveragePnlPercentage)) / 1e18, + isIbYield: isIbYield ?? false, + group: this.group + }, ]; }); // The key weeklyAveragePnlPercentage is the daily yield of qETH in 18 decimals, timing 365 should give you the APR. 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 1451b2f3d..ac519fad0 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 @@ -12,12 +12,16 @@ export class YearnAprHandler implements AprHandler { this.sourceUrl = aprHandlerConfig.sourceUrl; this.isIbYield = aprHandlerConfig.isIbYield; } - async getAprs(): Promise<{ [p: string]: { apr: number; isIbYield: boolean } }> { + async getAprs() { try { const { data } = await axios.get(this.sourceUrl); const aprs = Object.fromEntries( data.map(({ address, apy: { net_apy } }) => { - return [address.toLowerCase(), { apr: net_apy, isIbYield: this.isIbYield ?? false }]; + return [address.toLowerCase(), { + apr: net_apy, + isIbYield: this.isIbYield ?? false, + group: this.group + }]; }), ); 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 dc3dda53c..3d4c3873f 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 @@ -13,7 +13,7 @@ export class IbTokensAprService implements PoolAprService { private ibTokensAprHandlers: IbTokensAprHandlers; constructor(aprConfig: IbAprConfig) { - this.ibTokensAprHandlers = new IbTokensAprHandlers(aprConfig); + this.ibTokensAprHandlers = new IbTokensAprHandlers(aprConfig, networkContext.chain); } getAprServiceName(): string { From 09e5403484f9f82dfcb570078831d96a52593607 Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Thu, 12 Oct 2023 21:01:39 +0200 Subject: [PATCH 2/2] adding maker gnosis self-config handler --- .../sources/maker-gnosis-apr-handler.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-gnosis-apr-handler.ts diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-gnosis-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-gnosis-apr-handler.ts new file mode 100644 index 000000000..a89220193 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-gnosis-apr-handler.ts @@ -0,0 +1,36 @@ +import { AprHandler } from '../ib-linear-apr-handlers'; +import { getContractAt } from '../../../../../web3/contract'; +import { Chain } from '@prisma/client'; + +const helperAbi = ['function vaultAPY() view returns (uint256)']; + +/** Sets the config data used internally */ +const config = { + "GNOSIS": { + sdaiAddress: '0xaf204776c7245bf4147c2612bf6e5972ee483701', + helperAddress: '0xd499b51fcfc66bd31248ef4b28d656d67e591a94', + } +} + +/** Makes handler callable by chain */ +export const chains = Object.keys(config) as Chain[]; + +export class Handler implements AprHandler { + async getAprs(chain: Chain) { + if (chain !== 'GNOSIS') { + throw `Handler supports GNOSIS only, but called for ${chain}` + } + + const helper = getContractAt(config[chain].helperAddress, helperAbi); + const vaultAPY = await helper.vaultAPY(); + const apr = Number(vaultAPY) * (10 ** -18); + + return { + [config[chain].sdaiAddress]: { + apr, + isIbYield: true, + group: 'MAKER' + } + } + } +}