From 8ddbf9e5ace8c575be927c47f12c274dfbb681e8 Mon Sep 17 00:00:00 2001 From: franz Date: Mon, 6 Nov 2023 16:48:27 +0100 Subject: [PATCH 01/32] unused --- modules/gnosis/gnosis-safe.service.ts | 54 --------------------------- 1 file changed, 54 deletions(-) delete mode 100644 modules/gnosis/gnosis-safe.service.ts diff --git a/modules/gnosis/gnosis-safe.service.ts b/modules/gnosis/gnosis-safe.service.ts deleted file mode 100644 index 5ecff4151..000000000 --- a/modules/gnosis/gnosis-safe.service.ts +++ /dev/null @@ -1,54 +0,0 @@ -import Safe, { ContractNetworksConfig, EthersAdapter } from '@gnosis.pm/safe-core-sdk'; -import { ethers, providers } from 'ethers'; -import { getAddress } from 'ethers/lib/utils'; -import { Cache } from 'memory-cache'; -import { networkContext } from '../network/network-context.service'; - -const CACHE_KEY_PREFIX = `gnosis-address-is-multisig_`; -const TIMEOUT = 2592000; //30 days - -const contractNetworks: ContractNetworksConfig = { - 250: { - safeProxyFactoryAddress: '0xc3C41Ab65Dabe3ae250A0A1FE4706FdB7ECEB951', - multiSendAddress: '0xd1b160Ee570632ac402Efb230d720669604918e8', - safeMasterCopyAddress: '0x87EB227FE974e9E1d3Bc4Da562e0Bd3C348c2B34', - }, -}; - -export class GnosisSafeService { - private cache = new Cache(); - - public async isAddressGnosisSafe(address: string) { - const key = `${CACHE_KEY_PREFIX}:${networkContext.chainId}:${address}`; - const cachedValue = this.cache.get(key); - if (cachedValue != null) { - return cachedValue; - } - - try { - await Safe.create({ - ethAdapter: await this.getAdapter(), - safeAddress: getAddress(address), - contractNetworks, - }); - - this.cache.put(key, true, TIMEOUT); - return true; - } catch { - this.cache.put(key, false, TIMEOUT); - return false; - } - } - - private async getAdapter() { - const provider = new providers.JsonRpcProvider(networkContext.data.rpcUrl); - const signer = ethers.Wallet.createRandom(); - - return new EthersAdapter({ - ethers, - signer: signer.connect(provider), - }); - } -} - -export const gnosisSafeService = new GnosisSafeService(); From 05311c3804d647a80313560178fae431292af48e Mon Sep 17 00:00:00 2001 From: franz Date: Mon, 6 Nov 2023 17:54:57 +0100 Subject: [PATCH 02/32] change poolGetPool --- modules/pool/lib/pool-gql-loader.service.ts | 7 ++++--- modules/pool/pool.gql | 2 +- modules/pool/pool.resolvers.ts | 11 +++++++++-- modules/pool/pool.service.ts | 11 ++++++----- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index b381545ee..de5cd2c7a 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -11,6 +11,7 @@ import { import { GqlBalancePoolAprItem, GqlBalancePoolAprSubItem, + GqlChain, GqlPoolDynamicData, GqlPoolFeaturedPoolGroup, GqlPoolInvestConfig, @@ -33,16 +34,16 @@ import { import { isSameAddress } from '@balancer-labs/sdk'; import _ from 'lodash'; import { prisma } from '../../../prisma/prisma-client'; -import { Prisma, PrismaPoolAprType } from '@prisma/client'; +import { Chain, Prisma, PrismaPoolAprType } from '@prisma/client'; import { isWeightedPoolV2 } from './pool-utils'; import { oldBnum } from '../../big-number/old-big-number'; import { networkContext } from '../../network/network-context.service'; import { fixedNumber } from '../../view-helpers/fixed-number'; export class PoolGqlLoaderService { - public async getPool(id: string): Promise { + public async getPool(id: string, chain: Chain): Promise { const pool = await prisma.prismaPool.findUnique({ - where: { id_chain: { id, chain: networkContext.chain } }, + where: { id_chain: { id, chain: chain } }, include: prismaPoolWithExpandedNesting.include, }); diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index af90e7f62..c4b984cb7 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -1,5 +1,5 @@ extend type Query { - poolGetPool(id: String!): GqlPoolBase! + poolGetPool(id: String!, chain: GqlChain): GqlPoolBase! poolGetPools( first: Int skip: Int diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index d958ca087..064838421 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -3,11 +3,18 @@ import { Resolvers } from '../../schema'; import { isAdminRoute } from '../auth/auth-context'; import { prisma } from '../../prisma/prisma-client'; import { networkContext } from '../network/network-context.service'; +import { headerChain } from '../context/header-chain'; const balancerResolvers: Resolvers = { Query: { - poolGetPool: async (parent, { id }, context) => { - return poolService.getGqlPool(id); + poolGetPool: async (parent, { id, chain }, context) => { + const currentChain = headerChain(); + if (!chain && currentChain) { + chain = currentChain; + } else if (!chain) { + throw new Error('Chain is required'); + } + return poolService.getGqlPool(id, chain); }, poolGetPools: async (parent, args, context) => { return poolService.getGqlPools(args); diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index 852a03bc0..39c0a93f2 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -4,6 +4,7 @@ import { Cache } from 'memory-cache'; import moment from 'moment-timezone'; import { prisma } from '../../prisma/prisma-client'; import { + GqlChain, GqlPoolBatchSwap, GqlPoolFeaturedPoolGroup, GqlPoolJoinExit, @@ -61,8 +62,8 @@ export class PoolService { return networkContext.config.contentService; } - public async getGqlPool(id: string): Promise { - return this.poolGqlLoaderService.getPool(id); + public async getGqlPool(id: string, chain: GqlChain): Promise { + return this.poolGqlLoaderService.getPool(id, chain); } public async getGqlPools(args: QueryPoolGetPoolsArgs): Promise { @@ -438,7 +439,7 @@ export class PoolService { await prisma.prismaPoolLinearData.deleteMany({ where: { chain: networkContext.chain, poolId: poolId }, }); - + await prisma.prismaPoolGyroData.deleteMany({ where: { chain: networkContext.chain, poolId: poolId }, }); @@ -481,9 +482,9 @@ export class PoolService { }, }); - if(gauge && gauge.votingGauge) + if (gauge && gauge.votingGauge) await prisma.prismaVotingGauge.deleteMany({ - where: { chain: networkContext.chain, id: gauge.votingGauge.id } + where: { chain: networkContext.chain, id: gauge.votingGauge.id }, }); await prisma.prismaPoolStakingGauge.deleteMany({ From ce7e6650950a6e374673355104df42da28834987 Mon Sep 17 00:00:00 2001 From: franz Date: Mon, 6 Nov 2023 18:24:50 +0100 Subject: [PATCH 03/32] poolGetSwaps and poolGetBatchSwaps --- modules/pool/lib/pool-swap.service.ts | 8 ++++++-- modules/pool/pool.gql | 1 + modules/pool/pool.resolvers.ts | 12 ++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index 83430ab05..2dd2a472c 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -85,7 +85,9 @@ export class PoolSwapService { tokenOut: { in: args.where?.tokenOutIn || undefined, }, - chain: networkContext.chain, + chain: { + in: args.where?.chainIn || undefined, + }, }, orderBy: { timestamp: 'desc' }, }); @@ -144,7 +146,9 @@ export class PoolSwapService { tokenOut: { in: args.where?.tokenOutIn || undefined, }, - chain: networkContext.chain, + chain: { + in: args.where?.chainIn || undefined, + }, }, orderBy: { timestamp: 'desc' }, include: { diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index c4b984cb7..2cc0925a4 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -707,6 +707,7 @@ input GqlPoolSwapFilter { tokenInIn: [String!] tokenOutIn: [String!] poolIdIn: [String!] + chainIn: [GqlChain!] } type GqlPoolStaking { diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 064838421..c30b40b11 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -26,9 +26,21 @@ const balancerResolvers: Resolvers = { return poolService.getPoolFilters(); }, poolGetSwaps: async (parent, args, context) => { + const currentChain = headerChain(); + if (!args.where?.chainIn && currentChain) { + args.where = { ...args.where, chainIn: [currentChain] }; + } else if (!args.where?.chainIn) { + throw new Error('Chain is required'); + } return poolService.getPoolSwaps(args); }, poolGetBatchSwaps: async (parent, args, context) => { + const currentChain = headerChain(); + if (!args.where?.chainIn && currentChain) { + args.where = { ...args.where, chainIn: [currentChain] }; + } else if (!args.where?.chainIn) { + throw new Error('Chain is required'); + } return poolService.getPoolBatchSwaps(args); }, poolGetJoinExits: async (parent, args, context) => { From aca12ca64ccab11e4fd575b7a718959233d489ee Mon Sep 17 00:00:00 2001 From: franz Date: Mon, 6 Nov 2023 18:25:06 +0100 Subject: [PATCH 04/32] cleanup --- modules/token/token.resolvers.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/token/token.resolvers.ts b/modules/token/token.resolvers.ts index 988a6111a..8af8f11d3 100644 --- a/modules/token/token.resolvers.ts +++ b/modules/token/token.resolvers.ts @@ -2,13 +2,12 @@ import { Resolvers } from '../../schema'; import _ from 'lodash'; import { isAdminRoute } from '../auth/auth-context'; import { tokenService } from './token.service'; -import { networkContext } from '../network/network-context.service'; import { headerChain } from '../context/header-chain'; const resolvers: Resolvers = { Query: { tokenGetTokens: async (parent, { chains }, context) => { - const currentChain = headerChain() + const currentChain = headerChain(); if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { @@ -17,7 +16,7 @@ const resolvers: Resolvers = { return tokenService.getTokenDefinitions(chains); }, tokenGetCurrentPrices: async (parent, { chains }, context) => { - const currentChain = headerChain() + const currentChain = headerChain(); if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { From bc5c4f418d2ae7ffac1ca703f45e4c1ab5bd858e Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 10:04:10 +0100 Subject: [PATCH 05/32] user swaps --- modules/pool/lib/pool-swap.service.ts | 10 ++++++++-- modules/pool/pool.gql | 2 ++ .../balancer-subgraph/balancer-subgraph.service.ts | 4 ++-- modules/user/user.gql | 2 +- modules/user/user.resolvers.ts | 14 ++++++++++---- modules/user/user.service.ts | 11 ++++++++--- 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index 2dd2a472c..38846075e 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -15,12 +15,13 @@ import { QueryPoolGetSwapsArgs, QueryPoolGetUserSwapVolumeArgs, } from '../../../schema'; -import { PrismaPoolSwap } from '@prisma/client'; +import { Chain, PrismaPoolSwap } from '@prisma/client'; import _ from 'lodash'; import { isSupportedInt, prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { PrismaPoolBatchSwapWithSwaps, prismaPoolMinimal } from '../../../prisma/prisma-types'; import { networkContext } from '../../network/network-context.service'; import * as Sentry from '@sentry/node'; +import { AllNetworkConfigsKeyedOnChain } from '../../network/network-config'; export class PoolSwapService { constructor( @@ -96,10 +97,14 @@ export class PoolSwapService { public async getUserSwapsForPool( userAddress: string, poolId: string, + chain: Chain, first = 10, skip = 0, ): Promise { - const result = await this.balancerSubgraphService.getSwaps({ + const balancerSubgraphService = new BalancerSubgraphService( + AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, + ); + const result = await balancerSubgraphService.getSwaps({ first, skip, where: { @@ -112,6 +117,7 @@ export class PoolSwapService { return result.swaps.map((swap) => ({ id: swap.id, + chain: chain, userAddress, poolId: swap.poolId.id, tokenIn: swap.tokenIn, diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index 2cc0925a4..04c80623e 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -659,6 +659,7 @@ type GqlPoolFilterDefinition { type GqlPoolSwap { id: ID! + chain: GqlChain! poolId: String! userAddress: String! tokenIn: String! @@ -672,6 +673,7 @@ type GqlPoolSwap { type GqlPoolBatchSwap { id: ID! + chain: GqlChain! userAddress: String! tokenIn: String! tokenOut: String! diff --git a/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts b/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts index 0a4023c9c..43b779b58 100644 --- a/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts +++ b/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts @@ -52,7 +52,7 @@ const PORTFOLIO_POOLS_CACHE_KEY = `balance-subgraph_portfolio-pools`; export class BalancerSubgraphService { private cache: CacheClass; - constructor() { + constructor(private readonly subgraphUrl = networkContext.data.subgraphs.balancer) { this.cache = new Cache(); } @@ -314,7 +314,7 @@ export class BalancerSubgraphService { } private get sdk() { - const client = new GraphQLClient(networkContext.data.subgraphs.balancer); + const client = new GraphQLClient(this.subgraphUrl); return getSdk(client); } diff --git a/modules/user/user.gql b/modules/user/user.gql index 62803f158..50223a760 100644 --- a/modules/user/user.gql +++ b/modules/user/user.gql @@ -2,7 +2,7 @@ extend type Query { userGetPoolBalances(chains: [GqlChain!], address: String): [GqlUserPoolBalance!]! userGetStaking: [GqlPoolStaking!]! userGetPoolJoinExits(first: Int = 10, skip: Int = 0, poolId: String!): [GqlPoolJoinExit!]! - userGetSwaps(first: Int = 10, skip: Int = 0, poolId: String!): [GqlPoolSwap!]! + userGetSwaps(first: Int = 10, skip: Int = 0, poolId: String!, chain: GqlChain, address: String): [GqlPoolSwap!]! } extend type Mutation { diff --git a/modules/user/user.resolvers.ts b/modules/user/user.resolvers.ts index 0c7424b6f..ec2f2ba54 100644 --- a/modules/user/user.resolvers.ts +++ b/modules/user/user.resolvers.ts @@ -7,7 +7,7 @@ import { headerChain } from '../context/header-chain'; const resolvers: Resolvers = { Query: { userGetPoolBalances: async (parent, { chains, address }, context) => { - const currentChain = headerChain() + const currentChain = headerChain(); if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { @@ -27,9 +27,15 @@ const resolvers: Resolvers = { return userService.getUserPoolInvestments(accountAddress, poolId, first, skip); }, - userGetSwaps: async (parent, { first, skip, poolId }, context) => { - const accountAddress = getRequiredAccountAddress(context); - return userService.getUserSwaps(accountAddress, poolId, first, skip); + userGetSwaps: async (parent, { first, skip, poolId, chain, address }, context) => { + const currentChain = headerChain(); + if (!chain && currentChain) { + chain = currentChain; + } else if (!chain) { + throw new Error('Chain is required'); + } + const accountAddress = address || getRequiredAccountAddress(context); + return userService.getUserSwaps(accountAddress, poolId, chain, first, skip); }, userGetStaking: async (parent, {}, context) => { const accountAddress = getRequiredAccountAddress(context); diff --git a/modules/user/user.service.ts b/modules/user/user.service.ts index fd603906c..22aa391a0 100644 --- a/modules/user/user.service.ts +++ b/modules/user/user.service.ts @@ -5,7 +5,6 @@ import { coingeckoService } from '../coingecko/coingecko.service'; import { PoolSnapshotService } from '../pool/lib/pool-snapshot.service'; import { PoolSwapService } from '../pool/lib/pool-swap.service'; import { balancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; -import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { reliquarySubgraphService } from '../subgraphs/reliquary-subgraph/reliquary.service'; import { userSnapshotSubgraphService } from '../subgraphs/user-snapshot-subgraph/user-snapshot-subgraph.service'; import { tokenService } from '../token/token.service'; @@ -40,8 +39,14 @@ export class UserService { return this.poolSwapService.getUserJoinExitsForPool(address, poolId, first, skip); } - public async getUserSwaps(address: string, poolId: string, first?: number, skip?: number): Promise { - return this.poolSwapService.getUserSwapsForPool(address, poolId, first, skip); + public async getUserSwaps( + address: string, + poolId: string, + chain: Chain, + first?: number, + skip?: number, + ): Promise { + return this.poolSwapService.getUserSwapsForPool(address, poolId, chain, first, skip); } public async getUserFbeetsBalance(address: string): Promise> { From 863ff81acb13c5e47675f1f5e87ddda2b5ba394b Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 10:37:16 +0100 Subject: [PATCH 06/32] remove sanity poolFilters --- modules/content/sanity-content.service.ts | 33 ----------------------- modules/pool/pool.gql | 1 - modules/pool/pool.resolvers.ts | 3 --- 3 files changed, 37 deletions(-) diff --git a/modules/content/sanity-content.service.ts b/modules/content/sanity-content.service.ts index 00d6dd8b0..67403a1f2 100644 --- a/modules/content/sanity-content.service.ts +++ b/modules/content/sanity-content.service.ts @@ -26,11 +26,6 @@ interface SanityToken { interface SanityPoolConfig { incentivizedPools: string[]; blacklistedPools: string[]; - poolFilters: { - id: string; - title: string; - pools: string[]; - }[]; } const SANITY_TOKEN_TYPE_MAP: { [key: string]: string } = { @@ -209,13 +204,11 @@ export class SanityContentService implements ContentService { const response = await getSanityClient().fetch(`*[_type == "config" && chainId == ${networkContext.chainId}][0]{ incentivizedPools, blacklistedPools, - poolFilters }`); const config: SanityPoolConfig = { incentivizedPools: response?.incentivizedPools ?? [], blacklistedPools: response?.blacklistedPools ?? [], - poolFilters: response?.poolFilters ?? [], }; const categories = await prisma.prismaPoolCategory.findMany({ where: { chain: networkContext.chain } }); @@ -224,32 +217,6 @@ export class SanityContentService implements ContentService { await this.updatePoolCategory(incentivized, config.incentivizedPools, 'INCENTIVIZED'); await this.updatePoolCategory(blacklisted, config.blacklistedPools, 'BLACK_LISTED'); - - await prisma.$transaction([ - prisma.prismaPoolFilterMap.deleteMany({ where: { chain: networkContext.chain } }), - prisma.prismaPoolFilter.deleteMany({ where: { chain: networkContext.chain } }), - prisma.prismaPoolFilter.createMany({ - data: config.poolFilters.map((item) => ({ - id: item.id, - chain: networkContext.chain, - title: item.title, - })), - skipDuplicates: true, - }), - prisma.prismaPoolFilterMap.createMany({ - data: config.poolFilters - .map((item) => { - return item.pools.map((poolId) => ({ - id: `${item.id}-${poolId}`, - chain: networkContext.chain, - poolId, - filterId: item.id, - })); - }) - .flat(), - skipDuplicates: true, - }), - ]); } private async updatePoolCategory(currentPoolIds: string[], newPoolIds: string[], category: PrismaPoolCategoryType) { diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index 04c80623e..f21b0f40d 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -16,7 +16,6 @@ extend type Query { where: GqlPoolFilter textSearch: String ): Int! - poolGetPoolFilters: [GqlPoolFilterDefinition!]! poolGetSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolSwap!]! poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index c30b40b11..fa646878c 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -22,9 +22,6 @@ const balancerResolvers: Resolvers = { poolGetPoolsCount: async (parent, args, context) => { return poolService.getPoolsCount(args); }, - poolGetPoolFilters: async (parent, {}, context) => { - return poolService.getPoolFilters(); - }, poolGetSwaps: async (parent, args, context) => { const currentChain = headerChain(); if (!args.where?.chainIn && currentChain) { From 5d88651b2bbb0e076023746ec000d340fc8fe145 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 12:58:07 +0100 Subject: [PATCH 07/32] joinExit --- modules/pool/lib/pool-swap.service.ts | 42 ++++++++++++++++++--------- modules/pool/pool.gql | 2 ++ modules/pool/pool.resolvers.ts | 6 ++++ 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index 38846075e..e230009e9 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -32,20 +32,36 @@ export class PoolSwapService { public async getJoinExits(args: QueryPoolGetJoinExitsArgs): Promise { const first = !args.first || args.first > 100 ? 10 : args.first; - const { joinExits } = await this.balancerSubgraphService.getPoolJoinExits({ - where: { pool_in: args.where?.poolIdIn }, - first, - skip: args.skip, - orderBy: JoinExit_OrderBy.Timestamp, - orderDirection: OrderDirection.Desc, - }); + const allChainsJoinExits: GqlPoolJoinExit[] = []; + + for (const chain of args.where!.chainIn!) { + const balancerSubgraphService = new BalancerSubgraphService( + AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, + ); + + const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ + where: { pool_in: args.where?.poolIdIn }, + first, + skip: args.skip, + orderBy: JoinExit_OrderBy.Timestamp, + orderDirection: OrderDirection.Desc, + }); - return joinExits.map((joinExit) => ({ - ...joinExit, - __typename: 'GqlPoolJoinExit', - poolId: joinExit.pool.id, - amounts: joinExit.amounts.map((amount, index) => ({ address: joinExit.pool.tokensList[index], amount })), - })); + const mappedJoinExits: GqlPoolJoinExit[] = joinExits.map((joinExit) => ({ + ...joinExit, + __typename: 'GqlPoolJoinExit', + chain: chain, + poolId: joinExit.pool.id, + amounts: joinExit.amounts.map((amount, index) => ({ + address: joinExit.pool.tokensList[index], + amount, + })), + })); + + allChainsJoinExits.push(...mappedJoinExits); + } + + return allChainsJoinExits; } public async getUserJoinExitsForPool( diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index f21b0f40d..d91af3d26 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -730,10 +730,12 @@ enum GqlPoolStakingGaugeStatus { input GqlPoolJoinExitFilter { poolIdIn: [String!] + chainIn: [GqlChain!] } type GqlPoolJoinExit { id: ID! + chain: GqlChain! type: GqlPoolJoinExitType! sender: String! poolId: String! diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index fa646878c..012b2cd56 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -41,6 +41,12 @@ const balancerResolvers: Resolvers = { return poolService.getPoolBatchSwaps(args); }, poolGetJoinExits: async (parent, args, context) => { + const currentChain = headerChain(); + if (!args.where?.chainIn && currentChain) { + args.where = { ...args.where, chainIn: [currentChain] }; + } else if (!args.where?.chainIn) { + throw new Error('Chain is required'); + } return poolService.getPoolJoinExits(args); }, poolGetUserSwapVolume: async (parent, args, context) => { From e99ebc52782d182065709010f7dc4bb5d6f11db7 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 13:03:23 +0100 Subject: [PATCH 08/32] getUserJoinExitsForPool --- modules/pool/lib/pool-swap.service.ts | 7 ++++++- modules/user/user.gql | 8 +++++++- modules/user/user.resolvers.ts | 12 +++++++++--- modules/user/user.service.ts | 3 ++- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index e230009e9..09ae3d080 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -67,10 +67,14 @@ export class PoolSwapService { public async getUserJoinExitsForPool( userAddress: string, poolId: string, + chain: Chain, first = 10, skip = 0, ): Promise { - const { joinExits } = await this.balancerSubgraphService.getPoolJoinExits({ + const balancerSubgraphService = new BalancerSubgraphService( + AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, + ); + const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ where: { pool: poolId, user: userAddress }, first, skip: skip, @@ -82,6 +86,7 @@ export class PoolSwapService { ...joinExit, __typename: 'GqlPoolJoinExit', poolId: joinExit.pool.id, + chain: chain, amounts: joinExit.amounts.map((amount, index) => ({ address: joinExit.pool.tokensList[index], amount })), })); } diff --git a/modules/user/user.gql b/modules/user/user.gql index 50223a760..9a595a15c 100644 --- a/modules/user/user.gql +++ b/modules/user/user.gql @@ -1,7 +1,13 @@ extend type Query { userGetPoolBalances(chains: [GqlChain!], address: String): [GqlUserPoolBalance!]! userGetStaking: [GqlPoolStaking!]! - userGetPoolJoinExits(first: Int = 10, skip: Int = 0, poolId: String!): [GqlPoolJoinExit!]! + userGetPoolJoinExits( + first: Int = 10 + skip: Int = 0 + poolId: String! + chain: GqlChain + address: String + ): [GqlPoolJoinExit!]! userGetSwaps(first: Int = 10, skip: Int = 0, poolId: String!, chain: GqlChain, address: String): [GqlPoolSwap!]! } diff --git a/modules/user/user.resolvers.ts b/modules/user/user.resolvers.ts index ec2f2ba54..6b391fcb6 100644 --- a/modules/user/user.resolvers.ts +++ b/modules/user/user.resolvers.ts @@ -22,10 +22,16 @@ const resolvers: Resolvers = { tokenPrice: tokenService.getPriceForToken(tokenPrices[balance.chain] || [], balance.tokenAddress), })); }, - userGetPoolJoinExits: async (parent, { first, skip, poolId }, context) => { - const accountAddress = getRequiredAccountAddress(context); + userGetPoolJoinExits: async (parent, { first, skip, poolId, chain, address }, context) => { + const currentChain = headerChain(); + if (!chain && currentChain) { + chain = currentChain; + } else if (!chain) { + throw new Error('Chain is required'); + } + const accountAddress = address || getRequiredAccountAddress(context); - return userService.getUserPoolInvestments(accountAddress, poolId, first, skip); + return userService.getUserPoolInvestments(accountAddress, poolId, chain, first, skip); }, userGetSwaps: async (parent, { first, skip, poolId, chain, address }, context) => { const currentChain = headerChain(); diff --git a/modules/user/user.service.ts b/modules/user/user.service.ts index 22aa391a0..cb7028c39 100644 --- a/modules/user/user.service.ts +++ b/modules/user/user.service.ts @@ -33,10 +33,11 @@ export class UserService { public async getUserPoolInvestments( address: string, poolId: string, + chain: Chain, first?: number, skip?: number, ): Promise { - return this.poolSwapService.getUserJoinExitsForPool(address, poolId, first, skip); + return this.poolSwapService.getUserJoinExitsForPool(address, poolId, chain, first, skip); } public async getUserSwaps( From 922a0d51aa06b8cfe1ef2d54260f6ce6b3689fd6 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 13:36:26 +0100 Subject: [PATCH 09/32] remove unused userSwapVolume --- modules/pool/lib/pool-swap.service.ts | 22 ---------------------- modules/pool/pool.gql | 1 - modules/pool/pool.resolvers.ts | 3 --- modules/pool/pool.service.ts | 5 ----- 4 files changed, 31 deletions(-) diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index 09ae3d080..b3330e68a 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -13,7 +13,6 @@ import { QueryPoolGetBatchSwapsArgs, QueryPoolGetJoinExitsArgs, QueryPoolGetSwapsArgs, - QueryPoolGetUserSwapVolumeArgs, } from '../../../schema'; import { Chain, PrismaPoolSwap } from '@prisma/client'; import _ from 'lodash'; @@ -184,27 +183,6 @@ export class PoolSwapService { }); } - public async getUserSwapVolume(args: QueryPoolGetUserSwapVolumeArgs) { - const yesterday = moment().subtract(1, 'day').unix(); - const take = !args.first || args.first > 100 ? 10 : args.first; - - const result = await prisma.prismaPoolSwap.groupBy({ - take, - skip: args.skip || undefined, - by: ['userAddress'], - _sum: { valueUSD: true }, - orderBy: { _sum: { valueUSD: 'desc' } }, - where: { - poolId: { in: args.where?.poolIdIn || undefined }, - tokenIn: { in: args.where?.tokenInIn || undefined }, - tokenOut: { in: args.where?.tokenOutIn || undefined }, - timestamp: { gte: yesterday }, - }, - }); - - return result.map((item) => ({ userAddress: item.userAddress, swapVolumeUSD: `${item._sum.valueUSD || 0}` })); - } - /** * Syncs all swaps for the last 48 hours. We fetch the timestamp of the last stored swap to avoid * duplicate effort. Return an array of poolIds with swaps added. diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index d91af3d26..58db21daa 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -19,7 +19,6 @@ extend type Query { poolGetSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolSwap!]! poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! - poolGetUserSwapVolume(first: Int, skip: Int, where: GqlUserSwapVolumeFilter): [GqlPoolUserSwapVolume!]! poolGetFeaturedPoolGroups: [GqlPoolFeaturedPoolGroup!]! poolGetSnapshots(id: String!, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! poolGetAllPoolsSnapshots(range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 012b2cd56..3429aaf84 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -49,9 +49,6 @@ const balancerResolvers: Resolvers = { } return poolService.getPoolJoinExits(args); }, - poolGetUserSwapVolume: async (parent, args, context) => { - return poolService.getPoolUserSwapVolume(args); - }, poolGetFeaturedPoolGroups: async (parent, args, context) => { return poolService.getFeaturedPoolGroups(); }, diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index 39c0a93f2..3839ed2b4 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -17,7 +17,6 @@ import { QueryPoolGetJoinExitsArgs, QueryPoolGetPoolsArgs, QueryPoolGetSwapsArgs, - QueryPoolGetUserSwapVolumeArgs, } from '../../schema'; import { coingeckoService } from '../coingecko/coingecko.service'; import { balancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; @@ -104,10 +103,6 @@ export class PoolService { return this.poolSwapService.getJoinExits(args); } - public async getPoolUserSwapVolume(args: QueryPoolGetUserSwapVolumeArgs): Promise { - return this.poolSwapService.getUserSwapVolume(args); - } - public async getFeaturedPoolGroups(): Promise { const cached: GqlPoolFeaturedPoolGroup[] = await this.cache.get( `${FEATURED_POOL_GROUPS_CACHE_KEY}:${networkContext.chainId}`, From 1eb702fe2d03525590ed18f20ca7cf5161fc4ea5 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 14:23:54 +0100 Subject: [PATCH 10/32] poolSnapshot --- modules/beethoven/beets.gql | 2 +- modules/beethoven/beets.resolvers.ts | 3 ++- modules/pool/lib/pool-snapshot.service.ts | 11 +++++------ modules/pool/pool.gql | 5 +++-- modules/pool/pool.resolvers.ts | 20 ++++++++++++++++---- modules/pool/pool.service.ts | 10 +++++----- modules/user/lib/user-snapshot.service.ts | 14 +++++++++++--- modules/user/user.service.ts | 3 ++- 8 files changed, 45 insertions(+), 23 deletions(-) diff --git a/modules/beethoven/beets.gql b/modules/beethoven/beets.gql index 445412974..caa15efbb 100644 --- a/modules/beethoven/beets.gql +++ b/modules/beethoven/beets.gql @@ -5,7 +5,7 @@ extend type Query { userGetFbeetsBalance: GqlUserFbeetsBalance! - userGetPoolSnapshots(poolId: String!, range: GqlUserSnapshotDataRange!): [GqlUserPoolSnapshot!]! + userGetPoolSnapshots(poolId: String!, chain: GqlChain!, range: GqlUserSnapshotDataRange!): [GqlUserPoolSnapshot!]! userGetRelicSnapshots(farmId: String!, range: GqlUserSnapshotDataRange!): [GqlUserRelicSnapshot!]! userGetPortfolioSnapshots(days: Int!): [GqlUserPortfolioSnapshot!]! diff --git a/modules/beethoven/beets.resolvers.ts b/modules/beethoven/beets.resolvers.ts index ecb709df7..87e705789 100644 --- a/modules/beethoven/beets.resolvers.ts +++ b/modules/beethoven/beets.resolvers.ts @@ -36,12 +36,13 @@ const beetsResolvers: Resolvers = { ...balance, }; }, - userGetPoolSnapshots: async (parent, { poolId, range }, context) => { + userGetPoolSnapshots: async (parent, { poolId, chain, range }, context) => { const accountAddress = getRequiredAccountAddress(context); return userService.getUserBalanceSnapshotsForPool( accountAddress.toLowerCase(), poolId.toLowerCase(), + chain, range, ); }, diff --git a/modules/pool/lib/pool-snapshot.service.ts b/modules/pool/lib/pool-snapshot.service.ts index e64062b73..3c51d26cc 100644 --- a/modules/pool/lib/pool-snapshot.service.ts +++ b/modules/pool/lib/pool-snapshot.service.ts @@ -1,4 +1,3 @@ -import * as Sentry from '@sentry/node'; import { balancerSubgraphService, BalancerSubgraphService, @@ -12,7 +11,7 @@ import { import { GqlPoolSnapshotDataRange } from '../../../schema'; import moment from 'moment-timezone'; import _ from 'lodash'; -import { PrismaPoolSnapshot } from '@prisma/client'; +import { Chain, PrismaPoolSnapshot } from '@prisma/client'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { prismaPoolWithExpandedNesting } from '../../../prisma/prisma-types'; import { CoingeckoService } from '../../coingecko/coingecko.service'; @@ -27,11 +26,11 @@ export class PoolSnapshotService { private readonly coingeckoService: CoingeckoService, ) {} - public async getSnapshotsForPool(poolId: string, range: GqlPoolSnapshotDataRange) { + public async getSnapshotsForPool(poolId: string, chain: Chain, range: GqlPoolSnapshotDataRange) { const timestamp = this.getTimestampForRange(range); return prisma.prismaPoolSnapshot.findMany({ - where: { poolId, timestamp: { gte: timestamp }, chain: networkContext.chain }, + where: { poolId, timestamp: { gte: timestamp }, chain: chain }, orderBy: { timestamp: 'asc' }, }); } @@ -42,7 +41,7 @@ export class PoolSnapshotService { }); } - public async getSnapshotsForAllPools(range: GqlPoolSnapshotDataRange) { + public async getSnapshotsForAllPools(chains: Chain[], range: GqlPoolSnapshotDataRange) { const timestamp = this.getTimestampForRange(range); return prisma.prismaPoolSnapshot.findMany({ @@ -54,7 +53,7 @@ export class PoolSnapshotService { pool: { categories: { none: { category: 'BLACK_LISTED' } }, }, - chain: networkContext.chain, + chain: { in: chains }, }, orderBy: { timestamp: 'asc' }, }); diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index 58db21daa..240fce4c1 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -20,8 +20,8 @@ extend type Query { poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! poolGetFeaturedPoolGroups: [GqlPoolFeaturedPoolGroup!]! - poolGetSnapshots(id: String!, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! - poolGetAllPoolsSnapshots(range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! + poolGetSnapshots(id: String!, chain: GqlChain, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! + poolGetAllPoolsSnapshots(chains: [GqlChain!], range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! poolGetLinearPools: [GqlPoolLinear!]! } @@ -804,6 +804,7 @@ enum GqlPoolSnapshotDataRange { type GqlPoolSnapshot { id: ID! + chain: GqlChain! poolId: String! timestamp: Int! totalLiquidity: String! diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 3429aaf84..403635ab9 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -52,8 +52,14 @@ const balancerResolvers: Resolvers = { poolGetFeaturedPoolGroups: async (parent, args, context) => { return poolService.getFeaturedPoolGroups(); }, - poolGetSnapshots: async (parent, { id, range }, context) => { - const snapshots = await poolService.getSnapshotsForPool(id, range); + poolGetSnapshots: async (parent, { id, chain, range }, context) => { + const currentChain = headerChain(); + if (!chain && currentChain) { + chain = currentChain; + } else if (!chain) { + throw new Error('Chain is required'); + } + const snapshots = await poolService.getSnapshotsForPool(id, chain, range); return snapshots.map((snapshot) => ({ ...snapshot, @@ -67,8 +73,14 @@ const balancerResolvers: Resolvers = { holdersCount: `${snapshot.holdersCount}`, })); }, - poolGetAllPoolsSnapshots: async (parent, { range }, context) => { - const snapshots = await poolService.getSnapshotsForAllPools(range); + poolGetAllPoolsSnapshots: async (parent, { chains, range }, context) => { + const currentChain = headerChain(); + if (!chains && currentChain) { + chains = [currentChain]; + } else if (!chains) { + chains = []; + } + const snapshots = await poolService.getSnapshotsForAllPools(chains, range); return snapshots.map((snapshot) => ({ ...snapshot, diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index 3839ed2b4..29a863b85 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -1,4 +1,4 @@ -import { PrismaPoolFilter, PrismaPoolStakingType, PrismaPoolSwap } from '@prisma/client'; +import { Chain, PrismaPoolFilter, PrismaPoolStakingType, PrismaPoolSwap } from '@prisma/client'; import _, { chain, includes } from 'lodash'; import { Cache } from 'memory-cache'; import moment from 'moment-timezone'; @@ -123,12 +123,12 @@ export class PoolService { return featuredPoolGroups; } - public async getSnapshotsForAllPools(range: GqlPoolSnapshotDataRange) { - return this.poolSnapshotService.getSnapshotsForAllPools(range); + public async getSnapshotsForAllPools(chains: Chain[], range: GqlPoolSnapshotDataRange) { + return this.poolSnapshotService.getSnapshotsForAllPools(chains, range); } - public async getSnapshotsForPool(poolId: string, range: GqlPoolSnapshotDataRange) { - return this.poolSnapshotService.getSnapshotsForPool(poolId, range); + public async getSnapshotsForPool(poolId: string, chain: Chain, range: GqlPoolSnapshotDataRange) { + return this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); } public async getSnapshotsForReliquaryFarm(id: number, range: GqlPoolSnapshotDataRange) { diff --git a/modules/user/lib/user-snapshot.service.ts b/modules/user/lib/user-snapshot.service.ts index c31e9c2bc..f5d262761 100644 --- a/modules/user/lib/user-snapshot.service.ts +++ b/modules/user/lib/user-snapshot.service.ts @@ -4,7 +4,14 @@ import moment from 'moment-timezone'; import { UserPoolSnapshot, UserRelicSnapshot } from '../user-types'; import { GqlUserSnapshotDataRange } from '../../../schema'; import { PoolSnapshotService } from '../../pool/lib/pool-snapshot.service'; -import { Prisma, PrismaPool, PrismaPoolSnapshot, PrismaPoolStaking, PrismaUserRelicSnapshot } from '@prisma/client'; +import { + Chain, + Prisma, + PrismaPool, + PrismaPoolSnapshot, + PrismaPoolStaking, + PrismaUserRelicSnapshot, +} from '@prisma/client'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { oneDayInSeconds, secondsPerDay } from '../../common/time'; import { UserBalanceSnapshotFragment } from '../../subgraphs/user-snapshot-subgraph/generated/user-snapshot-subgraph-types'; @@ -309,6 +316,7 @@ export class UserSnapshotService { public async getUserPoolBalanceSnapshotsForPool( userAddress: string, poolId: string, + chain: Chain, range: GqlUserSnapshotDataRange, ): Promise { const oldestRequestedSnapshotTimestamp = this.getTimestampForRange(range); @@ -374,7 +382,7 @@ export class UserSnapshotService { const prismaInput: Prisma.PrismaUserPoolBalanceSnapshotCreateManyInput[] = []; - poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, range); + poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); /* For each snapshot from the subgraph, this will get the poolSnapshot for the same timestamp and enrich with $ value data @@ -436,7 +444,7 @@ export class UserSnapshotService { // Only get them if we didn't get them above if (poolSnapshots.length === 0) { - poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, range); + poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); } /* diff --git a/modules/user/user.service.ts b/modules/user/user.service.ts index cb7028c39..716785074 100644 --- a/modules/user/user.service.ts +++ b/modules/user/user.service.ts @@ -61,9 +61,10 @@ export class UserService { public async getUserBalanceSnapshotsForPool( accountAddress: string, poolId: string, + chain: Chain, days: GqlUserSnapshotDataRange, ): Promise { - return this.userSnapshotService.getUserPoolBalanceSnapshotsForPool(accountAddress, poolId, days); + return this.userSnapshotService.getUserPoolBalanceSnapshotsForPool(accountAddress, poolId, chain, days); } public async getUserRelicSnapshots(accountAddress: string, farmId: string, days: GqlUserSnapshotDataRange) { From dee68da3bda72684ee8100b9ed96d183eaacfc60 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 16:39:07 +0100 Subject: [PATCH 11/32] linearPools --- modules/pool/lib/pool-gql-loader.service.ts | 4 +- modules/pool/pool.gql | 2 +- modules/pool/pool.resolvers.ts | 12 +++- modules/pool/pool.service.ts | 4 +- modules/user/user-snapshot.service.test.ts | 61 ++++++++++++++++++--- 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index de5cd2c7a..85e841c54 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -67,9 +67,9 @@ export class PoolGqlLoaderService { return pools.map((pool) => this.mapToMinimalGqlPool(pool)); } - public async getLinearPools(): Promise { + public async getLinearPools(chains: Chain[]): Promise { const pools = await prisma.prismaPool.findMany({ - where: { type: 'LINEAR', chain: networkContext.chain }, + where: { type: 'LINEAR', chain: { in: chains } }, orderBy: { dynamicData: { totalLiquidity: 'desc' } }, include: prismaPoolWithExpandedNesting.include, }); diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index 240fce4c1..f744fde6d 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -22,7 +22,7 @@ extend type Query { poolGetFeaturedPoolGroups: [GqlPoolFeaturedPoolGroup!]! poolGetSnapshots(id: String!, chain: GqlChain, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! poolGetAllPoolsSnapshots(chains: [GqlChain!], range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! - poolGetLinearPools: [GqlPoolLinear!]! + poolGetLinearPools(chains: [GqlChain!]): [GqlPoolLinear!]! } extend type Mutation { diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 403635ab9..3a88f526c 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -78,7 +78,7 @@ const balancerResolvers: Resolvers = { if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - chains = []; + throw new Error('Chain is required'); } const snapshots = await poolService.getSnapshotsForAllPools(chains, range); @@ -94,8 +94,14 @@ const balancerResolvers: Resolvers = { holdersCount: `${snapshot.holdersCount}`, })); }, - poolGetLinearPools: async () => { - return poolService.getGqlLinearPools(); + poolGetLinearPools: async (parent, { chains }, context) => { + const currentChain = headerChain(); + if (!chains && currentChain) { + chains = [currentChain]; + } else if (!chains) { + throw new Error('Chain is required'); + } + return poolService.getGqlLinearPools(chains); }, }, Mutation: { diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index 29a863b85..a6a69bd96 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -69,8 +69,8 @@ export class PoolService { return this.poolGqlLoaderService.getPools(args); } - public async getGqlLinearPools(): Promise { - return this.poolGqlLoaderService.getLinearPools(); + public async getGqlLinearPools(chains: Chain[]): Promise { + return this.poolGqlLoaderService.getLinearPools(chains); } public async getPoolsCount(args: QueryPoolGetPoolsArgs): Promise { diff --git a/modules/user/user-snapshot.service.test.ts b/modules/user/user-snapshot.service.test.ts index 47d8da75b..f97fc4d57 100644 --- a/modules/user/user-snapshot.service.test.ts +++ b/modules/user/user-snapshot.service.test.ts @@ -13,6 +13,7 @@ import { mockServer } from '../tests-helper/mocks/mockHttpServer'; import { userService } from './user.service'; import { secondsPerDay } from '../common/time'; import { networkContext } from '../network/network-context.service'; +import { Chain } from '@prisma/client'; /* TEST SETUP: @@ -182,7 +183,12 @@ test('The user requests the user stats for the first time, requesting from subgr ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); //check if 4th snapshot has been inferred from three present ones expect(snapshotsFromService.length).toBe(4); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -298,6 +304,7 @@ test('User in in the pool for a very long time, requests various different time const thirtySnapshotsFromService = await userService.getUserBalanceSnapshotsForPool( userAddress, poolId1, + Chain.FANTOM, 'THIRTY_DAYS', ); @@ -316,6 +323,7 @@ test('User in in the pool for a very long time, requests various different time const ninetySnapshotsFromService = await userService.getUserBalanceSnapshotsForPool( userAddress, poolId1, + Chain.FANTOM, 'NINETY_DAYS', ); //also includes the one from today @@ -412,7 +420,12 @@ Mock data for user-balance-subgraph (important that timestamps are ASC, as this ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); //check if 4th snapshot has been inferred from three present ones expect(snapshotsFromService.length).toBe(4); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -535,7 +548,12 @@ Mock data for user-balance-subgraph (important that timestamps are ASC, as this ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); //check if 4th snapshot has been inferred from three present ones expect(snapshotsFromService.length).toBe(2); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -627,7 +645,12 @@ test('Return a snapshot with 0 valueUSD if there is no pool snapshot for the giv ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, pool2Id, 'THIRTY_DAYS'); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( + userAddress, + pool2Id, + Chain.FANTOM, + 'THIRTY_DAYS', + ); // should get all 4 snapshots expect(snapshotsFromService.length).toBe(4); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -661,6 +684,7 @@ test('Return a snapshot with 0 valueUSD if there is no pool snapshot for the giv const snapshotsAfterAdditionalPoolSnapshot = await userService.getUserBalanceSnapshotsForPool( userAddress, pool2Id, + Chain.FANTOM, 'THIRTY_DAYS', ); //expect still the same results here as above @@ -804,7 +828,12 @@ test('User snapshots in the database must be picked up and synced by the sync pr expect(snapshotsFromDb.length).toBe(3); // after the sync, all 4 snapshots should be present - const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); expect(snapshotsAfterSync.length).toBe(4); // check if balances are calculated correctly @@ -1000,7 +1029,12 @@ test('User has left and re-entered the pool. Make sure the sync does not persist // after the sync, 5 snapshots should be present. //Sevendaysago, sixdaysago (inferred), fivedaysago (0 balance), fourdays ago (0 balance), threedaysago and twodaysago (0 balance) - const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); expect(snapshotsAfterSync.length).toBe(6); const snapshotsFromDbAfterGet = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -1115,7 +1149,12 @@ test('Todays user snapshot must be gradually updated based on an updated pool sn ], ); - const userSnapshotsBefore = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const userSnapshotsBefore = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); expect(userSnapshotsBefore.length).toBe(1); // check if balances are calculated correctly @@ -1166,7 +1205,12 @@ test('Todays user snapshot must be gradually updated based on an updated pool sn await userService.syncUserBalanceSnapshots(); // check numbers again - const userSnapshotsAfter = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const userSnapshotsAfter = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); expect(userSnapshotsBefore.length).toBe(1); // check if balances are calculated correctly @@ -1292,6 +1336,7 @@ test('User requests pool snapshots for Fidelio Duetto Pool. Make sure fBeets are const userBalanceSnapshots = await userService.getUserBalanceSnapshotsForPool( userAddress, fidelioPoolId, + Chain.FANTOM, 'THIRTY_DAYS', ); expect(userBalanceSnapshots.length).toBe(4); From a99c49acf6843d8459b54ce86c2c389e5016d731 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 16:44:11 +0100 Subject: [PATCH 12/32] userstaking --- modules/pool/pool.gql | 1 + modules/token/token.resolvers.ts | 2 +- modules/user/lib/user-balance.service.ts | 4 ++-- modules/user/user.gql | 2 +- modules/user/user.resolvers.ts | 14 ++++++++++---- modules/user/user.service.ts | 4 ++-- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index f744fde6d..b033434ef 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -712,6 +712,7 @@ input GqlPoolSwapFilter { type GqlPoolStaking { id: ID! + chain: GqlChain! type: GqlPoolStakingType! address: String! gauge: GqlPoolStakingGauge diff --git a/modules/token/token.resolvers.ts b/modules/token/token.resolvers.ts index 8af8f11d3..1fd73b5c9 100644 --- a/modules/token/token.resolvers.ts +++ b/modules/token/token.resolvers.ts @@ -11,7 +11,7 @@ const resolvers: Resolvers = { if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - chains = []; + throw new Error('Chain is required'); } return tokenService.getTokenDefinitions(chains); }, diff --git a/modules/user/lib/user-balance.service.ts b/modules/user/lib/user-balance.service.ts index 200f7837b..fb98fb1f2 100644 --- a/modules/user/lib/user-balance.service.ts +++ b/modules/user/lib/user-balance.service.ts @@ -74,12 +74,12 @@ export class UserBalanceService { }; } - public async getUserStaking(address: string): Promise { + public async getUserStaking(address: string, chains: Chain[]): Promise { const user = await prisma.prismaUser.findUnique({ where: { address }, include: { stakedBalances: { - where: { chain: networkContext.chain, balanceNum: { gt: 0 } }, + where: { chain: { in: chains }, balanceNum: { gt: 0 } }, include: { staking: { include: { diff --git a/modules/user/user.gql b/modules/user/user.gql index 9a595a15c..bdeabede4 100644 --- a/modules/user/user.gql +++ b/modules/user/user.gql @@ -1,6 +1,6 @@ extend type Query { userGetPoolBalances(chains: [GqlChain!], address: String): [GqlUserPoolBalance!]! - userGetStaking: [GqlPoolStaking!]! + userGetStaking(chains: [GqlChain!], address: String): [GqlPoolStaking!]! userGetPoolJoinExits( first: Int = 10 skip: Int = 0 diff --git a/modules/user/user.resolvers.ts b/modules/user/user.resolvers.ts index 6b391fcb6..e94480d62 100644 --- a/modules/user/user.resolvers.ts +++ b/modules/user/user.resolvers.ts @@ -11,7 +11,7 @@ const resolvers: Resolvers = { if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - chains = []; + throw new Error('Chain is required'); } const accountAddress = address || getRequiredAccountAddress(context); const tokenPrices = await tokenService.getTokenPricesForChains(chains); @@ -43,10 +43,16 @@ const resolvers: Resolvers = { const accountAddress = address || getRequiredAccountAddress(context); return userService.getUserSwaps(accountAddress, poolId, chain, first, skip); }, - userGetStaking: async (parent, {}, context) => { - const accountAddress = getRequiredAccountAddress(context); + userGetStaking: async (parent, { chains, address }, context) => { + const currentChain = headerChain(); + if (!chains && currentChain) { + chains = [currentChain]; + } else if (!chains) { + throw new Error('Chain is required'); + } + const accountAddress = address || getRequiredAccountAddress(context); - return userService.getUserStaking(accountAddress); + return userService.getUserStaking(accountAddress, chains); }, }, Mutation: { diff --git a/modules/user/user.service.ts b/modules/user/user.service.ts index 716785074..f58c6104f 100644 --- a/modules/user/user.service.ts +++ b/modules/user/user.service.ts @@ -54,8 +54,8 @@ export class UserService { return this.userBalanceService.getUserFbeetsBalance(address); } - public async getUserStaking(address: string): Promise { - return this.userBalanceService.getUserStaking(address); + public async getUserStaking(address: string, chains: Chain[]): Promise { + return this.userBalanceService.getUserStaking(address, chains); } public async getUserBalanceSnapshotsForPool( From 78d36c128b124aa889e14ae8f7ef3da5d33707c1 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 16:52:04 +0100 Subject: [PATCH 13/32] throw error --- modules/token/token.resolvers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/token/token.resolvers.ts b/modules/token/token.resolvers.ts index 1fd73b5c9..b5c54cafe 100644 --- a/modules/token/token.resolvers.ts +++ b/modules/token/token.resolvers.ts @@ -20,7 +20,7 @@ const resolvers: Resolvers = { if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - chains = []; + throw new Error('Chain is required'); } const prices = await tokenService.getWhiteListedTokenPrices(chains); From 7497f1c0b939f321aad8cb5679c9a9ed8df7718f Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 8 Nov 2023 10:06:27 +0800 Subject: [PATCH 14/32] Add user address filter to pools query --- modules/pool/lib/pool-gql-loader.service.ts | 40 +++++++++++++++++++-- modules/pool/pool.gql | 2 ++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index b381545ee..4ed99b862 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -131,6 +131,7 @@ export class PoolGqlLoaderService { private mapQueryArgsToPoolQuery(args: QueryPoolGetPoolsArgs): Prisma.PrismaPoolFindManyArgs { let orderBy: Prisma.PrismaPoolOrderByWithRelationInput = {}; const orderDirection = args.orderDirection || undefined; + const userAddress = args.userAddress; switch (args.orderBy) { case 'totalLiquidity': @@ -206,6 +207,35 @@ export class PoolGqlLoaderService { }); } + const userArgs: Prisma.PrismaPoolWhereInput = userAddress + ? { + OR: [ + { + userWalletBalances: { + some: { + userAddress: { + equals: userAddress, + mode: 'insensitive' as const, + }, + balanceNum: { gt: 0 }, + }, + }, + }, + { + userStakedBalances: { + some: { + userAddress: { + equals: userAddress, + mode: 'insensitive' as const, + }, + balanceNum: { gt: 0 }, + }, + }, + }, + ], + } + : {}; + const filterArgs: Prisma.PrismaPoolWhereInput = { dynamicData: { totalSharesNum: { @@ -271,7 +301,10 @@ export class PoolGqlLoaderService { if (!textSearch) { return { ...baseQuery, - where: filterArgs, + where: { + ...filterArgs, + ...userArgs, + }, }; } @@ -279,10 +312,11 @@ export class PoolGqlLoaderService { ...baseQuery, where: { OR: [ - { name: textSearch, ...filterArgs }, - { symbol: textSearch, ...filterArgs }, + { name: textSearch, ...filterArgs, ...userArgs }, + { symbol: textSearch, ...filterArgs, ...userArgs }, { ...filterArgs, + ...userArgs, allTokens: { some: { OR: [ diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index af90e7f62..0457a378d 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -7,6 +7,7 @@ extend type Query { orderDirection: GqlPoolOrderDirection where: GqlPoolFilter textSearch: String + userAddress: String ): [GqlPoolMinimal!]! poolGetPoolsCount( first: Int @@ -15,6 +16,7 @@ extend type Query { orderDirection: GqlPoolOrderDirection where: GqlPoolFilter textSearch: String + userAddress: String ): Int! poolGetPoolFilters: [GqlPoolFilterDefinition!]! poolGetSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolSwap!]! From b6c88a1b8c21cc5bde0137380bb8893e6eb85b9a Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 10:37:16 +0100 Subject: [PATCH 15/32] remove sanity poolFilters --- modules/content/sanity-content.service.ts | 33 ----------------------- modules/pool/pool.gql | 1 - modules/pool/pool.resolvers.ts | 3 --- 3 files changed, 37 deletions(-) diff --git a/modules/content/sanity-content.service.ts b/modules/content/sanity-content.service.ts index 00d6dd8b0..67403a1f2 100644 --- a/modules/content/sanity-content.service.ts +++ b/modules/content/sanity-content.service.ts @@ -26,11 +26,6 @@ interface SanityToken { interface SanityPoolConfig { incentivizedPools: string[]; blacklistedPools: string[]; - poolFilters: { - id: string; - title: string; - pools: string[]; - }[]; } const SANITY_TOKEN_TYPE_MAP: { [key: string]: string } = { @@ -209,13 +204,11 @@ export class SanityContentService implements ContentService { const response = await getSanityClient().fetch(`*[_type == "config" && chainId == ${networkContext.chainId}][0]{ incentivizedPools, blacklistedPools, - poolFilters }`); const config: SanityPoolConfig = { incentivizedPools: response?.incentivizedPools ?? [], blacklistedPools: response?.blacklistedPools ?? [], - poolFilters: response?.poolFilters ?? [], }; const categories = await prisma.prismaPoolCategory.findMany({ where: { chain: networkContext.chain } }); @@ -224,32 +217,6 @@ export class SanityContentService implements ContentService { await this.updatePoolCategory(incentivized, config.incentivizedPools, 'INCENTIVIZED'); await this.updatePoolCategory(blacklisted, config.blacklistedPools, 'BLACK_LISTED'); - - await prisma.$transaction([ - prisma.prismaPoolFilterMap.deleteMany({ where: { chain: networkContext.chain } }), - prisma.prismaPoolFilter.deleteMany({ where: { chain: networkContext.chain } }), - prisma.prismaPoolFilter.createMany({ - data: config.poolFilters.map((item) => ({ - id: item.id, - chain: networkContext.chain, - title: item.title, - })), - skipDuplicates: true, - }), - prisma.prismaPoolFilterMap.createMany({ - data: config.poolFilters - .map((item) => { - return item.pools.map((poolId) => ({ - id: `${item.id}-${poolId}`, - chain: networkContext.chain, - poolId, - filterId: item.id, - })); - }) - .flat(), - skipDuplicates: true, - }), - ]); } private async updatePoolCategory(currentPoolIds: string[], newPoolIds: string[], category: PrismaPoolCategoryType) { diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index af90e7f62..dfa3a7786 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -16,7 +16,6 @@ extend type Query { where: GqlPoolFilter textSearch: String ): Int! - poolGetPoolFilters: [GqlPoolFilterDefinition!]! poolGetSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolSwap!]! poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index d958ca087..9f29bf8f2 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -15,9 +15,6 @@ const balancerResolvers: Resolvers = { poolGetPoolsCount: async (parent, args, context) => { return poolService.getPoolsCount(args); }, - poolGetPoolFilters: async (parent, {}, context) => { - return poolService.getPoolFilters(); - }, poolGetSwaps: async (parent, args, context) => { return poolService.getPoolSwaps(args); }, From 9c8abfe1ec27e502b1c435fba44c68f4ab6e7d1c Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 7 Nov 2023 13:36:26 +0100 Subject: [PATCH 16/32] remove unused userSwapVolume --- modules/pool/lib/pool-swap.service.ts | 22 ---------------------- modules/pool/pool.gql | 1 - modules/pool/pool.resolvers.ts | 3 --- modules/pool/pool.service.ts | 5 ----- 4 files changed, 31 deletions(-) diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index 83430ab05..7de0530db 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -13,7 +13,6 @@ import { QueryPoolGetBatchSwapsArgs, QueryPoolGetJoinExitsArgs, QueryPoolGetSwapsArgs, - QueryPoolGetUserSwapVolumeArgs, } from '../../../schema'; import { PrismaPoolSwap } from '@prisma/client'; import _ from 'lodash'; @@ -153,27 +152,6 @@ export class PoolSwapService { }); } - public async getUserSwapVolume(args: QueryPoolGetUserSwapVolumeArgs) { - const yesterday = moment().subtract(1, 'day').unix(); - const take = !args.first || args.first > 100 ? 10 : args.first; - - const result = await prisma.prismaPoolSwap.groupBy({ - take, - skip: args.skip || undefined, - by: ['userAddress'], - _sum: { valueUSD: true }, - orderBy: { _sum: { valueUSD: 'desc' } }, - where: { - poolId: { in: args.where?.poolIdIn || undefined }, - tokenIn: { in: args.where?.tokenInIn || undefined }, - tokenOut: { in: args.where?.tokenOutIn || undefined }, - timestamp: { gte: yesterday }, - }, - }); - - return result.map((item) => ({ userAddress: item.userAddress, swapVolumeUSD: `${item._sum.valueUSD || 0}` })); - } - /** * Syncs all swaps for the last 48 hours. We fetch the timestamp of the last stored swap to avoid * duplicate effort. Return an array of poolIds with swaps added. diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index dfa3a7786..061eaa2ab 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -19,7 +19,6 @@ extend type Query { poolGetSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolSwap!]! poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! - poolGetUserSwapVolume(first: Int, skip: Int, where: GqlUserSwapVolumeFilter): [GqlPoolUserSwapVolume!]! poolGetFeaturedPoolGroups: [GqlPoolFeaturedPoolGroup!]! poolGetSnapshots(id: String!, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! poolGetAllPoolsSnapshots(range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 9f29bf8f2..c3f80f032 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -24,9 +24,6 @@ const balancerResolvers: Resolvers = { poolGetJoinExits: async (parent, args, context) => { return poolService.getPoolJoinExits(args); }, - poolGetUserSwapVolume: async (parent, args, context) => { - return poolService.getPoolUserSwapVolume(args); - }, poolGetFeaturedPoolGroups: async (parent, args, context) => { return poolService.getFeaturedPoolGroups(); }, diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index 852a03bc0..97e2d37f1 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -16,7 +16,6 @@ import { QueryPoolGetJoinExitsArgs, QueryPoolGetPoolsArgs, QueryPoolGetSwapsArgs, - QueryPoolGetUserSwapVolumeArgs, } from '../../schema'; import { coingeckoService } from '../coingecko/coingecko.service'; import { balancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; @@ -103,10 +102,6 @@ export class PoolService { return this.poolSwapService.getJoinExits(args); } - public async getPoolUserSwapVolume(args: QueryPoolGetUserSwapVolumeArgs): Promise { - return this.poolSwapService.getUserSwapVolume(args); - } - public async getFeaturedPoolGroups(): Promise { const cached: GqlPoolFeaturedPoolGroup[] = await this.cache.get( `${FEATURED_POOL_GROUPS_CACHE_KEY}:${networkContext.chainId}`, From 1d79b07bdabdedca7d326fb45b9454cbb01bd60b Mon Sep 17 00:00:00 2001 From: franz Date: Wed, 8 Nov 2023 16:25:41 +0100 Subject: [PATCH 17/32] Revert "remove unused userSwapVolume" This reverts commit 922a0d51aa06b8cfe1ef2d54260f6ce6b3689fd6. --- modules/pool/lib/pool-swap.service.ts | 22 ++++++++++++++++++++++ modules/pool/pool.gql | 1 + modules/pool/pool.resolvers.ts | 3 +++ modules/pool/pool.service.ts | 5 +++++ 4 files changed, 31 insertions(+) diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index b3330e68a..09ae3d080 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -13,6 +13,7 @@ import { QueryPoolGetBatchSwapsArgs, QueryPoolGetJoinExitsArgs, QueryPoolGetSwapsArgs, + QueryPoolGetUserSwapVolumeArgs, } from '../../../schema'; import { Chain, PrismaPoolSwap } from '@prisma/client'; import _ from 'lodash'; @@ -183,6 +184,27 @@ export class PoolSwapService { }); } + public async getUserSwapVolume(args: QueryPoolGetUserSwapVolumeArgs) { + const yesterday = moment().subtract(1, 'day').unix(); + const take = !args.first || args.first > 100 ? 10 : args.first; + + const result = await prisma.prismaPoolSwap.groupBy({ + take, + skip: args.skip || undefined, + by: ['userAddress'], + _sum: { valueUSD: true }, + orderBy: { _sum: { valueUSD: 'desc' } }, + where: { + poolId: { in: args.where?.poolIdIn || undefined }, + tokenIn: { in: args.where?.tokenInIn || undefined }, + tokenOut: { in: args.where?.tokenOutIn || undefined }, + timestamp: { gte: yesterday }, + }, + }); + + return result.map((item) => ({ userAddress: item.userAddress, swapVolumeUSD: `${item._sum.valueUSD || 0}` })); + } + /** * Syncs all swaps for the last 48 hours. We fetch the timestamp of the last stored swap to avoid * duplicate effort. Return an array of poolIds with swaps added. diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index b033434ef..148eecd3d 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -19,6 +19,7 @@ extend type Query { poolGetSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolSwap!]! poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! + poolGetUserSwapVolume(first: Int, skip: Int, where: GqlUserSwapVolumeFilter): [GqlPoolUserSwapVolume!]! poolGetFeaturedPoolGroups: [GqlPoolFeaturedPoolGroup!]! poolGetSnapshots(id: String!, chain: GqlChain, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! poolGetAllPoolsSnapshots(chains: [GqlChain!], range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 3a88f526c..8301488c8 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -49,6 +49,9 @@ const balancerResolvers: Resolvers = { } return poolService.getPoolJoinExits(args); }, + poolGetUserSwapVolume: async (parent, args, context) => { + return poolService.getPoolUserSwapVolume(args); + }, poolGetFeaturedPoolGroups: async (parent, args, context) => { return poolService.getFeaturedPoolGroups(); }, diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index a6a69bd96..d75daab8d 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -17,6 +17,7 @@ import { QueryPoolGetJoinExitsArgs, QueryPoolGetPoolsArgs, QueryPoolGetSwapsArgs, + QueryPoolGetUserSwapVolumeArgs, } from '../../schema'; import { coingeckoService } from '../coingecko/coingecko.service'; import { balancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; @@ -103,6 +104,10 @@ export class PoolService { return this.poolSwapService.getJoinExits(args); } + public async getPoolUserSwapVolume(args: QueryPoolGetUserSwapVolumeArgs): Promise { + return this.poolSwapService.getUserSwapVolume(args); + } + public async getFeaturedPoolGroups(): Promise { const cached: GqlPoolFeaturedPoolGroup[] = await this.cache.get( `${FEATURED_POOL_GROUPS_CACHE_KEY}:${networkContext.chainId}`, From 381183d0bca4d7c93fa89dc6c0b685d081af0a33 Mon Sep 17 00:00:00 2001 From: franz Date: Wed, 8 Nov 2023 16:25:53 +0100 Subject: [PATCH 18/32] Revert "remove sanity poolFilters" This reverts commit 863ff81acb13c5e47675f1f5e87ddda2b5ba394b. --- modules/content/sanity-content.service.ts | 33 +++++++++++++++++++++++ modules/pool/pool.gql | 1 + modules/pool/pool.resolvers.ts | 3 +++ 3 files changed, 37 insertions(+) diff --git a/modules/content/sanity-content.service.ts b/modules/content/sanity-content.service.ts index 67403a1f2..00d6dd8b0 100644 --- a/modules/content/sanity-content.service.ts +++ b/modules/content/sanity-content.service.ts @@ -26,6 +26,11 @@ interface SanityToken { interface SanityPoolConfig { incentivizedPools: string[]; blacklistedPools: string[]; + poolFilters: { + id: string; + title: string; + pools: string[]; + }[]; } const SANITY_TOKEN_TYPE_MAP: { [key: string]: string } = { @@ -204,11 +209,13 @@ export class SanityContentService implements ContentService { const response = await getSanityClient().fetch(`*[_type == "config" && chainId == ${networkContext.chainId}][0]{ incentivizedPools, blacklistedPools, + poolFilters }`); const config: SanityPoolConfig = { incentivizedPools: response?.incentivizedPools ?? [], blacklistedPools: response?.blacklistedPools ?? [], + poolFilters: response?.poolFilters ?? [], }; const categories = await prisma.prismaPoolCategory.findMany({ where: { chain: networkContext.chain } }); @@ -217,6 +224,32 @@ export class SanityContentService implements ContentService { await this.updatePoolCategory(incentivized, config.incentivizedPools, 'INCENTIVIZED'); await this.updatePoolCategory(blacklisted, config.blacklistedPools, 'BLACK_LISTED'); + + await prisma.$transaction([ + prisma.prismaPoolFilterMap.deleteMany({ where: { chain: networkContext.chain } }), + prisma.prismaPoolFilter.deleteMany({ where: { chain: networkContext.chain } }), + prisma.prismaPoolFilter.createMany({ + data: config.poolFilters.map((item) => ({ + id: item.id, + chain: networkContext.chain, + title: item.title, + })), + skipDuplicates: true, + }), + prisma.prismaPoolFilterMap.createMany({ + data: config.poolFilters + .map((item) => { + return item.pools.map((poolId) => ({ + id: `${item.id}-${poolId}`, + chain: networkContext.chain, + poolId, + filterId: item.id, + })); + }) + .flat(), + skipDuplicates: true, + }), + ]); } private async updatePoolCategory(currentPoolIds: string[], newPoolIds: string[], category: PrismaPoolCategoryType) { diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index 148eecd3d..697ae197d 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -16,6 +16,7 @@ extend type Query { where: GqlPoolFilter textSearch: String ): Int! + poolGetPoolFilters: [GqlPoolFilterDefinition!]! poolGetSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolSwap!]! poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 8301488c8..7d8319f3a 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -22,6 +22,9 @@ const balancerResolvers: Resolvers = { poolGetPoolsCount: async (parent, args, context) => { return poolService.getPoolsCount(args); }, + poolGetPoolFilters: async (parent, {}, context) => { + return poolService.getPoolFilters(); + }, poolGetSwaps: async (parent, args, context) => { const currentChain = headerChain(); if (!args.where?.chainIn && currentChain) { From f1d058c7312a11455b5835868827c7231474afd0 Mon Sep 17 00:00:00 2001 From: franz Date: Thu, 9 Nov 2023 13:01:04 +0100 Subject: [PATCH 19/32] return timestamp --- modules/balancer/balancer.resolvers.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/balancer/balancer.resolvers.ts b/modules/balancer/balancer.resolvers.ts index ba97d0c87..00723d41e 100644 --- a/modules/balancer/balancer.resolvers.ts +++ b/modules/balancer/balancer.resolvers.ts @@ -1,9 +1,10 @@ +import moment from 'moment'; import { Resolvers } from '../../schema'; const balancerResolvers: Resolvers = { Query: { balancerQueryTest: async (parent, {}, context) => { - return 'test'; + return `${moment().utc().valueOf()}`; }, }, Mutation: { From 1e0cecb95429421b5b4e53f2b2d196b952c01bb2 Mon Sep 17 00:00:00 2001 From: franz Date: Thu, 9 Nov 2023 13:45:08 +0100 Subject: [PATCH 20/32] include blacklisted pools by default --- modules/pool/lib/pool-gql-loader.service.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index 4ed99b862..06b567f3e 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -261,11 +261,15 @@ export class PoolGqlLoaderService { mode: 'insensitive', }, categories: { - every: { - category: { - notIn: ['BLACK_LISTED', ...(where?.categoryNotIn || [])], - }, - }, + ...(where?.categoryNotIn + ? { + every: { + category: { + notIn: where.categoryNotIn, + }, + }, + } + : {}), ...(where?.categoryIn ? { some: { From a465433fc2d1cd3467b5307fbcb8cbb78f2b16b0 Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Thu, 9 Nov 2023 21:16:12 +0100 Subject: [PATCH 21/32] new composable stable factory on zkevm (#525) --- modules/network/zkevm.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index cc45ad53e..80a53b2ef 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -72,6 +72,7 @@ const zkevmNetworkData: NetworkData = { composableStablePoolFactories: [ '0x8ea89804145c007e7d226001a96955ad53836087', '0x956ccab09898c0af2aca5e6c229c3ad4e93d9288', + '0x577e5993b9cc480f07f98b5ebd055604bd9071c4' ], weightedPoolV2Factories: ['0x03f3fb107e74f2eac9358862e91ad3c692712054'], swapProtocolFeePercentage: 0.5, From c6f9f8cbc29b4c4a43e36ab86ec5d9de1e1ee630 Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Fri, 10 Nov 2023 10:47:58 +0100 Subject: [PATCH 22/32] Revert "Feature/multichain filter" (#526) --- modules/beethoven/beets.gql | 2 +- modules/beethoven/beets.resolvers.ts | 3 +- modules/gnosis/gnosis-safe.service.ts | 54 +++++++++++++++ modules/pool/lib/pool-gql-loader.service.ts | 11 ++- modules/pool/lib/pool-snapshot.service.ts | 11 +-- modules/pool/lib/pool-swap.service.ts | 67 +++++-------------- modules/pool/pool.gql | 15 ++--- modules/pool/pool.resolvers.ts | 59 +++------------- modules/pool/pool.service.ts | 25 ++++--- .../balancer-subgraph.service.ts | 4 +- modules/token/token.resolvers.ts | 9 +-- modules/user/lib/user-balance.service.ts | 4 +- modules/user/lib/user-snapshot.service.ts | 14 +--- modules/user/user-snapshot.service.test.ts | 61 +++-------------- modules/user/user.gql | 12 +--- modules/user/user.resolvers.ts | 40 +++-------- modules/user/user.service.ts | 21 ++---- 17 files changed, 150 insertions(+), 262 deletions(-) create mode 100644 modules/gnosis/gnosis-safe.service.ts diff --git a/modules/beethoven/beets.gql b/modules/beethoven/beets.gql index caa15efbb..445412974 100644 --- a/modules/beethoven/beets.gql +++ b/modules/beethoven/beets.gql @@ -5,7 +5,7 @@ extend type Query { userGetFbeetsBalance: GqlUserFbeetsBalance! - userGetPoolSnapshots(poolId: String!, chain: GqlChain!, range: GqlUserSnapshotDataRange!): [GqlUserPoolSnapshot!]! + userGetPoolSnapshots(poolId: String!, range: GqlUserSnapshotDataRange!): [GqlUserPoolSnapshot!]! userGetRelicSnapshots(farmId: String!, range: GqlUserSnapshotDataRange!): [GqlUserRelicSnapshot!]! userGetPortfolioSnapshots(days: Int!): [GqlUserPortfolioSnapshot!]! diff --git a/modules/beethoven/beets.resolvers.ts b/modules/beethoven/beets.resolvers.ts index 87e705789..ecb709df7 100644 --- a/modules/beethoven/beets.resolvers.ts +++ b/modules/beethoven/beets.resolvers.ts @@ -36,13 +36,12 @@ const beetsResolvers: Resolvers = { ...balance, }; }, - userGetPoolSnapshots: async (parent, { poolId, chain, range }, context) => { + userGetPoolSnapshots: async (parent, { poolId, range }, context) => { const accountAddress = getRequiredAccountAddress(context); return userService.getUserBalanceSnapshotsForPool( accountAddress.toLowerCase(), poolId.toLowerCase(), - chain, range, ); }, diff --git a/modules/gnosis/gnosis-safe.service.ts b/modules/gnosis/gnosis-safe.service.ts new file mode 100644 index 000000000..5ecff4151 --- /dev/null +++ b/modules/gnosis/gnosis-safe.service.ts @@ -0,0 +1,54 @@ +import Safe, { ContractNetworksConfig, EthersAdapter } from '@gnosis.pm/safe-core-sdk'; +import { ethers, providers } from 'ethers'; +import { getAddress } from 'ethers/lib/utils'; +import { Cache } from 'memory-cache'; +import { networkContext } from '../network/network-context.service'; + +const CACHE_KEY_PREFIX = `gnosis-address-is-multisig_`; +const TIMEOUT = 2592000; //30 days + +const contractNetworks: ContractNetworksConfig = { + 250: { + safeProxyFactoryAddress: '0xc3C41Ab65Dabe3ae250A0A1FE4706FdB7ECEB951', + multiSendAddress: '0xd1b160Ee570632ac402Efb230d720669604918e8', + safeMasterCopyAddress: '0x87EB227FE974e9E1d3Bc4Da562e0Bd3C348c2B34', + }, +}; + +export class GnosisSafeService { + private cache = new Cache(); + + public async isAddressGnosisSafe(address: string) { + const key = `${CACHE_KEY_PREFIX}:${networkContext.chainId}:${address}`; + const cachedValue = this.cache.get(key); + if (cachedValue != null) { + return cachedValue; + } + + try { + await Safe.create({ + ethAdapter: await this.getAdapter(), + safeAddress: getAddress(address), + contractNetworks, + }); + + this.cache.put(key, true, TIMEOUT); + return true; + } catch { + this.cache.put(key, false, TIMEOUT); + return false; + } + } + + private async getAdapter() { + const provider = new providers.JsonRpcProvider(networkContext.data.rpcUrl); + const signer = ethers.Wallet.createRandom(); + + return new EthersAdapter({ + ethers, + signer: signer.connect(provider), + }); + } +} + +export const gnosisSafeService = new GnosisSafeService(); diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index 85e841c54..b381545ee 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -11,7 +11,6 @@ import { import { GqlBalancePoolAprItem, GqlBalancePoolAprSubItem, - GqlChain, GqlPoolDynamicData, GqlPoolFeaturedPoolGroup, GqlPoolInvestConfig, @@ -34,16 +33,16 @@ import { import { isSameAddress } from '@balancer-labs/sdk'; import _ from 'lodash'; import { prisma } from '../../../prisma/prisma-client'; -import { Chain, Prisma, PrismaPoolAprType } from '@prisma/client'; +import { Prisma, PrismaPoolAprType } from '@prisma/client'; import { isWeightedPoolV2 } from './pool-utils'; import { oldBnum } from '../../big-number/old-big-number'; import { networkContext } from '../../network/network-context.service'; import { fixedNumber } from '../../view-helpers/fixed-number'; export class PoolGqlLoaderService { - public async getPool(id: string, chain: Chain): Promise { + public async getPool(id: string): Promise { const pool = await prisma.prismaPool.findUnique({ - where: { id_chain: { id, chain: chain } }, + where: { id_chain: { id, chain: networkContext.chain } }, include: prismaPoolWithExpandedNesting.include, }); @@ -67,9 +66,9 @@ export class PoolGqlLoaderService { return pools.map((pool) => this.mapToMinimalGqlPool(pool)); } - public async getLinearPools(chains: Chain[]): Promise { + public async getLinearPools(): Promise { const pools = await prisma.prismaPool.findMany({ - where: { type: 'LINEAR', chain: { in: chains } }, + where: { type: 'LINEAR', chain: networkContext.chain }, orderBy: { dynamicData: { totalLiquidity: 'desc' } }, include: prismaPoolWithExpandedNesting.include, }); diff --git a/modules/pool/lib/pool-snapshot.service.ts b/modules/pool/lib/pool-snapshot.service.ts index 3c51d26cc..e64062b73 100644 --- a/modules/pool/lib/pool-snapshot.service.ts +++ b/modules/pool/lib/pool-snapshot.service.ts @@ -1,3 +1,4 @@ +import * as Sentry from '@sentry/node'; import { balancerSubgraphService, BalancerSubgraphService, @@ -11,7 +12,7 @@ import { import { GqlPoolSnapshotDataRange } from '../../../schema'; import moment from 'moment-timezone'; import _ from 'lodash'; -import { Chain, PrismaPoolSnapshot } from '@prisma/client'; +import { PrismaPoolSnapshot } from '@prisma/client'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { prismaPoolWithExpandedNesting } from '../../../prisma/prisma-types'; import { CoingeckoService } from '../../coingecko/coingecko.service'; @@ -26,11 +27,11 @@ export class PoolSnapshotService { private readonly coingeckoService: CoingeckoService, ) {} - public async getSnapshotsForPool(poolId: string, chain: Chain, range: GqlPoolSnapshotDataRange) { + public async getSnapshotsForPool(poolId: string, range: GqlPoolSnapshotDataRange) { const timestamp = this.getTimestampForRange(range); return prisma.prismaPoolSnapshot.findMany({ - where: { poolId, timestamp: { gte: timestamp }, chain: chain }, + where: { poolId, timestamp: { gte: timestamp }, chain: networkContext.chain }, orderBy: { timestamp: 'asc' }, }); } @@ -41,7 +42,7 @@ export class PoolSnapshotService { }); } - public async getSnapshotsForAllPools(chains: Chain[], range: GqlPoolSnapshotDataRange) { + public async getSnapshotsForAllPools(range: GqlPoolSnapshotDataRange) { const timestamp = this.getTimestampForRange(range); return prisma.prismaPoolSnapshot.findMany({ @@ -53,7 +54,7 @@ export class PoolSnapshotService { pool: { categories: { none: { category: 'BLACK_LISTED' } }, }, - chain: { in: chains }, + chain: networkContext.chain, }, orderBy: { timestamp: 'asc' }, }); diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index b3330e68a..7de0530db 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -14,13 +14,12 @@ import { QueryPoolGetJoinExitsArgs, QueryPoolGetSwapsArgs, } from '../../../schema'; -import { Chain, PrismaPoolSwap } from '@prisma/client'; +import { PrismaPoolSwap } from '@prisma/client'; import _ from 'lodash'; import { isSupportedInt, prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { PrismaPoolBatchSwapWithSwaps, prismaPoolMinimal } from '../../../prisma/prisma-types'; import { networkContext } from '../../network/network-context.service'; import * as Sentry from '@sentry/node'; -import { AllNetworkConfigsKeyedOnChain } from '../../network/network-config'; export class PoolSwapService { constructor( @@ -31,49 +30,29 @@ export class PoolSwapService { public async getJoinExits(args: QueryPoolGetJoinExitsArgs): Promise { const first = !args.first || args.first > 100 ? 10 : args.first; - const allChainsJoinExits: GqlPoolJoinExit[] = []; - - for (const chain of args.where!.chainIn!) { - const balancerSubgraphService = new BalancerSubgraphService( - AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, - ); - - const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ - where: { pool_in: args.where?.poolIdIn }, - first, - skip: args.skip, - orderBy: JoinExit_OrderBy.Timestamp, - orderDirection: OrderDirection.Desc, - }); - - const mappedJoinExits: GqlPoolJoinExit[] = joinExits.map((joinExit) => ({ - ...joinExit, - __typename: 'GqlPoolJoinExit', - chain: chain, - poolId: joinExit.pool.id, - amounts: joinExit.amounts.map((amount, index) => ({ - address: joinExit.pool.tokensList[index], - amount, - })), - })); - - allChainsJoinExits.push(...mappedJoinExits); - } + const { joinExits } = await this.balancerSubgraphService.getPoolJoinExits({ + where: { pool_in: args.where?.poolIdIn }, + first, + skip: args.skip, + orderBy: JoinExit_OrderBy.Timestamp, + orderDirection: OrderDirection.Desc, + }); - return allChainsJoinExits; + return joinExits.map((joinExit) => ({ + ...joinExit, + __typename: 'GqlPoolJoinExit', + poolId: joinExit.pool.id, + amounts: joinExit.amounts.map((amount, index) => ({ address: joinExit.pool.tokensList[index], amount })), + })); } public async getUserJoinExitsForPool( userAddress: string, poolId: string, - chain: Chain, first = 10, skip = 0, ): Promise { - const balancerSubgraphService = new BalancerSubgraphService( - AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, - ); - const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ + const { joinExits } = await this.balancerSubgraphService.getPoolJoinExits({ where: { pool: poolId, user: userAddress }, first, skip: skip, @@ -85,7 +64,6 @@ export class PoolSwapService { ...joinExit, __typename: 'GqlPoolJoinExit', poolId: joinExit.pool.id, - chain: chain, amounts: joinExit.amounts.map((amount, index) => ({ address: joinExit.pool.tokensList[index], amount })), })); } @@ -106,9 +84,7 @@ export class PoolSwapService { tokenOut: { in: args.where?.tokenOutIn || undefined, }, - chain: { - in: args.where?.chainIn || undefined, - }, + chain: networkContext.chain, }, orderBy: { timestamp: 'desc' }, }); @@ -117,14 +93,10 @@ export class PoolSwapService { public async getUserSwapsForPool( userAddress: string, poolId: string, - chain: Chain, first = 10, skip = 0, ): Promise { - const balancerSubgraphService = new BalancerSubgraphService( - AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, - ); - const result = await balancerSubgraphService.getSwaps({ + const result = await this.balancerSubgraphService.getSwaps({ first, skip, where: { @@ -137,7 +109,6 @@ export class PoolSwapService { return result.swaps.map((swap) => ({ id: swap.id, - chain: chain, userAddress, poolId: swap.poolId.id, tokenIn: swap.tokenIn, @@ -172,9 +143,7 @@ export class PoolSwapService { tokenOut: { in: args.where?.tokenOutIn || undefined, }, - chain: { - in: args.where?.chainIn || undefined, - }, + chain: networkContext.chain, }, orderBy: { timestamp: 'desc' }, include: { diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index b033434ef..061eaa2ab 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -1,5 +1,5 @@ extend type Query { - poolGetPool(id: String!, chain: GqlChain): GqlPoolBase! + poolGetPool(id: String!): GqlPoolBase! poolGetPools( first: Int skip: Int @@ -20,9 +20,9 @@ extend type Query { poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! poolGetFeaturedPoolGroups: [GqlPoolFeaturedPoolGroup!]! - poolGetSnapshots(id: String!, chain: GqlChain, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! - poolGetAllPoolsSnapshots(chains: [GqlChain!], range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! - poolGetLinearPools(chains: [GqlChain!]): [GqlPoolLinear!]! + poolGetSnapshots(id: String!, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! + poolGetAllPoolsSnapshots(range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! + poolGetLinearPools: [GqlPoolLinear!]! } extend type Mutation { @@ -657,7 +657,6 @@ type GqlPoolFilterDefinition { type GqlPoolSwap { id: ID! - chain: GqlChain! poolId: String! userAddress: String! tokenIn: String! @@ -671,7 +670,6 @@ type GqlPoolSwap { type GqlPoolBatchSwap { id: ID! - chain: GqlChain! userAddress: String! tokenIn: String! tokenOut: String! @@ -707,12 +705,10 @@ input GqlPoolSwapFilter { tokenInIn: [String!] tokenOutIn: [String!] poolIdIn: [String!] - chainIn: [GqlChain!] } type GqlPoolStaking { id: ID! - chain: GqlChain! type: GqlPoolStakingType! address: String! gauge: GqlPoolStakingGauge @@ -730,12 +726,10 @@ enum GqlPoolStakingGaugeStatus { input GqlPoolJoinExitFilter { poolIdIn: [String!] - chainIn: [GqlChain!] } type GqlPoolJoinExit { id: ID! - chain: GqlChain! type: GqlPoolJoinExitType! sender: String! poolId: String! @@ -805,7 +799,6 @@ enum GqlPoolSnapshotDataRange { type GqlPoolSnapshot { id: ID! - chain: GqlChain! poolId: String! timestamp: Int! totalLiquidity: String! diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 3a88f526c..c3f80f032 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -3,18 +3,11 @@ import { Resolvers } from '../../schema'; import { isAdminRoute } from '../auth/auth-context'; import { prisma } from '../../prisma/prisma-client'; import { networkContext } from '../network/network-context.service'; -import { headerChain } from '../context/header-chain'; const balancerResolvers: Resolvers = { Query: { - poolGetPool: async (parent, { id, chain }, context) => { - const currentChain = headerChain(); - if (!chain && currentChain) { - chain = currentChain; - } else if (!chain) { - throw new Error('Chain is required'); - } - return poolService.getGqlPool(id, chain); + poolGetPool: async (parent, { id }, context) => { + return poolService.getGqlPool(id); }, poolGetPools: async (parent, args, context) => { return poolService.getGqlPools(args); @@ -23,43 +16,19 @@ const balancerResolvers: Resolvers = { return poolService.getPoolsCount(args); }, poolGetSwaps: async (parent, args, context) => { - const currentChain = headerChain(); - if (!args.where?.chainIn && currentChain) { - args.where = { ...args.where, chainIn: [currentChain] }; - } else if (!args.where?.chainIn) { - throw new Error('Chain is required'); - } return poolService.getPoolSwaps(args); }, poolGetBatchSwaps: async (parent, args, context) => { - const currentChain = headerChain(); - if (!args.where?.chainIn && currentChain) { - args.where = { ...args.where, chainIn: [currentChain] }; - } else if (!args.where?.chainIn) { - throw new Error('Chain is required'); - } return poolService.getPoolBatchSwaps(args); }, poolGetJoinExits: async (parent, args, context) => { - const currentChain = headerChain(); - if (!args.where?.chainIn && currentChain) { - args.where = { ...args.where, chainIn: [currentChain] }; - } else if (!args.where?.chainIn) { - throw new Error('Chain is required'); - } return poolService.getPoolJoinExits(args); }, poolGetFeaturedPoolGroups: async (parent, args, context) => { return poolService.getFeaturedPoolGroups(); }, - poolGetSnapshots: async (parent, { id, chain, range }, context) => { - const currentChain = headerChain(); - if (!chain && currentChain) { - chain = currentChain; - } else if (!chain) { - throw new Error('Chain is required'); - } - const snapshots = await poolService.getSnapshotsForPool(id, chain, range); + poolGetSnapshots: async (parent, { id, range }, context) => { + const snapshots = await poolService.getSnapshotsForPool(id, range); return snapshots.map((snapshot) => ({ ...snapshot, @@ -73,14 +42,8 @@ const balancerResolvers: Resolvers = { holdersCount: `${snapshot.holdersCount}`, })); }, - poolGetAllPoolsSnapshots: async (parent, { chains, range }, context) => { - const currentChain = headerChain(); - if (!chains && currentChain) { - chains = [currentChain]; - } else if (!chains) { - throw new Error('Chain is required'); - } - const snapshots = await poolService.getSnapshotsForAllPools(chains, range); + poolGetAllPoolsSnapshots: async (parent, { range }, context) => { + const snapshots = await poolService.getSnapshotsForAllPools(range); return snapshots.map((snapshot) => ({ ...snapshot, @@ -94,14 +57,8 @@ const balancerResolvers: Resolvers = { holdersCount: `${snapshot.holdersCount}`, })); }, - poolGetLinearPools: async (parent, { chains }, context) => { - const currentChain = headerChain(); - if (!chains && currentChain) { - chains = [currentChain]; - } else if (!chains) { - throw new Error('Chain is required'); - } - return poolService.getGqlLinearPools(chains); + poolGetLinearPools: async () => { + return poolService.getGqlLinearPools(); }, }, Mutation: { diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index a6a69bd96..97e2d37f1 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -1,10 +1,9 @@ -import { Chain, PrismaPoolFilter, PrismaPoolStakingType, PrismaPoolSwap } from '@prisma/client'; +import { PrismaPoolFilter, PrismaPoolStakingType, PrismaPoolSwap } from '@prisma/client'; import _, { chain, includes } from 'lodash'; import { Cache } from 'memory-cache'; import moment from 'moment-timezone'; import { prisma } from '../../prisma/prisma-client'; import { - GqlChain, GqlPoolBatchSwap, GqlPoolFeaturedPoolGroup, GqlPoolJoinExit, @@ -61,16 +60,16 @@ export class PoolService { return networkContext.config.contentService; } - public async getGqlPool(id: string, chain: GqlChain): Promise { - return this.poolGqlLoaderService.getPool(id, chain); + public async getGqlPool(id: string): Promise { + return this.poolGqlLoaderService.getPool(id); } public async getGqlPools(args: QueryPoolGetPoolsArgs): Promise { return this.poolGqlLoaderService.getPools(args); } - public async getGqlLinearPools(chains: Chain[]): Promise { - return this.poolGqlLoaderService.getLinearPools(chains); + public async getGqlLinearPools(): Promise { + return this.poolGqlLoaderService.getLinearPools(); } public async getPoolsCount(args: QueryPoolGetPoolsArgs): Promise { @@ -123,12 +122,12 @@ export class PoolService { return featuredPoolGroups; } - public async getSnapshotsForAllPools(chains: Chain[], range: GqlPoolSnapshotDataRange) { - return this.poolSnapshotService.getSnapshotsForAllPools(chains, range); + public async getSnapshotsForAllPools(range: GqlPoolSnapshotDataRange) { + return this.poolSnapshotService.getSnapshotsForAllPools(range); } - public async getSnapshotsForPool(poolId: string, chain: Chain, range: GqlPoolSnapshotDataRange) { - return this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); + public async getSnapshotsForPool(poolId: string, range: GqlPoolSnapshotDataRange) { + return this.poolSnapshotService.getSnapshotsForPool(poolId, range); } public async getSnapshotsForReliquaryFarm(id: number, range: GqlPoolSnapshotDataRange) { @@ -434,7 +433,7 @@ export class PoolService { await prisma.prismaPoolLinearData.deleteMany({ where: { chain: networkContext.chain, poolId: poolId }, }); - + await prisma.prismaPoolGyroData.deleteMany({ where: { chain: networkContext.chain, poolId: poolId }, }); @@ -477,9 +476,9 @@ export class PoolService { }, }); - if (gauge && gauge.votingGauge) + if(gauge && gauge.votingGauge) await prisma.prismaVotingGauge.deleteMany({ - where: { chain: networkContext.chain, id: gauge.votingGauge.id }, + where: { chain: networkContext.chain, id: gauge.votingGauge.id } }); await prisma.prismaPoolStakingGauge.deleteMany({ diff --git a/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts b/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts index 43b779b58..0a4023c9c 100644 --- a/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts +++ b/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts @@ -52,7 +52,7 @@ const PORTFOLIO_POOLS_CACHE_KEY = `balance-subgraph_portfolio-pools`; export class BalancerSubgraphService { private cache: CacheClass; - constructor(private readonly subgraphUrl = networkContext.data.subgraphs.balancer) { + constructor() { this.cache = new Cache(); } @@ -314,7 +314,7 @@ export class BalancerSubgraphService { } private get sdk() { - const client = new GraphQLClient(this.subgraphUrl); + const client = new GraphQLClient(networkContext.data.subgraphs.balancer); return getSdk(client); } diff --git a/modules/token/token.resolvers.ts b/modules/token/token.resolvers.ts index b5c54cafe..988a6111a 100644 --- a/modules/token/token.resolvers.ts +++ b/modules/token/token.resolvers.ts @@ -2,25 +2,26 @@ import { Resolvers } from '../../schema'; import _ from 'lodash'; import { isAdminRoute } from '../auth/auth-context'; import { tokenService } from './token.service'; +import { networkContext } from '../network/network-context.service'; import { headerChain } from '../context/header-chain'; const resolvers: Resolvers = { Query: { tokenGetTokens: async (parent, { chains }, context) => { - const currentChain = headerChain(); + const currentChain = headerChain() if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - throw new Error('Chain is required'); + chains = []; } return tokenService.getTokenDefinitions(chains); }, tokenGetCurrentPrices: async (parent, { chains }, context) => { - const currentChain = headerChain(); + const currentChain = headerChain() if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - throw new Error('Chain is required'); + chains = []; } const prices = await tokenService.getWhiteListedTokenPrices(chains); diff --git a/modules/user/lib/user-balance.service.ts b/modules/user/lib/user-balance.service.ts index fb98fb1f2..200f7837b 100644 --- a/modules/user/lib/user-balance.service.ts +++ b/modules/user/lib/user-balance.service.ts @@ -74,12 +74,12 @@ export class UserBalanceService { }; } - public async getUserStaking(address: string, chains: Chain[]): Promise { + public async getUserStaking(address: string): Promise { const user = await prisma.prismaUser.findUnique({ where: { address }, include: { stakedBalances: { - where: { chain: { in: chains }, balanceNum: { gt: 0 } }, + where: { chain: networkContext.chain, balanceNum: { gt: 0 } }, include: { staking: { include: { diff --git a/modules/user/lib/user-snapshot.service.ts b/modules/user/lib/user-snapshot.service.ts index f5d262761..c31e9c2bc 100644 --- a/modules/user/lib/user-snapshot.service.ts +++ b/modules/user/lib/user-snapshot.service.ts @@ -4,14 +4,7 @@ import moment from 'moment-timezone'; import { UserPoolSnapshot, UserRelicSnapshot } from '../user-types'; import { GqlUserSnapshotDataRange } from '../../../schema'; import { PoolSnapshotService } from '../../pool/lib/pool-snapshot.service'; -import { - Chain, - Prisma, - PrismaPool, - PrismaPoolSnapshot, - PrismaPoolStaking, - PrismaUserRelicSnapshot, -} from '@prisma/client'; +import { Prisma, PrismaPool, PrismaPoolSnapshot, PrismaPoolStaking, PrismaUserRelicSnapshot } from '@prisma/client'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { oneDayInSeconds, secondsPerDay } from '../../common/time'; import { UserBalanceSnapshotFragment } from '../../subgraphs/user-snapshot-subgraph/generated/user-snapshot-subgraph-types'; @@ -316,7 +309,6 @@ export class UserSnapshotService { public async getUserPoolBalanceSnapshotsForPool( userAddress: string, poolId: string, - chain: Chain, range: GqlUserSnapshotDataRange, ): Promise { const oldestRequestedSnapshotTimestamp = this.getTimestampForRange(range); @@ -382,7 +374,7 @@ export class UserSnapshotService { const prismaInput: Prisma.PrismaUserPoolBalanceSnapshotCreateManyInput[] = []; - poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); + poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, range); /* For each snapshot from the subgraph, this will get the poolSnapshot for the same timestamp and enrich with $ value data @@ -444,7 +436,7 @@ export class UserSnapshotService { // Only get them if we didn't get them above if (poolSnapshots.length === 0) { - poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); + poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, range); } /* diff --git a/modules/user/user-snapshot.service.test.ts b/modules/user/user-snapshot.service.test.ts index f97fc4d57..47d8da75b 100644 --- a/modules/user/user-snapshot.service.test.ts +++ b/modules/user/user-snapshot.service.test.ts @@ -13,7 +13,6 @@ import { mockServer } from '../tests-helper/mocks/mockHttpServer'; import { userService } from './user.service'; import { secondsPerDay } from '../common/time'; import { networkContext } from '../network/network-context.service'; -import { Chain } from '@prisma/client'; /* TEST SETUP: @@ -183,12 +182,7 @@ test('The user requests the user stats for the first time, requesting from subgr ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); //check if 4th snapshot has been inferred from three present ones expect(snapshotsFromService.length).toBe(4); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -304,7 +298,6 @@ test('User in in the pool for a very long time, requests various different time const thirtySnapshotsFromService = await userService.getUserBalanceSnapshotsForPool( userAddress, poolId1, - Chain.FANTOM, 'THIRTY_DAYS', ); @@ -323,7 +316,6 @@ test('User in in the pool for a very long time, requests various different time const ninetySnapshotsFromService = await userService.getUserBalanceSnapshotsForPool( userAddress, poolId1, - Chain.FANTOM, 'NINETY_DAYS', ); //also includes the one from today @@ -420,12 +412,7 @@ Mock data for user-balance-subgraph (important that timestamps are ASC, as this ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); //check if 4th snapshot has been inferred from three present ones expect(snapshotsFromService.length).toBe(4); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -548,12 +535,7 @@ Mock data for user-balance-subgraph (important that timestamps are ASC, as this ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); //check if 4th snapshot has been inferred from three present ones expect(snapshotsFromService.length).toBe(2); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -645,12 +627,7 @@ test('Return a snapshot with 0 valueUSD if there is no pool snapshot for the giv ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( - userAddress, - pool2Id, - Chain.FANTOM, - 'THIRTY_DAYS', - ); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, pool2Id, 'THIRTY_DAYS'); // should get all 4 snapshots expect(snapshotsFromService.length).toBe(4); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -684,7 +661,6 @@ test('Return a snapshot with 0 valueUSD if there is no pool snapshot for the giv const snapshotsAfterAdditionalPoolSnapshot = await userService.getUserBalanceSnapshotsForPool( userAddress, pool2Id, - Chain.FANTOM, 'THIRTY_DAYS', ); //expect still the same results here as above @@ -828,12 +804,7 @@ test('User snapshots in the database must be picked up and synced by the sync pr expect(snapshotsFromDb.length).toBe(3); // after the sync, all 4 snapshots should be present - const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); + const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); expect(snapshotsAfterSync.length).toBe(4); // check if balances are calculated correctly @@ -1029,12 +1000,7 @@ test('User has left and re-entered the pool. Make sure the sync does not persist // after the sync, 5 snapshots should be present. //Sevendaysago, sixdaysago (inferred), fivedaysago (0 balance), fourdays ago (0 balance), threedaysago and twodaysago (0 balance) - const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); + const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); expect(snapshotsAfterSync.length).toBe(6); const snapshotsFromDbAfterGet = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -1149,12 +1115,7 @@ test('Todays user snapshot must be gradually updated based on an updated pool sn ], ); - const userSnapshotsBefore = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); + const userSnapshotsBefore = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); expect(userSnapshotsBefore.length).toBe(1); // check if balances are calculated correctly @@ -1205,12 +1166,7 @@ test('Todays user snapshot must be gradually updated based on an updated pool sn await userService.syncUserBalanceSnapshots(); // check numbers again - const userSnapshotsAfter = await userService.getUserBalanceSnapshotsForPool( - userAddress, - poolId1, - Chain.FANTOM, - 'THIRTY_DAYS', - ); + const userSnapshotsAfter = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); expect(userSnapshotsBefore.length).toBe(1); // check if balances are calculated correctly @@ -1336,7 +1292,6 @@ test('User requests pool snapshots for Fidelio Duetto Pool. Make sure fBeets are const userBalanceSnapshots = await userService.getUserBalanceSnapshotsForPool( userAddress, fidelioPoolId, - Chain.FANTOM, 'THIRTY_DAYS', ); expect(userBalanceSnapshots.length).toBe(4); diff --git a/modules/user/user.gql b/modules/user/user.gql index bdeabede4..62803f158 100644 --- a/modules/user/user.gql +++ b/modules/user/user.gql @@ -1,14 +1,8 @@ extend type Query { userGetPoolBalances(chains: [GqlChain!], address: String): [GqlUserPoolBalance!]! - userGetStaking(chains: [GqlChain!], address: String): [GqlPoolStaking!]! - userGetPoolJoinExits( - first: Int = 10 - skip: Int = 0 - poolId: String! - chain: GqlChain - address: String - ): [GqlPoolJoinExit!]! - userGetSwaps(first: Int = 10, skip: Int = 0, poolId: String!, chain: GqlChain, address: String): [GqlPoolSwap!]! + userGetStaking: [GqlPoolStaking!]! + userGetPoolJoinExits(first: Int = 10, skip: Int = 0, poolId: String!): [GqlPoolJoinExit!]! + userGetSwaps(first: Int = 10, skip: Int = 0, poolId: String!): [GqlPoolSwap!]! } extend type Mutation { diff --git a/modules/user/user.resolvers.ts b/modules/user/user.resolvers.ts index e94480d62..0c7424b6f 100644 --- a/modules/user/user.resolvers.ts +++ b/modules/user/user.resolvers.ts @@ -7,11 +7,11 @@ import { headerChain } from '../context/header-chain'; const resolvers: Resolvers = { Query: { userGetPoolBalances: async (parent, { chains, address }, context) => { - const currentChain = headerChain(); + const currentChain = headerChain() if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - throw new Error('Chain is required'); + chains = []; } const accountAddress = address || getRequiredAccountAddress(context); const tokenPrices = await tokenService.getTokenPricesForChains(chains); @@ -22,37 +22,19 @@ const resolvers: Resolvers = { tokenPrice: tokenService.getPriceForToken(tokenPrices[balance.chain] || [], balance.tokenAddress), })); }, - userGetPoolJoinExits: async (parent, { first, skip, poolId, chain, address }, context) => { - const currentChain = headerChain(); - if (!chain && currentChain) { - chain = currentChain; - } else if (!chain) { - throw new Error('Chain is required'); - } - const accountAddress = address || getRequiredAccountAddress(context); + userGetPoolJoinExits: async (parent, { first, skip, poolId }, context) => { + const accountAddress = getRequiredAccountAddress(context); - return userService.getUserPoolInvestments(accountAddress, poolId, chain, first, skip); + return userService.getUserPoolInvestments(accountAddress, poolId, first, skip); }, - userGetSwaps: async (parent, { first, skip, poolId, chain, address }, context) => { - const currentChain = headerChain(); - if (!chain && currentChain) { - chain = currentChain; - } else if (!chain) { - throw new Error('Chain is required'); - } - const accountAddress = address || getRequiredAccountAddress(context); - return userService.getUserSwaps(accountAddress, poolId, chain, first, skip); + userGetSwaps: async (parent, { first, skip, poolId }, context) => { + const accountAddress = getRequiredAccountAddress(context); + return userService.getUserSwaps(accountAddress, poolId, first, skip); }, - userGetStaking: async (parent, { chains, address }, context) => { - const currentChain = headerChain(); - if (!chains && currentChain) { - chains = [currentChain]; - } else if (!chains) { - throw new Error('Chain is required'); - } - const accountAddress = address || getRequiredAccountAddress(context); + userGetStaking: async (parent, {}, context) => { + const accountAddress = getRequiredAccountAddress(context); - return userService.getUserStaking(accountAddress, chains); + return userService.getUserStaking(accountAddress); }, }, Mutation: { diff --git a/modules/user/user.service.ts b/modules/user/user.service.ts index f58c6104f..fd603906c 100644 --- a/modules/user/user.service.ts +++ b/modules/user/user.service.ts @@ -5,6 +5,7 @@ import { coingeckoService } from '../coingecko/coingecko.service'; import { PoolSnapshotService } from '../pool/lib/pool-snapshot.service'; import { PoolSwapService } from '../pool/lib/pool-swap.service'; import { balancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; +import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { reliquarySubgraphService } from '../subgraphs/reliquary-subgraph/reliquary.service'; import { userSnapshotSubgraphService } from '../subgraphs/user-snapshot-subgraph/user-snapshot-subgraph.service'; import { tokenService } from '../token/token.service'; @@ -33,38 +34,30 @@ export class UserService { public async getUserPoolInvestments( address: string, poolId: string, - chain: Chain, first?: number, skip?: number, ): Promise { - return this.poolSwapService.getUserJoinExitsForPool(address, poolId, chain, first, skip); + return this.poolSwapService.getUserJoinExitsForPool(address, poolId, first, skip); } - public async getUserSwaps( - address: string, - poolId: string, - chain: Chain, - first?: number, - skip?: number, - ): Promise { - return this.poolSwapService.getUserSwapsForPool(address, poolId, chain, first, skip); + public async getUserSwaps(address: string, poolId: string, first?: number, skip?: number): Promise { + return this.poolSwapService.getUserSwapsForPool(address, poolId, first, skip); } public async getUserFbeetsBalance(address: string): Promise> { return this.userBalanceService.getUserFbeetsBalance(address); } - public async getUserStaking(address: string, chains: Chain[]): Promise { - return this.userBalanceService.getUserStaking(address, chains); + public async getUserStaking(address: string): Promise { + return this.userBalanceService.getUserStaking(address); } public async getUserBalanceSnapshotsForPool( accountAddress: string, poolId: string, - chain: Chain, days: GqlUserSnapshotDataRange, ): Promise { - return this.userSnapshotService.getUserPoolBalanceSnapshotsForPool(accountAddress, poolId, chain, days); + return this.userSnapshotService.getUserPoolBalanceSnapshotsForPool(accountAddress, poolId, days); } public async getUserRelicSnapshots(accountAddress: string, farmId: string, days: GqlUserSnapshotDataRange) { From 5158418ca5395159017bd0705a0667801c102bb3 Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:11:55 +0100 Subject: [PATCH 23/32] Revert "Revert "Feature/multichain filter" (#526)" This reverts commit c6f9f8cbc29b4c4a43e36ab86ec5d9de1e1ee630. --- modules/beethoven/beets.gql | 2 +- modules/beethoven/beets.resolvers.ts | 3 +- modules/gnosis/gnosis-safe.service.ts | 54 --------------- modules/pool/lib/pool-gql-loader.service.ts | 11 +-- modules/pool/lib/pool-snapshot.service.ts | 11 ++- modules/pool/lib/pool-swap.service.ts | 67 ++++++++++++++----- modules/pool/pool.gql | 15 +++-- modules/pool/pool.resolvers.ts | 59 +++++++++++++--- modules/pool/pool.service.ts | 25 +++---- .../balancer-subgraph.service.ts | 4 +- modules/token/token.resolvers.ts | 9 ++- modules/user/lib/user-balance.service.ts | 4 +- modules/user/lib/user-snapshot.service.ts | 14 +++- modules/user/user-snapshot.service.test.ts | 61 ++++++++++++++--- modules/user/user.gql | 12 +++- modules/user/user.resolvers.ts | 40 ++++++++--- modules/user/user.service.ts | 21 ++++-- 17 files changed, 262 insertions(+), 150 deletions(-) delete mode 100644 modules/gnosis/gnosis-safe.service.ts diff --git a/modules/beethoven/beets.gql b/modules/beethoven/beets.gql index 445412974..caa15efbb 100644 --- a/modules/beethoven/beets.gql +++ b/modules/beethoven/beets.gql @@ -5,7 +5,7 @@ extend type Query { userGetFbeetsBalance: GqlUserFbeetsBalance! - userGetPoolSnapshots(poolId: String!, range: GqlUserSnapshotDataRange!): [GqlUserPoolSnapshot!]! + userGetPoolSnapshots(poolId: String!, chain: GqlChain!, range: GqlUserSnapshotDataRange!): [GqlUserPoolSnapshot!]! userGetRelicSnapshots(farmId: String!, range: GqlUserSnapshotDataRange!): [GqlUserRelicSnapshot!]! userGetPortfolioSnapshots(days: Int!): [GqlUserPortfolioSnapshot!]! diff --git a/modules/beethoven/beets.resolvers.ts b/modules/beethoven/beets.resolvers.ts index ecb709df7..87e705789 100644 --- a/modules/beethoven/beets.resolvers.ts +++ b/modules/beethoven/beets.resolvers.ts @@ -36,12 +36,13 @@ const beetsResolvers: Resolvers = { ...balance, }; }, - userGetPoolSnapshots: async (parent, { poolId, range }, context) => { + userGetPoolSnapshots: async (parent, { poolId, chain, range }, context) => { const accountAddress = getRequiredAccountAddress(context); return userService.getUserBalanceSnapshotsForPool( accountAddress.toLowerCase(), poolId.toLowerCase(), + chain, range, ); }, diff --git a/modules/gnosis/gnosis-safe.service.ts b/modules/gnosis/gnosis-safe.service.ts deleted file mode 100644 index 5ecff4151..000000000 --- a/modules/gnosis/gnosis-safe.service.ts +++ /dev/null @@ -1,54 +0,0 @@ -import Safe, { ContractNetworksConfig, EthersAdapter } from '@gnosis.pm/safe-core-sdk'; -import { ethers, providers } from 'ethers'; -import { getAddress } from 'ethers/lib/utils'; -import { Cache } from 'memory-cache'; -import { networkContext } from '../network/network-context.service'; - -const CACHE_KEY_PREFIX = `gnosis-address-is-multisig_`; -const TIMEOUT = 2592000; //30 days - -const contractNetworks: ContractNetworksConfig = { - 250: { - safeProxyFactoryAddress: '0xc3C41Ab65Dabe3ae250A0A1FE4706FdB7ECEB951', - multiSendAddress: '0xd1b160Ee570632ac402Efb230d720669604918e8', - safeMasterCopyAddress: '0x87EB227FE974e9E1d3Bc4Da562e0Bd3C348c2B34', - }, -}; - -export class GnosisSafeService { - private cache = new Cache(); - - public async isAddressGnosisSafe(address: string) { - const key = `${CACHE_KEY_PREFIX}:${networkContext.chainId}:${address}`; - const cachedValue = this.cache.get(key); - if (cachedValue != null) { - return cachedValue; - } - - try { - await Safe.create({ - ethAdapter: await this.getAdapter(), - safeAddress: getAddress(address), - contractNetworks, - }); - - this.cache.put(key, true, TIMEOUT); - return true; - } catch { - this.cache.put(key, false, TIMEOUT); - return false; - } - } - - private async getAdapter() { - const provider = new providers.JsonRpcProvider(networkContext.data.rpcUrl); - const signer = ethers.Wallet.createRandom(); - - return new EthersAdapter({ - ethers, - signer: signer.connect(provider), - }); - } -} - -export const gnosisSafeService = new GnosisSafeService(); diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index b381545ee..85e841c54 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -11,6 +11,7 @@ import { import { GqlBalancePoolAprItem, GqlBalancePoolAprSubItem, + GqlChain, GqlPoolDynamicData, GqlPoolFeaturedPoolGroup, GqlPoolInvestConfig, @@ -33,16 +34,16 @@ import { import { isSameAddress } from '@balancer-labs/sdk'; import _ from 'lodash'; import { prisma } from '../../../prisma/prisma-client'; -import { Prisma, PrismaPoolAprType } from '@prisma/client'; +import { Chain, Prisma, PrismaPoolAprType } from '@prisma/client'; import { isWeightedPoolV2 } from './pool-utils'; import { oldBnum } from '../../big-number/old-big-number'; import { networkContext } from '../../network/network-context.service'; import { fixedNumber } from '../../view-helpers/fixed-number'; export class PoolGqlLoaderService { - public async getPool(id: string): Promise { + public async getPool(id: string, chain: Chain): Promise { const pool = await prisma.prismaPool.findUnique({ - where: { id_chain: { id, chain: networkContext.chain } }, + where: { id_chain: { id, chain: chain } }, include: prismaPoolWithExpandedNesting.include, }); @@ -66,9 +67,9 @@ export class PoolGqlLoaderService { return pools.map((pool) => this.mapToMinimalGqlPool(pool)); } - public async getLinearPools(): Promise { + public async getLinearPools(chains: Chain[]): Promise { const pools = await prisma.prismaPool.findMany({ - where: { type: 'LINEAR', chain: networkContext.chain }, + where: { type: 'LINEAR', chain: { in: chains } }, orderBy: { dynamicData: { totalLiquidity: 'desc' } }, include: prismaPoolWithExpandedNesting.include, }); diff --git a/modules/pool/lib/pool-snapshot.service.ts b/modules/pool/lib/pool-snapshot.service.ts index e64062b73..3c51d26cc 100644 --- a/modules/pool/lib/pool-snapshot.service.ts +++ b/modules/pool/lib/pool-snapshot.service.ts @@ -1,4 +1,3 @@ -import * as Sentry from '@sentry/node'; import { balancerSubgraphService, BalancerSubgraphService, @@ -12,7 +11,7 @@ import { import { GqlPoolSnapshotDataRange } from '../../../schema'; import moment from 'moment-timezone'; import _ from 'lodash'; -import { PrismaPoolSnapshot } from '@prisma/client'; +import { Chain, PrismaPoolSnapshot } from '@prisma/client'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { prismaPoolWithExpandedNesting } from '../../../prisma/prisma-types'; import { CoingeckoService } from '../../coingecko/coingecko.service'; @@ -27,11 +26,11 @@ export class PoolSnapshotService { private readonly coingeckoService: CoingeckoService, ) {} - public async getSnapshotsForPool(poolId: string, range: GqlPoolSnapshotDataRange) { + public async getSnapshotsForPool(poolId: string, chain: Chain, range: GqlPoolSnapshotDataRange) { const timestamp = this.getTimestampForRange(range); return prisma.prismaPoolSnapshot.findMany({ - where: { poolId, timestamp: { gte: timestamp }, chain: networkContext.chain }, + where: { poolId, timestamp: { gte: timestamp }, chain: chain }, orderBy: { timestamp: 'asc' }, }); } @@ -42,7 +41,7 @@ export class PoolSnapshotService { }); } - public async getSnapshotsForAllPools(range: GqlPoolSnapshotDataRange) { + public async getSnapshotsForAllPools(chains: Chain[], range: GqlPoolSnapshotDataRange) { const timestamp = this.getTimestampForRange(range); return prisma.prismaPoolSnapshot.findMany({ @@ -54,7 +53,7 @@ export class PoolSnapshotService { pool: { categories: { none: { category: 'BLACK_LISTED' } }, }, - chain: networkContext.chain, + chain: { in: chains }, }, orderBy: { timestamp: 'asc' }, }); diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index 7de0530db..b3330e68a 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -14,12 +14,13 @@ import { QueryPoolGetJoinExitsArgs, QueryPoolGetSwapsArgs, } from '../../../schema'; -import { PrismaPoolSwap } from '@prisma/client'; +import { Chain, PrismaPoolSwap } from '@prisma/client'; import _ from 'lodash'; import { isSupportedInt, prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { PrismaPoolBatchSwapWithSwaps, prismaPoolMinimal } from '../../../prisma/prisma-types'; import { networkContext } from '../../network/network-context.service'; import * as Sentry from '@sentry/node'; +import { AllNetworkConfigsKeyedOnChain } from '../../network/network-config'; export class PoolSwapService { constructor( @@ -30,29 +31,49 @@ export class PoolSwapService { public async getJoinExits(args: QueryPoolGetJoinExitsArgs): Promise { const first = !args.first || args.first > 100 ? 10 : args.first; - const { joinExits } = await this.balancerSubgraphService.getPoolJoinExits({ - where: { pool_in: args.where?.poolIdIn }, - first, - skip: args.skip, - orderBy: JoinExit_OrderBy.Timestamp, - orderDirection: OrderDirection.Desc, - }); + const allChainsJoinExits: GqlPoolJoinExit[] = []; - return joinExits.map((joinExit) => ({ - ...joinExit, - __typename: 'GqlPoolJoinExit', - poolId: joinExit.pool.id, - amounts: joinExit.amounts.map((amount, index) => ({ address: joinExit.pool.tokensList[index], amount })), - })); + for (const chain of args.where!.chainIn!) { + const balancerSubgraphService = new BalancerSubgraphService( + AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, + ); + + const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ + where: { pool_in: args.where?.poolIdIn }, + first, + skip: args.skip, + orderBy: JoinExit_OrderBy.Timestamp, + orderDirection: OrderDirection.Desc, + }); + + const mappedJoinExits: GqlPoolJoinExit[] = joinExits.map((joinExit) => ({ + ...joinExit, + __typename: 'GqlPoolJoinExit', + chain: chain, + poolId: joinExit.pool.id, + amounts: joinExit.amounts.map((amount, index) => ({ + address: joinExit.pool.tokensList[index], + amount, + })), + })); + + allChainsJoinExits.push(...mappedJoinExits); + } + + return allChainsJoinExits; } public async getUserJoinExitsForPool( userAddress: string, poolId: string, + chain: Chain, first = 10, skip = 0, ): Promise { - const { joinExits } = await this.balancerSubgraphService.getPoolJoinExits({ + const balancerSubgraphService = new BalancerSubgraphService( + AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, + ); + const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ where: { pool: poolId, user: userAddress }, first, skip: skip, @@ -64,6 +85,7 @@ export class PoolSwapService { ...joinExit, __typename: 'GqlPoolJoinExit', poolId: joinExit.pool.id, + chain: chain, amounts: joinExit.amounts.map((amount, index) => ({ address: joinExit.pool.tokensList[index], amount })), })); } @@ -84,7 +106,9 @@ export class PoolSwapService { tokenOut: { in: args.where?.tokenOutIn || undefined, }, - chain: networkContext.chain, + chain: { + in: args.where?.chainIn || undefined, + }, }, orderBy: { timestamp: 'desc' }, }); @@ -93,10 +117,14 @@ export class PoolSwapService { public async getUserSwapsForPool( userAddress: string, poolId: string, + chain: Chain, first = 10, skip = 0, ): Promise { - const result = await this.balancerSubgraphService.getSwaps({ + const balancerSubgraphService = new BalancerSubgraphService( + AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, + ); + const result = await balancerSubgraphService.getSwaps({ first, skip, where: { @@ -109,6 +137,7 @@ export class PoolSwapService { return result.swaps.map((swap) => ({ id: swap.id, + chain: chain, userAddress, poolId: swap.poolId.id, tokenIn: swap.tokenIn, @@ -143,7 +172,9 @@ export class PoolSwapService { tokenOut: { in: args.where?.tokenOutIn || undefined, }, - chain: networkContext.chain, + chain: { + in: args.where?.chainIn || undefined, + }, }, orderBy: { timestamp: 'desc' }, include: { diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index 061eaa2ab..b033434ef 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -1,5 +1,5 @@ extend type Query { - poolGetPool(id: String!): GqlPoolBase! + poolGetPool(id: String!, chain: GqlChain): GqlPoolBase! poolGetPools( first: Int skip: Int @@ -20,9 +20,9 @@ extend type Query { poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! poolGetFeaturedPoolGroups: [GqlPoolFeaturedPoolGroup!]! - poolGetSnapshots(id: String!, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! - poolGetAllPoolsSnapshots(range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! - poolGetLinearPools: [GqlPoolLinear!]! + poolGetSnapshots(id: String!, chain: GqlChain, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! + poolGetAllPoolsSnapshots(chains: [GqlChain!], range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! + poolGetLinearPools(chains: [GqlChain!]): [GqlPoolLinear!]! } extend type Mutation { @@ -657,6 +657,7 @@ type GqlPoolFilterDefinition { type GqlPoolSwap { id: ID! + chain: GqlChain! poolId: String! userAddress: String! tokenIn: String! @@ -670,6 +671,7 @@ type GqlPoolSwap { type GqlPoolBatchSwap { id: ID! + chain: GqlChain! userAddress: String! tokenIn: String! tokenOut: String! @@ -705,10 +707,12 @@ input GqlPoolSwapFilter { tokenInIn: [String!] tokenOutIn: [String!] poolIdIn: [String!] + chainIn: [GqlChain!] } type GqlPoolStaking { id: ID! + chain: GqlChain! type: GqlPoolStakingType! address: String! gauge: GqlPoolStakingGauge @@ -726,10 +730,12 @@ enum GqlPoolStakingGaugeStatus { input GqlPoolJoinExitFilter { poolIdIn: [String!] + chainIn: [GqlChain!] } type GqlPoolJoinExit { id: ID! + chain: GqlChain! type: GqlPoolJoinExitType! sender: String! poolId: String! @@ -799,6 +805,7 @@ enum GqlPoolSnapshotDataRange { type GqlPoolSnapshot { id: ID! + chain: GqlChain! poolId: String! timestamp: Int! totalLiquidity: String! diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index c3f80f032..3a88f526c 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -3,11 +3,18 @@ import { Resolvers } from '../../schema'; import { isAdminRoute } from '../auth/auth-context'; import { prisma } from '../../prisma/prisma-client'; import { networkContext } from '../network/network-context.service'; +import { headerChain } from '../context/header-chain'; const balancerResolvers: Resolvers = { Query: { - poolGetPool: async (parent, { id }, context) => { - return poolService.getGqlPool(id); + poolGetPool: async (parent, { id, chain }, context) => { + const currentChain = headerChain(); + if (!chain && currentChain) { + chain = currentChain; + } else if (!chain) { + throw new Error('Chain is required'); + } + return poolService.getGqlPool(id, chain); }, poolGetPools: async (parent, args, context) => { return poolService.getGqlPools(args); @@ -16,19 +23,43 @@ const balancerResolvers: Resolvers = { return poolService.getPoolsCount(args); }, poolGetSwaps: async (parent, args, context) => { + const currentChain = headerChain(); + if (!args.where?.chainIn && currentChain) { + args.where = { ...args.where, chainIn: [currentChain] }; + } else if (!args.where?.chainIn) { + throw new Error('Chain is required'); + } return poolService.getPoolSwaps(args); }, poolGetBatchSwaps: async (parent, args, context) => { + const currentChain = headerChain(); + if (!args.where?.chainIn && currentChain) { + args.where = { ...args.where, chainIn: [currentChain] }; + } else if (!args.where?.chainIn) { + throw new Error('Chain is required'); + } return poolService.getPoolBatchSwaps(args); }, poolGetJoinExits: async (parent, args, context) => { + const currentChain = headerChain(); + if (!args.where?.chainIn && currentChain) { + args.where = { ...args.where, chainIn: [currentChain] }; + } else if (!args.where?.chainIn) { + throw new Error('Chain is required'); + } return poolService.getPoolJoinExits(args); }, poolGetFeaturedPoolGroups: async (parent, args, context) => { return poolService.getFeaturedPoolGroups(); }, - poolGetSnapshots: async (parent, { id, range }, context) => { - const snapshots = await poolService.getSnapshotsForPool(id, range); + poolGetSnapshots: async (parent, { id, chain, range }, context) => { + const currentChain = headerChain(); + if (!chain && currentChain) { + chain = currentChain; + } else if (!chain) { + throw new Error('Chain is required'); + } + const snapshots = await poolService.getSnapshotsForPool(id, chain, range); return snapshots.map((snapshot) => ({ ...snapshot, @@ -42,8 +73,14 @@ const balancerResolvers: Resolvers = { holdersCount: `${snapshot.holdersCount}`, })); }, - poolGetAllPoolsSnapshots: async (parent, { range }, context) => { - const snapshots = await poolService.getSnapshotsForAllPools(range); + poolGetAllPoolsSnapshots: async (parent, { chains, range }, context) => { + const currentChain = headerChain(); + if (!chains && currentChain) { + chains = [currentChain]; + } else if (!chains) { + throw new Error('Chain is required'); + } + const snapshots = await poolService.getSnapshotsForAllPools(chains, range); return snapshots.map((snapshot) => ({ ...snapshot, @@ -57,8 +94,14 @@ const balancerResolvers: Resolvers = { holdersCount: `${snapshot.holdersCount}`, })); }, - poolGetLinearPools: async () => { - return poolService.getGqlLinearPools(); + poolGetLinearPools: async (parent, { chains }, context) => { + const currentChain = headerChain(); + if (!chains && currentChain) { + chains = [currentChain]; + } else if (!chains) { + throw new Error('Chain is required'); + } + return poolService.getGqlLinearPools(chains); }, }, Mutation: { diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index 97e2d37f1..a6a69bd96 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -1,9 +1,10 @@ -import { PrismaPoolFilter, PrismaPoolStakingType, PrismaPoolSwap } from '@prisma/client'; +import { Chain, PrismaPoolFilter, PrismaPoolStakingType, PrismaPoolSwap } from '@prisma/client'; import _, { chain, includes } from 'lodash'; import { Cache } from 'memory-cache'; import moment from 'moment-timezone'; import { prisma } from '../../prisma/prisma-client'; import { + GqlChain, GqlPoolBatchSwap, GqlPoolFeaturedPoolGroup, GqlPoolJoinExit, @@ -60,16 +61,16 @@ export class PoolService { return networkContext.config.contentService; } - public async getGqlPool(id: string): Promise { - return this.poolGqlLoaderService.getPool(id); + public async getGqlPool(id: string, chain: GqlChain): Promise { + return this.poolGqlLoaderService.getPool(id, chain); } public async getGqlPools(args: QueryPoolGetPoolsArgs): Promise { return this.poolGqlLoaderService.getPools(args); } - public async getGqlLinearPools(): Promise { - return this.poolGqlLoaderService.getLinearPools(); + public async getGqlLinearPools(chains: Chain[]): Promise { + return this.poolGqlLoaderService.getLinearPools(chains); } public async getPoolsCount(args: QueryPoolGetPoolsArgs): Promise { @@ -122,12 +123,12 @@ export class PoolService { return featuredPoolGroups; } - public async getSnapshotsForAllPools(range: GqlPoolSnapshotDataRange) { - return this.poolSnapshotService.getSnapshotsForAllPools(range); + public async getSnapshotsForAllPools(chains: Chain[], range: GqlPoolSnapshotDataRange) { + return this.poolSnapshotService.getSnapshotsForAllPools(chains, range); } - public async getSnapshotsForPool(poolId: string, range: GqlPoolSnapshotDataRange) { - return this.poolSnapshotService.getSnapshotsForPool(poolId, range); + public async getSnapshotsForPool(poolId: string, chain: Chain, range: GqlPoolSnapshotDataRange) { + return this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); } public async getSnapshotsForReliquaryFarm(id: number, range: GqlPoolSnapshotDataRange) { @@ -433,7 +434,7 @@ export class PoolService { await prisma.prismaPoolLinearData.deleteMany({ where: { chain: networkContext.chain, poolId: poolId }, }); - + await prisma.prismaPoolGyroData.deleteMany({ where: { chain: networkContext.chain, poolId: poolId }, }); @@ -476,9 +477,9 @@ export class PoolService { }, }); - if(gauge && gauge.votingGauge) + if (gauge && gauge.votingGauge) await prisma.prismaVotingGauge.deleteMany({ - where: { chain: networkContext.chain, id: gauge.votingGauge.id } + where: { chain: networkContext.chain, id: gauge.votingGauge.id }, }); await prisma.prismaPoolStakingGauge.deleteMany({ diff --git a/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts b/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts index 0a4023c9c..43b779b58 100644 --- a/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts +++ b/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts @@ -52,7 +52,7 @@ const PORTFOLIO_POOLS_CACHE_KEY = `balance-subgraph_portfolio-pools`; export class BalancerSubgraphService { private cache: CacheClass; - constructor() { + constructor(private readonly subgraphUrl = networkContext.data.subgraphs.balancer) { this.cache = new Cache(); } @@ -314,7 +314,7 @@ export class BalancerSubgraphService { } private get sdk() { - const client = new GraphQLClient(networkContext.data.subgraphs.balancer); + const client = new GraphQLClient(this.subgraphUrl); return getSdk(client); } diff --git a/modules/token/token.resolvers.ts b/modules/token/token.resolvers.ts index 988a6111a..b5c54cafe 100644 --- a/modules/token/token.resolvers.ts +++ b/modules/token/token.resolvers.ts @@ -2,26 +2,25 @@ import { Resolvers } from '../../schema'; import _ from 'lodash'; import { isAdminRoute } from '../auth/auth-context'; import { tokenService } from './token.service'; -import { networkContext } from '../network/network-context.service'; import { headerChain } from '../context/header-chain'; const resolvers: Resolvers = { Query: { tokenGetTokens: async (parent, { chains }, context) => { - const currentChain = headerChain() + const currentChain = headerChain(); if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - chains = []; + throw new Error('Chain is required'); } return tokenService.getTokenDefinitions(chains); }, tokenGetCurrentPrices: async (parent, { chains }, context) => { - const currentChain = headerChain() + const currentChain = headerChain(); if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - chains = []; + throw new Error('Chain is required'); } const prices = await tokenService.getWhiteListedTokenPrices(chains); diff --git a/modules/user/lib/user-balance.service.ts b/modules/user/lib/user-balance.service.ts index 200f7837b..fb98fb1f2 100644 --- a/modules/user/lib/user-balance.service.ts +++ b/modules/user/lib/user-balance.service.ts @@ -74,12 +74,12 @@ export class UserBalanceService { }; } - public async getUserStaking(address: string): Promise { + public async getUserStaking(address: string, chains: Chain[]): Promise { const user = await prisma.prismaUser.findUnique({ where: { address }, include: { stakedBalances: { - where: { chain: networkContext.chain, balanceNum: { gt: 0 } }, + where: { chain: { in: chains }, balanceNum: { gt: 0 } }, include: { staking: { include: { diff --git a/modules/user/lib/user-snapshot.service.ts b/modules/user/lib/user-snapshot.service.ts index c31e9c2bc..f5d262761 100644 --- a/modules/user/lib/user-snapshot.service.ts +++ b/modules/user/lib/user-snapshot.service.ts @@ -4,7 +4,14 @@ import moment from 'moment-timezone'; import { UserPoolSnapshot, UserRelicSnapshot } from '../user-types'; import { GqlUserSnapshotDataRange } from '../../../schema'; import { PoolSnapshotService } from '../../pool/lib/pool-snapshot.service'; -import { Prisma, PrismaPool, PrismaPoolSnapshot, PrismaPoolStaking, PrismaUserRelicSnapshot } from '@prisma/client'; +import { + Chain, + Prisma, + PrismaPool, + PrismaPoolSnapshot, + PrismaPoolStaking, + PrismaUserRelicSnapshot, +} from '@prisma/client'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { oneDayInSeconds, secondsPerDay } from '../../common/time'; import { UserBalanceSnapshotFragment } from '../../subgraphs/user-snapshot-subgraph/generated/user-snapshot-subgraph-types'; @@ -309,6 +316,7 @@ export class UserSnapshotService { public async getUserPoolBalanceSnapshotsForPool( userAddress: string, poolId: string, + chain: Chain, range: GqlUserSnapshotDataRange, ): Promise { const oldestRequestedSnapshotTimestamp = this.getTimestampForRange(range); @@ -374,7 +382,7 @@ export class UserSnapshotService { const prismaInput: Prisma.PrismaUserPoolBalanceSnapshotCreateManyInput[] = []; - poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, range); + poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); /* For each snapshot from the subgraph, this will get the poolSnapshot for the same timestamp and enrich with $ value data @@ -436,7 +444,7 @@ export class UserSnapshotService { // Only get them if we didn't get them above if (poolSnapshots.length === 0) { - poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, range); + poolSnapshots = await this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); } /* diff --git a/modules/user/user-snapshot.service.test.ts b/modules/user/user-snapshot.service.test.ts index 47d8da75b..f97fc4d57 100644 --- a/modules/user/user-snapshot.service.test.ts +++ b/modules/user/user-snapshot.service.test.ts @@ -13,6 +13,7 @@ import { mockServer } from '../tests-helper/mocks/mockHttpServer'; import { userService } from './user.service'; import { secondsPerDay } from '../common/time'; import { networkContext } from '../network/network-context.service'; +import { Chain } from '@prisma/client'; /* TEST SETUP: @@ -182,7 +183,12 @@ test('The user requests the user stats for the first time, requesting from subgr ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); //check if 4th snapshot has been inferred from three present ones expect(snapshotsFromService.length).toBe(4); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -298,6 +304,7 @@ test('User in in the pool for a very long time, requests various different time const thirtySnapshotsFromService = await userService.getUserBalanceSnapshotsForPool( userAddress, poolId1, + Chain.FANTOM, 'THIRTY_DAYS', ); @@ -316,6 +323,7 @@ test('User in in the pool for a very long time, requests various different time const ninetySnapshotsFromService = await userService.getUserBalanceSnapshotsForPool( userAddress, poolId1, + Chain.FANTOM, 'NINETY_DAYS', ); //also includes the one from today @@ -412,7 +420,12 @@ Mock data for user-balance-subgraph (important that timestamps are ASC, as this ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); //check if 4th snapshot has been inferred from three present ones expect(snapshotsFromService.length).toBe(4); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -535,7 +548,12 @@ Mock data for user-balance-subgraph (important that timestamps are ASC, as this ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); //check if 4th snapshot has been inferred from three present ones expect(snapshotsFromService.length).toBe(2); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -627,7 +645,12 @@ test('Return a snapshot with 0 valueUSD if there is no pool snapshot for the giv ], ); - const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool(userAddress, pool2Id, 'THIRTY_DAYS'); + const snapshotsFromService = await userService.getUserBalanceSnapshotsForPool( + userAddress, + pool2Id, + Chain.FANTOM, + 'THIRTY_DAYS', + ); // should get all 4 snapshots expect(snapshotsFromService.length).toBe(4); const snapshotsFromDb = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -661,6 +684,7 @@ test('Return a snapshot with 0 valueUSD if there is no pool snapshot for the giv const snapshotsAfterAdditionalPoolSnapshot = await userService.getUserBalanceSnapshotsForPool( userAddress, pool2Id, + Chain.FANTOM, 'THIRTY_DAYS', ); //expect still the same results here as above @@ -804,7 +828,12 @@ test('User snapshots in the database must be picked up and synced by the sync pr expect(snapshotsFromDb.length).toBe(3); // after the sync, all 4 snapshots should be present - const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); expect(snapshotsAfterSync.length).toBe(4); // check if balances are calculated correctly @@ -1000,7 +1029,12 @@ test('User has left and re-entered the pool. Make sure the sync does not persist // after the sync, 5 snapshots should be present. //Sevendaysago, sixdaysago (inferred), fivedaysago (0 balance), fourdays ago (0 balance), threedaysago and twodaysago (0 balance) - const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const snapshotsAfterSync = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); expect(snapshotsAfterSync.length).toBe(6); const snapshotsFromDbAfterGet = await prisma.prismaUserPoolBalanceSnapshot.findMany({ @@ -1115,7 +1149,12 @@ test('Todays user snapshot must be gradually updated based on an updated pool sn ], ); - const userSnapshotsBefore = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const userSnapshotsBefore = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); expect(userSnapshotsBefore.length).toBe(1); // check if balances are calculated correctly @@ -1166,7 +1205,12 @@ test('Todays user snapshot must be gradually updated based on an updated pool sn await userService.syncUserBalanceSnapshots(); // check numbers again - const userSnapshotsAfter = await userService.getUserBalanceSnapshotsForPool(userAddress, poolId1, 'THIRTY_DAYS'); + const userSnapshotsAfter = await userService.getUserBalanceSnapshotsForPool( + userAddress, + poolId1, + Chain.FANTOM, + 'THIRTY_DAYS', + ); expect(userSnapshotsBefore.length).toBe(1); // check if balances are calculated correctly @@ -1292,6 +1336,7 @@ test('User requests pool snapshots for Fidelio Duetto Pool. Make sure fBeets are const userBalanceSnapshots = await userService.getUserBalanceSnapshotsForPool( userAddress, fidelioPoolId, + Chain.FANTOM, 'THIRTY_DAYS', ); expect(userBalanceSnapshots.length).toBe(4); diff --git a/modules/user/user.gql b/modules/user/user.gql index 62803f158..bdeabede4 100644 --- a/modules/user/user.gql +++ b/modules/user/user.gql @@ -1,8 +1,14 @@ extend type Query { userGetPoolBalances(chains: [GqlChain!], address: String): [GqlUserPoolBalance!]! - userGetStaking: [GqlPoolStaking!]! - userGetPoolJoinExits(first: Int = 10, skip: Int = 0, poolId: String!): [GqlPoolJoinExit!]! - userGetSwaps(first: Int = 10, skip: Int = 0, poolId: String!): [GqlPoolSwap!]! + userGetStaking(chains: [GqlChain!], address: String): [GqlPoolStaking!]! + userGetPoolJoinExits( + first: Int = 10 + skip: Int = 0 + poolId: String! + chain: GqlChain + address: String + ): [GqlPoolJoinExit!]! + userGetSwaps(first: Int = 10, skip: Int = 0, poolId: String!, chain: GqlChain, address: String): [GqlPoolSwap!]! } extend type Mutation { diff --git a/modules/user/user.resolvers.ts b/modules/user/user.resolvers.ts index 0c7424b6f..e94480d62 100644 --- a/modules/user/user.resolvers.ts +++ b/modules/user/user.resolvers.ts @@ -7,11 +7,11 @@ import { headerChain } from '../context/header-chain'; const resolvers: Resolvers = { Query: { userGetPoolBalances: async (parent, { chains, address }, context) => { - const currentChain = headerChain() + const currentChain = headerChain(); if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - chains = []; + throw new Error('Chain is required'); } const accountAddress = address || getRequiredAccountAddress(context); const tokenPrices = await tokenService.getTokenPricesForChains(chains); @@ -22,19 +22,37 @@ const resolvers: Resolvers = { tokenPrice: tokenService.getPriceForToken(tokenPrices[balance.chain] || [], balance.tokenAddress), })); }, - userGetPoolJoinExits: async (parent, { first, skip, poolId }, context) => { - const accountAddress = getRequiredAccountAddress(context); + userGetPoolJoinExits: async (parent, { first, skip, poolId, chain, address }, context) => { + const currentChain = headerChain(); + if (!chain && currentChain) { + chain = currentChain; + } else if (!chain) { + throw new Error('Chain is required'); + } + const accountAddress = address || getRequiredAccountAddress(context); - return userService.getUserPoolInvestments(accountAddress, poolId, first, skip); + return userService.getUserPoolInvestments(accountAddress, poolId, chain, first, skip); }, - userGetSwaps: async (parent, { first, skip, poolId }, context) => { - const accountAddress = getRequiredAccountAddress(context); - return userService.getUserSwaps(accountAddress, poolId, first, skip); + userGetSwaps: async (parent, { first, skip, poolId, chain, address }, context) => { + const currentChain = headerChain(); + if (!chain && currentChain) { + chain = currentChain; + } else if (!chain) { + throw new Error('Chain is required'); + } + const accountAddress = address || getRequiredAccountAddress(context); + return userService.getUserSwaps(accountAddress, poolId, chain, first, skip); }, - userGetStaking: async (parent, {}, context) => { - const accountAddress = getRequiredAccountAddress(context); + userGetStaking: async (parent, { chains, address }, context) => { + const currentChain = headerChain(); + if (!chains && currentChain) { + chains = [currentChain]; + } else if (!chains) { + throw new Error('Chain is required'); + } + const accountAddress = address || getRequiredAccountAddress(context); - return userService.getUserStaking(accountAddress); + return userService.getUserStaking(accountAddress, chains); }, }, Mutation: { diff --git a/modules/user/user.service.ts b/modules/user/user.service.ts index fd603906c..f58c6104f 100644 --- a/modules/user/user.service.ts +++ b/modules/user/user.service.ts @@ -5,7 +5,6 @@ import { coingeckoService } from '../coingecko/coingecko.service'; import { PoolSnapshotService } from '../pool/lib/pool-snapshot.service'; import { PoolSwapService } from '../pool/lib/pool-swap.service'; import { balancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; -import { gaugeSubgraphService } from '../subgraphs/gauge-subgraph/gauge-subgraph.service'; import { reliquarySubgraphService } from '../subgraphs/reliquary-subgraph/reliquary.service'; import { userSnapshotSubgraphService } from '../subgraphs/user-snapshot-subgraph/user-snapshot-subgraph.service'; import { tokenService } from '../token/token.service'; @@ -34,30 +33,38 @@ export class UserService { public async getUserPoolInvestments( address: string, poolId: string, + chain: Chain, first?: number, skip?: number, ): Promise { - return this.poolSwapService.getUserJoinExitsForPool(address, poolId, first, skip); + return this.poolSwapService.getUserJoinExitsForPool(address, poolId, chain, first, skip); } - public async getUserSwaps(address: string, poolId: string, first?: number, skip?: number): Promise { - return this.poolSwapService.getUserSwapsForPool(address, poolId, first, skip); + public async getUserSwaps( + address: string, + poolId: string, + chain: Chain, + first?: number, + skip?: number, + ): Promise { + return this.poolSwapService.getUserSwapsForPool(address, poolId, chain, first, skip); } public async getUserFbeetsBalance(address: string): Promise> { return this.userBalanceService.getUserFbeetsBalance(address); } - public async getUserStaking(address: string): Promise { - return this.userBalanceService.getUserStaking(address); + public async getUserStaking(address: string, chains: Chain[]): Promise { + return this.userBalanceService.getUserStaking(address, chains); } public async getUserBalanceSnapshotsForPool( accountAddress: string, poolId: string, + chain: Chain, days: GqlUserSnapshotDataRange, ): Promise { - return this.userSnapshotService.getUserPoolBalanceSnapshotsForPool(accountAddress, poolId, days); + return this.userSnapshotService.getUserPoolBalanceSnapshotsForPool(accountAddress, poolId, chain, days); } public async getUserRelicSnapshots(accountAddress: string, farmId: string, days: GqlUserSnapshotDataRange) { From a222cd695b719a3d71468189794f6af8515ca268 Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Fri, 10 Nov 2023 12:20:52 +0100 Subject: [PATCH 24/32] balancerSubgraphService per network --- modules/network/arbitrum.ts | 4 + modules/network/avalanche.ts | 4 + modules/network/base.ts | 4 + modules/network/fantom.ts | 4 + modules/network/gnosis.ts | 4 + modules/network/mainnet.ts | 28 +++-- modules/network/network-config-types.ts | 7 ++ modules/network/network-context.service.ts | 4 + modules/network/optimism.ts | 4 + modules/network/polygon.ts | 4 + modules/network/zkevm.ts | 4 + modules/pool/lib/pool-creator.service.ts | 13 +- modules/pool/lib/pool-snapshot.service.ts | 39 +++--- modules/pool/lib/pool-swap.service.ts | 45 +++---- modules/pool/lib/pool-usd-data.service.ts | 6 +- modules/pool/pool.service.ts | 113 ++++++++++-------- .../balancer-subgraph.service.ts | 21 ++-- .../lib/user-sync-wallet-balance.service.ts | 14 ++- modules/user/user.service.ts | 5 +- 19 files changed, 197 insertions(+), 130 deletions(-) diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 5a5264910..20bb523f5 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -17,6 +17,7 @@ import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/ import { coingeckoService } from '../coingecko/coingecko.service'; import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; import { env } from '../../app/env'; +import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const arbitrumNetworkData: NetworkData = { chain: { @@ -249,6 +250,9 @@ export const arbitrumNetworkConfig: NetworkConfig = { new SwapsPriceHandlerService(), ], userStakedBalanceServices: [new UserSyncGaugeBalanceService()], + services: { + balancerSubgraphService: new BalancerSubgraphService(arbitrumNetworkData.subgraphs.balancer, arbitrumNetworkData.chain.id), + }, /* For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index 5725ea5b6..f696e5005 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -17,6 +17,7 @@ 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 { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const avalancheNetworkData: NetworkData = { chain: { @@ -239,6 +240,9 @@ export const avalancheNetworkConfig: NetworkConfig = { new SwapsPriceHandlerService(), ], userStakedBalanceServices: [new UserSyncGaugeBalanceService()], + services: { + balancerSubgraphService: new BalancerSubgraphService(avalancheNetworkData.subgraphs.balancer, avalancheNetworkData.chain.id), + }, /* For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. diff --git a/modules/network/base.ts b/modules/network/base.ts index 51e43a18b..c25d9b91e 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -16,6 +16,7 @@ import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/ import { coingeckoService } from '../coingecko/coingecko.service'; import { env } from '../../app/env'; import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; +import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const baseNetworkData: NetworkData = { chain: { @@ -137,6 +138,9 @@ export const baseNetworkConfig: NetworkConfig = { new SwapsPriceHandlerService(), ], userStakedBalanceServices: [new UserSyncGaugeBalanceService()], + services: { + balancerSubgraphService: new BalancerSubgraphService(baseNetworkData.subgraphs.balancer, baseNetworkData.chain.id), + }, /* For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index 38ba6a11c..a266d331c 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -26,6 +26,7 @@ import { coingeckoService } from '../coingecko/coingecko.service'; import { env } from '../../app/env'; import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-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'; const fantomNetworkData: NetworkData = { chain: { @@ -345,6 +346,9 @@ export const fantomNetworkConfig: NetworkConfig = { ), new UserSyncReliquaryFarmBalanceService(fantomNetworkData.reliquary!.address), ], + services: { + balancerSubgraphService: new BalancerSubgraphService(fantomNetworkData.subgraphs.balancer, fantomNetworkData.chain.id), + }, /* For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index 5c4f30d84..d00aa09f0 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -17,6 +17,7 @@ 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 { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const gnosisNetworkData: NetworkData = { chain: { @@ -166,6 +167,9 @@ export const gnosisNetworkConfig: NetworkConfig = { new SwapsPriceHandlerService(), ], userStakedBalanceServices: [new UserSyncGaugeBalanceService()], + services: { + balancerSubgraphService: new BalancerSubgraphService(gnosisNetworkData.subgraphs.balancer, gnosisNetworkData.chain.id), + }, /* For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index e693631bb..8e77f13ff 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -17,6 +17,7 @@ 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 { env } from '../../app/env'; +import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const underlyingTokens = { USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', @@ -25,7 +26,7 @@ const underlyingTokens = { wETH: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', }; -export const mainnetNetworkData: NetworkData = { +const data: NetworkData = { chain: { slug: 'ethereum', id: 1, @@ -367,25 +368,25 @@ export const mainnetNetworkData: NetworkData = { }; export const mainnetNetworkConfig: NetworkConfig = { - data: mainnetNetworkData, + data, contentService: new GithubContentService(), - provider: new ethers.providers.JsonRpcProvider({ url: mainnetNetworkData.rpcUrl, timeout: 60000 }), + provider: new ethers.providers.JsonRpcProvider({ url: data.rpcUrl, timeout: 60000 }), poolAprServices: [ new IbTokensAprService( - mainnetNetworkData.ibAprConfig, - mainnetNetworkData.chain.prismaId, - mainnetNetworkData.balancer.yieldProtocolFeePercentage, - mainnetNetworkData.balancer.swapProtocolFeePercentage, + data.ibAprConfig, + data.chain.prismaId, + data.balancer.yieldProtocolFeePercentage, + data.balancer.swapProtocolFeePercentage, ), new PhantomStableAprService( - mainnetNetworkData.chain.prismaId, - mainnetNetworkData.balancer.yieldProtocolFeePercentage, + data.chain.prismaId, + data.balancer.yieldProtocolFeePercentage, ), new BoostedPoolAprService(), - new SwapFeeAprService(mainnetNetworkData.balancer.swapProtocolFeePercentage), - new GaugeAprService(tokenService, [mainnetNetworkData.bal!.address]), + new SwapFeeAprService(data.balancer.swapProtocolFeePercentage), + new GaugeAprService(tokenService, [data.bal!.address]), ], - poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, mainnetNetworkData.bal!.address)], + poolStakingServices: [new GaugeStakingService(gaugeSubgraphService, data.bal!.address)], tokenPriceHandlers: [ new CoingeckoPriceHandlerService(coingeckoService), new BptPriceHandlerService(), @@ -393,6 +394,9 @@ export const mainnetNetworkConfig: NetworkConfig = { new SwapsPriceHandlerService(), ], userStakedBalanceServices: [new UserSyncGaugeBalanceService()], + services: { + balancerSubgraphService: new BalancerSubgraphService(data.subgraphs.balancer, 1), + }, /* For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. diff --git a/modules/network/network-config-types.ts b/modules/network/network-config-types.ts index a34c742e2..10c8e33dd 100644 --- a/modules/network/network-config-types.ts +++ b/modules/network/network-config-types.ts @@ -7,6 +7,7 @@ import { BaseProvider } from '@ethersproject/providers'; import { GqlChain } from '../../schema'; import { ContentService } from '../content/content-types'; import { AaveAprConfig, IbAprConfig } from './apr-config-types'; +import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; export interface NetworkConfig { data: NetworkData; @@ -17,7 +18,13 @@ export interface NetworkConfig { tokenPriceHandlers: TokenPriceHandler[]; provider: BaseProvider; workerJobs: WorkerJob[]; + services: NetworkServices; } + +interface NetworkServices { + balancerSubgraphService: BalancerSubgraphService; +} + export interface WorkerJob { name: string; interval: number; diff --git a/modules/network/network-context.service.ts b/modules/network/network-context.service.ts index 3522175c8..6eef167f6 100644 --- a/modules/network/network-context.service.ts +++ b/modules/network/network-context.service.ts @@ -57,6 +57,10 @@ export class NetworkContextService { public get protocolSupportedChainIds(): string[] { return this.isBalancerChain ? BalancerChainIds : BeethovenChainIds; } + + public get services() { + return this.config.services; + } } export const networkContext = new NetworkContextService(env.DEFAULT_CHAIN_ID); diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index c36471992..af9a1a00d 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -18,6 +18,7 @@ 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 { env } from '../../app/env'; +import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const optimismNetworkData: NetworkData = { chain: { @@ -294,6 +295,9 @@ export const optimismNetworkConfig: NetworkConfig = { new SwapsPriceHandlerService(), ], userStakedBalanceServices: [new UserSyncGaugeBalanceService()], + services: { + balancerSubgraphService: new BalancerSubgraphService(optimismNetworkData.subgraphs.balancer, optimismNetworkData.chain.id), + }, /* For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index cf3c9227f..8fd44b1fd 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -17,6 +17,7 @@ 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 { env } from '../../app/env'; +import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const polygonNetworkData: NetworkData = { chain: { @@ -284,6 +285,9 @@ export const polygonNetworkConfig: NetworkConfig = { new SwapsPriceHandlerService(), ], userStakedBalanceServices: [new UserSyncGaugeBalanceService()], + services: { + balancerSubgraphService: new BalancerSubgraphService(polygonNetworkData.subgraphs.balancer, polygonNetworkData.chain.id), + }, /* For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index 80a53b2ef..77ed05875 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -17,6 +17,7 @@ import { CoingeckoPriceHandlerService } from '../token/lib/token-price-handlers/ import { coingeckoService } from '../coingecko/coingecko.service'; import { env } from '../../app/env'; import { IbTokensAprService } from '../pool/lib/apr-data-sources/ib-tokens-apr.service'; +import { BalancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; const zkevmNetworkData: NetworkData = { chain: { @@ -185,6 +186,9 @@ export const zkevmNetworkConfig: NetworkConfig = { new SwapsPriceHandlerService(), ], userStakedBalanceServices: [new UserSyncGaugeBalanceService()], + services: { + balancerSubgraphService: new BalancerSubgraphService(zkevmNetworkData.subgraphs.balancer, zkevmNetworkData.chain.id), + }, /* For sub-minute jobs we set the alarmEvaluationPeriod and alarmDatapointsToAlarm to 1 instead of the default 3. This is needed because the minimum alarm period is 1 minute and we want the alarm to trigger already after 1 minute instead of 3. diff --git a/modules/pool/lib/pool-creator.service.ts b/modules/pool/lib/pool-creator.service.ts index e9f296e58..fb22dc4fb 100644 --- a/modules/pool/lib/pool-creator.service.ts +++ b/modules/pool/lib/pool-creator.service.ts @@ -1,4 +1,3 @@ -import { balancerSubgraphService } from '../../subgraphs/balancer-subgraph/balancer-subgraph.service'; import { BalancerPoolFragment } from '../../subgraphs/balancer-subgraph/generated/balancer-subgraph-types'; import { prisma } from '../../../prisma/prisma-client'; import { ZERO_ADDRESS } from '@gnosis.pm/safe-core-sdk/dist/src/utils/constants'; @@ -12,9 +11,13 @@ import { networkContext } from '../../network/network-context.service'; export class PoolCreatorService { constructor(private readonly userService: UserService) {} + private get balancerSubgraphService() { + return networkContext.services.balancerSubgraphService; + } + public async syncAllPoolsFromSubgraph(blockNumber: number): Promise { const existingPools = await prisma.prismaPool.findMany({ where: { chain: networkContext.chain } }); - const subgraphPools = await balancerSubgraphService.getAllPools({}, false); + const subgraphPools = await this.balancerSubgraphService.getAllPools({}, false); const sortedSubgraphPools = this.sortSubgraphPools(subgraphPools); const poolIds: string[] = []; @@ -43,7 +46,7 @@ export class PoolCreatorService { where: { chain: networkContext.chain }, }); - const subgraphPools = await balancerSubgraphService.getAllPools( + const subgraphPools = await this.balancerSubgraphService.getAllPools( { where: { createTime_gte: latest?.createTime || 0 }, }, @@ -66,7 +69,7 @@ export class PoolCreatorService { } public async reloadPoolNestedTokens(poolId: string): Promise { - const subgraphPools = await balancerSubgraphService.getAllPools({}, false); + const subgraphPools = await this.balancerSubgraphService.getAllPools({}, false); const poolToLoad = subgraphPools.find((pool) => pool.id === poolId); if (!poolToLoad) { @@ -335,7 +338,7 @@ export class PoolCreatorService { } public async reloadPoolTokenIndexes(poolId: string): Promise { - const { pool: subgraphPool } = await balancerSubgraphService.getPool({ id: poolId }); + const { pool: subgraphPool } = await this.balancerSubgraphService.getPool({ id: poolId }); if (!subgraphPool) { throw new Error('Pool with id does not exist'); diff --git a/modules/pool/lib/pool-snapshot.service.ts b/modules/pool/lib/pool-snapshot.service.ts index 3c51d26cc..ac54bacc0 100644 --- a/modules/pool/lib/pool-snapshot.service.ts +++ b/modules/pool/lib/pool-snapshot.service.ts @@ -1,7 +1,3 @@ -import { - balancerSubgraphService, - BalancerSubgraphService, -} from '../../subgraphs/balancer-subgraph/balancer-subgraph.service'; import { prisma } from '../../../prisma/prisma-client'; import { BalancerPoolSnapshotFragment, @@ -22,10 +18,17 @@ import { TokenHistoricalPrices } from '../../coingecko/coingecko-types'; export class PoolSnapshotService { constructor( - private readonly balancerSubgraphService: BalancerSubgraphService, private readonly coingeckoService: CoingeckoService, ) {} + private get balancerSubgraphService() { + return networkContext.config.services.balancerSubgraphService; + } + + private get chain() { + return networkContext.chain; + } + public async getSnapshotsForPool(poolId: string, chain: Chain, range: GqlPoolSnapshotDataRange) { const timestamp = this.getTimestampForRange(range); @@ -37,7 +40,7 @@ export class PoolSnapshotService { public async getSnapshotForPool(poolId: string, timestamp: number) { return prisma.prismaPoolSnapshot.findUnique({ - where: { id_chain: { id: `${poolId}-${timestamp}`, chain: networkContext.chain } }, + where: { id_chain: { id: `${poolId}-${timestamp}`, chain: this.chain } }, }); } @@ -82,14 +85,14 @@ export class PoolSnapshotService { where: { // there is no guarantee that a pool receives a swap per day, so we get the last day with a swap timestamp: { lte: moment().utc().startOf('day').subtract(daysToSync, 'days').unix() }, - chain: networkContext.chain, + chain: this.chain, }, orderBy: { timestamp: 'desc' }, distinct: 'poolId', }); const poolIds = _.uniq(allSnapshots.map((snapshot) => snapshot.pool.id)); - const pools = await prisma.prismaPool.findMany({ where: { id: { in: poolIds }, chain: networkContext.chain } }); + const pools = await prisma.prismaPool.findMany({ where: { id: { in: poolIds }, chain: this.chain } }); for (const pool of pools) { const snapshots = allSnapshots.filter((snapshot) => snapshot.pool.id === pool.id); @@ -116,7 +119,7 @@ export class PoolSnapshotService { ); return prisma.prismaPoolSnapshot.upsert({ - where: { id_chain: { id: snapshot.id, chain: networkContext.chain } }, + where: { id_chain: { id: snapshot.id, chain: this.chain } }, create: data, update: data, }); @@ -129,8 +132,8 @@ export class PoolSnapshotService { const poolsWithoutSnapshots = await prisma.prismaPool.findMany({ where: { OR: [ - { type: 'PHANTOM_STABLE', chain: networkContext.chain }, - { tokens: { some: { nestedPoolId: { not: null } } }, chain: networkContext.chain }, + { type: 'PHANTOM_STABLE', chain: this.chain }, + { tokens: { some: { nestedPoolId: { not: null } } }, chain: this.chain }, ], }, include: { tokens: true }, @@ -168,7 +171,7 @@ export class PoolSnapshotService { public async createPoolSnapshotsForPoolsMissingSubgraphData(poolId: string, numDays = -1) { const pool = await prisma.prismaPool.findUniqueOrThrow({ - where: { id_chain: { id: poolId, chain: networkContext.chain } }, + where: { id_chain: { id: poolId, chain: this.chain } }, include: prismaPoolWithExpandedNesting.include, }); @@ -183,7 +186,7 @@ export class PoolSnapshotService { throw new Error('Unsupported pool type'); } - const swaps = await balancerSubgraphService.getAllSwapsWithPaging({ where: { poolId }, startTimestamp }); + const swaps = await this.balancerSubgraphService.getAllSwapsWithPaging({ where: { poolId }, startTimestamp }); const tokenPriceMap: TokenHistoricalPrices = {}; @@ -194,7 +197,7 @@ export class PoolSnapshotService { if (token.nestedPoolId && token.nestedPool) { const snapshots = await prisma.prismaPoolSnapshot.findMany({ - where: { poolId: token.nestedPoolId, chain: networkContext.chain }, + where: { poolId: token.nestedPoolId, chain: this.chain }, }); tokenPriceMap[token.address] = snapshots.map((snapshot) => ({ @@ -207,7 +210,7 @@ export class PoolSnapshotService { where: { tokenAddress: token.address, timestamp: { gte: startTimestamp }, - chain: networkContext.chain, + chain: this.chain, }, }); if (priceForDays.length === 0) { @@ -277,7 +280,7 @@ export class PoolSnapshotService { const id = `${poolId}-${startTimestamp}`; const data = { id, - chain: networkContext.chain, + chain: this.chain, poolId, timestamp: startTimestamp, totalLiquidity: totalLiquidity || 0, @@ -297,7 +300,7 @@ export class PoolSnapshotService { try { await prisma.prismaPoolSnapshot.upsert({ - where: { id_chain: { id, chain: networkContext.chain } }, + where: { id_chain: { id, chain: this.chain } }, create: data, update: data, }); @@ -318,7 +321,7 @@ export class PoolSnapshotService { return { id: snapshot.id, - chain: networkContext.chain, + chain: this.chain, poolId: snapshot.pool.id, timestamp: snapshot.timestamp, totalLiquidity: parseFloat(snapshot.liquidity), diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index b3330e68a..58bf051ea 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -6,7 +6,6 @@ import { Swap_OrderBy, } from '../../subgraphs/balancer-subgraph/generated/balancer-subgraph-types'; import { tokenService, TokenService } from '../../token/token.service'; -import { BalancerSubgraphService } from '../../subgraphs/balancer-subgraph/balancer-subgraph.service'; import { GqlPoolJoinExit, GqlPoolSwap, @@ -25,18 +24,24 @@ import { AllNetworkConfigsKeyedOnChain } from '../../network/network-config'; export class PoolSwapService { constructor( private readonly tokenService: TokenService, - private readonly balancerSubgraphService: BalancerSubgraphService, ) {} + private get balancerSubgraphService() { + return networkContext.services.balancerSubgraphService; + } + + private get chain() { + return networkContext.chain; + } + public async getJoinExits(args: QueryPoolGetJoinExitsArgs): Promise { const first = !args.first || args.first > 100 ? 10 : args.first; const allChainsJoinExits: GqlPoolJoinExit[] = []; for (const chain of args.where!.chainIn!) { - const balancerSubgraphService = new BalancerSubgraphService( - AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, - ); + const balancerSubgraphService = + AllNetworkConfigsKeyedOnChain[chain].services.balancerSubgraphService; const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ where: { pool_in: args.where?.poolIdIn }, @@ -70,9 +75,9 @@ export class PoolSwapService { first = 10, skip = 0, ): Promise { - const balancerSubgraphService = new BalancerSubgraphService( - AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, - ); + const balancerSubgraphService = + AllNetworkConfigsKeyedOnChain[chain].services.balancerSubgraphService; + const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ where: { pool: poolId, user: userAddress }, first, @@ -121,9 +126,9 @@ export class PoolSwapService { first = 10, skip = 0, ): Promise { - const balancerSubgraphService = new BalancerSubgraphService( - AllNetworkConfigsKeyedOnChain[chain].data.subgraphs.balancer, - ); + const balancerSubgraphService = + AllNetworkConfigsKeyedOnChain[chain].services.balancerSubgraphService; + const result = await balancerSubgraphService.getSwaps({ first, skip, @@ -191,7 +196,7 @@ export class PoolSwapService { const tokenPrices = await this.tokenService.getTokenPrices(); const lastSwap = await prisma.prismaPoolSwap.findFirst({ orderBy: { timestamp: 'desc' }, - where: { chain: networkContext.chain }, + where: { chain: this.chain }, }); const twoDaysAgo = moment().subtract(2, 'day').unix(); //ensure we only sync the last 48 hours worth of swaps @@ -256,7 +261,7 @@ export class PoolSwapService { return { id: swap.id, - chain: networkContext.chain, + chain: this.chain, timestamp: swap.timestamp, poolId: swap.poolId.id, userAddress: swap.userAddress.id, @@ -290,13 +295,13 @@ export class PoolSwapService { await prisma.prismaPoolSwap.deleteMany({ where: { timestamp: { lt: twoDaysAgo }, - chain: networkContext.chain, + chain: this.chain, }, }); await prisma.prismaPoolBatchSwap.deleteMany({ where: { timestamp: { lt: twoDaysAgo }, - chain: networkContext.chain, + chain: this.chain, }, }); @@ -305,14 +310,14 @@ export class PoolSwapService { private async createBatchSwaps(txs: string[]) { const tokenPrices = await this.tokenService.getTokenPrices(); - const swaps = await prisma.prismaPoolSwap.findMany({ where: { tx: { in: txs }, chain: networkContext.chain } }); + const swaps = await prisma.prismaPoolSwap.findMany({ where: { tx: { in: txs }, chain: this.chain } }); const groupedByTxAndUser = _.groupBy(swaps, (swap) => `${swap.tx}${swap.userAddress}`); let operations: any[] = [ prisma.prismaPoolSwap.updateMany({ - where: { tx: { in: txs }, chain: networkContext.chain }, + where: { tx: { in: txs }, chain: this.chain }, data: { batchSwapId: null, batchSwapIdx: null }, }), - prisma.prismaPoolBatchSwap.deleteMany({ where: { tx: { in: txs }, chain: networkContext.chain } }), + prisma.prismaPoolBatchSwap.deleteMany({ where: { tx: { in: txs }, chain: this.chain } }), ]; for (const group of Object.values(groupedByTxAndUser)) { @@ -339,7 +344,7 @@ export class PoolSwapService { prisma.prismaPoolBatchSwap.create({ data: { id: startSwap.id, - chain: networkContext.chain, + chain: this.chain, timestamp: startSwap.timestamp, userAddress: startSwap.userAddress, tokenIn: startSwap.tokenIn, @@ -354,7 +359,7 @@ export class PoolSwapService { }), ...batchSwaps.map((swap, index) => prisma.prismaPoolSwap.update({ - where: { id_chain: { id: swap.id, chain: networkContext.chain } }, + where: { id_chain: { id: swap.id, chain: this.chain } }, data: { batchSwapId: startSwap.id, batchSwapIdx: index }, }), ), diff --git a/modules/pool/lib/pool-usd-data.service.ts b/modules/pool/lib/pool-usd-data.service.ts index da03195d0..aafffbf3c 100644 --- a/modules/pool/lib/pool-usd-data.service.ts +++ b/modules/pool/lib/pool-usd-data.service.ts @@ -4,7 +4,6 @@ import moment from 'moment-timezone'; import { isSupportedInt, prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { TokenService } from '../../token/token.service'; import { BlocksSubgraphService } from '../../subgraphs/blocks-subgraph/blocks-subgraph.service'; -import { BalancerSubgraphService } from '../../subgraphs/balancer-subgraph/balancer-subgraph.service'; import { networkContext } from '../../network/network-context.service'; import { capturesYield } from './pool-utils'; import * as Sentry from '@sentry/node'; @@ -13,9 +12,12 @@ export class PoolUsdDataService { constructor( private readonly tokenService: TokenService, private readonly blockSubgraphService: BlocksSubgraphService, - private readonly balancerSubgraphService: BalancerSubgraphService, ) {} + private get balancerSubgraphService() { + return networkContext.services.balancerSubgraphService; + } + /** * Liquidity is dependent on token prices, so the values here are constantly in flux. * When updating, the easiest is to update all pools at once. diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index a6a69bd96..6f7816f4f 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -19,7 +19,6 @@ import { QueryPoolGetSwapsArgs, } from '../../schema'; import { coingeckoService } from '../coingecko/coingecko.service'; -import { balancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; import { blocksSubgraphService } from '../subgraphs/blocks-subgraph/blocks-subgraph.service'; import { tokenService } from '../token/token.service'; import { userService } from '../user/user.service'; @@ -53,6 +52,14 @@ export class PoolService { private readonly reliquarySnapshotService: ReliquarySnapshotService, ) {} + private get chain() { + return networkContext.chain; + } + + private get chainId() { + return networkContext.chainId; + } + private get poolStakingServices(): PoolStakingService[] { return networkContext.config.poolStakingServices; } @@ -61,6 +68,10 @@ export class PoolService { return networkContext.config.contentService; } + private get balancerSubgraphService() { + return networkContext.services.balancerSubgraphService; + } + public async getGqlPool(id: string, chain: GqlChain): Promise { return this.poolGqlLoaderService.getPool(id, chain); } @@ -78,7 +89,7 @@ export class PoolService { } public async getPoolFilters(): Promise { - return prisma.prismaPoolFilter.findMany({ where: { chain: networkContext.chain } }); + return prisma.prismaPoolFilter.findMany({ where: { chain: this.chain } }); } public async getPoolSwaps(args: QueryPoolGetSwapsArgs): Promise { @@ -105,7 +116,7 @@ export class PoolService { public async getFeaturedPoolGroups(): Promise { const cached: GqlPoolFeaturedPoolGroup[] = await this.cache.get( - `${FEATURED_POOL_GROUPS_CACHE_KEY}:${networkContext.chainId}`, + `${FEATURED_POOL_GROUPS_CACHE_KEY}:${this.chainId}`, ); if (cached) { @@ -115,7 +126,7 @@ export class PoolService { const featuredPoolGroups = await this.poolGqlLoaderService.getFeaturedPoolGroups(); this.cache.put( - `${FEATURED_POOL_GROUPS_CACHE_KEY}:${networkContext.chainId}`, + `${FEATURED_POOL_GROUPS_CACHE_KEY}:${this.chainId}`, featuredPoolGroups, 60 * 5 * 1000, ); @@ -154,7 +165,7 @@ export class PoolService { public async syncPoolAllTokensRelationship(): Promise { const pools = await prisma.prismaPool.findMany({ select: { id: true }, - where: { chain: networkContext.chain }, + where: { chain: this.chain }, }); for (const pool of pools) { @@ -183,7 +194,7 @@ export class PoolService { categories: { none: { category: 'BLACK_LISTED' }, }, - chain: networkContext.chain, + chain: this.chain, }, }); const poolIds = result.map((item) => item.id); @@ -216,7 +227,7 @@ export class PoolService { public async loadOnChainDataForPoolsWithActiveUpdates() { const blockNumber = await networkContext.provider.getBlockNumber(); const timestamp = moment().subtract(5, 'minutes').unix(); - const poolIds = await balancerSubgraphService.getPoolsWithActiveUpdates(timestamp); + const poolIds = await this.balancerSubgraphService.getPoolsWithActiveUpdates(timestamp); await this.poolOnChainDataService.updateOnChainData(poolIds, blockNumber); } @@ -271,7 +282,7 @@ export class PoolService { public async loadSnapshotsForPools(poolIds: string[], reload: boolean) { if (reload) { await prisma.prismaPoolSnapshot.deleteMany({ - where: { chain: networkContext.chain, poolId: { in: poolIds } }, + where: { chain: this.chain, poolId: { in: poolIds } }, }); } @@ -279,7 +290,7 @@ export class PoolService { } public async loadSnapshotsForAllPools() { - await prisma.prismaPoolSnapshot.deleteMany({ where: { chain: networkContext.chain } }); + await prisma.prismaPoolSnapshot.deleteMany({ where: { chain: this.chain } }); const pools = await prisma.prismaPool.findMany({ select: { id: true }, where: { @@ -288,7 +299,7 @@ export class PoolService { gt: 0.000000000001, }, }, - chain: networkContext.chain, + chain: this.chain, }, }); const chunks = _.chunk(pools, 10); @@ -308,10 +319,10 @@ export class PoolService { } public async loadReliquarySnapshotsForAllFarms() { - await prisma.prismaReliquaryTokenBalanceSnapshot.deleteMany({ where: { chain: networkContext.chain } }); - await prisma.prismaReliquaryLevelSnapshot.deleteMany({ where: { chain: networkContext.chain } }); - await prisma.prismaReliquaryFarmSnapshot.deleteMany({ where: { chain: networkContext.chain } }); - const farms = await prisma.prismaPoolStakingReliquaryFarm.findMany({ where: { chain: networkContext.chain } }); + await prisma.prismaReliquaryTokenBalanceSnapshot.deleteMany({ where: { chain: this.chain } }); + await prisma.prismaReliquaryLevelSnapshot.deleteMany({ where: { chain: this.chain } }); + await prisma.prismaReliquaryFarmSnapshot.deleteMany({ where: { chain: this.chain } }); + const farms = await prisma.prismaPoolStakingReliquaryFarm.findMany({ where: { chain: this.chain } }); const farmIds = farms.map((farm) => parseFloat(farm.id)); for (const farmId of farmIds) { await this.reliquarySnapshotService.loadAllSnapshotsForFarm(farmId); @@ -347,10 +358,10 @@ export class PoolService { } public async syncPoolVersionForAllPools() { - const subgraphPools = await balancerSubgraphService.getAllPools({}, false); + const subgraphPools = await this.balancerSubgraphService.getAllPools({}, false); for (const subgraphPool of subgraphPools) { await prisma.prismaPool.update({ - where: { id_chain: { chain: networkContext.chain, id: subgraphPool.id } }, + where: { id_chain: { chain: this.chain, id: subgraphPool.id } }, data: { version: subgraphPool.poolTypeVersion ? subgraphPool.poolTypeVersion : 1, }, @@ -360,7 +371,7 @@ export class PoolService { public async addToBlackList(poolId: string) { const category = await prisma.prismaPoolCategory.findFirst({ - where: { poolId, chain: networkContext.chain, category: 'BLACK_LISTED' }, + where: { poolId, chain: this.chain, category: 'BLACK_LISTED' }, }); if (category) { @@ -369,9 +380,9 @@ export class PoolService { await prisma.prismaPoolCategory.create({ data: { - id: `${networkContext.chain}-${poolId}-BLACK_LISTED`, + id: `${this.chain}-${poolId}-BLACK_LISTED`, category: 'BLACK_LISTED', - chain: networkContext.chain, + chain: this.chain, poolId, }, }); @@ -381,7 +392,7 @@ export class PoolService { await prisma.prismaPoolCategory.deleteMany({ where: { category: 'BLACK_LISTED', - chain: networkContext.chain, + chain: this.chain, poolId, }, }); @@ -389,87 +400,87 @@ export class PoolService { public async deletePool(poolId: string) { const pool = await prisma.prismaPool.findUniqueOrThrow({ - where: { id_chain: { id: poolId, chain: networkContext.chain } }, + where: { id_chain: { id: poolId, chain: this.chain } }, }); const poolTokens = await prisma.prismaPoolToken.findMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); const poolTokenIds = poolTokens.map((poolToken) => poolToken.id); const poolTokenAddresses = poolTokens.map((poolToken) => poolToken.address); await prisma.prismaPoolSnapshot.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaTokenType.deleteMany({ - where: { chain: networkContext.chain, tokenAddress: pool.address }, + where: { chain: this.chain, tokenAddress: pool.address }, }); await prisma.prismaUserWalletBalance.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPoolTokenDynamicData.deleteMany({ - where: { chain: networkContext.chain, poolTokenId: { in: poolTokenIds } }, + where: { chain: this.chain, poolTokenId: { in: poolTokenIds } }, }); await prisma.prismaTokenDynamicData.deleteMany({ - where: { chain: networkContext.chain, tokenAddress: { in: poolTokenAddresses } }, + where: { chain: this.chain, tokenAddress: { in: poolTokenAddresses } }, }); await prisma.prismaPoolToken.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPoolDynamicData.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPoolToken.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPoolLinearData.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPoolGyroData.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPoolExpandedTokens.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPoolLinearDynamicData.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPoolAprItem.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPoolSwap.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); const poolStaking = await prisma.prismaPoolStaking.findMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); for (const staking of poolStaking) { switch (staking.type) { case 'GAUGE': await prisma.prismaPoolStakingGaugeReward.deleteMany({ - where: { chain: networkContext.chain, gaugeId: staking.id }, + where: { chain: this.chain, gaugeId: staking.id }, }); // delete votingGauge entry before deleting the staking gauge let gauge = await prisma.prismaPoolStakingGauge.findFirst({ where: { - chain: networkContext.chain, + chain: this.chain, stakingId: staking.id, }, select: { @@ -479,30 +490,30 @@ export class PoolService { if (gauge && gauge.votingGauge) await prisma.prismaVotingGauge.deleteMany({ - where: { chain: networkContext.chain, id: gauge.votingGauge.id }, + where: { chain: this.chain, id: gauge.votingGauge.id }, }); await prisma.prismaPoolStakingGauge.deleteMany({ - where: { chain: networkContext.chain, stakingId: staking.id }, + where: { chain: this.chain, stakingId: staking.id }, }); break; case 'MASTER_CHEF': await prisma.prismaPoolStakingMasterChefFarmRewarder.deleteMany({ - where: { chain: networkContext.chain, farmId: staking.id }, + where: { chain: this.chain, farmId: staking.id }, }); await prisma.prismaPoolStakingMasterChefFarm.deleteMany({ - where: { chain: networkContext.chain, stakingId: staking.id }, + where: { chain: this.chain, stakingId: staking.id }, }); break; case 'RELIQUARY': await prisma.prismaPoolStakingReliquaryFarmLevel.deleteMany({ - where: { chain: networkContext.chain, farmId: staking.id.split('-')[1] }, + where: { chain: this.chain, farmId: staking.id.split('-')[1] }, }); await prisma.prismaPoolStakingReliquaryFarm.deleteMany({ - where: { chain: networkContext.chain, stakingId: staking.id }, + where: { chain: this.chain, stakingId: staking.id }, }); break; default: @@ -511,15 +522,15 @@ export class PoolService { } await prisma.prismaUserStakedBalance.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPoolStaking.deleteMany({ - where: { chain: networkContext.chain, poolId: poolId }, + where: { chain: this.chain, poolId: poolId }, }); await prisma.prismaPool.delete({ - where: { id_chain: { id: poolId, chain: networkContext.chain } }, + where: { id_chain: { id: poolId, chain: this.chain } }, }); } } @@ -527,11 +538,11 @@ export class PoolService { export const poolService = new PoolService( new PoolCreatorService(userService), new PoolOnChainDataService(tokenService), - new PoolUsdDataService(tokenService, blocksSubgraphService, balancerSubgraphService), + new PoolUsdDataService(tokenService, blocksSubgraphService), new PoolGqlLoaderService(), new PoolAprUpdaterService(), new PoolSyncService(), - new PoolSwapService(tokenService, balancerSubgraphService), - new PoolSnapshotService(balancerSubgraphService, coingeckoService), + new PoolSwapService(tokenService), + new PoolSnapshotService(coingeckoService), new ReliquarySnapshotService(reliquarySubgraphService), ); diff --git a/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts b/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts index 43b779b58..0ca49121f 100644 --- a/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts +++ b/modules/subgraphs/balancer-subgraph/balancer-subgraph.service.ts @@ -44,16 +44,17 @@ import { subgraphLoadAll } from '../subgraph-util'; import { Cache, CacheClass } from 'memory-cache'; import { fiveMinutesInMs, twentyFourHoursInMs } from '../../common/time'; import { BalancerUserPoolShare } from './balancer-subgraph-types'; -import { networkContext } from '../../network/network-context.service'; const ALL_POOLS_CACHE_KEY = `balance-subgraph_all-pools`; const PORTFOLIO_POOLS_CACHE_KEY = `balance-subgraph_portfolio-pools`; export class BalancerSubgraphService { private cache: CacheClass; + private sdk: ReturnType; - constructor(private readonly subgraphUrl = networkContext.data.subgraphs.balancer) { + constructor(subgraphUrl: string, private chainId: number) { this.cache = new Cache(); + this.sdk = getSdk(new GraphQLClient(subgraphUrl)); } public async getMetadata() { @@ -265,7 +266,7 @@ export class BalancerSubgraphService { public async getPortfolioPoolsData(previousBlockNumber: number): Promise { const cached = this.cache.get( - `${PORTFOLIO_POOLS_CACHE_KEY}:${networkContext.chainId}`, + `${PORTFOLIO_POOLS_CACHE_KEY}:${this.chainId}`, ) as BalancerPortfolioPoolsDataQuery | null; if (cached) { @@ -274,13 +275,13 @@ export class BalancerSubgraphService { const portfolioPools = await this.sdk.BalancerPortfolioPoolsData({ previousBlockNumber }); - this.cache.put(`${PORTFOLIO_POOLS_CACHE_KEY}:${networkContext.chainId}`, portfolioPools, fiveMinutesInMs); + this.cache.put(`${PORTFOLIO_POOLS_CACHE_KEY}:${this.chainId}`, portfolioPools, fiveMinutesInMs); return portfolioPools; } public async getAllPoolsAtBlock(block: number): Promise { - const cached = this.cache.get(`${ALL_POOLS_CACHE_KEY}:${networkContext.chainId}:${block}`) as + const cached = this.cache.get(`${ALL_POOLS_CACHE_KEY}:${this.chainId}:${block}`) as | BalancerPoolFragment[] | null; @@ -294,7 +295,7 @@ export class BalancerSubgraphService { block: { number: block }, }); - this.cache.put(`${ALL_POOLS_CACHE_KEY}:${networkContext.chainId}:${block}`, pools, twentyFourHoursInMs); + this.cache.put(`${ALL_POOLS_CACHE_KEY}:${this.chainId}:${block}`, pools, twentyFourHoursInMs); return pools; } @@ -313,12 +314,6 @@ export class BalancerSubgraphService { return [...ampUpdates, ...gradualWeightUpdates].map((item) => item.poolId.id); } - private get sdk() { - const client = new GraphQLClient(this.subgraphUrl); - - return getSdk(client); - } - private normalizeBalancerUser(user: BalancerUserFragment): BalancerUserFragment { return { ...user, @@ -330,5 +325,3 @@ export class BalancerSubgraphService { }; } } - -export const balancerSubgraphService = new BalancerSubgraphService(); diff --git a/modules/user/lib/user-sync-wallet-balance.service.ts b/modules/user/lib/user-sync-wallet-balance.service.ts index 52b1591ae..571418aa9 100644 --- a/modules/user/lib/user-sync-wallet-balance.service.ts +++ b/modules/user/lib/user-sync-wallet-balance.service.ts @@ -6,7 +6,6 @@ import _ from 'lodash'; import { prisma } from '../../../prisma/prisma-client'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { BalancerUserPoolShare } from '../../subgraphs/balancer-subgraph/balancer-subgraph-types'; -import { balancerSubgraphService } from '../../subgraphs/balancer-subgraph/balancer-subgraph.service'; import { beetsBarService } from '../../subgraphs/beets-bar-subgraph/beets-bar.service'; import { BeetsBarUserFragment } from '../../subgraphs/beets-bar-subgraph/generated/beets-bar-subgraph-types'; import { Multicaller, MulticallUserBalance } from '../../web3/multicaller'; @@ -15,9 +14,14 @@ import { networkContext } from '../../network/network-context.service'; export class UserSyncWalletBalanceService { constructor() {} + + private get balancerSubgraphService() { + return networkContext.services.balancerSubgraphService; + } + public async initBalancesForPools() { console.log('initBalancesForPools: loading balances, pools, block...'); - const { block } = await balancerSubgraphService.getMetadata(); + const { block } = await this.balancerSubgraphService.getMetadata(); let endBlock = block.number; console.log(`Loading balances at block ${endBlock}`); @@ -32,7 +36,7 @@ export class UserSyncWalletBalanceService { where: { dynamicData: { totalSharesNum: { gt: 0.000000000001 } }, chain: networkContext.chain }, }); const poolIdsToInit = pools.map((pool) => pool.id); - const shares = await balancerSubgraphService.getAllPoolSharesWithBalance(poolIdsToInit, [ + const shares = await this.balancerSubgraphService.getAllPoolSharesWithBalance(poolIdsToInit, [ AddressZero, networkContext.data.balancer.vault, ]); @@ -227,9 +231,9 @@ export class UserSyncWalletBalanceService { } public async initBalancesForPool(poolId: string) { - const { block } = await balancerSubgraphService.getMetadata(); + const { block } = await this.balancerSubgraphService.getMetadata(); - const shares = await balancerSubgraphService.getAllPoolSharesWithBalance([poolId], [AddressZero]); + const shares = await this.balancerSubgraphService.getAllPoolSharesWithBalance([poolId], [AddressZero]); await prismaBulkExecuteOperations( [ diff --git a/modules/user/user.service.ts b/modules/user/user.service.ts index f58c6104f..872e3c505 100644 --- a/modules/user/user.service.ts +++ b/modules/user/user.service.ts @@ -4,7 +4,6 @@ import { GqlPoolJoinExit, GqlPoolSwap, GqlUserSnapshotDataRange } from '../../sc import { coingeckoService } from '../coingecko/coingecko.service'; import { PoolSnapshotService } from '../pool/lib/pool-snapshot.service'; import { PoolSwapService } from '../pool/lib/pool-swap.service'; -import { balancerSubgraphService } from '../subgraphs/balancer-subgraph/balancer-subgraph.service'; import { reliquarySubgraphService } from '../subgraphs/reliquary-subgraph/reliquary.service'; import { userSnapshotSubgraphService } from '../subgraphs/user-snapshot-subgraph/user-snapshot-subgraph.service'; import { tokenService } from '../token/token.service'; @@ -143,10 +142,10 @@ export class UserService { export const userService = new UserService( new UserBalanceService(), new UserSyncWalletBalanceService(), - new PoolSwapService(tokenService, balancerSubgraphService), + new PoolSwapService(tokenService), new UserSnapshotService( userSnapshotSubgraphService, reliquarySubgraphService, - new PoolSnapshotService(balancerSubgraphService, coingeckoService), + new PoolSnapshotService(coingeckoService), ), ); From 18980a153d77a3dd6b5a02556dfdfc4a995c7f89 Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 14 Nov 2023 16:56:12 +0100 Subject: [PATCH 25/32] vebal sync error handling --- modules/vebal/vebal-voting-list.service.ts | 20 ++++++++++++++++---- modules/vebal/voting-gauges.repository.ts | 18 ++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/modules/vebal/vebal-voting-list.service.ts b/modules/vebal/vebal-voting-list.service.ts index 8f8abec59..3f78e2061 100644 --- a/modules/vebal/vebal-voting-list.service.ts +++ b/modules/vebal/vebal-voting-list.service.ts @@ -135,8 +135,10 @@ export class VeBalVotingListService { async sync(votingGaugeAddresses: string[]) { const chunks = chunk(votingGaugeAddresses, 50); + const syncErrors: Error[] = []; for (const addressChunk of chunks) { - const votingGauges = await this.fetchVotingGauges(addressChunk); + const { votingGauges, errors } = await this.fetchVotingGauges(addressChunk); + syncErrors.push(...errors); /* We avoid saving gauges in specialVotingGaugeAddresses because they require special handling @@ -145,20 +147,30 @@ export class VeBalVotingListService { (gauge) => !specialVotingGaugeAddresses.includes(gauge.gaugeAddress), ); - await this.votingGauges.saveVotingGauges(cleanVotingGauges); + const { saveErrors } = await this.votingGauges.saveVotingGauges(cleanVotingGauges); + syncErrors.push(...saveErrors); + } + if (syncErrors.length > 0) { + throw new Error(`Errors while syncing voting gauges: ${syncErrors.map((error) => error.message)}`); } } async fetchVotingGauges(votingGaugeAddresses: string[]) { + const errors: Error[] = []; + const subgraphGauges = await this.votingGauges.fetchVotingGaugesFromSubgraph(votingGaugeAddresses); const onchainGauges = await this.votingGauges.fetchOnchainVotingGauges(votingGaugeAddresses); const votingGauges = this.votingGauges.updateOnchainGaugesWithSubgraphData(onchainGauges, subgraphGauges); - this.throwIfMissingVotingGaugeData(votingGauges); + try { + this.throwIfMissingVotingGaugeData(votingGauges); + } catch (error) { + errors.push(error as Error); + } - return votingGauges; + return { votingGauges, errors }; } throwIfMissingVotingGaugeData(votingGauges: VotingGauge[]) { diff --git a/modules/vebal/voting-gauges.repository.ts b/modules/vebal/voting-gauges.repository.ts index 4485a35bf..78d16a8c7 100644 --- a/modules/vebal/voting-gauges.repository.ts +++ b/modules/vebal/voting-gauges.repository.ts @@ -119,16 +119,22 @@ export class VotingGaugesRepository { } async saveVotingGauges(votingGauges: VotingGauge[]) { - const votingGaugesWithStakingGaugeId = Promise.all( + const saveErrors: Error[] = []; + const votingGaugesWithStakingGaugeId = await Promise.all( votingGauges.map(async (gauge) => { - const stakingId = await this.findStakingGaugeId(gauge); - gauge.stakingGaugeId = stakingId; - await this.saveVotingGauge(gauge); - return gauge; + try { + const stakingId = await this.findStakingGaugeId(gauge); + gauge.stakingGaugeId = stakingId; + await this.saveVotingGauge(gauge); + return gauge; + } catch (error) { + saveErrors.push(error as Error); + return gauge; + } }), ); - return votingGaugesWithStakingGaugeId; + return { votingGaugesWithStakingGaugeId, saveErrors }; } async saveVotingGauge(gauge: VotingGauge) { From 8e571a571f124f6e77c44b1f4bcb80083ca40f4e Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 14 Nov 2023 17:05:04 +0100 Subject: [PATCH 26/32] fix test --- modules/vebal/debug-voting-list.spec.ts | 2 +- modules/vebal/voting-gauges.repository.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/vebal/debug-voting-list.spec.ts b/modules/vebal/debug-voting-list.spec.ts index 4a9f0331a..21874ed6e 100644 --- a/modules/vebal/debug-voting-list.spec.ts +++ b/modules/vebal/debug-voting-list.spec.ts @@ -286,7 +286,7 @@ it('Uses streamer-v1-map to find gauges (that use streamer instead of recipient) const service = new VeBalVotingListService(); const rootGaugeAddresses = [oldRootV1GaugeAddress, anotherOldRootV1GaugeAddress]; - const fetchedVotingGauges = await service.fetchVotingGauges(rootGaugeAddresses); + const { votingGauges: fetchedVotingGauges } = await service.fetchVotingGauges(rootGaugeAddresses); const repository = new VotingGaugesRepository(); const savedGauges = await repository.saveVotingGauges(fetchedVotingGauges); diff --git a/modules/vebal/voting-gauges.repository.spec.ts b/modules/vebal/voting-gauges.repository.spec.ts index 46a8115f0..941705780 100644 --- a/modules/vebal/voting-gauges.repository.spec.ts +++ b/modules/vebal/voting-gauges.repository.spec.ts @@ -107,7 +107,7 @@ const repository = new VotingGaugesRepository(prismaMock); it('successfully saves onchain gauges', async () => { const votingGauge = aVotingGauge({ network: Chain.OPTIMISM }); - const votingGauges = await repository.saveVotingGauges([votingGauge]); + const { votingGaugesWithStakingGaugeId: votingGauges } = await repository.saveVotingGauges([votingGauge]); expect(votingGauges[0]).toMatchObject(votingGauge); expect(votingGauges[0].stakingGaugeId).toBe(defaultStakingGaugeId); From c6ce462d00d6767e7d271ed8dccaccf89f792cac Mon Sep 17 00:00:00 2001 From: franz Date: Tue, 14 Nov 2023 21:11:04 +0100 Subject: [PATCH 27/32] generically parse apr group --- modules/pool/lib/pool-gql-loader.service.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index 85e841c54..6fe369657 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -751,18 +751,7 @@ export class PoolGqlLoaderService { }), ); const apr = _.sumBy(items, 'apr'); - let title = ''; - - switch (group) { - case 'YEARN': - title = 'Yearn boosted APR'; - break; - case 'REAPER': - title = 'Reaper boosted APR'; - break; - case 'OVERNIGHT': - title = 'Overnight boosted APR'; - } + const title = `${group.charAt(0) + group.slice(1).toLowerCase()} boosted APR`; return { id: `${pool.id}-${group}`, From 7539083449a63c42d3f3a6e1ec81c2a1bfe1d527 Mon Sep 17 00:00:00 2001 From: franz Date: Wed, 15 Nov 2023 12:43:05 +0100 Subject: [PATCH 28/32] safe iteration --- modules/pool/lib/pool-swap.service.ts | 59 +++++++++++++-------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/modules/pool/lib/pool-swap.service.ts b/modules/pool/lib/pool-swap.service.ts index 58bf051ea..1c975a2f9 100644 --- a/modules/pool/lib/pool-swap.service.ts +++ b/modules/pool/lib/pool-swap.service.ts @@ -22,9 +22,7 @@ import * as Sentry from '@sentry/node'; import { AllNetworkConfigsKeyedOnChain } from '../../network/network-config'; export class PoolSwapService { - constructor( - private readonly tokenService: TokenService, - ) {} + constructor(private readonly tokenService: TokenService) {} private get balancerSubgraphService() { return networkContext.services.balancerSubgraphService; @@ -39,30 +37,31 @@ export class PoolSwapService { const allChainsJoinExits: GqlPoolJoinExit[] = []; - for (const chain of args.where!.chainIn!) { - const balancerSubgraphService = - AllNetworkConfigsKeyedOnChain[chain].services.balancerSubgraphService; - - const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ - where: { pool_in: args.where?.poolIdIn }, - first, - skip: args.skip, - orderBy: JoinExit_OrderBy.Timestamp, - orderDirection: OrderDirection.Desc, - }); - - const mappedJoinExits: GqlPoolJoinExit[] = joinExits.map((joinExit) => ({ - ...joinExit, - __typename: 'GqlPoolJoinExit', - chain: chain, - poolId: joinExit.pool.id, - amounts: joinExit.amounts.map((amount, index) => ({ - address: joinExit.pool.tokensList[index], - amount, - })), - })); - - allChainsJoinExits.push(...mappedJoinExits); + if (args.where?.chainIn) { + for (const chain of args.where.chainIn) { + const balancerSubgraphService = AllNetworkConfigsKeyedOnChain[chain].services.balancerSubgraphService; + + const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ + where: { pool_in: args.where?.poolIdIn }, + first, + skip: args.skip, + orderBy: JoinExit_OrderBy.Timestamp, + orderDirection: OrderDirection.Desc, + }); + + const mappedJoinExits: GqlPoolJoinExit[] = joinExits.map((joinExit) => ({ + ...joinExit, + __typename: 'GqlPoolJoinExit', + chain: chain, + poolId: joinExit.pool.id, + amounts: joinExit.amounts.map((amount, index) => ({ + address: joinExit.pool.tokensList[index], + amount, + })), + })); + + allChainsJoinExits.push(...mappedJoinExits); + } } return allChainsJoinExits; @@ -75,8 +74,7 @@ export class PoolSwapService { first = 10, skip = 0, ): Promise { - const balancerSubgraphService = - AllNetworkConfigsKeyedOnChain[chain].services.balancerSubgraphService; + const balancerSubgraphService = AllNetworkConfigsKeyedOnChain[chain].services.balancerSubgraphService; const { joinExits } = await balancerSubgraphService.getPoolJoinExits({ where: { pool: poolId, user: userAddress }, @@ -126,8 +124,7 @@ export class PoolSwapService { first = 10, skip = 0, ): Promise { - const balancerSubgraphService = - AllNetworkConfigsKeyedOnChain[chain].services.balancerSubgraphService; + const balancerSubgraphService = AllNetworkConfigsKeyedOnChain[chain].services.balancerSubgraphService; const result = await balancerSubgraphService.getSwaps({ first, From 10cce4bf0bb541d6fe0c54212df2cb58b9f9f357 Mon Sep 17 00:00:00 2001 From: franz Date: Wed, 15 Nov 2023 13:32:13 +0100 Subject: [PATCH 29/32] more specific errors for chain param --- modules/pool/pool.resolvers.ts | 14 +++++++------- modules/user/user.resolvers.ts | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 3a88f526c..e9fe7431b 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -12,7 +12,7 @@ const balancerResolvers: Resolvers = { if (!chain && currentChain) { chain = currentChain; } else if (!chain) { - throw new Error('Chain is required'); + throw new Error('poolGetPool error: Provide "chain" param'); } return poolService.getGqlPool(id, chain); }, @@ -27,7 +27,7 @@ const balancerResolvers: Resolvers = { if (!args.where?.chainIn && currentChain) { args.where = { ...args.where, chainIn: [currentChain] }; } else if (!args.where?.chainIn) { - throw new Error('Chain is required'); + throw new Error('poolGetSwaps error: Provide "where.chainIn" param'); } return poolService.getPoolSwaps(args); }, @@ -36,7 +36,7 @@ const balancerResolvers: Resolvers = { if (!args.where?.chainIn && currentChain) { args.where = { ...args.where, chainIn: [currentChain] }; } else if (!args.where?.chainIn) { - throw new Error('Chain is required'); + throw new Error('poolGetBatchSwaps error: Provide "where.chainIn" param'); } return poolService.getPoolBatchSwaps(args); }, @@ -45,7 +45,7 @@ const balancerResolvers: Resolvers = { if (!args.where?.chainIn && currentChain) { args.where = { ...args.where, chainIn: [currentChain] }; } else if (!args.where?.chainIn) { - throw new Error('Chain is required'); + throw new Error('poolGetJoinExits error: Provide "where.chainIn" param'); } return poolService.getPoolJoinExits(args); }, @@ -57,7 +57,7 @@ const balancerResolvers: Resolvers = { if (!chain && currentChain) { chain = currentChain; } else if (!chain) { - throw new Error('Chain is required'); + throw new Error('poolGetSnapshots error: Provide "chain" param'); } const snapshots = await poolService.getSnapshotsForPool(id, chain, range); @@ -78,7 +78,7 @@ const balancerResolvers: Resolvers = { if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - throw new Error('Chain is required'); + throw new Error('poolGetAllPoolsSnapshots error: Provide "chains" param'); } const snapshots = await poolService.getSnapshotsForAllPools(chains, range); @@ -99,7 +99,7 @@ const balancerResolvers: Resolvers = { if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - throw new Error('Chain is required'); + throw new Error('poolGetLinearPools error: Provide "chains" param'); } return poolService.getGqlLinearPools(chains); }, diff --git a/modules/user/user.resolvers.ts b/modules/user/user.resolvers.ts index e94480d62..8912e1186 100644 --- a/modules/user/user.resolvers.ts +++ b/modules/user/user.resolvers.ts @@ -11,7 +11,7 @@ const resolvers: Resolvers = { if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - throw new Error('Chain is required'); + throw new Error('userGetPoolBalances error: Provide "chains" param'); } const accountAddress = address || getRequiredAccountAddress(context); const tokenPrices = await tokenService.getTokenPricesForChains(chains); @@ -27,7 +27,7 @@ const resolvers: Resolvers = { if (!chain && currentChain) { chain = currentChain; } else if (!chain) { - throw new Error('Chain is required'); + throw new Error('userGetPoolJoinExits error: Provide "chain" param'); } const accountAddress = address || getRequiredAccountAddress(context); @@ -38,7 +38,7 @@ const resolvers: Resolvers = { if (!chain && currentChain) { chain = currentChain; } else if (!chain) { - throw new Error('Chain is required'); + throw new Error('userGetSwaps error: Provide "chain" param'); } const accountAddress = address || getRequiredAccountAddress(context); return userService.getUserSwaps(accountAddress, poolId, chain, first, skip); @@ -48,7 +48,7 @@ const resolvers: Resolvers = { if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - throw new Error('Chain is required'); + throw new Error('userGetStaking error: Provide "chains" param'); } const accountAddress = address || getRequiredAccountAddress(context); From ef157748c11a3f2818417bd0c4303f4813251979 Mon Sep 17 00:00:00 2001 From: franz Date: Wed, 15 Nov 2023 13:44:38 +0100 Subject: [PATCH 30/32] better errors for token queries --- modules/token/token.resolvers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/token/token.resolvers.ts b/modules/token/token.resolvers.ts index b5c54cafe..8bc79db4c 100644 --- a/modules/token/token.resolvers.ts +++ b/modules/token/token.resolvers.ts @@ -11,7 +11,7 @@ const resolvers: Resolvers = { if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - throw new Error('Chain is required'); + throw new Error('tokenGetTokens error: Provide "chains" param'); } return tokenService.getTokenDefinitions(chains); }, @@ -20,7 +20,7 @@ const resolvers: Resolvers = { if (!chains && currentChain) { chains = [currentChain]; } else if (!chains) { - throw new Error('Chain is required'); + throw new Error('tokenGetCurrentPrices error: Provide "chains" param'); } const prices = await tokenService.getWhiteListedTokenPrices(chains); From f8b30b7eb39057cd741dac834f2df4ede9ebcb75 Mon Sep 17 00:00:00 2001 From: franz Date: Wed, 15 Nov 2023 17:34:24 +0100 Subject: [PATCH 31/32] add userAddress to where --- modules/pool/lib/pool-gql-loader.service.ts | 2 +- modules/pool/pool.gql | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index 6b71bb69f..4d965269e 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -132,7 +132,7 @@ export class PoolGqlLoaderService { private mapQueryArgsToPoolQuery(args: QueryPoolGetPoolsArgs): Prisma.PrismaPoolFindManyArgs { let orderBy: Prisma.PrismaPoolOrderByWithRelationInput = {}; const orderDirection = args.orderDirection || undefined; - const userAddress = args.userAddress; + const userAddress = args.where?.userAddress; switch (args.orderBy) { case 'totalLiquidity': diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index 36fee06ac..219dea792 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -7,7 +7,6 @@ extend type Query { orderDirection: GqlPoolOrderDirection where: GqlPoolFilter textSearch: String - userAddress: String ): [GqlPoolMinimal!]! poolGetPoolsCount( first: Int @@ -16,7 +15,6 @@ extend type Query { orderDirection: GqlPoolOrderDirection where: GqlPoolFilter textSearch: String - userAddress: String ): Int! poolGetSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolSwap!]! poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! @@ -618,6 +616,7 @@ input GqlPoolFilter { chainIn: [GqlChain!] chainNotIn: [GqlChain!] createTime: GqlPoolTimePeriod + userAddress: String } enum GqlPoolFilterCategory { From b54f8158af3796bb8c88439ccc5fae78d91a7825 Mon Sep 17 00:00:00 2001 From: franz Date: Thu, 16 Nov 2023 11:21:18 +0100 Subject: [PATCH 32/32] fix network.context chain --- modules/user/lib/user-snapshot.service.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/modules/user/lib/user-snapshot.service.ts b/modules/user/lib/user-snapshot.service.ts index f5d262761..d886305d8 100644 --- a/modules/user/lib/user-snapshot.service.ts +++ b/modules/user/lib/user-snapshot.service.ts @@ -257,6 +257,7 @@ export class UserSnapshotService { const userPoolBalanceSnapshotData = this.createUserPoolSnapshotData( poolSnapshot, pool, + networkContext.chain, userSubgraphSnapshot, totalBalance, walletBalance, @@ -328,6 +329,7 @@ export class UserSnapshotService { userAddress, 0, poolId, + chain, ); let storedUserSnapshotsInRangeForPool = storedUserSnapshotsForPool.filter( @@ -347,7 +349,7 @@ export class UserSnapshotService { const pool = await prisma.prismaPool.findUniqueOrThrow({ where: { - id_chain: { id: poolId, chain: networkContext.chain }, + id_chain: { id: poolId, chain: chain }, }, include: { staking: true, @@ -422,6 +424,7 @@ export class UserSnapshotService { const userPoolBalanceSnapshotData = this.createUserPoolSnapshotData( poolSnapshotForTimestamp, pool, + chain, userSubgraphSnapshot, totalBalance, walletBalance, @@ -439,6 +442,7 @@ export class UserSnapshotService { userAddress, oldestRequestedSnapshotTimestamp, poolId, + chain, ); } @@ -475,7 +479,7 @@ export class UserSnapshotService { lt: oldestRequestedSnapshotTimestamp, }, poolId: poolId, - chain: networkContext.chain, + chain: chain, }, orderBy: { timestamp: 'desc' }, }); @@ -573,7 +577,7 @@ export class UserSnapshotService { (1 - networkContext.data.balancer.swapProtocolFeePercentage) }`; await prisma.prismaUserPoolBalanceSnapshot.update({ - where: { id_chain: { id: currentSnapshot.id, chain: networkContext.chain } }, + where: { id_chain: { id: currentSnapshot.id, chain: chain } }, data: currentSnapshot, }); } @@ -621,6 +625,7 @@ export class UserSnapshotService { private createUserPoolSnapshotData( poolSnapshot: PrismaPoolSnapshot | undefined | null, pool: PrismaPool & { staking: PrismaPoolStaking[] }, + chain: Chain, subgraphSnapshot: UserBalanceSnapshotFragment, totalBalance: number, walletBalance: string, @@ -631,7 +636,7 @@ export class UserSnapshotService { const userPoolBalanceSnapshotData = { id: `${pool.id}-${subgraphSnapshot.user.id.toLowerCase()}-${subgraphSnapshot.timestamp}`, - chain: networkContext.chain, + chain: chain, timestamp: subgraphSnapshot.timestamp, userAddress: subgraphSnapshot.user.id.toLowerCase(), poolId: pool.id, @@ -702,6 +707,7 @@ export class UserSnapshotService { userAddress: string, oldestRequestedSnapshotTimestamp: number, poolId: string, + chain: Chain, ) { return await prisma.prismaUserPoolBalanceSnapshot.findMany({ where: { @@ -710,7 +716,7 @@ export class UserSnapshotService { gte: oldestRequestedSnapshotTimestamp, }, poolId: poolId, - chain: networkContext.chain, + chain: chain, }, orderBy: { timestamp: 'asc' }, });