diff --git a/modules/content/content-types.ts b/modules/content/content-types.ts index 4e4e65df7..8d0051851 100644 --- a/modules/content/content-types.ts +++ b/modules/content/content-types.ts @@ -13,8 +13,6 @@ export interface HomeScreenFeaturedPoolGroup { id: string; items: (HomeScreenFeaturedPoolGroupItemPoolId | HomeScreenFeaturedPoolGroupItemExternalLink)[]; title: string; - primary: boolean; - chain: GqlChain; } interface HomeScreenFeaturedPoolGroupItemPoolId { @@ -32,6 +30,12 @@ interface HomeScreenFeaturedPoolGroupItemExternalLink { image: string; } +export interface FeaturedPool { + poolId: string; + primary: boolean; + chain: GqlChain; +} + export interface HomeScreenNewsItem { id: string; timestamp: string; @@ -45,5 +49,6 @@ export interface ContentService { syncTokenContentData(): Promise; syncPoolContentData(): Promise; getFeaturedPoolGroups(chains: Chain[]): Promise; + getFeaturedPools(chains: Chain[]): Promise; getNewsItems(): Promise; } diff --git a/modules/content/github-content.service.ts b/modules/content/github-content.service.ts index 578db0eea..ac798a5d5 100644 --- a/modules/content/github-content.service.ts +++ b/modules/content/github-content.service.ts @@ -3,7 +3,7 @@ import { Chain, Prisma } from '@prisma/client'; import axios from 'axios'; import { prisma } from '../../prisma/prisma-client'; import { networkContext } from '../network/network-context.service'; -import { ContentService, HomeScreenFeaturedPoolGroup, HomeScreenNewsItem } from './content-types'; +import { ContentService, FeaturedPool, HomeScreenFeaturedPoolGroup, HomeScreenNewsItem } from './content-types'; import { chainIdToChain } from '../network/network-config'; const POOLS_METADATA_URL = 'https://raw.githubusercontent.com/balancer/metadata/main/pools/featured.json'; @@ -168,25 +168,21 @@ export class GithubContentService implements ContentService { await prisma.prismaTokenType.createMany({ skipDuplicates: true, data: types }); } async syncPoolContentData(): Promise {} + async getFeaturedPoolGroups(chains: Chain[]): Promise { + return []; + } + + async getFeaturedPools(chains: Chain[]): Promise { const { data } = await axios.get(POOLS_METADATA_URL); const pools = data.filter((pool) => chains.includes(chainIdToChain[pool.chainId])); - return pools.map(({ id, imageUrl, primary, chainId }) => ({ - id, - _type: 'homeScreenFeaturedPoolGroupPoolId', - title: 'Popular pools', - items: [ - { - _key: '', - _type: 'homeScreenFeaturedPoolGroupPoolId', - poolId: id, - }, - ], - icon: imageUrl, + return pools.map(({ id, primary, chainId }) => ({ + poolId: id, chain: chainIdToChain[chainId], primary: Boolean(primary), - })) as HomeScreenFeaturedPoolGroup[]; + })) as FeaturedPool[]; } + async getNewsItems(): Promise { return []; } diff --git a/modules/content/sanity-content.service.ts b/modules/content/sanity-content.service.ts index d48fef8aa..e512718e9 100644 --- a/modules/content/sanity-content.service.ts +++ b/modules/content/sanity-content.service.ts @@ -1,7 +1,13 @@ import { isSameAddress } from '@balancer-labs/sdk'; import { Chain, Prisma, PrismaPoolCategoryType } from '@prisma/client'; import { prisma } from '../../prisma/prisma-client'; -import { ConfigHomeScreen, ContentService, HomeScreenFeaturedPoolGroup, HomeScreenNewsItem } from './content-types'; +import { + ConfigHomeScreen, + ContentService, + FeaturedPool, + HomeScreenFeaturedPoolGroup, + HomeScreenNewsItem, +} from './content-types'; import SanityClient from '@sanity/client'; import { env } from '../../app/env'; import { chainToIdMap } from '../network/network-config'; @@ -279,18 +285,53 @@ export class SanityContentService implements ContentService { } `); if (data) { - featuredPoolGroups.push( - ...data.featuredPoolGroups.map((pool, i) => ({ - ...pool, - chain: chain, - primary: i === 0 ? true : false, - })), - ); + featuredPoolGroups.push(...data.featuredPoolGroups); } } return featuredPoolGroups; } + public async getFeaturedPools(chains: Chain[]): Promise { + const featuredPools: FeaturedPool[] = []; + for (const chain of chains) { + const data = await this.getSanityClient().fetch(` + *[_type == "homeScreen" && chainId == ${chainToIdMap[chain]}][0]{ + ..., + "featuredPoolGroups": featuredPoolGroups[]{ + ..., + "icon": icon.asset->url + "?w=64", + "items": items[]{ + ..., + "image": image.asset->url + "?w=600" + } + }, + "newsItems": newsItems[]{ + ..., + "image": image.asset->url + "?w=800" + } + } + `); + if (data) { + const featuredPoolGroupItems = data.featuredPoolGroups.find( + (group) => group.id === 'popular-pools', + )?.items; + if (featuredPoolGroupItems) { + for (let i = 0; i < featuredPoolGroupItems.length; i++) { + const group = featuredPoolGroupItems[i]; + if (group._type === 'homeScreenFeaturedPoolGroupPoolId') { + featuredPools.push({ + poolId: group.poolId, + primary: i === 0 ? true : false, + chain: chain, + }); + } + } + } + } + } + return featuredPools; + } + public async getNewsItems(): Promise { const data = await this.getSanityClient().fetch(` *[_type == "homeScreen" && chainId == ${chainToIdMap[this.chain]}][0]{ diff --git a/modules/pool/lib/pool-gql-loader.service.ts b/modules/pool/lib/pool-gql-loader.service.ts index 6b98fae01..fac3005a0 100644 --- a/modules/pool/lib/pool-gql-loader.service.ts +++ b/modules/pool/lib/pool-gql-loader.service.ts @@ -13,6 +13,7 @@ import { GqlBalancePoolAprSubItem, GqlPoolDynamicData, GqlPoolFeaturedPoolGroup, + GqlPoolFeaturedPool, GqlPoolGyro, GqlPoolInvestConfig, GqlPoolInvestOption, @@ -44,8 +45,8 @@ import { parseUnits } from 'ethers/lib/utils'; import { formatFixed } from '@ethersproject/bignumber'; import { BalancerChainIds, BeethovenChainIds, chainIdToChain, chainToIdMap } from '../../network/network-config'; import { GithubContentService } from '../../content/github-content.service'; -import SanityClientConstructor from '@sanity/client'; import { SanityContentService } from '../../content/sanity-content.service'; +import { FeaturedPool } from '../../content/content-types'; export class PoolGqlLoaderService { public async getPool(id: string, chain: Chain, userAddress?: string): Promise { @@ -160,10 +161,7 @@ export class PoolGqlLoaderService { public async getFeaturedPoolGroups(chains: Chain[]): Promise { const featuredPoolGroups = []; - if (chains.some((chain) => BalancerChainIds.includes(chainToIdMap[chain]))) { - const githubContentService = new GithubContentService(); - featuredPoolGroups.push(...(await githubContentService.getFeaturedPoolGroups(chains))); - } else if (chains.some((chain) => BeethovenChainIds.includes(chainToIdMap[chain]))) { + if (chains.some((chain) => BeethovenChainIds.includes(chainToIdMap[chain]))) { const sanityContentService = new SanityContentService('FANTOM'); featuredPoolGroups.push(...(await sanityContentService.getFeaturedPoolGroups(chains))); } @@ -202,6 +200,32 @@ export class PoolGqlLoaderService { }); } + public async getFeaturedPools(chains: Chain[]): Promise { + const featuredPoolsFromService: FeaturedPool[] = []; + if (chains.some((chain) => BalancerChainIds.includes(chainToIdMap[chain]))) { + const githubContentService = new GithubContentService(); + featuredPoolsFromService.push(...(await githubContentService.getFeaturedPools(chains))); + } + if (chains.some((chain) => BeethovenChainIds.includes(chainToIdMap[chain]))) { + // chain in constructor doesnt matter for this query as we pass the chain in the param + const sanityContentService = new SanityContentService('FANTOM'); + featuredPoolsFromService.push(...(await sanityContentService.getFeaturedPools(chains))); + } + + const featuredPools: GqlPoolFeaturedPool[] = []; + + for (const contentPool of featuredPoolsFromService) { + const pool = await this.getPool(contentPool.poolId.toLowerCase(), contentPool.chain); + featuredPools.push({ + poolId: contentPool.poolId, + primary: contentPool.primary, + pool: pool, + }); + } + + return featuredPools; + } + private mapQueryArgsToPoolQuery(args: QueryPoolGetPoolsArgs): Prisma.PrismaPoolFindManyArgs { let orderBy: Prisma.PrismaPoolOrderByWithRelationInput = {}; const orderDirection = args.orderDirection || undefined; diff --git a/modules/pool/pool.gql b/modules/pool/pool.gql index f37cbd14a..f1fa5ed92 100644 --- a/modules/pool/pool.gql +++ b/modules/pool/pool.gql @@ -20,6 +20,7 @@ extend type Query { poolGetBatchSwaps(first: Int, skip: Int, where: GqlPoolSwapFilter): [GqlPoolBatchSwap!]! poolGetJoinExits(first: Int, skip: Int, where: GqlPoolJoinExitFilter): [GqlPoolJoinExit!]! poolGetFeaturedPoolGroups(chains: [GqlChain!]): [GqlPoolFeaturedPoolGroup!]! + poolGetFeaturedPools(chains: [GqlChain!]!): [GqlPoolFeaturedPool!]! poolGetSnapshots(id: String!, chain: GqlChain, range: GqlPoolSnapshotDataRange!): [GqlPoolSnapshot!]! poolGetLinearPools(chains: [GqlChain!]): [GqlPoolLinear!]! poolGetGyroPools(chains: [GqlChain!]): [GqlPoolGyro!]! @@ -815,12 +816,16 @@ type GqlPoolUserSwapVolume { swapVolumeUSD: BigDecimal! } +type GqlPoolFeaturedPool { + poolId: ID! + primary: Boolean! + pool: GqlPoolBase! +} + type GqlPoolFeaturedPoolGroup { id: ID! title: String! icon: String! - primary: Boolean - chain: GqlChain! items: [GqlPoolFeaturedPoolGroupItem!]! } diff --git a/modules/pool/pool.resolvers.ts b/modules/pool/pool.resolvers.ts index 18a13603a..9f2ff0d7e 100644 --- a/modules/pool/pool.resolvers.ts +++ b/modules/pool/pool.resolvers.ts @@ -58,6 +58,9 @@ const balancerResolvers: Resolvers = { } return poolService.getFeaturedPoolGroups(chains); }, + poolGetFeaturedPools: async (parent, { chains }, context) => { + return poolService.getFeaturedPools(chains); + }, poolGetSnapshots: async (parent, { id, chain, range }, context) => { const currentChain = headerChain(); if (!chain && currentChain) { diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index 70ea01962..9461b541f 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -6,6 +6,7 @@ import { prisma } from '../../prisma/prisma-client'; import { GqlChain, GqlPoolBatchSwap, + GqlPoolFeaturedPool, GqlPoolFeaturedPoolGroup, GqlPoolGyro, GqlPoolJoinExit, @@ -120,6 +121,10 @@ export class PoolService { return this.poolGqlLoaderService.getFeaturedPoolGroups(chains); } + public async getFeaturedPools(chains: Chain[]): Promise { + return this.poolGqlLoaderService.getFeaturedPools(chains); + } + public async getSnapshotsForPool(poolId: string, chain: Chain, range: GqlPoolSnapshotDataRange) { return this.poolSnapshotService.getSnapshotsForPool(poolId, chain, range); }