diff --git a/src/composables/queries/usePoolsQuery.ts b/src/composables/queries/usePoolsQuery.ts index 7563b6221e..78a93d2c28 100644 --- a/src/composables/queries/usePoolsQuery.ts +++ b/src/composables/queries/usePoolsQuery.ts @@ -7,17 +7,20 @@ import { Pool } from '@/services/pool/types'; import useNetwork from '../useNetwork'; import { useTokens } from '@/providers/tokens.provider'; import { configService } from '@/services/config/config.service'; -import { GraphQLArgs, PoolsRepositoryFetchOptions } from '@balancer-labs/sdk'; -import { getPoolsFallbackRepository } from '@/dependencies/PoolsFallbackRepository'; -import { PoolDecorator } from '@/services/pool/decorators/pool.decorator'; +import { PoolsRepositoryFetchOptions } from '@balancer-labs/sdk'; import { flatten } from 'lodash'; import { tokenTreeLeafs } from '../usePoolHelpers'; -import { balancerSubgraphService } from '@/services/balancer/subgraph/balancer-subgraph.service'; import { balancerAPIService } from '@/services/balancer/api/balancer-api.service'; import { poolsStoreService } from '@/services/pool/pools-store.service'; import { isBalancerApiDefined } from '@/lib/utils/balancer/api'; import { bnum } from '@/lib/utils'; import { PoolFilterOptions } from '@/types/pools'; +import { + GqlPoolOrderBy, + GqlPoolOrderDirection, +} from '@/services/api/graphql/generated/api-types'; +import { ApiArgs } from '@/services/balancer/api/entities/pools'; +import { mapNetworkToApiChain, mapPoolTypeToApiType } from '@/lib/utils/api'; type PoolsQueryResponse = { pools: Pool[]; @@ -28,7 +31,7 @@ export default function usePoolsQuery(filterOptions: PoolFilterOptions) { /** * COMPOSABLES */ - const { injectTokens, tokens: tokenMeta } = useTokens(); + const { injectTokens } = useTokens(); const { networkId } = useNetwork(); let poolsRepository = initializePoolsRepository(); @@ -37,14 +40,6 @@ export default function usePoolsQuery(filterOptions: PoolFilterOptions) { */ function initializePoolsRepository() { - const FallbackRepository = getPoolsFallbackRepository(); - const fallbackRepository = new FallbackRepository(buildRepositories(), { - timeout: 30 * 1000, - }); - return fallbackRepository; - } - - function initializeDecoratedAPIRepository() { return { fetch: async (options: PoolsRepositoryFetchOptions): Promise => { const pools = await balancerAPIService.pools.get(getQueryArgs(options)); @@ -63,80 +58,47 @@ export default function usePoolsQuery(filterOptions: PoolFilterOptions) { }; } - function initializeDecoratedSubgraphRepository() { - return { - fetch: async (options: PoolsRepositoryFetchOptions): Promise => { - const pools = await balancerSubgraphService.pools.get( - getQueryArgs(options) - ); - - const poolDecorator = new PoolDecorator(pools); - let decoratedPools = await poolDecorator.decorate(tokenMeta.value); - - const tokens = flatten( - pools.map(pool => [ - ...pool.tokensList, - ...tokenTreeLeafs(pool.tokens), - pool.address, - ]) - ); - await injectTokens(tokens); - - decoratedPools = await poolDecorator.reCalculateTotalLiquidities(); - - return decoratedPools; - }, - }; - } - - function buildRepositories() { - const repositories: any[] = []; - if (isBalancerApiDefined) { - const balancerApiRepository = initializeDecoratedAPIRepository(); - repositories.push(balancerApiRepository); + function convertSortFieldToOrderBy( + sortField: string | undefined + ): GqlPoolOrderBy { + switch (sortField) { + case 'apr': + return GqlPoolOrderBy.Apr; + case 'volume': + return GqlPoolOrderBy.Volume24h; + case 'totalLiquidity': + default: + return GqlPoolOrderBy.TotalLiquidity; } - const subgraphRepository = initializeDecoratedSubgraphRepository(); - repositories.push(subgraphRepository); - - return repositories; } - function getQueryArgs(options: PoolsRepositoryFetchOptions): GraphQLArgs { + function getQueryArgs(options: PoolsRepositoryFetchOptions): ApiArgs { const { tokens, poolIds, poolTypes, sortField } = filterOptions.value; const hasPoolIdFilters = !!poolIds?.length && poolIds?.length > 0; const hasPoolTypeFilters = !!poolTypes?.length; - const tokensListFilterOperation = filterOptions.value.useExactTokens - ? 'eq' - : 'contains'; - const tokenListFormatted = tokens?.map(address => address.toLowerCase()) || []; - const orderBy = isBalancerApiDefined - ? sortField || 'totalLiquidity' - : 'totalLiquidity'; + const orderBy = convertSortFieldToOrderBy(sortField); - const queryArgs: GraphQLArgs = { - chainId: configService.network.chainId, + const queryArgs: ApiArgs = { orderBy, - orderDirection: 'desc', + orderDirection: GqlPoolOrderDirection.Desc, where: { - tokensList: { [tokensListFilterOperation]: tokenListFormatted }, - poolType: { in: POOLS.IncludedPoolTypes }, - totalShares: { gt: 0.00001 }, - id: { not_in: POOLS.BlockList }, + chainIn: [mapNetworkToApiChain(configService.network.chainId)], + tokensIn: tokenListFormatted, + poolTypeIn: POOLS.IncludedPoolTypes.map(mapPoolTypeToApiType), + idNotIn: POOLS.BlockList, }, }; if (queryArgs.where && hasPoolTypeFilters && !!poolTypes?.length) { - queryArgs.where.poolType = { - in: poolTypes, - }; + queryArgs.where.poolTypeIn = poolTypes.map(mapPoolTypeToApiType); } if (queryArgs.where && hasPoolIdFilters) { - queryArgs.where.id = { in: filterOptions.value.poolIds }; + queryArgs.where.idIn = filterOptions.value.poolIds; } if (options.first) { queryArgs.first = filterOptions.value.first || options.first; @@ -145,8 +107,6 @@ export default function usePoolsQuery(filterOptions: PoolFilterOptions) { queryArgs.skip = options.skip; } - // console.log('queryArgs', queryArgs); - return queryArgs; } diff --git a/src/lib/utils/api.ts b/src/lib/utils/api.ts index de2b63dc21..1bbbc17ed3 100644 --- a/src/lib/utils/api.ts +++ b/src/lib/utils/api.ts @@ -1,5 +1,6 @@ import { GqlChain, + GqlPoolFilterType, GqlPoolMinimalType, } from '@/services/api/graphql/generated/api-types'; import { Network } from '@/lib/config'; @@ -37,6 +38,32 @@ export function mapApiChain( } } +export function mapNetworkToApiChain(network: Network): GqlChain { + switch (network) { + case Network.ARBITRUM: + return GqlChain.Arbitrum; + case Network.AVALANCHE: + return GqlChain.Avalanche; + case Network.BASE: + return GqlChain.Base; + case Network.GNOSIS: + return GqlChain.Gnosis; + case Network.FANTOM: + return GqlChain.Fantom; + case Network.OPTIMISM: + return GqlChain.Optimism; + case Network.POLYGON: + return GqlChain.Polygon; + case Network.MAINNET: + return GqlChain.Mainnet; + case Network.ZKEVM: + return GqlChain.Zkevm; + + default: + throw new Error(`Unexpected Network: ${network}`); + } +} + export function mapApiPoolType( apiPoolType: GqlPoolMinimalType ): PoolType | null { @@ -65,3 +92,40 @@ export function mapApiPoolType( return null; } } + +export function mapPoolTypeToApiType( + poolType: PoolType | string +): GqlPoolFilterType { + switch (poolType) { + case PoolType.Element: + return GqlPoolFilterType.Element; + case PoolType.Gyro2: + return GqlPoolFilterType.Gyro3; + case PoolType.Gyro3: + return GqlPoolFilterType.Gyro3; + case PoolType.GyroE: + return GqlPoolFilterType.Gyroe; + case PoolType.Investment: + return GqlPoolFilterType.Investment; + case PoolType.EulerLinear: + return GqlPoolFilterType.Linear; + case PoolType.Linear: + return GqlPoolFilterType.Linear; + case PoolType.LiquidityBootstrapping: + return GqlPoolFilterType.LiquidityBootstrapping; + case PoolType.MetaStable: + return GqlPoolFilterType.MetaStable; + case PoolType.StablePhantom: + return GqlPoolFilterType.PhantomStable; + case PoolType.Stable: + return GqlPoolFilterType.Stable; + case PoolType.ComposableStable: + return GqlPoolFilterType.Stable; + case PoolType.FX: + return GqlPoolFilterType.Stable; + case PoolType.Weighted: + return GqlPoolFilterType.Weighted; + default: + throw new Error(`Unexpected Pool Type ${poolType}`); + } +} diff --git a/src/services/api/graphql/generated/api-types.ts b/src/services/api/graphql/generated/api-types.ts index db6e023588..776c711cfd 100644 --- a/src/services/api/graphql/generated/api-types.ts +++ b/src/services/api/graphql/generated/api-types.ts @@ -1358,8 +1358,10 @@ export type QueryUserGetSwapsArgs = { export type GetPoolsQueryVariables = Exact<{ first?: InputMaybe; + skip?: InputMaybe; orderBy?: InputMaybe; orderDirection?: InputMaybe; + where?: InputMaybe; }>; export type GetPoolsQuery = { @@ -1495,13 +1497,17 @@ export type VeBalGetVotingListQuery = { export const GetPoolsDocument = gql` query GetPools( $first: Int + $skip: Int $orderBy: GqlPoolOrderBy $orderDirection: GqlPoolOrderDirection + $where: GqlPoolFilter ) { pools: poolGetPools( first: $first + skip: $skip orderBy: $orderBy orderDirection: $orderDirection + where: $where ) { id chain diff --git a/src/services/api/graphql/pool.graphql b/src/services/api/graphql/pool.graphql index 290e9c9c8a..05ed8b7420 100644 --- a/src/services/api/graphql/pool.graphql +++ b/src/services/api/graphql/pool.graphql @@ -1,9 +1,11 @@ query GetPools( $first: Int + $skip: Int $orderBy: GqlPoolOrderBy $orderDirection: GqlPoolOrderDirection + $where: GqlPoolFilter ) { - pools: poolGetPools (first: $first, orderBy: $orderBy, orderDirection: $orderDirection) { + pools: poolGetPools (first: $first, skip: $skip, orderBy: $orderBy, orderDirection: $orderDirection, where: $where) { id chain address diff --git a/src/services/balancer/api/entities/pools/index.ts b/src/services/balancer/api/entities/pools/index.ts index b96e029e7b..b9b5807a3b 100644 --- a/src/services/balancer/api/entities/pools/index.ts +++ b/src/services/balancer/api/entities/pools/index.ts @@ -3,13 +3,13 @@ import { getApi } from '@/dependencies/balancer-api'; import { Pool } from '@/services/pool/types'; import { GetPoolsQuery, + GqlPoolFilter, GqlPoolOrderBy, GqlPoolOrderDirection, } from '@/services/api/graphql/generated/api-types'; import { PoolsQueryBuilder } from '@/types/subgraph'; import { AprBreakdown, - GraphQLArgs, GraphQLQuery, PoolToken, PoolType, @@ -24,6 +24,14 @@ import { mapApiChain, mapApiPoolType } from '@/lib/utils/api'; export type ApiPools = GetPoolsQuery['pools']; export type ApiPool = ApiPools[number]; +export interface ApiArgs { + first?: number; + skip?: number; + orderBy?: GqlPoolOrderBy; + orderDirection?: GqlPoolOrderDirection; + where?: GqlPoolFilter; +} + export default class Pools { service: Service; queryBuilder: PoolsQueryBuilder; @@ -38,13 +46,15 @@ export default class Pools { this.queryBuilder = _queryBuilder; } - public async get(args: GraphQLArgs = {}): Promise { + public async get(args: ApiArgs = {}): Promise { const api = getApi(); console.log('Getting pools from API'); const response = await api.GetPools({ first: args.first || 10, - orderBy: GqlPoolOrderBy.TotalLiquidity, - orderDirection: GqlPoolOrderDirection.Desc, + skip: args.skip || 0, + orderBy: args.orderBy || GqlPoolOrderBy.TotalLiquidity, + orderDirection: args.orderDirection || GqlPoolOrderDirection.Desc, + where: args.where, }); const pools: ApiPools = response.pools; console.log('Got pools from API', pools); @@ -123,9 +133,15 @@ export default class Pools { owner: apiPool.owner ?? undefined, factory: apiPool.factory ?? undefined, symbol: apiPool.symbol ?? undefined, - tokens: (apiPool.allTokens || []).map(this.mapToken), - tokensList: (apiPool.allTokens || []).map(t => t.address), - tokenAddresses: (apiPool.allTokens || []).map(t => t.address), + tokens: (apiPool.allTokens || []) + .map(this.mapToken) + .filter(token => token.address !== apiPool.address), + tokensList: (apiPool.allTokens || []) + .map(t => t.address) + .filter(address => address !== apiPool.address), + tokenAddresses: (apiPool.allTokens || []) + .map(t => t.address) + .filter(address => address !== apiPool.address), totalLiquidity: apiPool.dynamicData.totalLiquidity, totalShares: apiPool.dynamicData.totalShares, totalSwapFee: apiPool.dynamicData.lifetimeSwapFees,