From e96fa3985d546c0d1ec4f2e9d8cec1eaf0feff8c Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 17 Oct 2023 15:34:04 +0800 Subject: [PATCH 1/3] Add chains to tokens and token prices queries --- modules/coingecko/coingecko.service.ts | 4 +-- modules/token/lib/token-price.service.ts | 28 ++++++++++---------- modules/token/token-types.ts | 2 ++ modules/token/token.gql | 6 +++-- modules/token/token.resolvers.ts | 9 ++++--- modules/token/token.service.ts | 33 ++++++++++++++---------- 6 files changed, 47 insertions(+), 35 deletions(-) diff --git a/modules/coingecko/coingecko.service.ts b/modules/coingecko/coingecko.service.ts index 14f7fedc5..d638b9ff7 100644 --- a/modules/coingecko/coingecko.service.ts +++ b/modules/coingecko/coingecko.service.ts @@ -109,7 +109,7 @@ export class CoingeckoService { try { if (addresses.length / addressesPerRequest > 10) throw new Error('Too many requests for rate limit.'); - const tokenDefinitions = await tokenService.getTokenDefinitions(); + const tokenDefinitions = await tokenService.getTokenDefinitions([networkContext.chain]); const mapped = addresses.map((address) => this.getMappedTokenDetails(address, tokenDefinitions)); const groupedByPlatform = _.groupBy(mapped, 'platform'); @@ -144,7 +144,7 @@ export class CoingeckoService { const now = Math.floor(Date.now() / 1000); const end = now; const start = end - days * twentyFourHoursInSecs; - const tokenDefinitions = await tokenService.getTokenDefinitions(); + const tokenDefinitions = await tokenService.getTokenDefinitions([networkContext.chain]); const mapped = this.getMappedTokenDetails(address, tokenDefinitions); const endpoint = `/coins/${mapped.platform}/contract/${mapped.address}/market_chart/range?vs_currency=${this.fiatParam}&from=${start}&to=${end}`; diff --git a/modules/token/lib/token-price.service.ts b/modules/token/lib/token-price.service.ts index 6a704f541..caf7ae810 100644 --- a/modules/token/lib/token-price.service.ts +++ b/modules/token/lib/token-price.service.ts @@ -2,7 +2,7 @@ import { TokenPriceHandler, TokenPriceItem } from '../token-types'; import { prisma } from '../../../prisma/prisma-client'; import _ from 'lodash'; import { secondsPerDay, timestampRoundedUpToNearestHour } from '../../common/time'; -import { PrismaTokenCurrentPrice, PrismaTokenPrice } from '@prisma/client'; +import { Chain, PrismaTokenCurrentPrice, PrismaTokenPrice } from '@prisma/client'; import moment from 'moment-timezone'; import { GqlTokenChartDataRange } from '../../../schema'; import { Cache, CacheClass } from 'memory-cache'; @@ -23,27 +23,27 @@ export class TokenPriceService { return networkContext.config.tokenPriceHandlers; } - public async getWhiteListedCurrentTokenPrices(): Promise { + public async getWhiteListedCurrentTokenPrices(chains: Chain[]): Promise { const tokenPrices = await prisma.prismaTokenCurrentPrice.findMany({ orderBy: { timestamp: 'desc' }, distinct: ['tokenAddress'], where: { - chain: networkContext.chain, - token: { - types: { some: { type: 'WHITE_LISTED' } }, - }, + chain: { in: chains }, + token: { types: { some: { type: 'WHITE_LISTED' } } }, }, }); - const wethPrice = tokenPrices.find( - (tokenPrice) => tokenPrice.tokenAddress === networkContext.data.weth.address, - ); + for (const chain of chains) { + const wethPrice = tokenPrices.find( + (tokenPrice) => tokenPrice.tokenAddress === AllNetworkConfigsKeyedOnChain[chain].data.weth.address, + ); - if (wethPrice) { - tokenPrices.push({ - ...wethPrice, - tokenAddress: networkContext.data.eth.address, - }); + if (wethPrice) { + tokenPrices.push({ + ...wethPrice, + tokenAddress: AllNetworkConfigsKeyedOnChain[chain].data.eth.address, + }); + } } return tokenPrices; diff --git a/modules/token/token-types.ts b/modules/token/token-types.ts index 72795a730..56a6d2400 100644 --- a/modules/token/token-types.ts +++ b/modules/token/token-types.ts @@ -1,4 +1,5 @@ import { PrismaTokenWithTypesAndPrices, PrismaTokenWithTypes } from '../../prisma/prisma-types'; +import { Chain } from '@prisma/client'; export interface TokenPriceHandler { exitIfFails: boolean; @@ -24,6 +25,7 @@ export interface TokenDefinition { symbol: string; decimals: number; chainId: number; + chain: Chain; logoURI?: string | null; priority: number; coingeckoPlatformId?: string | null; diff --git a/modules/token/token.gql b/modules/token/token.gql index 826e10924..3453da192 100644 --- a/modules/token/token.gql +++ b/modules/token/token.gql @@ -1,6 +1,6 @@ extend type Query { - tokenGetTokens: [GqlToken!]! - tokenGetCurrentPrices: [GqlTokenPrice!]! + tokenGetTokens(chains: [GqlChain!]!): [GqlToken!]! + tokenGetCurrentPrices(chains: [GqlChain!]!): [GqlTokenPrice!]! tokenGetHistoricalPrices(addresses: [String!]!): [GqlHistoricalTokenPrice!]! tokenGetTokensDynamicData(addresses: [String!]!): [GqlTokenDynamicData!]! tokenGetTokenDynamicData(address: String!): GqlTokenDynamicData @@ -28,6 +28,7 @@ extend type Mutation { type GqlTokenPrice { address: String! + chain: GqlChain! price: Float! } @@ -55,6 +56,7 @@ type GqlToken { logoURI: String priority: Int! tradable: Boolean! + chain: GqlChain! } type GqlTokenDynamicData { diff --git a/modules/token/token.resolvers.ts b/modules/token/token.resolvers.ts index 85bc89bcc..81e4c8241 100644 --- a/modules/token/token.resolvers.ts +++ b/modules/token/token.resolvers.ts @@ -5,15 +5,16 @@ import { tokenService } from './token.service'; const resolvers: Resolvers = { Query: { - tokenGetTokens: async () => { - return tokenService.getTokenDefinitions(); + tokenGetTokens: async (parent, { chains }, context) => { + return tokenService.getTokenDefinitions(chains); }, - tokenGetCurrentPrices: async (parent, {}, context) => { - const prices = await tokenService.getWhiteListedTokenPrices(); + tokenGetCurrentPrices: async (parent, { chains }, context) => { + const prices = await tokenService.getWhiteListedTokenPrices(chains); return prices.map((price) => ({ address: price.tokenAddress, price: price.price, + chain: price.chain, })); }, tokenGetHistoricalPrices: async (parent, { addresses }, context) => { diff --git a/modules/token/token.service.ts b/modules/token/token.service.ts index e9c6b3651..1ee17e58c 100644 --- a/modules/token/token.service.ts +++ b/modules/token/token.service.ts @@ -8,6 +8,7 @@ import { GqlTokenChartDataRange, MutationTokenDeletePriceArgs, MutationTokenDele import { coingeckoService } from '../coingecko/coingecko.service'; import { networkContext } from '../network/network-context.service'; import { Dictionary } from 'lodash'; +import { AllNetworkConfigsKeyedOnChain } from '../network/network-config'; const TOKEN_PRICES_CACHE_KEY = `token:prices:current`; const TOKEN_PRICES_24H_AGO_CACHE_KEY = `token:prices:24h-ago`; @@ -49,27 +50,33 @@ export class TokenService { return tokens; } - public async getTokenDefinitions(): Promise { + public async getTokenDefinitions(chains: Chain[]): Promise { const tokens = await prisma.prismaToken.findMany({ - where: { types: { some: { type: 'WHITE_LISTED' } }, chain: networkContext.chain }, + where: { types: { some: { type: 'WHITE_LISTED' } }, chain: { in: chains } }, include: { types: true }, orderBy: { priority: 'desc' }, }); - const weth = tokens.find((token) => token.address === networkContext.data.weth.address); + for (const chain of chains) { + const weth = tokens.find( + (token) => + token.chain === chain && token.address === AllNetworkConfigsKeyedOnChain[chain].data.weth.address, + ); - if (weth) { - tokens.push({ - ...weth, - name: networkContext.data.eth.name, - address: networkContext.data.eth.address, - symbol: networkContext.data.eth.symbol, - }); + if (weth) { + tokens.push({ + ...weth, + name: AllNetworkConfigsKeyedOnChain[chain].data.eth.name, + address: AllNetworkConfigsKeyedOnChain[chain].data.eth.address, + symbol: AllNetworkConfigsKeyedOnChain[chain].data.eth.symbol, + chain: AllNetworkConfigsKeyedOnChain[chain].data.chain.prismaId, + }); + } } return tokens.map((token) => ({ ...token, - chainId: networkContext.data.chain.id, + chainId: AllNetworkConfigsKeyedOnChain[token.chain].data.chain.id, //TODO: some linear wrapped tokens are tradable. ie: xBOO tradable: !token.types.find( (type) => type.type === 'PHANTOM_BPT' || type.type === 'BPT' || type.type === 'LINEAR_WRAPPED_TOKEN', @@ -100,7 +107,7 @@ export class TokenService { return response; } - public async getWhiteListedTokenPrices(): Promise { + public async getWhiteListedTokenPrices(chains: Chain[]): Promise { /*const cached = this.cache.get(WHITE_LISTED_TOKEN_PRICES_CACHE_KEY) as PrismaTokenCurrentPrice[] | null; if (cached) { @@ -112,7 +119,7 @@ export class TokenService { return tokenPrices;*/ - return this.tokenPriceService.getWhiteListedCurrentTokenPrices(); + return this.tokenPriceService.getWhiteListedCurrentTokenPrices(chains); } public async getProtocolTokenPrice(): Promise { From c8a6b8c1d001342569e3c68806a540edb3f3b5a5 Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:15:16 +0200 Subject: [PATCH 2/3] all chains as default --- modules/token/token.gql | 4 ++-- modules/token/token.resolvers.ts | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/token/token.gql b/modules/token/token.gql index 3453da192..5481e271b 100644 --- a/modules/token/token.gql +++ b/modules/token/token.gql @@ -1,6 +1,6 @@ extend type Query { - tokenGetTokens(chains: [GqlChain!]!): [GqlToken!]! - tokenGetCurrentPrices(chains: [GqlChain!]!): [GqlTokenPrice!]! + tokenGetTokens(chains: [GqlChain!]): [GqlToken!]! + tokenGetCurrentPrices(chains: [GqlChain!]): [GqlTokenPrice!]! tokenGetHistoricalPrices(addresses: [String!]!): [GqlHistoricalTokenPrice!]! tokenGetTokensDynamicData(addresses: [String!]!): [GqlTokenDynamicData!]! tokenGetTokenDynamicData(address: String!): GqlTokenDynamicData diff --git a/modules/token/token.resolvers.ts b/modules/token/token.resolvers.ts index 81e4c8241..5149a57c5 100644 --- a/modules/token/token.resolvers.ts +++ b/modules/token/token.resolvers.ts @@ -2,13 +2,18 @@ import { Resolvers } from '../../schema'; import _ from 'lodash'; import { isAdminRoute } from '../auth/auth-context'; import { tokenService } from './token.service'; +import { $Enums } from '@prisma/client'; + +const allChains = Object.values($Enums.Chain); const resolvers: Resolvers = { Query: { tokenGetTokens: async (parent, { chains }, context) => { + chains = chains && chains.length > 0 ? chains : allChains; return tokenService.getTokenDefinitions(chains); }, tokenGetCurrentPrices: async (parent, { chains }, context) => { + chains = chains && chains.length > 0 ? chains : allChains; const prices = await tokenService.getWhiteListedTokenPrices(chains); return prices.map((price) => ({ From f6857260d6116aea97aa55c88df9c102de764cbb Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Wed, 18 Oct 2023 11:45:11 +0200 Subject: [PATCH 3/3] falling back to the default chain for filtering --- modules/token/token.resolvers.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/token/token.resolvers.ts b/modules/token/token.resolvers.ts index 5149a57c5..94f794e3a 100644 --- a/modules/token/token.resolvers.ts +++ b/modules/token/token.resolvers.ts @@ -2,18 +2,16 @@ import { Resolvers } from '../../schema'; import _ from 'lodash'; import { isAdminRoute } from '../auth/auth-context'; import { tokenService } from './token.service'; -import { $Enums } from '@prisma/client'; - -const allChains = Object.values($Enums.Chain); +import { networkContext } from '../network/network-context.service'; const resolvers: Resolvers = { Query: { tokenGetTokens: async (parent, { chains }, context) => { - chains = chains && chains.length > 0 ? chains : allChains; + chains = chains && chains.length > 0 ? chains : [networkContext.chain]; return tokenService.getTokenDefinitions(chains); }, tokenGetCurrentPrices: async (parent, { chains }, context) => { - chains = chains && chains.length > 0 ? chains : allChains; + chains = chains && chains.length > 0 ? chains : [networkContext.chain]; const prices = await tokenService.getWhiteListedTokenPrices(chains); return prices.map((price) => ({