Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add chains array param to user balance query #482

Merged
merged 6 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions modules/network/network-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { gnosisNetworkConfig } from './gnosis';
import { zkevmNetworkConfig } from './zkevm';
import { avalancheNetworkConfig } from './avalanche';
import { baseNetworkConfig } from './base';
import { Chain } from '@prisma/client';
import { keyBy, pickBy } from 'lodash';

export const AllNetworkConfigs: { [chainId: string]: NetworkConfig } = {
'250': fantomNetworkConfig,
Expand All @@ -21,5 +23,17 @@ export const AllNetworkConfigs: { [chainId: string]: NetworkConfig } = {
'8453': baseNetworkConfig,
};

export const AllNetworkConfigsKeyedOnChain: { [chain in Chain]: NetworkConfig } = {
FANTOM: fantomNetworkConfig,
OPTIMISM: optimismNetworkConfig,
MAINNET: mainnetNetworkConfig,
ARBITRUM: arbitrumNetworkConfig,
POLYGON: polygonNetworkConfig,
GNOSIS: gnosisNetworkConfig,
ZKEVM: zkevmNetworkConfig,
AVALANCHE: avalancheNetworkConfig,
BASE: baseNetworkConfig,
};

export const BalancerChainIds = ['1', '137', '42161', '100', '1101', '43114', '8453'];
export const BeethovenChainIds = ['250', '10'];
9 changes: 5 additions & 4 deletions modules/token/lib/token-price.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Cache, CacheClass } from 'memory-cache';
import * as Sentry from '@sentry/node';
import { networkContext } from '../../network/network-context.service';
import { TokenHistoricalPrices } from '../../coingecko/coingecko-types';
import { AllNetworkConfigsKeyedOnChain } from '../../network/network-config';

const TOKEN_HISTORICAL_PRICES_CACHE_KEY = `token-historical-prices`;
const NESTED_BPT_HISTORICAL_PRICES_CACHE_KEY = `nested-bpt-historical-prices`;
Expand Down Expand Up @@ -48,21 +49,21 @@ export class TokenPriceService {
return tokenPrices;
}

