From d497a71b2c1104bcedc9618f73c613a7727df3d6 Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Wed, 11 Dec 2024 12:25:05 +0100 Subject: [PATCH 1/6] fix: handle checksum addresses in tag assignment (#1256) --- .changeset/chatty-kids-knock.md | 5 +++++ modules/actions/pool/sync-incentivized-category.ts | 2 ++ modules/sources/github/pool-erc4626-tags.ts | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .changeset/chatty-kids-knock.md diff --git a/.changeset/chatty-kids-knock.md b/.changeset/chatty-kids-knock.md new file mode 100644 index 000000000..5b91b047b --- /dev/null +++ b/.changeset/chatty-kids-knock.md @@ -0,0 +1,5 @@ +--- +'backend': patch +--- + +fix: handle checksum addresses in tags assignment diff --git a/modules/actions/pool/sync-incentivized-category.ts b/modules/actions/pool/sync-incentivized-category.ts index fbc050642..317a6644d 100644 --- a/modules/actions/pool/sync-incentivized-category.ts +++ b/modules/actions/pool/sync-incentivized-category.ts @@ -16,6 +16,8 @@ export const syncIncentivizedCategory = async () => { const ids = poolsWithReward.map(({ poolId }) => poolId); + if (!ids.length) return; + await prisma.$transaction([ // Remove incentivized category from pools prisma.$executeRaw`UPDATE "PrismaPool" diff --git a/modules/sources/github/pool-erc4626-tags.ts b/modules/sources/github/pool-erc4626-tags.ts index df6e19691..52f8dc586 100644 --- a/modules/sources/github/pool-erc4626-tags.ts +++ b/modules/sources/github/pool-erc4626-tags.ts @@ -18,7 +18,7 @@ export const getErc4626Tags = async ( for (const erc4626Metadata of erc4626MetadataList) { for (const chainId in erc4626Metadata.addresses) { - const addresses = erc4626Metadata.addresses[chainId]; + const addresses = erc4626Metadata.addresses[chainId].map((address) => address.toLowerCase()); const poolsWithThisErc4626Token = await prisma.prismaPool.findMany({ where: { chain: chainIdToChain[chainId], From 1a0f0880d3d4acd7897492ef2be0d94e287534ea Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Wed, 11 Dec 2024 12:25:20 +0100 Subject: [PATCH 2/6] Morpho APRs and pricing (#1255) --- .changeset/four-taxis-jump.md | 5 ++ config/base.ts | 1 + config/mainnet.ts | 1 + .../apr-data-sources/yb-apr-handlers/index.ts | 7 +- .../yb-apr-handlers/sources/index.ts | 1 + .../sources/morpho-apr-handler.ts | 72 +++++++++++++++++++ .../morpho-price-handler.service.ts | 67 +++++++++++++++++ modules/token/lib/token-price.service.ts | 2 + 8 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 .changeset/four-taxis-jump.md create mode 100644 modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/morpho-apr-handler.ts create mode 100644 modules/token/lib/token-price-handlers/morpho-price-handler.service.ts diff --git a/.changeset/four-taxis-jump.md b/.changeset/four-taxis-jump.md new file mode 100644 index 000000000..2165123f1 --- /dev/null +++ b/.changeset/four-taxis-jump.md @@ -0,0 +1,5 @@ +--- +'backend': patch +--- + +Morpho APRs and pricing diff --git a/config/base.ts b/config/base.ts index 3519db394..4b3c68b25 100644 --- a/config/base.ts +++ b/config/base.ts @@ -66,6 +66,7 @@ export default { }, }, ybAprConfig: { + morpho: true, defaultHandlers: { cbETH: { tokenAddress: '0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22', diff --git a/config/mainnet.ts b/config/mainnet.ts index 835f2bf6e..b26ba411c 100644 --- a/config/mainnet.ts +++ b/config/mainnet.ts @@ -113,6 +113,7 @@ export default { }, }, ybAprConfig: { + morpho: true, aave: { v2: { subgraphUrl: `https://gateway-arbitrum.network.thegraph.com/api/${env.THEGRAPH_API_KEY_BALANCER}/subgraphs/id/8wR23o1zkS4gpLqLNU4kG3JHYVucqGyopL5utGxP2q1N`, diff --git a/modules/pool/lib/apr-data-sources/yb-apr-handlers/index.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/index.ts index 59806b6ff..83284c04d 100644 --- a/modules/pool/lib/apr-data-sources/yb-apr-handlers/index.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/index.ts @@ -7,13 +7,10 @@ export type { AprHandler, AprHandlerConstructor, TokenApr }; const sourceToHandler = { aave: sources.AaveAprHandler, beefy: sources.BeefyAprHandler, - bloom: sources.BloomAprHandler, - sftmx: sources.SftmxAprHandler, // euler: sources.EulerAprHandler, // Removed, pools rekt // gearbox: sources.GearboxAprHandler, // Removed, endpoint is down // idle: sources.IdleAprHandler, // Removed, endpoint is down maker: sources.MakerAprHandler, - ovix: sources.OvixAprHandler, // reaper: sources.ReaperCryptAprHandler, // Removed, pools rekt tetu: sources.TetuAprHandler, tranchess: sources.TranchessAprHandler, @@ -27,6 +24,10 @@ const sourceToHandler = { dforce: sources.DForce, defillama: sources.Defillama, teth: sources.TreehouseAprHandler, + morpho: sources.MorphoAprHandler, + ovix: sources.OvixAprHandler, + bloom: sources.BloomAprHandler, + sftmx: sources.SftmxAprHandler, }; export class YbAprHandlers { diff --git a/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/index.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/index.ts index 852331233..f65e00054 100644 --- a/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/index.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/index.ts @@ -17,6 +17,7 @@ export * from './etherfi-apr-handler'; export * from './dforce-apr-handler'; export * from './defillama-apr-handler'; export * from './teth'; +export * from './morpho-apr-handler'; // These need a refactor, because they depend on the network context export * from './sftmx-apr-handler'; export * from './ovix-apr-handler'; diff --git a/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/morpho-apr-handler.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/morpho-apr-handler.ts new file mode 100644 index 000000000..2656c6807 --- /dev/null +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/morpho-apr-handler.ts @@ -0,0 +1,72 @@ +import { gql, request } from 'graphql-request'; +import { AprHandler } from '../types'; +import { Chain } from '@prisma/client'; + +const url = 'https://blue-api.morpho.org/graphql'; +const query = gql` + { + vaults(first: 1000, where: { netApy_gte: 0.00001 }) { + items { + address + chain { + network + } + state { + netApy + } + } + } + } +`; + +type Vault = { + address: string; + chain: { + network: 'ethereum' | 'base'; + }; + state: { + netApy: number; + }; +}; + +type BlueApiResponse = { + vaults: { + items: Vault[]; + }; +}; + +export class MorphoAprHandler implements AprHandler { + group = 'MORPHO'; + + constructor() {} + + async getAprs(chain: Chain) { + if (chain !== Chain.MAINNET && chain !== Chain.BASE) { + return {}; + } + + const morphoChain = chain === Chain.MAINNET ? 'ethereum' : 'base'; + + try { + const r = await request(url, query); + const items = r?.vaults?.items; + const aprs = Object.fromEntries( + items + .filter((vault) => vault.chain.network === morphoChain) + .map((vault) => [ + vault.address, + { + apr: vault.state.netApy, + group: this.group, + isIbYield: true, + }, + ]), + ); + + return aprs; + } catch (e) { + console.error(`Failed to fetch Morpho APRs`, e); + return {}; + } + } +} diff --git a/modules/token/lib/token-price-handlers/morpho-price-handler.service.ts b/modules/token/lib/token-price-handlers/morpho-price-handler.service.ts new file mode 100644 index 000000000..66fa750e2 --- /dev/null +++ b/modules/token/lib/token-price-handlers/morpho-price-handler.service.ts @@ -0,0 +1,67 @@ +import { gql, request } from 'graphql-request'; +import { TokenPriceHandler } from '../../token-types'; +import { PrismaTokenWithTypes } from '../../../../prisma/prisma-types'; +import { timestampRoundedUpToNearestHour } from '../../../common/time'; +import { updatePrices } from './price-handler-helper'; +import { Chain } from '@prisma/client'; + +const url = 'https://blue-api.morpho.org/graphql'; +const query = gql` + { + vaults(first: 1000, where: { totalAssetsUsd_gte: 0.01 }) { + items { + address + chain { + network + } + state { + sharePriceUsd + } + } + } + } +`; + +type Vault = { + address: string; + chain: { + network: 'ethereum' | 'base'; + }; + state: { + sharePriceUsd: number; + }; +}; + +type BlueApiResponse = { + vaults: { + items: Vault[]; + }; +}; + +export class MorphoPriceHandlerService implements TokenPriceHandler { + public readonly exitIfFails = false; + public readonly id = 'MorphoPriceHandlerService'; + + public async updatePricesForTokens(tokens: PrismaTokenWithTypes[]): Promise { + const timestamp = timestampRoundedUpToNearestHour(); + const addresses = tokens.map((token) => token.address); + const { + vaults: { items }, + } = await request(url, query); + + const morphoTokens = items + .filter((vault) => addresses.includes(vault.address.toLowerCase())) + .map((vault) => ({ + address: vault.address.toLowerCase(), + price: vault.state.sharePriceUsd, + chain: vault.chain.network === 'ethereum' ? Chain.MAINNET : Chain.BASE, + })); + + await updatePrices(this.id, morphoTokens, timestamp); + + const morphoTokenAddresses = morphoTokens.map((token) => token.address); + const updatedTokens = tokens.filter((token) => morphoTokenAddresses.includes(token.address)); + + return updatedTokens; + } +} diff --git a/modules/token/lib/token-price.service.ts b/modules/token/lib/token-price.service.ts index 1214f5a98..183954afc 100644 --- a/modules/token/lib/token-price.service.ts +++ b/modules/token/lib/token-price.service.ts @@ -15,6 +15,7 @@ import { BptPriceHandlerService } from './token-price-handlers/bpt-price-handler import { SwapsPriceHandlerService } from './token-price-handlers/swaps-price-handler.service'; import { PrismaTokenWithTypes } from '../../../prisma/prisma-types'; import { AavePriceHandlerService } from './token-price-handlers/aave-price-handler.service'; +import { MorphoPriceHandlerService } from './token-price-handlers/morpho-price-handler.service'; import config from '../../../config'; export class TokenPriceService { @@ -23,6 +24,7 @@ export class TokenPriceService { new FbeetsPriceHandlerService(), new ClqdrPriceHandlerService(), new AavePriceHandlerService(), + new MorphoPriceHandlerService(), new CoingeckoPriceHandlerService(), new BptPriceHandlerService(), new SwapsPriceHandlerService(), From 44d339d87decdc3eb03e05107c9de6b215403a7f Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:11:37 +0100 Subject: [PATCH 3/6] fix morpho aprs handler (#1257) --- .../yb-apr-handlers/sources/morpho-apr-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/morpho-apr-handler.ts b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/morpho-apr-handler.ts index 2656c6807..fe627ee97 100644 --- a/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/morpho-apr-handler.ts +++ b/modules/pool/lib/apr-data-sources/yb-apr-handlers/sources/morpho-apr-handler.ts @@ -54,7 +54,7 @@ export class MorphoAprHandler implements AprHandler { items .filter((vault) => vault.chain.network === morphoChain) .map((vault) => [ - vault.address, + vault.address.toLowerCase(), { apr: vault.state.netApy, group: this.group, From 75cb205242e22c7a95f1334b1f928f0b7742da6a Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:16:36 +0100 Subject: [PATCH 4/6] Quick fix (#1258) * handle all aave prices from aprs config * fix: add morpho apr type --- .changeset/rotten-carrots-hope.md | 5 + .../aave-price-handler.service.ts | 234 ++---------------- .../migration.sql | 2 + prisma/schema.prisma | 1 + prisma/schema/pool.prisma | 1 + 5 files changed, 35 insertions(+), 208 deletions(-) create mode 100644 .changeset/rotten-carrots-hope.md create mode 100644 prisma/migrations/20241211131416_add_morpho_apr_type/migration.sql diff --git a/.changeset/rotten-carrots-hope.md b/.changeset/rotten-carrots-hope.md new file mode 100644 index 000000000..24729bfd1 --- /dev/null +++ b/.changeset/rotten-carrots-hope.md @@ -0,0 +1,5 @@ +--- +'backend': patch +--- + +handle all aave prices from aprs config diff --git a/modules/token/lib/token-price-handlers/aave-price-handler.service.ts b/modules/token/lib/token-price-handlers/aave-price-handler.service.ts index ca0d7bd4a..d0f213457 100644 --- a/modules/token/lib/token-price-handlers/aave-price-handler.service.ts +++ b/modules/token/lib/token-price-handlers/aave-price-handler.service.ts @@ -7,220 +7,34 @@ import { tokenAndPrice, updatePrices } from './price-handler-helper'; import { Chain } from '@prisma/client'; import { parseAbiItem } from 'abitype'; import { getViemClient } from '../../../sources/viem-client'; - -const aaveTokens = { - [Chain.MAINNET]: [ - { - // stataEthUSDT - wrappedToken: '0x65799b9fd4206cdaa4a1db79254fcbc2fd2ffee6', - aToken: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', - underlying: '0xdac17f958d2ee523a2206206994597c13d831ec7', - }, - { - // stataEthUSDT - wrappedToken: '0x862c57d48becb45583aeba3f489696d22466ca1b', - aToken: '0x23878914efe38d27c4d67ab83ed1b93a74d4086a', - underlying: '0xdac17f958d2ee523a2206206994597c13d831ec7', - }, - { - // stataEthUSDC - wrappedToken: '0x02c2d189b45ce213a40097b62d311cf0dd16ec92', - aToken: '0x98c23e9d8f34fefb1b7bd6a91b7ff122f4e16f5c', - underlying: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - }, - { - // waEthLido - wrappedToken: '0x0fe906e030a44ef24ca8c7dc7b7c53a6c4f00ce9', - aToken: '0xfa1fdbbd71b0aa16162d76914d69cd8cb3ef92da', - underlying: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - }, - { - // waEthLidowstETH - wrappedToken: '0x775f661b0bd1739349b9a2a3ef60be277c5d2d29', - aToken: '0xc035a7cf15375ce2706766804551791ad035e0c2', - underlying: '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', - }, - ], - [Chain.OPTIMISM]: [ - { - // stataOptUSDC - USDC.e - wrappedToken: '0x9f281eb58fd98ad98ede0fc4c553ad4d73e7ca2c', - aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', - underlying: '0x7f5c764cbc14f9669b88837ca1490cca17c31607', - }, - { - // stataOptUSDC - USDCn - wrappedToken: '0x4dd03dfd36548c840b563745e3fbec320f37ba7e', - aToken: '0x38d693ce1df5aadf7bc62595a37d667ad57922e5', - underlying: '0x0b2c639c533813f4aa9d7837caf62653d097ff85', - }, - { - // stataOptUSDC - USDT - wrappedToken: '0x035c93db04e5aaea54e6cd0261c492a3e0638b37', - aToken: '0x6ab707aca953edaefbc4fd23ba73294241490620', - underlying: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58', - }, - ], - [Chain.ARBITRUM]: [ - { - // stataArbUSDT - wrappedToken: '0x8b5541b773dd781852940490b0c3dc1a8cdb6a87', - aToken: '0x6ab707aca953edaefbc4fd23ba73294241490620', - underlying: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - }, - { - // stataArbUSDT - wrappedToken: '0xb165a74407fe1e519d6bcbdec1ed3202b35a4140', - aToken: '0x6ab707aca953edaefbc4fd23ba73294241490620', - underlying: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', - }, - { - // stataArbUSDCn - wrappedToken: '0x7cfadfd5645b50be87d546f42699d863648251ad', - aToken: '0x724dc807b04555b71ed48a6896b6f41593b8c637', - underlying: '0xaf88d065e77c8cc2239327c5edb3a432268e5831', - }, - { - // stataArbUSDCn - USD Coin (Arb1) - wrappedToken: '0xbde67e089886ec0e615d6f054bc6f746189a3d56', - aToken: '0x724dc807b04555b71ed48a6896b6f41593b8c637', - underlying: '0xaf88d065e77c8cc2239327c5edb3a432268e5831', - }, - { - // stataArbUSDC - USD Coin (Arb1) - different wrapping - wrappedToken: '0x3a301e7917689b8e8a19498b8a28fc912583490c', - aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', - underlying: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - }, - ], - [Chain.POLYGON]: [ - { - //stataPolUSDT - wrappedToken: '0x31f5ac91804a4c0b54c0243789df5208993235a1', - aToken: '0x6ab707aca953edaefbc4fd23ba73294241490620', - underlying: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', - }, - { - //stataPolUSDT - wrappedToken: '0x87a1fdc4c726c459f597282be639a045062c0e46', - aToken: '0x6ab707aca953edaefbc4fd23ba73294241490620', - underlying: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', - }, - { - //stataPolUSDC - USD Coin (PoS) - wrappedToken: '0xc04296aa4534f5a3bab2d948705bc89317b2f1ed', - aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', - underlying: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', - }, - { - //stataPolUSDCn - USDCn - wrappedToken: '0x2dca80061632f3f87c9ca28364d1d0c30cd79a19', - aToken: '0xa4d94019934d8333ef880abffbf2fdd611c762bd', - underlying: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359', - }, - ], - [Chain.AVALANCHE]: [ - { - // stataAvaUSDT - wrappedToken: '0x759a2e28d4c3ad394d3125d5ab75a6a5d6782fd9', - aToken: '0x6ab707aca953edaefbc4fd23ba73294241490620', - underlying: '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7', - }, - { - // stataAvaUSDC - wrappedToken: '0xe7839ea8ea8543c7f5d9c9d7269c661904729fe7', - aToken: '0x625e7708f30ca75bfd92586e17077590c60eb4cd', - underlying: '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', - }, - { - // StataAvaDAI - wrappedToken: '0x234c4b76f749dfffd9c18ea7cc0972206b42d019', - aToken: '0x82e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee', - underlying: '0xd586e7f844cea2f87f50152665bcbc2c279d8d70', - }, - { - // stataAvaWETH - wrappedToken: '0x41bafe0091d55378ed921af3784622923651fdd8', - aToken: '0xe50fa9b3c56ffb159cb0fca61f5c9d750e8128c8', - underlying: '0x49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab', - }, - { - // stataAvaWAVAX - wrappedToken: '0xa291ae608d8854cdbf9838e28e9badcf10181669', - aToken: '0x6d80113e533a2c0fe82eabd35f1875dcea89ea97', - underlying: '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7', - }, - ], - [Chain.BASE]: [ - { - // Static Aave Base USDC - wrappedToken: '0x4ea71a20e655794051d1ee8b6e4a3269b13ccacc', - aToken: '0x4e65fe4dba92790696d040ac24aa414708f5c0ab ', - underlying: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', - }, - ], - [Chain.GNOSIS]: [ - { - // stataGnoUSDC - wrappedToken: '0x270ba1f35d8b87510d24f693fccc0da02e6e4eeb', - aToken: '0xc6b7aca6de8a6044e0e32d0c841a89244a10d284', - underlying: '0xddafbb505ad214d7b80b1f830fccc89b60fb7a83', - }, - { - // stataGnoUSDCe - wrappedToken: '0xf0e7ec247b918311afa054e0aedb99d74c31b809', - aToken: '0xc0333cb85b59a788d8c7cae5e1fd6e229a3e5a65', - underlying: '0x2a22f9c3b484c3629090feed35f17ff8f88f76f0', - }, - { - // waGnoUSDCe - wrappedToken: '0x51350d88c1bd32cc6a79368c9fb70373fb71f375', - aToken: '0xc0333cb85b59a788d8c7cae5e1fd6e229a3e5a65', - underlying: '0x2a22f9c3b484c3629090feed35f17ff8f88f76f0', - }, - { - // waGnoWETH - wrappedToken: '0x57f664882f762fa37903fc864e2b633d384b411a', - aToken: '0xa818f1b57c201e092c4a2017a91815034326efd1', - underlying: '0x6a023ccd1ff6f2045c3309768ead9e68f978f6e1', - }, - { - // waGnoGNO - wrappedToken: '0x7c16f0185a26db0ae7a9377f23bc18ea7ce5d644', - aToken: '0xa1fa064a85266e2ca82dee5c5ccec84df445760e', - underlying: '0x9c58bacc331c9aa871afd802db6379a98e80cedb', - }, - ], - [Chain.SEPOLIA]: [ - { - // Static Aave USDC - wrappedToken: '0x8a88124522dbbf1e56352ba3de1d9f78c143751e', - aToken: '0x16da4541ad1807f4443d92d26044c1147406eb80', - underlying: '0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8', - }, - { - // Static Aave DAI - wrappedToken: '0xde46e43f46ff74a23a65ebb0580cbe3dfe684a17', - aToken: '0x29598b72eb5cebd806c5dcd549490fda35b13cd8', - underlying: '0xff34b3d4aee8ddcd6f9afffb6fe49bd371b8a357', - }, - ], -}; +import config from '../../../../config'; export class AavePriceHandlerService implements TokenPriceHandler { public readonly exitIfFails = false; public readonly id = 'AavePriceHandlerService'; + aaveTokens = Object.keys(config).flatMap((chain) => { + const chainConfig = config[chain as keyof typeof config]; + const v3 = chainConfig.ybAprConfig.aave?.v3?.tokens; + if (!v3) return []; + return Object.values(v3).flatMap(({ aTokenAddress, underlyingAssetAddress, wrappedTokens }) => + Object.values(wrappedTokens).map((wrappedToken) => ({ + wrappedToken, + aToken: aTokenAddress, + underlying: underlyingAssetAddress, + chain: chain as Chain, + })), + ); + }); private getAcceptedTokens(tokens: PrismaTokenWithTypes[]): PrismaTokenWithTypes[] { - return tokens.filter((token) => - (aaveTokens[token.chain as keyof typeof aaveTokens] || []) - .flatMap((t) => t.wrappedToken) - .includes(token.address), - ); + const list = this.aaveTokens.map((token) => token.wrappedToken); + return tokens.filter((token) => list.includes(token.address)); } public async updatePricesForTokens(tokens: PrismaTokenWithTypes[]): Promise { const acceptedTokens = this.getAcceptedTokens(tokens); + const acceptedAddresses = acceptedTokens.map((token) => token.address); + const acceptedAaveTokens = this.aaveTokens.filter((token) => acceptedAddresses.includes(token.wrappedToken)); const tokenAndPrices: tokenAndPrice[] = []; const timestamp = timestampRoundedUpToNearestHour(); @@ -229,10 +43,14 @@ export class AavePriceHandlerService implements TokenPriceHandler { const updatedTokens: PrismaTokenWithTypes[] = []; for (const chain in tokensByChain) { - const aaveChain = chain as keyof typeof aaveTokens; + const aaveTokensForChain = acceptedAaveTokens.filter((token) => token.chain === (chain as Chain)); + if (!aaveTokensForChain.length) { + continue; + } + // Fetch rates for aave tokens - const addresses = aaveTokens[aaveChain].map((token) => token.wrappedToken); - const underlying = aaveTokens[aaveChain].map((token) => token.underlying); + const addresses = aaveTokensForChain.map((token) => token.wrappedToken); + const underlying = aaveTokensForChain.map((token) => token.underlying); const contracts = addresses.map((address) => ({ address: address as `0x${string}`, // Returns rates for the rebasing tokens returned in RAYs (27 decimals) @@ -256,7 +74,7 @@ export class AavePriceHandlerService implements TokenPriceHandler { ); for (const token of tokensByChain[chain]) { - const underlying = aaveTokens[aaveChain].find((t) => t.wrappedToken === token.address)?.underlying; + const underlying = aaveTokensForChain.find((t) => t.wrappedToken === token.address)?.underlying; if (!underlying) { throw new Error(`AavePriceHandlerService: Underlying token for ${token.address} not found`); } diff --git a/prisma/migrations/20241211131416_add_morpho_apr_type/migration.sql b/prisma/migrations/20241211131416_add_morpho_apr_type/migration.sql new file mode 100644 index 000000000..a3801aaff --- /dev/null +++ b/prisma/migrations/20241211131416_add_morpho_apr_type/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "PrismaPoolAprItemGroup" ADD VALUE 'MORPHO'; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a0774f379..9c92ab0dd 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -324,6 +324,7 @@ enum PrismaPoolAprItemGroup { EULER MAKER DEFAULT + MORPHO } model PrismaPoolExpandedTokens { diff --git a/prisma/schema/pool.prisma b/prisma/schema/pool.prisma index 659bffe14..28c610f71 100644 --- a/prisma/schema/pool.prisma +++ b/prisma/schema/pool.prisma @@ -268,6 +268,7 @@ enum PrismaPoolAprItemGroup { EULER MAKER DEFAULT + MORPHO } model PrismaPoolExpandedTokens { From cdf0cb6884db79d3d3c6fe70c0891e175110f3ff Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:46:18 +0100 Subject: [PATCH 5/6] fix: aave pricing (#1260) --- .changeset/calm-panthers-exercise.md | 5 ++++ .../aave-price-handler.service.ts | 29 ++++++++++--------- 2 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 .changeset/calm-panthers-exercise.md diff --git a/.changeset/calm-panthers-exercise.md b/.changeset/calm-panthers-exercise.md new file mode 100644 index 000000000..8fb5a82c0 --- /dev/null +++ b/.changeset/calm-panthers-exercise.md @@ -0,0 +1,5 @@ +--- +'backend': patch +--- + +aave pricing diff --git a/modules/token/lib/token-price-handlers/aave-price-handler.service.ts b/modules/token/lib/token-price-handlers/aave-price-handler.service.ts index d0f213457..3d5de278a 100644 --- a/modules/token/lib/token-price-handlers/aave-price-handler.service.ts +++ b/modules/token/lib/token-price-handlers/aave-price-handler.service.ts @@ -32,18 +32,17 @@ export class AavePriceHandlerService implements TokenPriceHandler { } public async updatePricesForTokens(tokens: PrismaTokenWithTypes[]): Promise { - const acceptedTokens = this.getAcceptedTokens(tokens); - const acceptedAddresses = acceptedTokens.map((token) => token.address); - const acceptedAaveTokens = this.aaveTokens.filter((token) => acceptedAddresses.includes(token.wrappedToken)); + const addresses = tokens.map((token) => token.address); + const aaveTokens = this.aaveTokens.filter((token) => addresses.includes(token.wrappedToken)); const tokenAndPrices: tokenAndPrice[] = []; const timestamp = timestampRoundedUpToNearestHour(); // Group tokens by chain - const tokensByChain = _.groupBy(acceptedTokens, 'chain'); + const tokensByChain = _.groupBy(aaveTokens, 'chain'); const updatedTokens: PrismaTokenWithTypes[] = []; for (const chain in tokensByChain) { - const aaveTokensForChain = acceptedAaveTokens.filter((token) => token.chain === (chain as Chain)); + const aaveTokensForChain = tokensByChain[chain]; if (!aaveTokensForChain.length) { continue; } @@ -73,22 +72,26 @@ export class AavePriceHandlerService implements TokenPriceHandler { underlyingPrices, ); - for (const token of tokensByChain[chain]) { - const underlying = aaveTokensForChain.find((t) => t.wrappedToken === token.address)?.underlying; - if (!underlying) { - throw new Error(`AavePriceHandlerService: Underlying token for ${token.address} not found`); + for (const token of aaveTokensForChain) { + const dbToken = tokens.find((t) => t.address === token.wrappedToken); + const underlying = token.underlying; + if (!dbToken || !underlyingMap[underlying]) { + console.error( + `AavePriceHandlerService: Underlying price for ${token.wrappedToken} on ${chain} not found`, + ); + continue; } try { - const price = Number((rateMap[token.address] * underlyingMap[underlying].price).toFixed(2)); + const price = Number((rateMap[token.wrappedToken] * underlyingMap[underlying].price).toFixed(2)); - updatedTokens.push(token); + updatedTokens.push(dbToken); tokenAndPrices.push({ - address: token.address, + address: token.wrappedToken, chain: token.chain, price, }); } catch (e: any) { - console.error('Aave price failed for', token.address, chain, e.message); + console.error('Aave price failed for', token.wrappedToken, chain, e.message); } } } From 26da4179cf366290fc7bc81928ab366fa969bfbc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:54:19 +0100 Subject: [PATCH 6/6] Version Packages (#1261) Co-authored-by: github-actions[bot] --- .changeset/calm-panthers-exercise.md | 5 ----- .changeset/chatty-kids-knock.md | 5 ----- .changeset/four-taxis-jump.md | 5 ----- .changeset/rotten-carrots-hope.md | 5 ----- CHANGELOG.md | 9 +++++++++ package.json | 2 +- 6 files changed, 10 insertions(+), 21 deletions(-) delete mode 100644 .changeset/calm-panthers-exercise.md delete mode 100644 .changeset/chatty-kids-knock.md delete mode 100644 .changeset/four-taxis-jump.md delete mode 100644 .changeset/rotten-carrots-hope.md diff --git a/.changeset/calm-panthers-exercise.md b/.changeset/calm-panthers-exercise.md deleted file mode 100644 index 8fb5a82c0..000000000 --- a/.changeset/calm-panthers-exercise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'backend': patch ---- - -aave pricing diff --git a/.changeset/chatty-kids-knock.md b/.changeset/chatty-kids-knock.md deleted file mode 100644 index 5b91b047b..000000000 --- a/.changeset/chatty-kids-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'backend': patch ---- - -fix: handle checksum addresses in tags assignment diff --git a/.changeset/four-taxis-jump.md b/.changeset/four-taxis-jump.md deleted file mode 100644 index 2165123f1..000000000 --- a/.changeset/four-taxis-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'backend': patch ---- - -Morpho APRs and pricing diff --git a/.changeset/rotten-carrots-hope.md b/.changeset/rotten-carrots-hope.md deleted file mode 100644 index 24729bfd1..000000000 --- a/.changeset/rotten-carrots-hope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'backend': patch ---- - -handle all aave prices from aprs config diff --git a/CHANGELOG.md b/CHANGELOG.md index a9382527d..9e47aa38d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # backend +## 1.26.3 + +### Patch Changes + +- cdf0cb6: aave pricing +- d497a71: fix: handle checksum addresses in tags assignment +- 1a0f088: Morpho APRs and pricing +- 75cb205: handle all aave prices from aprs config + ## 1.26.2 ### Patch Changes diff --git a/package.json b/package.json index 5bb2865b6..4f0e7d7db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "backend", - "version": "1.26.2", + "version": "1.26.3", "description": "Backend service for Beethoven X and Balancer", "repository": "https://github.com/balancer/backend", "author": "Beethoven X",