From cd42b3fae5d929222a627271b911013bbe3e6116 Mon Sep 17 00:00:00 2001 From: franz Date: Thu, 21 Dec 2023 20:56:00 +0100 Subject: [PATCH 1/6] exclude from coingecko --- modules/network/arbitrum.ts | 2 +- modules/network/mainnet.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 3a34524b7..5430e02b0 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -50,7 +50,7 @@ const arbitrumNetworkData: NetworkData = { coingecko: { nativeAssetId: 'ethereum', platformId: 'arbitrum-one', - excludedTokenAddresses: [], + excludedTokenAddresses: ['0x6dbf2155b0636cb3fd5359fccefb8a2c02b6cb51'], // plsRDNT, has coingecko entry but no price }, tokenPrices: { maxHourlyPriceHistoryNumDays: 100, diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index fe2fd1676..4f3404c57 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -57,7 +57,10 @@ const data: NetworkData = { coingecko: { nativeAssetId: 'ethereum', platformId: 'ethereum', - excludedTokenAddresses: ['0xa43a7c62d56df036c187e1966c03e2799d8987ed'], // truMatic, has coingecko entry but no price + excludedTokenAddresses: [ + '0xa43a7c62d56df036c187e1966c03e2799d8987ed', // truMatic, has coingecko entry but no price + '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d', // qETH, has coingecko entry but no price + ], }, tokenPrices: { maxHourlyPriceHistoryNumDays: 100, From a877fb17b88cfa43dc48d5ba06683424b3574ccb Mon Sep 17 00:00:00 2001 From: franz Date: Thu, 21 Dec 2023 21:14:04 +0100 Subject: [PATCH 2/6] exclude weeth from coingecko --- modules/network/mainnet.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 5744db4a1..b2bfab90f 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -60,6 +60,7 @@ const data: NetworkData = { excludedTokenAddresses: [ '0xa43a7c62d56df036c187e1966c03e2799d8987ed', // truMatic, has coingecko entry but no price '0x93ef1ea305d11a9b2a3ebb9bb4fcc34695292e7d', // qETH, has coingecko entry but no price + '0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee', // weEth, has coingekco entry but no price ], }, tokenPrices: { From fcff209a061f5798b5d15419f299ca2230154a0b Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:44:18 +0100 Subject: [PATCH 3/6] Update pool-onchain-gyro-fee.ts --- modules/pool/lib/pool-onchain-gyro-fee.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/pool/lib/pool-onchain-gyro-fee.ts b/modules/pool/lib/pool-onchain-gyro-fee.ts index aef4b3c3d..55f5f0511 100644 --- a/modules/pool/lib/pool-onchain-gyro-fee.ts +++ b/modules/pool/lib/pool-onchain-gyro-fee.ts @@ -70,9 +70,9 @@ export const fetchOnChainGyroFees = async (pools: PoolInput[], gyroConfigAddress const results = (await multicaller.execute()) as OnchainGyroFees; const defaultFee = results.defaultFee ?? '0'; - const eclpFee = results.eclpFee ?? '0'; - const twoClpFee = results.twoClpFee ?? '0'; - const threeClpFee = results.threeClpFee ?? '0'; + const eclpFee = results.eclpFee ?? defaultFee; + const twoClpFee = results.twoClpFee ?? defaultFee; + const threeClpFee = results.threeClpFee ?? defaultFee; let parsed: { [address: string]: string } = {}; if (results.pools) { From 1f0ae929d7d10c9bbe1d5058934854aac0e02c29 Mon Sep 17 00:00:00 2001 From: franzns <93920061+franzns@users.noreply.github.com> Date: Fri, 12 Jan 2024 15:15:30 +0100 Subject: [PATCH 4/6] removing sentry integrations (#35) --- app.ts | 6 +++--- worker/worker.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app.ts b/app.ts index 6151bbaff..2a4071599 100644 --- a/app.ts +++ b/app.ts @@ -31,9 +31,9 @@ async function startServer() { enabled: env.NODE_ENV === 'production', ignoreErrors: [/.*error: Provide.*chain.*param/], integrations: [ - new Sentry.Integrations.Apollo(), - new Sentry.Integrations.GraphQL(), - new Sentry.Integrations.Prisma({ client: prisma }), + // new Sentry.Integrations.Apollo(), + // new Sentry.Integrations.GraphQL(), + // new Sentry.Integrations.Prisma({ client: prisma }), new Sentry.Integrations.Express({ app }), new Sentry.Integrations.Http({ tracing: true }), new ProfilingIntegration(), diff --git a/worker/worker.ts b/worker/worker.ts index 375a8095a..9ef3cf5bb 100644 --- a/worker/worker.ts +++ b/worker/worker.ts @@ -13,10 +13,10 @@ export async function startWorker() { environment: `multichain-worker-${env.DEPLOYMENT_ENV}`, enabled: env.NODE_ENV === 'production', integrations: [ - new Sentry.Integrations.Apollo(), - new Sentry.Integrations.GraphQL(), - new Sentry.Integrations.Prisma({ client: prisma }), - new Sentry.Integrations.Express({ app }), + // new Sentry.Integrations.Apollo(), + // new Sentry.Integrations.GraphQL(), + // new Sentry.Integrations.Prisma({ client: prisma }), + // new Sentry.Integrations.Express({ app }), new Sentry.Integrations.Http({ tracing: true }), new ProfilingIntegration(), ], From a6418e6309146cc25ece764dfa5b4c15ea31ab71 Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Mon, 15 Jan 2024 13:47:50 +0100 Subject: [PATCH 5/6] disable old token purging (#39) --- modules/network/mainnet.ts | 12 ++++++------ worker/job-handlers.ts | 15 ++++++++------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index 0fa6025da..aa4b6b7de 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -494,11 +494,11 @@ export const mainnetNetworkConfig: NetworkConfig = { name: 'sync-global-coingecko-prices', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(2, 'minutes'), }, - { - name: 'global-purge-old-tokenprices', - interval: every(1, 'days'), - alarmEvaluationPeriod: 1, - alarmDatapointsToAlarm: 1, - }, + // { + // name: 'global-purge-old-tokenprices', + // interval: every(1, 'days'), + // alarmEvaluationPeriod: 1, + // alarmDatapointsToAlarm: 1, + // }, ], }; diff --git a/worker/job-handlers.ts b/worker/job-handlers.ts index aa91a476a..0e1e121ef 100644 --- a/worker/job-handlers.ts +++ b/worker/job-handlers.ts @@ -252,13 +252,14 @@ export function configureWorkerRoutes(app: Express) { await runIfNotAlreadyRunning(job.name, chainId, () => userService.syncUserRelicSnapshots(), res, next); break; case 'global-purge-old-tokenprices': - await runIfNotAlreadyRunning( - job.name, - chainId, - () => tokenService.purgeOldTokenPricesForAllChains(), - res, - next, - ); + // await runIfNotAlreadyRunning( + // job.name, + // chainId, + // () => tokenService.purgeOldTokenPricesForAllChains(), + // res, + // next, + // ); + res.sendStatus(200); break; case 'sync-coingecko-coinids': await runIfNotAlreadyRunning(job.name, chainId, () => tokenService.syncCoingeckoIds(), res, next); From fcd9c85f91b14bc891e47bfc932985521829e155 Mon Sep 17 00:00:00 2001 From: franzns <93920061+franzns@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:50:40 +0100 Subject: [PATCH 6/6] V3 canary (#43) * fix remaining phantomstable pool type checks * Update on change only (#30) * only update gauges if necessary * only update masterchef farms if necessary * Token yields update (#28) * renaming ib to yb i suppose ib stands for yield bearing * new aprs * removing obsolete ankr apr handler * fix plutusdao APR url * removing sentry integrations (#36) * create separate featuredPools endpoint for v3 (#34) * create separate featuredPools endpoint for v3 * cleanup * require chains param * stop token price purge for now (#41) --------- Co-authored-by: gmbronco <83549293+gmbronco@users.noreply.github.com> --- modules/content/content-types.ts | 9 +- modules/content/github-content.service.ts | 29 ++-- modules/content/sanity-content.service.ts | 62 +++++-- modules/network/apr-config-types.ts | 16 +- modules/network/arbitrum.ts | 29 +++- modules/network/avalanche.ts | 24 ++- modules/network/base.ts | 8 +- modules/network/fantom.ts | 41 +++-- modules/network/gnosis.ts | 8 +- modules/network/mainnet.ts | 26 ++- modules/network/network-config-types.ts | 8 +- modules/network/optimism.ts | 37 +++-- modules/network/polygon.ts | 8 +- modules/network/zkevm.ts | 14 +- .../boosted-pool-apr.service.ts | 10 +- .../sources/ankr-apr-handler.ts | 44 ----- .../sources/maker-gnosis-apr-handler.ts | 36 ----- .../phantom-stable-apr.service.ts | 2 +- .../index.ts} | 11 +- .../sources/aave-apr-handler.ts | 2 +- .../sources/abis/ReaperCrypt.json | 0 .../sources/abis/ReaperCryptStrategy.json | 0 .../sources/abis/bloom-bps-feed.ts | 0 .../sources/abis/maker-pot.ts | 0 .../sources/abis/oErc20.ts | 0 .../sources/abis/reaperStrategy.ts | 0 .../sources/abis/tesseraPool.ts | 0 .../sources/beefy-apr-handler.ts | 6 +- .../sources/bloom-apr-handler.ts | 8 +- .../sources/default-apr-handler.ts | 23 +-- .../sources/etherfi-apr-handler.ts | 50 ++++++ .../sources/euler-apr-handler.ts | 2 +- .../sources/gearbox-apr-handler.ts | 2 +- .../sources/idle-apr-handler.ts | 15 +- .../sources/index.ts | 3 +- .../sources/maker-apr-handler.ts | 6 +- .../sources/maker-gnosis-apr-handler.ts | 36 +++++ .../sources/ovix-apr-handler.ts | 2 +- .../sources/reaper-crypt-apr-handler.ts | 2 +- .../sources/sftmx-apr-handler.ts | 2 +- .../sources/stakewise-apr-handler.ts | 48 ++++++ .../sources/tessera-apr-handler.ts | 15 +- .../sources/tetu-apr-handler.ts | 2 +- .../sources/tranchess-apr-handler.ts | 4 +- .../sources/yearn-apr-handler.ts | 15 +- ...pr.service.ts => yb-tokens-apr.service.ts} | 26 +-- modules/pool/lib/pool-gql-loader.service.ts | 34 +++- modules/pool/lib/pool-snapshot.service.ts | 2 +- modules/pool/lib/pool-utils.ts | 2 +- .../pool/lib/staking/gauge-staking.service.ts | 153 ++++++++++-------- .../staking/master-chef-staking.service.ts | 79 +++++---- modules/pool/pool.gql | 9 +- modules/pool/pool.resolvers.ts | 3 + modules/pool/pool.service.ts | 5 + modules/vebal/vebal-voting-list.service.ts | 2 +- 55 files changed, 590 insertions(+), 390 deletions(-) delete mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts delete mode 100644 modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-gnosis-apr-handler.ts rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers/ib-linear-apr-handlers.ts => yb-apr-handlers/index.ts} (92%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/aave-apr-handler.ts (98%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/abis/ReaperCrypt.json (100%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/abis/ReaperCryptStrategy.json (100%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/abis/bloom-bps-feed.ts (100%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/abis/maker-pot.ts (100%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/abis/oErc20.ts (100%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/abis/reaperStrategy.ts (100%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/abis/tesseraPool.ts (100%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/beefy-apr-handler.ts (92%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/bloom-apr-handler.ts (89%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/default-apr-handler.ts (71%) create mode 100644 modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/etherfi-apr-handler.ts rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/euler-apr-handler.ts (97%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/gearbox-apr-handler.ts (96%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/idle-apr-handler.ts (84%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/index.ts (88%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/maker-apr-handler.ts (92%) create mode 100644 modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/maker-gnosis-apr-handler.ts rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/ovix-apr-handler.ts (96%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/reaper-crypt-apr-handler.ts (99%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/sftmx-apr-handler.ts (98%) create mode 100644 modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/stakewise-apr-handler.ts rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/tessera-apr-handler.ts (84%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/tetu-apr-handler.ts (96%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/tranchess-apr-handler.ts (94%) rename modules/pool/lib/apr-data-sources/{ib-linear-apr-handlers => yb-apr-handlers}/sources/yearn-apr-handler.ts (76%) rename modules/pool/lib/apr-data-sources/{ib-tokens-apr.service.ts => yb-tokens-apr.service.ts} (84%) diff --git a/modules/content/content-types.ts b/modules/content/content-types.ts index 4e4e65df7..8d0051851 100644 --- a/modules/content/content-types.ts +++ b/modules/content/content-types.ts @@ -13,8 +13,6 @@ export interface HomeScreenFeaturedPoolGroup { id: string; items: (HomeScreenFeaturedPoolGroupItemPoolId | HomeScreenFeaturedPoolGroupItemExternalLink)[]; title: string; - primary: boolean; - chain: GqlChain; } interface HomeScreenFeaturedPoolGroupItemPoolId { @@ -32,6 +30,12 @@ interface HomeScreenFeaturedPoolGroupItemExternalLink { image: string; } +export interface FeaturedPool { + poolId: string; + primary: boolean; + chain: GqlChain; +} + export interface HomeScreenNewsItem { id: string; timestamp: string; @@ -45,5 +49,6 @@ export interface ContentService { syncTokenContentData(): Promise; syncPoolContentData(): Promise; getFeaturedPoolGroups(chains: Chain[]): Promise; + getFeaturedPools(chains: Chain[]): Promise; getNewsItems(): Promise; } diff --git a/modules/content/github-content.service.ts b/modules/content/github-content.service.ts index 546556782..ac798a5d5 100644 --- a/modules/content/github-content.service.ts +++ b/modules/content/github-content.service.ts @@ -3,7 +3,7 @@ import { Chain, Prisma } from '@prisma/client'; import axios from 'axios'; import { prisma } from '../../prisma/prisma-client'; import { networkContext } from '../network/network-context.service'; -import { ContentService, HomeScreenFeaturedPoolGroup, HomeScreenNewsItem } from './content-types'; +import { ContentService, FeaturedPool, HomeScreenFeaturedPoolGroup, HomeScreenNewsItem } from './content-types'; import { chainIdToChain } from '../network/network-config'; const POOLS_METADATA_URL = 'https://raw.githubusercontent.com/balancer/metadata/main/pools/featured.json'; @@ -139,7 +139,10 @@ export class GithubContentService implements ContentService { }); } - if ((pool?.type === 'PHANTOM_STABLE' || pool?.type === 'LINEAR') && !tokenTypes.includes('PHANTOM_BPT')) { + if ( + (pool?.type === 'COMPOSABLE_STABLE' || pool?.type === 'LINEAR') && + !tokenTypes.includes('PHANTOM_BPT') + ) { types.push({ id: `${token.address}-phantom-bpt`, chain: networkContext.chain, @@ -165,25 +168,21 @@ export class GithubContentService implements ContentService { await prisma.prismaTokenType.createMany({ skipDuplicates: true, data: types }); } async syncPoolContentData(): Promise {} + async getFeaturedPoolGroups(chains: Chain[]): Promise { + return []; + } + + async getFeaturedPools(chains: Chain[]): Promise { const { data } = await axios.get(POOLS_METADATA_URL); const pools = data.filter((pool) => chains.includes(chainIdToChain[pool.chainId])); - return pools.map(({ id, imageUrl, primary, chainId }) => ({ - id, - _type: 'homeScreenFeaturedPoolGroupPoolId', - title: 'Popular pools', - items: [ - { - _key: '', - _type: 'homeScreenFeaturedPoolGroupPoolId', - poolId: id, - }, - ], - icon: imageUrl, + return pools.map(({ id, primary, chainId }) => ({ + poolId: id, chain: chainIdToChain[chainId], primary: Boolean(primary), - })) as HomeScreenFeaturedPoolGroup[]; + })) as FeaturedPool[]; } + async getNewsItems(): Promise { return []; } diff --git a/modules/content/sanity-content.service.ts b/modules/content/sanity-content.service.ts index 1ed63c6c7..e512718e9 100644 --- a/modules/content/sanity-content.service.ts +++ b/modules/content/sanity-content.service.ts @@ -1,7 +1,13 @@ import { isSameAddress } from '@balancer-labs/sdk'; import { Chain, Prisma, PrismaPoolCategoryType } from '@prisma/client'; import { prisma } from '../../prisma/prisma-client'; -import { ConfigHomeScreen, ContentService, HomeScreenFeaturedPoolGroup, HomeScreenNewsItem } from './content-types'; +import { + ConfigHomeScreen, + ContentService, + FeaturedPool, + HomeScreenFeaturedPoolGroup, + HomeScreenNewsItem, +} from './content-types'; import SanityClient from '@sanity/client'; import { env } from '../../app/env'; import { chainToIdMap } from '../network/network-config'; @@ -166,7 +172,10 @@ export class SanityContentService implements ContentService { }); } - if ((pool?.type === 'PHANTOM_STABLE' || pool?.type === 'LINEAR') && !tokenTypes.includes('PHANTOM_BPT')) { + if ( + (pool?.type === 'COMPOSABLE_STABLE' || pool?.type === 'LINEAR') && + !tokenTypes.includes('PHANTOM_BPT') + ) { types.push({ id: `${token.address}-phantom-bpt`, chain: this.chain, @@ -276,18 +285,53 @@ export class SanityContentService implements ContentService { } `); if (data) { - featuredPoolGroups.push( - ...data.featuredPoolGroups.map((pool, i) => ({ - ...pool, - chain: chain, - primary: i === 0 ? true : false, - })), - ); + featuredPoolGroups.push(...data.featuredPoolGroups); } } return featuredPoolGroups; } + public async getFeaturedPools(chains: Chain[]): Promise { + const featuredPools: FeaturedPool[] = []; + for (const chain of chains) { + const data = await this.getSanityClient().fetch(` + *[_type == "homeScreen" && chainId == ${chainToIdMap[chain]}][0]{ + ..., + "featuredPoolGroups": featuredPoolGroups[]{ + ..., + "icon": icon.asset->url + "?w=64", + "items": items[]{ + ..., + "image": image.asset->url + "?w=600" + } + }, + "newsItems": newsItems[]{ + ..., + "image": image.asset->url + "?w=800" + } + } + `); + if (data) { + const featuredPoolGroupItems = data.featuredPoolGroups.find( + (group) => group.id === 'popular-pools', + )?.items; + if (featuredPoolGroupItems) { + for (let i = 0; i < featuredPoolGroupItems.length; i++) { + const group = featuredPoolGroupItems[i]; + if (group._type === 'homeScreenFeaturedPoolGroupPoolId') { + featuredPools.push({ + poolId: group.poolId, + primary: i === 0 ? true : false, + chain: chain, + }); + } + } + } + } + } + return featuredPools; + } + public async getNewsItems(): Promise { const data = await this.getSanityClient().fetch(` *[_type == "homeScreen" && chainId == ${chainToIdMap[this.chain]}][0]{ diff --git a/modules/network/apr-config-types.ts b/modules/network/apr-config-types.ts index 93b9c8ac0..76a24aa87 100644 --- a/modules/network/apr-config-types.ts +++ b/modules/network/apr-config-types.ts @@ -1,6 +1,5 @@ -export interface IbAprConfig { +export interface YbAprConfig { aave?: AaveAprConfig; - ankr?: AnkrAprConfig; bloom?: BloomAprConfig; beefy?: BeefyAprConfig; sftmx?: SftmxAprConfig; @@ -14,6 +13,8 @@ export interface IbAprConfig { tetu?: TetuAprConfig; tranchess?: TranchessAprConfig; yearn?: YearnAprConfig; + stakewise?: string; + etherfi?: string; defaultHandlers?: DefaultHandlerAprConfig; fixedAprHandler?: FixedAprConfig; } @@ -34,17 +35,6 @@ export interface AaveAprConfig { }; } -export interface AnkrAprConfig { - sourceUrl: string; - tokens: { - [underlyingAssetName: string]: { - address: string; - serviceName: string; - isIbYield?: boolean; - }; - }; -} - export interface BeefyAprConfig { sourceUrl: string; tokens: { diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 55676c40b..5e5b8f475 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -15,11 +15,11 @@ 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 { YbTokensAprService } from '../pool/lib/apr-data-sources/yb-tokens-apr.service'; import { env } from '../../app/env'; import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; -const arbitrumNetworkData: NetworkData = { +export const arbitrumNetworkData: NetworkData = { chain: { slug: 'arbitrum', id: 42161, @@ -93,7 +93,7 @@ const arbitrumNetworkData: NetworkData = { poolIdsToExclude: [], }, }, - ibAprConfig: { + ybAprConfig: { aave: { v3: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-arbitrum', @@ -175,6 +175,25 @@ const arbitrumNetworkData: NetworkData = { path: 'sfrxethApr', isIbYield: true, }, + sFRAX: { + tokenAddress: '0xe3b3fe7bca19ca77ad877a5bebab186becfad906', + sourceUrl: 'https://api.frax.finance/v2/frax/sfrax/summary/history?range=1d', + path: 'items.0.sfraxApr', + isIbYield: true, + }, + ankrETH: { + tokenAddress: '0xe05a08226c49b636acf99c40da8dc6af83ce5bb3', + sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', + path: 'services.{serviceName == "eth"}.apy', + isIbYield: true, + }, + plsRDNT: { + tokenAddress: '0x6dbf2155b0636cb3fd5359fccefb8a2c02b6cb51', + sourceUrl: 'https://www.plutusdao.io/api/getPlsRdntInfo', + path: 'apr', + scale: 10000, + isIbYield: true, + }, }, }, beefy: { @@ -215,8 +234,8 @@ export const arbitrumNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: arbitrumNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - arbitrumNetworkData.ibAprConfig, + new YbTokensAprService( + arbitrumNetworkData.ybAprConfig, arbitrumNetworkData.chain.prismaId, arbitrumNetworkData.balancer.yieldProtocolFeePercentage, arbitrumNetworkData.balancer.swapProtocolFeePercentage, diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index 8cf724a68..d00e1b3e8 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -16,7 +16,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 { env } from '../../app/env'; -import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; +import { YbTokensAprService } from '../pool/lib/apr-data-sources/yb-tokens-apr.service'; import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const avalancheNetworkData: NetworkData = { @@ -91,7 +91,7 @@ const avalancheNetworkData: NetworkData = { poolIdsToExclude: [], }, }, - ibAprConfig: { + ybAprConfig: { aave: { v3: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v3-avalanche', @@ -141,16 +141,6 @@ const avalancheNetworkData: NetworkData = { }, }, }, - ankr: { - sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', - tokens: { - ankrAVAX: { - address: '0xc3344870d52688874b06d844e0c36cc39fc727f6', - serviceName: 'avax', - isIbYield: true, - }, - }, - }, defaultHandlers: { sAVAX: { tokenAddress: '0x2b2c81e08f1af8835a78bb2a90ae924ace0ea4be', @@ -173,6 +163,12 @@ const avalancheNetworkData: NetworkData = { // M * -12 = A (M is monthly rate and A is APR) => (M/x) = (A/100) => (A / -12x) = (A / 100) [replacing M by A/-12] => x = 100/-12 = -8,33333 scale: -8.3333, }, + ankrAVAX: { + tokenAddress: '0xc3344870d52688874b06d844e0c36cc39fc727f6', + sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', + path: 'services.{serviceName == "avax"}.apy', + isIbYield: true, + }, }, }, beefy: { @@ -209,8 +205,8 @@ export const avalancheNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: avalancheNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - avalancheNetworkData.ibAprConfig, + new YbTokensAprService( + avalancheNetworkData.ybAprConfig, avalancheNetworkData.chain.prismaId, avalancheNetworkData.balancer.yieldProtocolFeePercentage, avalancheNetworkData.balancer.swapProtocolFeePercentage, diff --git a/modules/network/base.ts b/modules/network/base.ts index 43344f5b5..28c6a7f64 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -15,7 +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'; +import { YbTokensAprService } from '../pool/lib/apr-data-sources/yb-tokens-apr.service'; import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const baseNetworkData: NetworkData = { @@ -66,7 +66,7 @@ const baseNetworkData: NetworkData = { swapProtocolFeePercentage: 0.5, yieldProtocolFeePercentage: 0.5, }, - ibAprConfig: { + ybAprConfig: { defaultHandlers: { cbETH: { tokenAddress: '0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22', @@ -129,8 +129,8 @@ export const baseNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: baseNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - baseNetworkData.ibAprConfig, + new YbTokensAprService( + baseNetworkData.ybAprConfig, baseNetworkData.chain.prismaId, baseNetworkData.balancer.yieldProtocolFeePercentage, baseNetworkData.balancer.swapProtocolFeePercentage, diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index ff3a5510c..36549c936 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -24,7 +24,7 @@ import { SanityContentService } from '../content/sanity-content.service'; 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'; +import { YbTokensAprService } from '../pool/lib/apr-data-sources/yb-tokens-apr.service'; import { BeetswarsGaugeVotingAprService } from '../pool/lib/apr-data-sources/fantom/beetswars-gauge-voting-apr'; import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; import { SftmxSubgraphService } from '../subgraphs/sftmx-subgraph/sftmx.service'; @@ -155,22 +155,7 @@ const fantomNetworkData: NetworkData = { poolIdsToExclude: [], }, }, - ibAprConfig: { - ankr: { - sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', - tokens: { - ankrETH: { - address: '0x12d8ce035c5de3ce39b1fdd4c1d5a745eaba3b8c', - serviceName: 'eth', - isIbYield: true, - }, - ankrFTM: { - address: '0xcfc785741dc0e98ad4c9f6394bb9d43cd1ef5179', - serviceName: 'ftm', - isIbYield: true, - }, - }, - }, + ybAprConfig: { // sftmx: { // tokens: { // sftmx: { @@ -246,6 +231,20 @@ const fantomNetworkData: NetworkData = { isIbYield: true, }, }, + defaultHandlers: { + ankrETH: { + tokenAddress: '0x12d8ce035c5de3ce39b1fdd4c1d5a745eaba3b8c', + sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', + path: 'services.{serviceName == "eth"}.apy', + isIbYield: true, + }, + ankrFTM: { + tokenAddress: '0xcfc785741dc0e98ad4c9f6394bb9d43cd1ef5179', + sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', + path: 'services.{serviceName == "ftm"}.apy', + isIbYield: true, + }, + }, }, copper: { proxyAddress: '0xbc8a71c75ffbd2807c021f4f81a8832392def93c', @@ -259,10 +258,6 @@ const fantomNetworkData: NetworkData = { stader: { sFtmxContract: '0xd7028092c830b5c8fce061af2e593413ebbc1fc1', }, - ankr: { - ankrFtmContract: '0xcfc785741dc0e98ad4c9f6394bb9d43cd1ef5179', - ankrEthContract: '0x12d8ce035c5de3ce39b1fdd4c1d5a745eaba3b8c', - }, datastudio: { main: { user: 'datafeed-service@datastudio-366113.iam.gserviceaccount.com', @@ -294,8 +289,8 @@ export const fantomNetworkConfig: NetworkConfig = { contentService: new SanityContentService(fantomNetworkData.chain.prismaId), provider: new ethers.providers.JsonRpcProvider({ url: fantomNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - fantomNetworkData.ibAprConfig, + new YbTokensAprService( + fantomNetworkData.ybAprConfig, fantomNetworkData.chain.prismaId, fantomNetworkData.balancer.yieldProtocolFeePercentage, fantomNetworkData.balancer.swapProtocolFeePercentage, diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index 8323dd363..fba9f6584 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -16,7 +16,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 { env } from '../../app/env'; -import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; +import { YbTokensAprService } from '../pool/lib/apr-data-sources/yb-tokens-apr.service'; import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const gnosisNetworkData: NetworkData = { @@ -89,7 +89,7 @@ const gnosisNetworkData: NetworkData = { poolIdsToExclude: [], }, }, - ibAprConfig: { + ybAprConfig: { defaultHandlers: { wstETH: { tokenAddress: '0x6c76971f98945ae98dd7d4dfca8711ebea946ea6', @@ -133,8 +133,8 @@ export const gnosisNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: gnosisNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - gnosisNetworkData.ibAprConfig, + new YbTokensAprService( + gnosisNetworkData.ybAprConfig, gnosisNetworkData.chain.prismaId, gnosisNetworkData.balancer.yieldProtocolFeePercentage, gnosisNetworkData.balancer.swapProtocolFeePercentage, diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index aa4b6b7de..3084758d9 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.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 { YbTokensAprService } from '../pool/lib/apr-data-sources/yb-tokens-apr.service'; import { env } from '../../app/env'; import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; @@ -114,7 +114,7 @@ const data: NetworkData = { ], }, }, - ibAprConfig: { + ybAprConfig: { aave: { v2: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/protocol-v2', @@ -180,16 +180,6 @@ const data: NetworkData = { }, }, }, - ankr: { - sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', - tokens: { - ankrETH: { - address: '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb', - serviceName: 'eth', - isIbYield: true, - }, - }, - }, bloom: { tokens: { tbyFeb1924: { @@ -258,6 +248,8 @@ const data: NetworkData = { }, }, }, + stakewise: '0xf1c9acdc66974dfb6decb12aa385b9cd01190e38', + etherfi: '0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee', defaultHandlers: { vETH: { tokenAddress: '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f', @@ -331,6 +323,12 @@ const data: NetworkData = { isIbYield: true, scale: 1, }, + ankrETH: { + tokenAddress: '0xe95a203b1a91a908f9b9ce46459d101078c2c3cb', + sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', + path: 'services.{serviceName == "eth"}.apy', + isIbYield: true, + }, }, }, beefy: { @@ -367,8 +365,8 @@ export const mainnetNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: data.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - data.ibAprConfig, + new YbTokensAprService( + data.ybAprConfig, data.chain.prismaId, data.balancer.yieldProtocolFeePercentage, data.balancer.swapProtocolFeePercentage, diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index 9127ac3a4..efeaabc08 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -6,7 +6,7 @@ import { TokenPriceHandler } from '../token/token-types'; import { BaseProvider } from '@ethersproject/providers'; import { GqlChain } from '../../schema'; import { ContentService } from '../content/content-types'; -import { IbAprConfig } from './apr-config-types'; +import { YbAprConfig } from './apr-config-types'; import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; import { SftmxSubgraphService } from '../subgraphs/sftmx-subgraph/sftmx.service'; @@ -113,7 +113,7 @@ export interface NetworkData { address: string; excludedFarmIds: string[]; }; - ibAprConfig: IbAprConfig; + ybAprConfig: YbAprConfig; reliquary?: { address: string; excludedFarmIds: string[]; @@ -137,10 +137,6 @@ export interface NetworkData { spooky?: { xBooContract: string; }; - ankr?: { - ankrFtmContract: string; - ankrEthContract: string; - }; overnight?: { aprEndpoint: string; }; diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index 34740a0b7..2faa94d8f 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -16,7 +16,7 @@ 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 { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; +import { YbTokensAprService } from '../pool/lib/apr-data-sources/yb-tokens-apr.service'; import { env } from '../../app/env'; import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; @@ -102,17 +102,7 @@ const optimismNetworkData: NetworkData = { poolIdsToExclude: [], }, }, - ibAprConfig: { - ankr: { - sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', - tokens: { - ankrETH: { - address: '0xe05a08226c49b636acf99c40da8dc6af83ce5bb3', - serviceName: 'eth', - isIbYield: true, - }, - }, - }, + ybAprConfig: { beefy: { sourceUrl: 'https://api.beefy.finance/apy/breakdown?_=', tokens: { @@ -208,6 +198,25 @@ const optimismNetworkData: NetworkData = { path: 'sfrxethApr', isIbYield: true, }, + sFRAX: { + tokenAddress: '0x2dd1b4d4548accea497050619965f91f78b3b532', + sourceUrl: 'https://api.frax.finance/v2/frax/sfrax/summary/history?range=1d', + path: 'items.0.sfraxApr', + isIbYield: true, + }, + stERN: { + tokenAddress: '0x3ee6107d9c93955acbb3f39871d32b02f82b78ab', + sourceUrl: + 'https://2ch9hbg8hh.execute-api.us-east-1.amazonaws.com/dev/api/vault/0x3eE6107d9C93955acBb3f39871D32B02F82B78AB:0xa', + path: 'data.yields.apy', + isIbYield: true, + }, + ankrETH: { + tokenAddress: '0xe05a08226c49b636acf99c40da8dc6af83ce5bb3', + sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', + path: 'services.{serviceName == "eth"}.apy', + isIbYield: true, + }, }, }, beefy: { @@ -253,8 +262,8 @@ export const optimismNetworkConfig: NetworkConfig = { contentService: new SanityContentService(optimismNetworkData.chain.prismaId), provider: new ethers.providers.JsonRpcProvider({ url: optimismNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - optimismNetworkData.ibAprConfig, + new YbTokensAprService( + optimismNetworkData.ybAprConfig, optimismNetworkData.chain.prismaId, optimismNetworkData.balancer.yieldProtocolFeePercentage, optimismNetworkData.balancer.swapProtocolFeePercentage, diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index 8598d6930..ae8f88d55 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.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 { YbTokensAprService } from '../pool/lib/apr-data-sources/yb-tokens-apr.service'; import { env } from '../../app/env'; import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; @@ -93,7 +93,7 @@ const polygonNetworkData: NetworkData = { poolIdsToExclude: [], }, }, - ibAprConfig: { + ybAprConfig: { aave: { v2: { subgraphUrl: 'https://api.thegraph.com/subgraphs/name/aave/aave-v2-matic', @@ -250,8 +250,8 @@ export const polygonNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: polygonNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - polygonNetworkData.ibAprConfig, + new YbTokensAprService( + polygonNetworkData.ybAprConfig, polygonNetworkData.chain.prismaId, polygonNetworkData.balancer.yieldProtocolFeePercentage, polygonNetworkData.balancer.swapProtocolFeePercentage, diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index b540565dd..d5e229b87 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -16,7 +16,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'; +import { YbTokensAprService } from '../pool/lib/apr-data-sources/yb-tokens-apr.service'; import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const zkevmNetworkData: NetworkData = { @@ -95,7 +95,7 @@ const zkevmNetworkData: NetworkData = { poolIdsToExclude: [], }, }, - ibAprConfig: { + ybAprConfig: { ovix: { tokens: { USDT: { @@ -121,6 +121,12 @@ const zkevmNetworkData: NetworkData = { path: 'rethAPR', isIbYield: true, }, + ankrETH: { + tokenAddress: '0x12d8ce035c5de3ce39b1fdd4c1d5a745eaba3b8c', + sourceUrl: 'https://api.staking.ankr.com/v1alpha/metrics', + path: 'services.{serviceName == "eth"}.apy', + isIbYield: true, + }, }, }, beefy: { @@ -157,8 +163,8 @@ export const zkevmNetworkConfig: NetworkConfig = { contentService: new GithubContentService(), provider: new ethers.providers.JsonRpcProvider({ url: zkevmNetworkData.rpcUrl, timeout: 60000 }), poolAprServices: [ - new IbTokensAprService( - zkevmNetworkData.ibAprConfig, + new YbTokensAprService( + zkevmNetworkData.ybAprConfig, zkevmNetworkData.chain.prismaId, zkevmNetworkData.balancer.yieldProtocolFeePercentage, zkevmNetworkData.balancer.swapProtocolFeePercentage, 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 a6c64e39c..c0e93d27f 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 @@ -11,7 +11,7 @@ export class BoostedPoolAprService implements PoolAprService { 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 boostedPools = pools.filter((pool) => pool.type === 'COMPOSABLE_STABLE' || pool.type === 'WEIGHTED'); const boostedPoolsWithNestedPool = await prisma.prismaPool.findMany({ where: { chain: networkContext.chain, id: { in: boostedPools.map((pool) => pool.id) } }, @@ -56,11 +56,11 @@ export class BoostedPoolAprService implements PoolAprService { //for phantom stable pools, the linear apr items have already been set in PhantomStableAprService, //so we're only concerned with finding the apr for phantom stable BPTs nested inside of //this phantom stable - if (pool.type === 'PHANTOM_STABLE') { - return token.nestedPool?.type === 'PHANTOM_STABLE'; + if (pool.type === 'COMPOSABLE_STABLE') { + return token.nestedPool?.type === 'COMPOSABLE_STABLE'; } - return token.nestedPool?.type === 'LINEAR' || token.nestedPool?.type === 'PHANTOM_STABLE'; + return token.nestedPool?.type === 'LINEAR' || token.nestedPool?.type === 'COMPOSABLE_STABLE'; }); const poolIds = tokens.map((token) => token.nestedPool?.id || ''); @@ -96,7 +96,7 @@ export class BoostedPoolAprService implements PoolAprService { if ( collectsYieldFee(pool) && //nested phantom stables already have the yield fee removed - token.nestedPool.type !== 'PHANTOM_STABLE' && + token.nestedPool.type !== 'COMPOSABLE_STABLE' && // nested tokens/bpts that dont have a rate provider, we don't take any fees token.dynamicData.priceRate !== '1.0' ) { 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 deleted file mode 100644 index 86c4e446d..000000000 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ankr-apr-handler.ts +++ /dev/null @@ -1,44 +0,0 @@ -import axios from 'axios'; -import * as Sentry from '@sentry/node'; -import { AprHandler } from '../ib-linear-apr-handlers'; -import { AnkrAprConfig } from '../../../../../network/apr-config-types'; - -export class AnkrAprHandler implements AprHandler { - tokens: { - [underlyingAssetName: string]: { - address: string; - serviceName: string; - isIbYield?: boolean; - }; - }; - url: string; - - constructor(config: AnkrAprConfig) { - this.tokens = config.tokens; - this.url = config.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, isIbYield }) => { - const service = services.find((service) => service.serviceName === serviceName); - if (!service) { - return [address, 0]; - } - return [address, { - apr: parseFloat(service.apy) / 1e2, - isIbYield: isIbYield ?? false, - }]; - }), - ); - 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/maker-gnosis-apr-handler.ts b/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-gnosis-apr-handler.ts deleted file mode 100644 index a89220193..000000000 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-gnosis-apr-handler.ts +++ /dev/null @@ -1,36 +0,0 @@ -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' - } - } - } -} 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 fff2dc917..de75b1b46 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 @@ -12,7 +12,7 @@ export class PhantomStableAprService implements PoolAprService { } public async updateAprForPools(pools: PrismaPoolWithTokens[]): Promise { - const phantomStablePools = pools.filter((pool) => pool.type === 'PHANTOM_STABLE'); + const phantomStablePools = pools.filter((pool) => pool.type === 'COMPOSABLE_STABLE'); const phantomStablePoolsExpanded = await prisma.prismaPool.findMany({ ...prismaPoolWithExpandedNesting, 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/yb-apr-handlers/index.ts similarity index 92% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/index.ts index adea7ee34..167dd23d6 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/ib-linear-apr-handlers.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/index.ts @@ -1,10 +1,9 @@ import * as sources from './sources'; -import { IbAprConfig } from '../../../../network/apr-config-types'; +import { YbAprConfig } from '../../../../network/apr-config-types'; import { Chain } from '@prisma/client'; const sourceToHandler = { aave: sources.AaveAprHandler, - ankr: sources.AnkrAprHandler, beefy: sources.BeefyAprHandler, bloom: sources.BloomAprHandler, sftmx: sources.SftmxAprHandler, @@ -19,19 +18,21 @@ const sourceToHandler = { tranchess: sources.TranchessAprHandler, yearn: sources.YearnAprHandler, defaultHandlers: sources.DefaultAprHandler, + stakewise: sources.Stakewise, + etherfi: sources.Etherfi, }; -export class IbLinearAprHandlers { +export class YbAprHandlers { private handlers: AprHandler[] = []; fixedAprTokens?: { [tokenName: string]: { address: string; apr: number; group?: string; isIbYield?: boolean } }; - constructor(aprConfig: IbAprConfig, private chain?: Chain) { + constructor(aprConfig: YbAprConfig, private chain?: Chain) { const { fixedAprHandler, ...config } = aprConfig; this.handlers = this.buildAprHandlers(config); this.fixedAprTokens = fixedAprHandler; } - private buildAprHandlers(aprConfig: IbAprConfig) { + private buildAprHandlers(aprConfig: YbAprConfig) { const handlers: AprHandler[] = []; // Add handlers from global configuration 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/yb-apr-handlers/sources/aave-apr-handler.ts similarity index 98% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/aave-apr-handler.ts index 5312b1985..3286759c4 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/aave-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/aave-apr-handler.ts @@ -1,6 +1,6 @@ import axios from 'axios'; import * as Sentry from '@sentry/node'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; export class AaveAprHandler implements AprHandler { tokens: { diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCrypt.json b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/ReaperCrypt.json similarity index 100% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCrypt.json rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/ReaperCrypt.json diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCryptStrategy.json b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/ReaperCryptStrategy.json similarity index 100% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/ReaperCryptStrategy.json rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/ReaperCryptStrategy.json diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/bloom-bps-feed.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/bloom-bps-feed.ts similarity index 100% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/bloom-bps-feed.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/bloom-bps-feed.ts diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/maker-pot.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/maker-pot.ts similarity index 100% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/maker-pot.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/maker-pot.ts diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/oErc20.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/oErc20.ts similarity index 100% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/oErc20.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/oErc20.ts diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/reaperStrategy.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/reaperStrategy.ts similarity index 100% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/reaperStrategy.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/reaperStrategy.ts diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/tesseraPool.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/tesseraPool.ts similarity index 100% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/abis/tesseraPool.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/abis/tesseraPool.ts 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/yb-apr-handlers/sources/beefy-apr-handler.ts similarity index 92% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/beefy-apr-handler.ts index 98e44bea3..147f55ea2 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/beefy-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/beefy-apr-handler.ts @@ -1,5 +1,5 @@ import { BeefyAprConfig } from '../../../../../network/apr-config-types'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import axios from 'axios'; import * as Sentry from '@sentry/node'; @@ -28,8 +28,8 @@ export class BeefyAprHandler implements AprHandler { [address]: { apr, isIbYield: isIbYield ?? false, - group: this.group - } + group: this.group, + }, }; }); 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/yb-apr-handlers/sources/bloom-apr-handler.ts similarity index 89% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/bloom-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/bloom-apr-handler.ts index 797cb390b..3dc7c7443 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/bloom-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/bloom-apr-handler.ts @@ -1,11 +1,11 @@ -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { BloomAprConfig } from '../../../../../network/apr-config-types'; import { getContractAt } from '../../../../../web3/contract'; import { abi as bloomBpsFeed } from './abis/bloom-bps-feed'; import * as Sentry from '@sentry/node'; export class BloomAprHandler implements AprHandler { - group = "DEFAULT"; + group = 'DEFAULT'; tokens: BloomAprConfig['tokens']; @@ -14,7 +14,7 @@ export class BloomAprHandler implements AprHandler { } async getAprs() { - const aprs: { [p: string]: { apr: number; isIbYield: boolean, group?: string } } = {}; + 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); @@ -26,7 +26,7 @@ export class BloomAprHandler implements AprHandler { aprs[address] = { apr: tokenApr, isIbYield: isIbYield ?? false, - group: this.group + group: this.group, }; } catch (error) { console.error(`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/yb-apr-handlers/sources/default-apr-handler.ts similarity index 71% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/default-apr-handler.ts index 3e393f780..839e8c518 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/default-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/default-apr-handler.ts @@ -1,6 +1,6 @@ import axios from 'axios'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import * as Sentry from '@sentry/node'; export class DefaultAprHandler implements AprHandler { @@ -37,8 +37,8 @@ export class DefaultAprHandler implements AprHandler { [this.tokenAddress]: { apr: scaledValue, isIbYield: this.isIbYield ?? false, - group: this.group - } + group: this.group, + }, }; } catch (error) { console.error(`Failed to fetch APRs in url ${this.url}:`, error); @@ -47,15 +47,20 @@ export class DefaultAprHandler implements AprHandler { } } - getValueFromPath(obj: any, path: string) { - if (path === '') { - return obj; - } + // Get a specific value from a JSON object based on a path + getValueFromPath = (obj: any, path: string) => { const parts = path.split('.'); let value = obj; for (const part of parts) { - value = value[part]; + if (part[0] === '{' && part[part.length - 1] === '}') { + const selector = part.slice(1, -1); + const variableName = selector.split('==')[0].trim(); + const variableValue = selector.split('==')[1].trim().replace(/"/g, ''); + value = value.find((v: any) => v[variableName] === variableValue); + } else { + value = value[part]; + } } return value; - } + }; } diff --git a/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/etherfi-apr-handler.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/etherfi-apr-handler.ts new file mode 100644 index 000000000..5d646cc01 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/etherfi-apr-handler.ts @@ -0,0 +1,50 @@ +const url = 'https://api.studio.thegraph.com/proxy/41778/syko-dev-mainnet/v0.0.3'; + +const query = ` + { + rebaseEventLinkedLists { + latest_aprs + } + } +`; + +const requestQuery = { + query, +}; + +interface Response { + data: { + rebaseEventLinkedLists: { + latest_aprs: string[]; + }[]; + }; +} + +export class Etherfi { + constructor(private tokenAddress: string) {} + + async getAprs() { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestQuery), + }); + + const { + data: { + rebaseEventLinkedLists: [{ latest_aprs }], + }, + } = (await response.json()) as Response; + + const avgApr = latest_aprs.map((apr) => Number(apr)).reduce((acc, apr) => acc + apr, 0) / latest_aprs.length; + + return { + [this.tokenAddress]: { + apr: avgApr / 10000, + isIbYield: true, + }, + }; + } +} 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/yb-apr-handlers/sources/euler-apr-handler.ts similarity index 97% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/euler-apr-handler.ts index 960954f78..25310f5f6 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/euler-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/euler-apr-handler.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { EulerAprConfig } from '../../../../../network/apr-config-types'; import * as Sentry from '@sentry/node'; 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/yb-apr-handlers/sources/gearbox-apr-handler.ts similarity index 96% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/gearbox-apr-handler.ts index 490d6f441..505dd69b8 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/gearbox-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/gearbox-apr-handler.ts @@ -1,7 +1,7 @@ import axios from 'axios'; import * as Sentry from '@sentry/node'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { GearBoxAprConfig } from '../../../../../network/apr-config-types'; export class GearboxAprHandler implements AprHandler { 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/yb-apr-handlers/sources/idle-apr-handler.ts similarity index 84% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/idle-apr-handler.ts index 24857b410..95128ee15 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/idle-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/idle-apr-handler.ts @@ -1,6 +1,6 @@ import axios from 'axios'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { IdleAprConfig } from '../../../../../network/apr-config-types'; import * as Sentry from '@sentry/node'; @@ -32,11 +32,14 @@ export class IdleAprHandler implements AprHandler { }); const [json] = data as { idleRate: string }[]; const value = Number(json.idleRate) / 1e20; - return [wrapped4626Address, { - apr: value, - isIbYield: isIbYield ?? false, - group: this.group, - }]; + 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/yb-apr-handlers/sources/index.ts similarity index 88% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/index.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/index.ts index 19f3c7453..74bb6844d 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/index.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/index.ts @@ -1,5 +1,4 @@ export * from './aave-apr-handler'; -export * from './ankr-apr-handler'; export * from './sftmx-apr-handler'; export * from './default-apr-handler'; export * from './euler-apr-handler'; @@ -15,3 +14,5 @@ export * from './beefy-apr-handler'; export * from './maker-apr-handler'; export * as MakerGnosis from './maker-gnosis-apr-handler'; export * from './bloom-apr-handler'; +export * from './stakewise-apr-handler'; +export * from './etherfi-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/yb-apr-handlers/sources/maker-apr-handler.ts similarity index 92% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/maker-apr-handler.ts index 0b47bf9be..6a8885e3d 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/maker-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/maker-apr-handler.ts @@ -1,4 +1,4 @@ -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { MakerAprConfig } from '../../../../../network/apr-config-types'; import { getContractAt } from '../../../../../web3/contract'; import { abi as makerPotAbi } from './abis/maker-pot'; @@ -19,7 +19,7 @@ export class MakerAprHandler implements AprHandler { } async getAprs() { - const aprs: { [p: string]: { apr: number; isIbYield: boolean, group: string } } = {}; + 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); @@ -31,7 +31,7 @@ export class MakerAprHandler implements AprHandler { aprs[address] = { apr: tokenApr, isIbYield: isIbYield ?? false, - group: this.group + group: this.group, }; } catch (error) { console.error(`Maker APR Failed for token ${address}: `, error); diff --git a/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/maker-gnosis-apr-handler.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/maker-gnosis-apr-handler.ts new file mode 100644 index 000000000..b52955fd7 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/maker-gnosis-apr-handler.ts @@ -0,0 +1,36 @@ +import { AprHandler } from '..'; +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', + }, + }; + } +} 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/yb-apr-handlers/sources/ovix-apr-handler.ts similarity index 96% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/ovix-apr-handler.ts index a8206b52d..a96288f72 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/ovix-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/ovix-apr-handler.ts @@ -2,7 +2,7 @@ import { BigNumber, Contract } from 'ethers'; import { abi } from './abis/oErc20'; import * as Sentry from '@sentry/node'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { networkContext } from '../../../../../network/network-context.service'; import { OvixAprConfig } from '../../../../../network/apr-config-types'; 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/yb-apr-handlers/sources/reaper-crypt-apr-handler.ts similarity index 99% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/reaper-crypt-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/reaper-crypt-apr-handler.ts index 6acf75005..d454deb16 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/yb-apr-handlers/sources/reaper-crypt-apr-handler.ts @@ -1,4 +1,4 @@ -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { getContractAt } from '../../../../../web3/contract'; import ReaperCryptStrategyAbi from './abis/ReaperCryptStrategy.json'; import axios from 'axios'; diff --git a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/sftmx-apr-handler.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/sftmx-apr-handler.ts similarity index 98% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/sftmx-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/sftmx-apr-handler.ts index 6c805269e..49c590d32 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/sftmx-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/sftmx-apr-handler.ts @@ -1,5 +1,5 @@ import * as Sentry from '@sentry/node'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { SftmxAprConfig } from '../../../../../network/apr-config-types'; import { BigNumber, ethers } from 'ethers'; import { getContractAt } from '../../../../../web3/contract'; diff --git a/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/stakewise-apr-handler.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/stakewise-apr-handler.ts new file mode 100644 index 000000000..ed87a7266 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/stakewise-apr-handler.ts @@ -0,0 +1,48 @@ +const url = 'https://mainnet-graph.stakewise.io/subgraphs/name/stakewise/stakewise'; + +const query = ` + { + osTokens { + apy + } + } +`; + +const requestQuery = { + query, +}; + +interface Response { + data: { + osTokens: { + apy: string[]; + }[]; + }; +} + +export class Stakewise { + constructor(private tokenAddress: string) {} + + async getAprs() { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestQuery), + }); + + const { + data: { + osTokens: [{ apy }], + }, + } = (await response.json()) as Response; + + return { + [this.tokenAddress]: { + apr: Number(apy) / 100, + isIbYield: true, + }, + }; + } +} 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/yb-apr-handlers/sources/tessera-apr-handler.ts similarity index 84% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/tessera-apr-handler.ts index f1d67f18f..ff3e94721 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tessera-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/tessera-apr-handler.ts @@ -1,7 +1,7 @@ import { Contract } from 'ethers'; import { abi } from './abis/tesseraPool'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { networkContext } from '../../../../../network/network-context.service'; import { TesseraAprConfig } from '../../../../../network/apr-config-types'; import * as Sentry from '@sentry/node'; @@ -31,11 +31,14 @@ 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, - group: this.group - }]); + 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/yb-apr-handlers/sources/tetu-apr-handler.ts similarity index 96% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/tetu-apr-handler.ts index d42480aac..bb281341f 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tetu-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/tetu-apr-handler.ts @@ -1,6 +1,6 @@ import axios from 'axios'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { TetuAprConfig } from '../../../../../network/apr-config-types'; import * as Sentry from '@sentry/node'; 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/yb-apr-handlers/sources/tranchess-apr-handler.ts similarity index 94% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/tranchess-apr-handler.ts index aec8047ee..e60c21bc3 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/tranchess-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/tranchess-apr-handler.ts @@ -1,6 +1,6 @@ import axios from 'axios'; -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import { TranchessAprConfig } from '../../../../../network/apr-config-types'; import * as Sentry from '@sentry/node'; @@ -33,7 +33,7 @@ export class TranchessAprHandler implements AprHandler { { apr: (365 * Number(weeklyAveragePnlPercentage)) / 1e18, isIbYield: isIbYield ?? false, - group: this.group + group: this.group, }, ]; }); 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/yb-apr-handlers/sources/yearn-apr-handler.ts similarity index 76% rename from modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts rename to modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/yearn-apr-handler.ts index ac519fad0..756bbcaba 100644 --- a/modules/pool/lib/apr-data-sources/ib-linear-apr-handlers/sources/yearn-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/yearn-apr-handler.ts @@ -1,4 +1,4 @@ -import { AprHandler } from '../ib-linear-apr-handlers'; +import { AprHandler } from '..'; import axios from 'axios'; import { YearnAprConfig } from '../../../../../network/apr-config-types'; import * as Sentry from '@sentry/node'; @@ -17,11 +17,14 @@ export class YearnAprHandler implements AprHandler { 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, - group: this.group - }]; + 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/yb-tokens-apr.service.ts similarity index 84% rename from modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts rename to modules/pool/lib/apr-data-sources/yb-tokens-apr.service.ts index d689eecd7..d7ad92276 100644 --- a/modules/pool/lib/apr-data-sources/ib-tokens-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/yb-tokens-apr.service.ts @@ -3,32 +3,32 @@ import { PrismaPoolWithTokens } from '../../../../prisma/prisma-types'; import { prisma } from '../../../../prisma/prisma-client'; import { prismaBulkExecuteOperations } from '../../../../prisma/prisma-util'; import { Chain, PrismaPoolAprItemGroup, PrismaPoolAprType, PrismaPoolLinearData } from '@prisma/client'; -import { IbLinearAprHandlers as IbTokensAprHandlers, TokenApr } from './ib-linear-apr-handlers/ib-linear-apr-handlers'; +import { YbAprHandlers, TokenApr } from './yb-apr-handlers'; import { tokenService } from '../../../token/token.service'; import { collectsYieldFee } from '../pool-utils'; -import { IbAprConfig } from '../../../network/apr-config-types'; +import { YbAprConfig } from '../../../network/apr-config-types'; -export class IbTokensAprService implements PoolAprService { - private ibTokensAprHandlers: IbTokensAprHandlers; +export class YbTokensAprService implements PoolAprService { + private ybTokensAprHandlers: YbAprHandlers; constructor( - aprConfig: IbAprConfig, + aprConfig: YbAprConfig, private chain: Chain, private defaultYieldFee: number, - private defaultSwapFee: number + private defaultSwapFee: number, ) { - this.ibTokensAprHandlers = new IbTokensAprHandlers(aprConfig, chain); + this.ybTokensAprHandlers = new YbAprHandlers(aprConfig, chain); } getAprServiceName(): string { - return 'IbTokensAprService'; + return 'YbTokensAprService'; } public async updateAprForPools(pools: PrismaPoolWithTokens[]): Promise { const operations: any[] = []; const tokenPrices = await tokenService.getTokenPrices(); const aprs = await this.fetchYieldTokensApr(); - const poolsWithIbTokens = pools.filter((pool) => { + const poolsWithYbTokens = pools.filter((pool) => { return pool.tokens.find((token) => { return Array.from(aprs.keys()) .map((key) => key.toLowerCase()) @@ -36,8 +36,8 @@ export class IbTokensAprService implements PoolAprService { }); }); - const poolsWithIbTokensExpanded = await prisma.prismaPool.findMany({ - where: { chain: this.chain, id: { in: poolsWithIbTokens.map((pool) => pool.id) } }, + const poolsWithYbTokensExpanded = await prisma.prismaPool.findMany({ + where: { chain: this.chain, id: { in: poolsWithYbTokens.map((pool) => pool.id) } }, include: { dynamicData: true, tokens: { @@ -50,7 +50,7 @@ export class IbTokensAprService implements PoolAprService { }, }); - for (const pool of poolsWithIbTokensExpanded) { + for (const pool of poolsWithYbTokensExpanded) { if (!pool.dynamicData) { continue; } @@ -115,7 +115,7 @@ export class IbTokensAprService implements PoolAprService { } private async fetchYieldTokensApr(): Promise> { - const data = await this.ibTokensAprHandlers.fetchAprsFromAllHandlers(); + const data = await this.ybTokensAprHandlers.fetchAprsFromAllHandlers(); return new Map( data .filter((tokenApr) => { diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index 6b98fae01..fac3005a0 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -13,6 +13,7 @@ import { GqlBalancePoolAprSubItem, GqlPoolDynamicData, GqlPoolFeaturedPoolGroup, + GqlPoolFeaturedPool, GqlPoolGyro, GqlPoolInvestConfig, GqlPoolInvestOption, @@ -44,8 +45,8 @@ import { parseUnits } from 'ethers/lib/utils'; import { formatFixed } from '@ethersproject/bignumber'; import { BalancerChainIds, BeethovenChainIds, chainIdToChain, chainToIdMap } from '../../network/network-config'; import { GithubContentService } from '../../content/github-content.service'; -import SanityClientConstructor from '@sanity/client'; import { SanityContentService } from '../../content/sanity-content.service'; +import { FeaturedPool } from '../../content/content-types'; export class PoolGqlLoaderService { public async getPool(id: string, chain: Chain, userAddress?: string): Promise { @@ -160,10 +161,7 @@ export class PoolGqlLoaderService { public async getFeaturedPoolGroups(chains: Chain[]): Promise { const featuredPoolGroups = []; - if (chains.some((chain) => BalancerChainIds.includes(chainToIdMap[chain]))) { - const githubContentService = new GithubContentService(); - featuredPoolGroups.push(...(await githubContentService.getFeaturedPoolGroups(chains))); - } else if (chains.some((chain) => BeethovenChainIds.includes(chainToIdMap[chain]))) { + if (chains.some((chain) => BeethovenChainIds.includes(chainToIdMap[chain]))) { const sanityContentService = new SanityContentService('FANTOM'); featuredPoolGroups.push(...(await sanityContentService.getFeaturedPoolGroups(chains))); } @@ -202,6 +200,32 @@ export class PoolGqlLoaderService { }); } + public async getFeaturedPools(chains: Chain[]): Promise { + const featuredPoolsFromService: FeaturedPool[] = []; + if (chains.some((chain) => BalancerChainIds.includes(chainToIdMap[chain]))) { + const githubContentService = new GithubContentService(); + featuredPoolsFromService.push(...(await githubContentService.getFeaturedPools(chains))); + } + if (chains.some((chain) => BeethovenChainIds.includes(chainToIdMap[chain]))) { + // chain in constructor doesnt matter for this query as we pass the chain in the param + const sanityContentService = new SanityContentService('FANTOM'); + featuredPoolsFromService.push(...(await sanityContentService.getFeaturedPools(chains))); + } + + const featuredPools: GqlPoolFeaturedPool[] = []; + + for (const contentPool of featuredPoolsFromService) { + const pool = await this.getPool(contentPool.poolId.toLowerCase(), contentPool.chain); + featuredPools.push({ + poolId: contentPool.poolId, + primary: contentPool.primary, + pool: pool, + }); + } + + return featuredPools; + } + private mapQueryArgsToPoolQuery(args: QueryPoolGetPoolsArgs): Prisma.PrismaPoolFindManyArgs { let orderBy: Prisma.PrismaPoolOrderByWithRelationInput = {}; const orderDirection = args.orderDirection || undefined; diff --git a/modules/pool/lib/pool-snapshot.service.ts b/modules/pool/lib/pool-snapshot.service.ts index f46e8c757..8e61477ca 100644 --- a/modules/pool/lib/pool-snapshot.service.ts +++ b/modules/pool/lib/pool-snapshot.service.ts @@ -112,7 +112,7 @@ export class PoolSnapshotService { const poolsWithoutSnapshots = await prisma.prismaPool.findMany({ where: { OR: [ - { type: 'PHANTOM_STABLE', chain: this.chain }, + { type: 'COMPOSABLE_STABLE', chain: this.chain }, { tokens: { some: { nestedPoolId: { not: null } } }, chain: this.chain }, ], }, diff --git a/modules/pool/lib/pool-utils.ts b/modules/pool/lib/pool-utils.ts index 321575fd9..b3fbc5d1c 100644 --- a/modules/pool/lib/pool-utils.ts +++ b/modules/pool/lib/pool-utils.ts @@ -9,7 +9,7 @@ type PoolWithTypeAndFactory = { }; export function isStablePool(poolType: PrismaPoolType) { - return poolType === 'STABLE' || poolType === 'META_STABLE' || poolType === 'PHANTOM_STABLE'; + return poolType === 'STABLE' || poolType === 'META_STABLE' || poolType === 'COMPOSABLE_STABLE'; } export function isWeightedPoolV2(pool: PoolWithTypeAndFactory) { diff --git a/modules/pool/lib/staking/gauge-staking.service.ts b/modules/pool/lib/staking/gauge-staking.service.ts index 5b56899df..9919c4a56 100644 --- a/modules/pool/lib/staking/gauge-staking.service.ts +++ b/modules/pool/lib/staking/gauge-staking.service.ts @@ -24,6 +24,8 @@ import type { JsonFragment } from '@ethersproject/abi'; import { Multicaller3 } from '../../../web3/multicaller3'; import { getInflationRate } from '../../../vebal/balancer-token-admin.service'; import _ from 'lodash'; +import { FtmStaking_OrderBy } from '../../../subgraphs/sftmx-subgraph/generated/sftmx-subgraph-types'; +import { total } from './bal-emissions'; interface GaugeRate { /** 1 for old gauges, 2 for gauges receiving cross chain BAL rewards */ @@ -81,15 +83,14 @@ export class GaugeStakingService implements PoolStakingService { ]); } - async syncStakingForPools(pools?: { id: string }[]): Promise { + async syncStakingForPools(): Promise { // Getting data from the DB and subgraph - const poolIds = ( - pools ?? - (await prisma.prismaPool.findMany({ - select: { id: true }, - where: { chain: networkContext.chain }, - })) - ).map((pool) => pool.id); + + const dbPools = await prisma.prismaPool.findMany({ + where: { chain: networkContext.chain }, + include: { staking: { include: { gauge: { include: { rewards: true } } } } }, + }); + const poolIds = dbPools.map((pool) => pool.id); const { pools: subgraphPoolsWithGauges } = await this.gaugeSubgraphService.getPoolsWithGauges(poolIds); const subgraphGauges = subgraphPoolsWithGauges @@ -101,7 +102,7 @@ export class GaugeStakingService implements PoolStakingService { .filter((pool) => pool.preferentialGauge) .map((pool) => pool.preferentialGauge!.id); - const dbGauges = subgraphGauges.map((gauge) => ({ + const gaugesForDb = subgraphGauges.map((gauge) => ({ id: gauge.id, poolId: gauge.poolId!, // we need to set the status based on the preferentialGauge entity on the gaugePool. If it's set there, it's preferential, otherwise it's active (or killed) @@ -130,52 +131,72 @@ export class GaugeStakingService implements PoolStakingService { }, }); - const onchainRates = await this.getOnchainRewardTokensData(dbGauges); + const onchainRates = await this.getOnchainRewardTokensData(gaugesForDb); // Prepare DB operations const operations: any[] = []; + const allDbStakings = dbPools.map((pool) => pool.staking).flat(); + const allDbStakingGauges = dbPools + .map((pool) => pool.staking) + .flat() + .map((gauge) => gauge.gauge); + // DB operations for gauges - for (const gauge of dbGauges) { - operations.push( - prisma.prismaPoolStaking.upsert({ - where: { id_chain: { id: gauge.id, chain: networkContext.chain } }, - create: { - id: gauge.id, - chain: networkContext.chain, - poolId: gauge.poolId, - type: 'GAUGE', - address: gauge.id, - }, - update: {}, - }), - ); - - operations.push( - prisma.prismaPoolStakingGauge.upsert({ - where: { id_chain: { id: gauge.id, chain: networkContext.chain } }, - create: { - id: gauge.id, - stakingId: gauge.id, - gaugeAddress: gauge.id, - chain: networkContext.chain, - status: gauge.status, - version: gauge.version, - workingSupply: onchainRates.find(({ id }) => `${gauge.id}-${this.balAddress}` === id) - ?.workingSupply, - totalSupply: onchainRates.find(({ id }) => id.includes(gauge.id))?.totalSupply, - }, - update: { - status: gauge.status, - version: gauge.version, - workingSupply: onchainRates.find(({ id }) => `${gauge.id}-${this.balAddress}` === id) - ?.workingSupply, - totalSupply: onchainRates.find(({ id }) => id.includes(gauge.id))?.totalSupply, - }, - }), - ); + for (const gauge of gaugesForDb) { + const dbStaking = allDbStakings.find((staking) => staking.id === gauge.id); + if (!dbStaking) { + operations.push( + prisma.prismaPoolStaking.upsert({ + where: { id_chain: { id: gauge.id, chain: networkContext.chain } }, + create: { + id: gauge.id, + chain: networkContext.chain, + poolId: gauge.poolId, + type: 'GAUGE', + address: gauge.id, + }, + update: {}, + }), + ); + } + + const dbStakingGauge = allDbStakingGauges.find((stakingGauge) => stakingGauge?.id === gauge.id); + const workingSupply = onchainRates.find(({ id }) => `${gauge.id}-${this.balAddress}` === id)?.workingSupply; + const totalSupply = onchainRates.find(({ id }) => id.includes(gauge.id))?.totalSupply; + if ( + !dbStakingGauge || + dbStakingGauge.status !== gauge.status || + dbStakingGauge.version !== gauge.version || + dbStakingGauge.workingSupply !== workingSupply || + dbStakingGauge.totalSupply !== totalSupply + ) { + operations.push( + prisma.prismaPoolStakingGauge.upsert({ + where: { id_chain: { id: gauge.id, chain: networkContext.chain } }, + create: { + id: gauge.id, + stakingId: gauge.id, + gaugeAddress: gauge.id, + chain: networkContext.chain, + status: gauge.status, + version: gauge.version, + workingSupply: workingSupply, + totalSupply: totalSupply, + }, + update: { + status: gauge.status, + version: gauge.version, + workingSupply: workingSupply, + totalSupply: totalSupply, + }, + }), + ); + } } + const allStakingGaugeRewards = allDbStakingGauges.map((gauge) => gauge?.rewards).flat(); + // DB operations for gauge reward tokens for (const { id, rewardPerSecond } of onchainRates) { const [gaugeId, tokenAddress] = id.toLowerCase().split('-'); @@ -188,24 +209,28 @@ export class GaugeStakingService implements PoolStakingService { continue; } - operations.push( - prisma.prismaPoolStakingGaugeReward.upsert({ - create: { - id, - chain: networkContext.chain, - gaugeId, - tokenAddress, - rewardPerSecond, - }, - update: { - rewardPerSecond, - }, - where: { id_chain: { id, chain: networkContext.chain } }, - }), - ); + const dbStakingGaugeRewards = allStakingGaugeRewards.find((rewards) => rewards?.id === id); + + if (!dbStakingGaugeRewards || dbStakingGaugeRewards.rewardPerSecond !== rewardPerSecond) { + operations.push( + prisma.prismaPoolStakingGaugeReward.upsert({ + create: { + id, + chain: networkContext.chain, + gaugeId, + tokenAddress, + rewardPerSecond, + }, + update: { + rewardPerSecond, + }, + where: { id_chain: { id, chain: networkContext.chain } }, + }), + ); + } } - await prismaBulkExecuteOperations(operations, true, undefined); + await prismaBulkExecuteOperations(operations, true); } private async getOnchainRewardTokensData( diff --git a/modules/pool/lib/staking/master-chef-staking.service.ts b/modules/pool/lib/staking/master-chef-staking.service.ts index 5dc744230..a10b2de79 100644 --- a/modules/pool/lib/staking/master-chef-staking.service.ts +++ b/modules/pool/lib/staking/master-chef-staking.service.ts @@ -47,27 +47,32 @@ export class MasterChefStakingService implements PoolStakingService { 18, ); - operations.push( - prisma.prismaPoolStaking.upsert({ - where: { id_chain: { id: farmId, chain: networkContext.chain } }, - create: { - id: farmId, - chain: networkContext.chain, - poolId: pool.id, - type: isFbeetsFarm ? 'FRESH_BEETS' : 'MASTER_CHEF', - address: isFbeetsFarm ? networkContext.data.fbeets!.address : farm.masterChef.id, - }, - update: {}, - }), - ); + const dbStaking = pool.staking.find((farm) => farm.id === farmId); - operations.push( - prisma.prismaPoolStakingMasterChefFarm.upsert({ - where: { id_chain: { id: farmId, chain: networkContext.chain } }, - create: { id: farmId, chain: networkContext.chain, stakingId: farmId, beetsPerBlock }, - update: { beetsPerBlock }, - }), - ); + if (!dbStaking) { + operations.push( + prisma.prismaPoolStaking.upsert({ + where: { id_chain: { id: farmId, chain: networkContext.chain } }, + create: { + id: farmId, + chain: networkContext.chain, + poolId: pool.id, + type: isFbeetsFarm ? 'FRESH_BEETS' : 'MASTER_CHEF', + address: isFbeetsFarm ? networkContext.data.fbeets!.address : farm.masterChef.id, + }, + update: {}, + }), + ); + } + + if (!dbStaking || !dbStaking.farm || dbStaking.farm.beetsPerBlock !== beetsPerBlock) + operations.push( + prisma.prismaPoolStakingMasterChefFarm.upsert({ + where: { id_chain: { id: farmId, chain: networkContext.chain } }, + create: { id: farmId, chain: networkContext.chain, stakingId: farmId, beetsPerBlock }, + update: { beetsPerBlock }, + }), + ); if (farm.rewarder) { for (const rewardToken of farm.rewarder.rewardTokens || []) { @@ -78,20 +83,26 @@ export class MasterChefStakingService implements PoolStakingService { ? formatFixed(rewardToken.rewardPerSecond, rewardToken.decimals) : '0.0'; - operations.push( - prisma.prismaPoolStakingMasterChefFarmRewarder.upsert({ - where: { id_chain: { id, chain: networkContext.chain } }, - create: { - id, - chain: networkContext.chain, - farmId, - tokenAddress: rewardToken.token, - address: farm.rewarder.id, - rewardPerSecond, - }, - update: { rewardPerSecond }, - }), - ); + if ( + !dbStaking || + !dbStaking.farm || + dbStaking.farm.rewarders.find((rewarder) => rewarder.id === id)?.rewardPerSecond !== + rewardPerSecond + ) + operations.push( + prisma.prismaPoolStakingMasterChefFarmRewarder.upsert({ + where: { id_chain: { id, chain: networkContext.chain } }, + create: { + id, + chain: networkContext.chain, + farmId, + tokenAddress: rewardToken.token, + address: farm.rewarder.id, + rewardPerSecond, + }, + update: { rewardPerSecond }, + }), + ); } } } diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index f37cbd14a..f1fa5ed92 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -20,6 +20,7 @@ extend type Query { poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! poolGetFeaturedPoolGroups(chains: [GqlChain!]): [GqlPoolFeaturedPoolGroup!]! + poolGetFeaturedPools(chains: [GqlChain!]!): [GqlPoolFeaturedPool!]! poolGetSnapshots(id: String!, chain: GqlChain, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! poolGetLinearPools(chains: [GqlChain!]): [GqlPoolLinear!]! poolGetGyroPools(chains: [GqlChain!]): [GqlPoolGyro!]! @@ -815,12 +816,16 @@ type GqlPoolUserSwapVolume { swapVolumeUSD: BigDecimal! } +type GqlPoolFeaturedPool { + poolId: ID! + primary: Boolean! + pool: GqlPoolBase! +} + type GqlPoolFeaturedPoolGroup { id: ID! title: String! icon: String! - primary: Boolean - chain: GqlChain! items: [GqlPoolFeaturedPoolGroupItem!]! } diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 18a13603a..9f2ff0d7e 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -58,6 +58,9 @@ const balancerResolvers: Resolvers = { } return poolService.getFeaturedPoolGroups(chains); }, + poolGetFeaturedPools: async (parent, { chains }, context) => { + return poolService.getFeaturedPools(chains); + }, poolGetSnapshots: async (parent, { id, chain, range }, context) => { const currentChain = headerChain(); if (!chain && currentChain) { diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index 70ea01962..9461b541f 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -6,6 +6,7 @@ import { prisma } from '../../prisma/prisma-client'; import { GqlChain, GqlPoolBatchSwap, + GqlPoolFeaturedPool, GqlPoolFeaturedPoolGroup, GqlPoolGyro, GqlPoolJoinExit, @@ -120,6 +121,10 @@ export class PoolService { return this.poolGqlLoaderService.getFeaturedPoolGroups(chains); } + public async getFeaturedPools(chains: Chain[]): Promise { + return this.poolGqlLoaderService.getFeaturedPools(chains); + } + public async getSnapshotsForPool(poolId: string, chain: Chain, range: GqlPoolSnapshotDataRange) { return this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); } diff --git a/modules/vebal/vebal-voting-list.service.ts b/modules/vebal/vebal-voting-list.service.ts index 02338e74d..db30f16b9 100644 --- a/modules/vebal/vebal-voting-list.service.ts +++ b/modules/vebal/vebal-voting-list.service.ts @@ -42,7 +42,7 @@ export class VeBalVotingListService { chain: pool.chain, symbol: pool.symbol, address: pool.address, - type: pool.type === 'COMPOSABLE_STABLE' ? 'PHANTOM_STABLE' : pool.type, + type: pool.type, tokens: pool.tokens.map((token) => ({ address: token.address, weight: token.dynamicData?.weight,