public async getCurrentTokenPrices(): Promise<PrismaTokenCurrentPrice[]> {
public async getCurrentTokenPrices(chain = networkContext.chain): Promise<PrismaTokenCurrentPrice[]> {
const tokenPrices = await prisma.prismaTokenCurrentPrice.findMany({
where: { chain: networkContext.chain },
where: { chain: chain },
orderBy: { timestamp: 'desc' },
distinct: ['tokenAddress'],
});

const wethPrice = tokenPrices.find(
(tokenPrice) => tokenPrice.tokenAddress === networkContext.data.weth.address,
(tokenPrice) => tokenPrice.tokenAddress === AllNetworkConfigsKeyedOnChain[chain].data.weth.address,
);

if (wethPrice) {
tokenPrices.push({
...wethPrice,
tokenAddress: networkContext.data.eth.address,
tokenAddress: AllNetworkConfigsKeyedOnChain[chain].data.eth.address,
});
}

Expand Down
34 changes: 20 additions & 14 deletions modules/token/token.service.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { TokenDefinition, TokenPriceItem } from './token-types';
import { prisma } from '../../prisma/prisma-client';
import { TokenPriceService } from './lib/token-price.service';
import { PrismaToken, PrismaTokenCurrentPrice, PrismaTokenDynamicData, PrismaTokenPrice } from '@prisma/client';
import { Chain, PrismaToken, PrismaTokenCurrentPrice, PrismaTokenDynamicData, PrismaTokenPrice } from '@prisma/client';
import { CoingeckoDataService } from './lib/coingecko-data.service';
import { Cache, CacheClass } from 'memory-cache';
import { GqlTokenChartDataRange, MutationTokenDeletePriceArgs, MutationTokenDeleteTokenTypeArgs } from '../../schema';
import { coingeckoService } from '../coingecko/coingecko.service';
import { networkContext } from '../network/network-context.service';
import { getContractAt } from '../web3/contract';
import ERC20Abi from '../web3/abi/ERC20.json';
import { BigNumber } from 'ethers';
import { formatFixed } from '@ethersproject/bignumber';
import { add } from 'lodash';
import { Dictionary } from 'lodash';

const TOKEN_PRICES_CACHE_KEY = `token:prices:current`;
const TOKEN_PRICES_24H_AGO_CACHE_KEY = `token:prices:24h-ago`;
Expand Down Expand Up @@ -42,10 +38,10 @@ export class TokenService {
}

public async getTokens(addresses?: string[]): Promise<PrismaToken[]> {
let tokens: PrismaToken[] | null = this.cache.get(`${ALL_TOKENS_CACHE_KEY}:${networkContext.chainId}`);
let tokens: PrismaToken[] | null = this.cache.get(`${ALL_TOKENS_CACHE_KEY}:${networkContext.chain}`);
if (!tokens) {
tokens = await prisma.prismaToken.findMany({ where: { chain: networkContext.chain } });
this.cache.put(`${ALL_TOKENS_CACHE_KEY}:${networkContext.chainId}`, tokens, 5 * 60 * 1000);
this.cache.put(`${ALL_TOKENS_CACHE_KEY}:${networkContext.chain}`, tokens, 5 * 60 * 1000);
}
if (addresses) {
return tokens.filter((token) => addresses.includes(token.address));
Expand Down Expand Up @@ -85,15 +81,25 @@ export class TokenService {
return this.tokenPriceService.updateTokenPrices();
}

public async getTokenPrices(): Promise<PrismaTokenCurrentPrice[]> {
let tokenPrices = this.cache.get(`${TOKEN_PRICES_CACHE_KEY}:${networkContext.chainId}`);
public async getTokenPrices(chain = networkContext.chain): Promise<PrismaTokenCurrentPrice[]> {
let tokenPrices = this.cache.get(`${TOKEN_PRICES_CACHE_KEY}:${chain}`);
if (!tokenPrices) {
tokenPrices = await this.tokenPriceService.getCurrentTokenPrices();
this.cache.put(`${TOKEN_PRICES_CACHE_KEY}:${networkContext.chainId}`, tokenPrices, 30 * 1000);
tokenPrices = await this.tokenPriceService.getCurrentTokenPrices(chain);
this.cache.put(`${TOKEN_PRICES_CACHE_KEY}:${chain}`, tokenPrices, 30 * 1000);
}
return tokenPrices;
}

public async getTokenPricesForChains(chains: Chain[]): Promise<Dictionary<PrismaTokenCurrentPrice[]>> {
const response: Dictionary<PrismaTokenCurrentPrice[]> = {};

for (const chain of chains) {
response[chain] = await this.getTokenPrices(chain);
}

return response;
}

public async getWhiteListedTokenPrices(): Promise<PrismaTokenCurrentPrice[]> {
/*const cached = this.cache.get(WHITE_LISTED_TOKEN_PRICES_CACHE_KEY) as PrismaTokenCurrentPrice[] | null;

Expand Down Expand Up @@ -190,11 +196,11 @@ export class TokenService {
}

public async getTokenPriceFrom24hAgo(): Promise<PrismaTokenCurrentPrice[]> {
let tokenPrices24hAgo = this.cache.get(`${TOKEN_PRICES_24H_AGO_CACHE_KEY}:${networkContext.chainId}`);
let tokenPrices24hAgo = this.cache.get(`${TOKEN_PRICES_24H_AGO_CACHE_KEY}:${networkContext.chain}`);
if (!tokenPrices24hAgo) {
tokenPrices24hAgo = await this.tokenPriceService.getTokenPriceFrom24hAgo();
this.cache.put(
`${TOKEN_PRICES_24H_AGO_CACHE_KEY}:${networkContext.chainId}`,
`${TOKEN_PRICES_24H_AGO_CACHE_KEY}:${networkContext.chain}`,
tokenPrices24hAgo,
60 * 15 * 1000,
);
Expand Down
11 changes: 7 additions & 4 deletions modules/user/lib/user-balance.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@ import { prisma } from '../../../prisma/prisma-client';
import _ from 'lodash';
import { parseUnits } from 'ethers/lib/utils';
import { formatFixed } from '@ethersproject/bignumber';
import { PrismaPoolStaking } from '@prisma/client';
import { Chain, PrismaPoolStaking } from '@prisma/client';
import { networkContext } from '../../network/network-context.service';

export class UserBalanceService {
constructor() {}

public async getUserPoolBalances(address: string): Promise<UserPoolBalance[]> {
public async getUserPoolBalances(address: string, chains: Chain[]): Promise<UserPoolBalance[]> {
const user = await prisma.prismaUser.findUnique({
where: { address: address.toLowerCase() },
include: {
walletBalances: {
where: { chain: networkContext.chain, poolId: { not: null }, balanceNum: { gt: 0 } },
where: { chain: { in: chains }, poolId: { not: null }, balanceNum: { gt: 0 } },
},
stakedBalances: {
where: { chain: networkContext.chain, poolId: { not: null }, balanceNum: { gt: 0 } },
where: { chain: { in: chains }, poolId: { not: null }, balanceNum: { gt: 0 } },
},
},
});
Expand All @@ -43,6 +43,8 @@ export class UserBalanceService {
totalBalance: formatFixed(stakedNum.add(walletNum), 18),
stakedBalance: stakedBalance?.balance || '0',
walletBalance: walletBalance?.balance || '0',
// the prisma query above ensures that one of these balances exists
chain: (stakedBalance?.chain || walletBalance?.chain)!,
};
});
}
Expand All @@ -68,6 +70,7 @@ export class UserBalanceService {
totalBalance: formatFixed(stakedNum.add(walletNum), 18),
stakedBalance: stakedBalance?.balance || '0',
walletBalance: walletBalance?.balance || '0',
chain: networkContext.chain,
};
}

Expand Down
3 changes: 2 additions & 1 deletion modules/user/user-types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AmountHumanReadable } from '../common/global-types';
import { PrismaPoolStaking, PrismaPoolStakingType } from '@prisma/client';
import { Chain, PrismaPoolStaking, PrismaPoolStakingType } from '@prisma/client';
import { Relic } from '../subgraphs/reliquary-subgraph/generated/reliquary-subgraph-types';

export interface UserStakedBalanceService {
Expand All @@ -14,6 +14,7 @@ export interface UserPoolBalance {
totalBalance: AmountHumanReadable;
walletBalance: AmountHumanReadable;
stakedBalance: AmountHumanReadable;
chain: Chain;
}

export interface UserSyncUserBalanceInput {
Expand Down
3 changes: 2 additions & 1 deletion modules/user/user.gql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extend type Query {
userGetPoolBalances: [GqlUserPoolBalance!]!
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!]!
Expand All @@ -24,4 +24,5 @@ type GqlUserPoolBalance {
totalBalance: AmountHumanReadable!
walletBalance: AmountHumanReadable!
stakedBalance: AmountHumanReadable!
chain: GqlChain!
}
12 changes: 7 additions & 5 deletions modules/user/user.resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ import { Resolvers } from '../../schema';
import { userService } from './user.service';
import { getRequiredAccountAddress, isAdminRoute } from '../auth/auth-context';
import { tokenService } from '../token/token.service';
import { networkContext } from '../network/network-context.service';

const resolvers: Resolvers = {
Query: {
userGetPoolBalances: async (parent, {}, context) => {
const accountAddress = getRequiredAccountAddress(context);
const tokenPrices = await tokenService.getTokenPrices();
const balances = await userService.getUserPoolBalances(accountAddress);
userGetPoolBalances: async (parent, { chains, address }, context) => {
chains = chains && chains.length > 0 ? chains : [networkContext.chain];
const accountAddress = address || getRequiredAccountAddress(context);
const tokenPrices = await tokenService.getTokenPricesForChains(chains);
const balances = await userService.getUserPoolBalances(accountAddress, chains);

return balances.map((balance) => ({
...balance,
tokenPrice: tokenService.getPriceForToken(tokenPrices, balance.tokenAddress),
tokenPrice: tokenService.getPriceForToken(tokenPrices[balance.chain] || [], balance.tokenAddress),
}));
},
userGetPoolJoinExits: async (parent, { first, skip, poolId }, context) => {
Expand Down
8 changes: 4 additions & 4 deletions modules/user/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PrismaPoolStaking, PrismaPoolStakingType } from '@prisma/client';
import { Chain, PrismaPoolStaking, PrismaPoolStakingType } from '@prisma/client';
import { prisma } from '../../prisma/prisma-client';
import { GqlPoolJoinExit, GqlPoolSwap, GqlUserSnapshotDataRange } from '../../schema';
import { coingeckoService } from '../coingecko/coingecko.service';
Expand Down Expand Up @@ -27,8 +27,8 @@ export class UserService {
return networkContext.config.userStakedBalanceServices;
}

public async getUserPoolBalances(address: string): Promise<UserPoolBalance[]> {
return this.userBalanceService.getUserPoolBalances(address);
public async getUserPoolBalances(address: string, chains: Chain[]): Promise<UserPoolBalance[]> {
return this.userBalanceService.getUserPoolBalances(address, chains);
}

public async getUserPoolInvestments(
Expand Down Expand Up @@ -85,7 +85,7 @@ export class UserService {
}

public async syncUserBalanceAllPools(userAddress: string) {
const allBalances = await this.userBalanceService.getUserPoolBalances(userAddress);
const allBalances = await this.userBalanceService.getUserPoolBalances(userAddress, [networkContext.chain]);
for (const userPoolBalance of allBalances) {
await this.syncUserBalance(userAddress, userPoolBalance.poolId);
}
Expand Down