diff --git a/CHANGELOG.md b/CHANGELOG.md index 506d08ace..2a55d327e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # backend +## 1.31.0 + +### Minor Changes + +- e047a6c: replacing blocks subgraph with data from events + +### Patch Changes + +- a29f079: hgETH APR + ## 1.30.0 ### Minor Changes diff --git a/apps/api/gql/generated-schema-ast.ts b/apps/api/gql/generated-schema-ast.ts index 812d62000..aa70b0b99 100644 --- a/apps/api/gql/generated-schema-ast.ts +++ b/apps/api/gql/generated-schema-ast.ts @@ -3682,7 +3682,6 @@ export const schema = gql` type Mutation { beetsPoolLoadReliquarySnapshotsForAllFarms: String! beetsSyncFbeetsRatio: String! - cacheAverageBlockTime: String! poolLoadOnChainDataForAllPools(chains: [GqlChain!]!): [GqlPoolMutationResult!]! poolLoadSnapshotsForPools(poolIds: [String!]!, reload: Boolean): String! poolReloadAllPoolAprs(chain: GqlChain!): String! @@ -3724,10 +3723,10 @@ export const schema = gql` type Query { beetsGetFbeetsRatio: String! beetsPoolGetReliquaryFarmSnapshots(id: String!, range: GqlPoolSnapshotDataRange!): [GqlReliquaryFarmSnapshot!]! - blocksGetAverageBlockTime: Float! - blocksGetBlocksPerDay: Float! - blocksGetBlocksPerSecond: Float! - blocksGetBlocksPerYear: Float! + blocksGetAverageBlockTime: Float! @deprecated + blocksGetBlocksPerDay: Float! @deprecated + blocksGetBlocksPerSecond: Float! @deprecated + blocksGetBlocksPerYear: Float! @deprecated contentGetNewsItems(chain: GqlChain): [GqlContentNewsItem!]! latestSyncedBlocks: GqlLatestSyncedBlocks! diff --git a/apps/api/gql/generated-schema.ts b/apps/api/gql/generated-schema.ts index 295e00082..64b930604 100644 --- a/apps/api/gql/generated-schema.ts +++ b/apps/api/gql/generated-schema.ts @@ -2452,7 +2452,6 @@ export interface Mutation { __typename?: 'Mutation'; beetsPoolLoadReliquarySnapshotsForAllFarms: Scalars['String']; beetsSyncFbeetsRatio: Scalars['String']; - cacheAverageBlockTime: Scalars['String']; poolLoadOnChainDataForAllPools: Array; poolLoadSnapshotsForPools: Scalars['String']; poolReloadAllPoolAprs: Scalars['String']; @@ -2558,9 +2557,13 @@ export interface Query { __typename?: 'Query'; beetsGetFbeetsRatio: Scalars['String']; beetsPoolGetReliquaryFarmSnapshots: Array; + /** @deprecated Field no longer supported */ blocksGetAverageBlockTime: Scalars['Float']; + /** @deprecated Field no longer supported */ blocksGetBlocksPerDay: Scalars['Float']; + /** @deprecated Field no longer supported */ blocksGetBlocksPerSecond: Scalars['Float']; + /** @deprecated Field no longer supported */ blocksGetBlocksPerYear: Scalars['Float']; contentGetNewsItems: Array; latestSyncedBlocks: GqlLatestSyncedBlocks; @@ -5317,7 +5320,6 @@ export type MutationResolvers< > = ResolversObject<{ beetsPoolLoadReliquarySnapshotsForAllFarms?: Resolver; beetsSyncFbeetsRatio?: Resolver; - cacheAverageBlockTime?: Resolver; poolLoadOnChainDataForAllPools?: Resolver< Array, ParentType, diff --git a/apps/api/gql/resolvers.ts b/apps/api/gql/resolvers.ts index 3fd4ac487..a87ad992e 100644 --- a/apps/api/gql/resolvers.ts +++ b/apps/api/gql/resolvers.ts @@ -27,7 +27,6 @@ export const resolvers = { ...vebalResolver.Query, }, Mutation: { - ...blocksResolver.Mutation, ...contentResolver.Mutation, ...poolResolver.Mutation, ...protocolResolver.Mutation, diff --git a/apps/api/gql/resolvers/blocks.resolvers.ts b/apps/api/gql/resolvers/blocks.resolvers.ts index 27506f333..bda72ed0e 100644 --- a/apps/api/gql/resolvers/blocks.resolvers.ts +++ b/apps/api/gql/resolvers/blocks.resolvers.ts @@ -1,30 +1,42 @@ import { Resolvers } from '../generated-schema'; -import { isAdminRoute } from '../../../../modules/auth/auth-context'; -import { blocksSubgraphService } from '../../../../modules/subgraphs/blocks-subgraph/blocks-subgraph.service'; +import { chainIdToChain } from '../../../../modules/network/chain-id-to-chain'; +import { blockNumbers } from '../../../../modules/block-numbers'; +import { GraphQLError } from 'graphql'; +import { env } from '../../../env'; const balancerResolvers: Resolvers = { Query: { blocksGetAverageBlockTime: async (parent, {}, context) => { - return blocksSubgraphService.getAverageBlockTime(); + const chainId = context.chainId || env.DEFAULT_CHAIN_ID; + const chain = chainIdToChain[chainId]; + + const service = blockNumbers(); + const blocksPerDay = await service.getBlocksPerDay(chain); + return 86400 / blocksPerDay; }, blocksGetBlocksPerSecond: async (parent, {}, context) => { - const avgBlockTime = await blocksSubgraphService.getAverageBlockTime(); - return 1 / avgBlockTime; + const chainId = context.chainId || env.DEFAULT_CHAIN_ID; + const chain = chainIdToChain[chainId]; + + const service = blockNumbers(); + const blocksPerDay = await service.getBlocksPerDay(chain); + return blocksPerDay / 86400; }, blocksGetBlocksPerDay: async (parent, {}, context) => { - return blocksSubgraphService.getBlocksPerDay(); + const chainId = context.chainId || env.DEFAULT_CHAIN_ID; + const chain = chainIdToChain[chainId]; + + const service = blockNumbers(); + const blocksPerDay = await service.getBlocksPerDay(chain); + return blocksPerDay; }, blocksGetBlocksPerYear: async (parent, {}, context) => { - return blocksSubgraphService.getBlocksPerYear(); - }, - }, - Mutation: { - cacheAverageBlockTime: async (parent, {}, context) => { - isAdminRoute(context); - - await blocksSubgraphService.cacheAverageBlockTime(); + const chainId = context.chainId || env.DEFAULT_CHAIN_ID; + const chain = chainIdToChain[chainId]; - return 'success'; + const service = blockNumbers(); + const blocksPerDay = await service.getBlocksPerDay(chain); + return blocksPerDay * 365; }, }, }; diff --git a/apps/api/gql/schema/blocks.gql b/apps/api/gql/schema/blocks.gql index fb9897c38..23b69636c 100644 --- a/apps/api/gql/schema/blocks.gql +++ b/apps/api/gql/schema/blocks.gql @@ -1,10 +1,6 @@ extend type Query { - blocksGetAverageBlockTime: Float! - blocksGetBlocksPerSecond: Float! - blocksGetBlocksPerDay: Float! - blocksGetBlocksPerYear: Float! -} - -extend type Mutation { - cacheAverageBlockTime: String! + blocksGetAverageBlockTime: Float! @deprecated + blocksGetBlocksPerSecond: Float! @deprecated + blocksGetBlocksPerDay: Float! @deprecated + blocksGetBlocksPerYear: Float! @deprecated } diff --git a/apps/worker/job-handlers.ts b/apps/worker/job-handlers.ts index 3996c988e..03ddfffa3 100644 --- a/apps/worker/job-handlers.ts +++ b/apps/worker/job-handlers.ts @@ -2,7 +2,6 @@ import * as Sentry from '@sentry/node'; import { Express, NextFunction } from 'express'; import { tokenService } from '../../modules/token/token.service'; import { poolService } from '../../modules/pool/pool.service'; -import { blocksSubgraphService } from '../../modules/subgraphs/blocks-subgraph/blocks-subgraph.service'; import { userService } from '../../modules/user/user.service'; import { protocolService } from '../../modules/protocol/protocol.service'; import { datastudioService } from '../../modules/datastudio/datastudio.service'; @@ -177,9 +176,6 @@ const setupJobHandlers = async (name: string, chainId: string, res: any, next: N next, ); break; - case 'cache-average-block-time': - await runIfNotAlreadyRunning(name, chainId, () => blocksSubgraphService.cacheAverageBlockTime(), res, next); - break; case 'sync-staking-for-pools': await runIfNotAlreadyRunning(name, chainId, () => StakingController().syncStaking(chain), res, next); break; diff --git a/codegen.ts b/codegen.ts index a4fdcb6f2..af74602fa 100644 --- a/codegen.ts +++ b/codegen.ts @@ -89,11 +89,6 @@ const files = { }, }, }, - ['modules/subgraphs/blocks-subgraph/generated/blocks-subgraph-types.ts']: { - schema: config.MAINNET.subgraphs.blocks, - documents: 'modules/subgraphs/blocks-subgraph/block-subgraph-queries.graphql', - ...defaults.types, - }, ['modules/subgraphs/beets-bar-subgraph/generated/beets-bar-subgraph-types.ts']: { schema: config.FANTOM.subgraphs.beetsBar, documents: 'modules/subgraphs/beets-bar-subgraph/beets-bar-subgraph-queries.graphql', diff --git a/config/mainnet.ts b/config/mainnet.ts index bec607853..72f0c74df 100644 --- a/config/mainnet.ts +++ b/config/mainnet.ts @@ -437,6 +437,12 @@ export default { path: 'value', isIbYield: true, }, + hgETH: { + tokenAddress: '0xc824a08db624942c5e5f330d56530cd1598859fd', + sourceUrl: 'https://universe.kelpdao.xyz/rseth/gainApy', + path: 'hgETH', + isIbYield: true, + }, sDOLA: { tokenAddress: '0xb45ad160634c528cc3d2926d9807104fa3157305', sourceUrl: 'https://www.inverse.finance/api/dola-staking', diff --git a/modules/actions/pool/update-liquidity.ts b/modules/actions/pool/update-liquidity.ts index 0bae42c23..86115d134 100644 --- a/modules/actions/pool/update-liquidity.ts +++ b/modules/actions/pool/update-liquidity.ts @@ -1,5 +1,5 @@ import { Chain } from '@prisma/client'; -import { BlockNumbersSubgraphClient, V3VaultSubgraphClient } from '../../sources/subgraphs'; +import { V3VaultSubgraphClient } from '../../sources/subgraphs'; import { V2SubgraphClient } from '../../subgraphs/balancer-subgraph'; import { getLiquidityAndSharesAtTimestamp } from '../../sources/enrichers/get-liquidity-and-shares-at-timestamp'; import { daysAgo, hoursAgo } from '../../common/time'; @@ -22,12 +22,11 @@ import _ from 'lodash'; export const updateLiquidity24hAgo = async ( ids: string[], subgraphClient: V2SubgraphClient | V3VaultSubgraphClient, - blocksClient: BlockNumbersSubgraphClient, chain: Chain, ) => { // Get liquidity data const ts = chain === Chain.SEPOLIA ? hoursAgo(1) : daysAgo(1); - const data = await getLiquidityAndSharesAtTimestamp(ids, subgraphClient, blocksClient, ts); + const data = await getLiquidityAndSharesAtTimestamp(chain, ids, subgraphClient, ts); if (!data) return; // Update liquidity data diff --git a/modules/actions/snapshots/pool-snapshot-service.ts b/modules/actions/snapshots/pool-snapshot-service.ts index 7fac53eae..3045877d3 100644 --- a/modules/actions/snapshots/pool-snapshot-service.ts +++ b/modules/actions/snapshots/pool-snapshot-service.ts @@ -10,9 +10,9 @@ import _ from 'lodash'; import { Chain, PrismaPoolSnapshot } from '@prisma/client'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { prismaPoolWithExpandedNesting } from '../../../prisma/prisma-types'; -import { blocksSubgraphService } from '../../subgraphs/blocks-subgraph/blocks-subgraph.service'; import { TokenHistoricalPrices } from '../../token/lib/coingecko-data.service'; import { V2SubgraphClient } from '../../subgraphs/balancer-subgraph'; +import { blockNumbers } from '../../block-numbers'; export class PoolSnapshotService { constructor( @@ -212,10 +212,10 @@ export class PoolSnapshotService { } } - const dailyBlocks = await blocksSubgraphService.getDailyBlocks(numDays); + const dailyBlocks = await blockNumbers().getDailyBlocks(this.chain, numDays); for (const block of dailyBlocks) { - const startTimestamp = parseInt(block.timestamp); + const startTimestamp = moment(block.timestamp).utc().startOf('day').unix(); const endTimestamp = startTimestamp + 86400; const swapsForDay = swaps.filter( (swap) => @@ -240,7 +240,7 @@ export class PoolSnapshotService { const { pool: poolAtBlock } = await this.balancerSubgraphService.legacyService.getPool({ id: poolId, - block: { number: parseInt(block.number) }, + block: { number: block.number }, }); if (!poolAtBlock) { diff --git a/modules/block-numbers/block-numbers.test.ts b/modules/block-numbers/block-numbers.test.ts new file mode 100644 index 000000000..1c16f2d68 --- /dev/null +++ b/modules/block-numbers/block-numbers.test.ts @@ -0,0 +1,60 @@ +import { expect, test, describe, mock, beforeEach } from 'bun:test'; +import { blockNumbers } from './index'; +import { Chain } from '@prisma/client'; + +describe('blockNumbers', () => { + const mockEvents = { + $queryRawUnsafe: mock(() => {}), + }; + + beforeEach(() => { + mockEvents.$queryRawUnsafe.mockReset(); + }); + + describe('getBlock', () => { + test('should return block number for given timestamp', async () => { + const mockEvent = [{ blockNumber: 12345 }]; + mockEvents.$queryRawUnsafe.mockResolvedValue(mockEvent); + + const service = blockNumbers(mockEvents as any); + const result = await service.getBlock(Chain.MAINNET, 1000); + + expect(result).toBe(12345); + }); + + test('should return undefined if no event found', async () => { + mockEvents.$queryRawUnsafe.mockResolvedValue([]); + + const service = blockNumbers(mockEvents as any); + const result = await service.getBlock(Chain.MAINNET, 1000); + + expect(result).toBeUndefined(); + }); + }); + + describe('getBlocksPerDay', () => { + test('should return count of blocks in last 24 hours', async () => { + mockEvents.$queryRawUnsafe.mockResolvedValue([{ max: 4000, min: 1000 }]); + + const service = blockNumbers(mockEvents as any); + const result = await service.getBlocksPerDay(Chain.MAINNET); + + expect(result).toBe(1000); + }); + }); + + describe('getDailyBlocks', () => { + test('should return daily block numbers', async () => { + const mockBlocks = [ + { timestamp: 1000, number: 12345 }, + { timestamp: 2000, number: 12445 }, + ]; + mockEvents.$queryRawUnsafe.mockResolvedValue(mockBlocks); + + const service = blockNumbers(mockEvents as any); + const result = await service.getDailyBlocks(Chain.MAINNET, 2); + + expect(result).toEqual(mockBlocks); + }); + }); +}); diff --git a/modules/block-numbers/index.ts b/modules/block-numbers/index.ts new file mode 100644 index 000000000..002314a57 --- /dev/null +++ b/modules/block-numbers/index.ts @@ -0,0 +1,67 @@ +import { Chain, Prisma } from '@prisma/client'; +import { prisma } from '../../prisma/prisma-client'; + +export const blockNumbers = (db = prisma) => ({ + /** + * Get the block number for a given timestamp + * + * @param chain + * @param timestamp + * @returns + */ + async getBlock(chain: Chain, timestamp: number) { + const [event] = await db.$queryRawUnsafe<{ blockNumber: number }[]>(` + SELECT "blockNumber" + FROM "PartitionedPoolEvent" + WHERE chain = '${chain}' + AND "blockTimestamp" <= ${timestamp}::integer + ORDER BY "blockTimestamp" DESC + LIMIT 1; + `); + + return event?.blockNumber; + }, + /** + * Gets the number of blocks per day meaning the speed of the chain. + * Calculated from average number of blocks per day for the last 3 days. + * + * @param chain + * @param timestamp + * @returns + */ + async getBlocksPerDay(chain: Chain) { + const [blocks] = await db.$queryRawUnsafe<{ max: number; min: number }[]>(` + SELECT + MAX("blockNumber") as max, + MIN("blockNumber") as min + FROM "PartitionedPoolEvent" + WHERE chain = '${chain}' + AND "blockTimestamp" >= (EXTRACT(EPOCH FROM NOW()) - 86400 * 3)::integer; + `); + + const range = blocks.max - blocks.min; + + return Math.ceil(range / 3); + }, + /** + * Block numbers for the last n days closest to 00:00:00 (UTC) + * + * @param chain + * @param days + * @returns + */ + async getDailyBlocks(chain: Chain, days: number) { + const blocks = await db.$queryRawUnsafe<{ timestamp: number; number: number }[]>(` + SELECT + ("blockTimestamp"/86400)::INTEGER * 86400 as timestamp, + MIN("blockNumber") as number + FROM "PartitionedPoolEvent" + WHERE chain = '${chain}' + AND "blockTimestamp" >= ((EXTRACT(EPOCH FROM NOW()) / 86400)::integer * 86400 - 86400 * ${days})::integer + GROUP BY 1 + ORDER BY 1 DESC; + `); + + return blocks; + }, +}); diff --git a/modules/controllers/pool-controller.ts b/modules/controllers/pool-controller.ts index 28090e91f..1fb03466d 100644 --- a/modules/controllers/pool-controller.ts +++ b/modules/controllers/pool-controller.ts @@ -7,7 +7,7 @@ import { syncOnChainDataForPools as syncOnChainDataForPoolsV2, } from '../actions/pool/v2'; import { getViemClient } from '../sources/viem-client'; -import { getBlockNumbersSubgraphClient, getV3JoinedSubgraphClient, getVaultSubgraphClient } from '../sources/subgraphs'; +import { getV3JoinedSubgraphClient, getVaultSubgraphClient } from '../sources/subgraphs'; import { prisma } from '../../prisma/prisma-client'; import { updateLiquidity24hAgo, updateLiquidityValuesForPools } from '../actions/pool/update-liquidity'; import { Chain, PrismaLastBlockSyncedCategory } from '@prisma/client'; @@ -101,8 +101,6 @@ export function PoolController(tracer?: any) { throw new Error(`Chain not configured: ${chain}`); } - const blocksSubgraph = getBlockNumbersSubgraphClient(blocks); - const poolIds = await prisma.prismaPoolDynamicData.findMany({ where: { chain }, select: { poolId: true }, @@ -111,7 +109,6 @@ export function PoolController(tracer?: any) { const updates = await updateLiquidity24hAgo( poolIds.map(({ poolId }) => poolId), subgraph, - blocksSubgraph, chain, ); @@ -295,8 +292,6 @@ export function PoolController(tracer?: any) { throw new Error(`Chain not configured: ${chain}`); } - const blocksSubgraph = getBlockNumbersSubgraphClient(blocks); - const poolIds = await prisma.prismaPoolDynamicData.findMany({ where: { chain }, select: { poolId: true }, @@ -305,7 +300,6 @@ export function PoolController(tracer?: any) { const updates = await updateLiquidity24hAgo( poolIds.map(({ poolId }) => poolId), subgraph, - blocksSubgraph, chain, ); diff --git a/modules/datastudio/datastudio.service.ts b/modules/datastudio/datastudio.service.ts index d07dd6731..731e1a027 100644 --- a/modules/datastudio/datastudio.service.ts +++ b/modules/datastudio/datastudio.service.ts @@ -5,7 +5,6 @@ import moment from 'moment-timezone'; import { JWT } from 'google-auth-library'; import { SecretsManager, secretsManager } from './secrets-manager'; import { googleJwtClient, GoogleJwtClient } from './google-jwt-client'; -import { blocksSubgraphService } from '../subgraphs/blocks-subgraph/blocks-subgraph.service'; import { tokenService } from '../token/token.service'; import { beetsService } from '../beets/beets.service'; import { oneDayInSeconds, secondsPerDay } from '../common/time'; @@ -14,6 +13,7 @@ import { networkContext } from '../network/network-context.service'; import { DeploymentEnv } from '../network/network-config-types'; import { Chain } from '@prisma/client'; import config from '../../config'; +import { blockNumbers } from '../block-numbers'; export class DatastudioService { constructor(private readonly secretsManager: SecretsManager, private readonly jwtClientHelper: GoogleJwtClient) {} @@ -238,9 +238,9 @@ export class DatastudioService { } // add emission data + const blocksPerDay = await blockNumbers().getBlocksPerDay(chain); + const tokenPrices = await tokenService.getTokenPrices(chain); for (const stake of pool.staking) { - const blocksPerDay = await blocksSubgraphService.getBlocksPerDay(); - const tokenPrices = await tokenService.getTokenPrices(stake.chain); const beetsPrice = tokenService.getPriceForToken( tokenPrices, config[chain].beets?.address || '', diff --git a/modules/network/arbitrum.ts b/modules/network/arbitrum.ts index 38a0bd046..7a8f46f95 100644 --- a/modules/network/arbitrum.ts +++ b/modules/network/arbitrum.ts @@ -69,10 +69,6 @@ export const arbitrumNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/avalanche.ts b/modules/network/avalanche.ts index 24915dd08..c0a39fafa 100644 --- a/modules/network/avalanche.ts +++ b/modules/network/avalanche.ts @@ -70,10 +70,6 @@ export const avalancheNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/base.ts b/modules/network/base.ts index 51b01c15f..9a5ff21d1 100644 --- a/modules/network/base.ts +++ b/modules/network/base.ts @@ -69,10 +69,6 @@ export const baseNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/fantom.ts b/modules/network/fantom.ts index e3232d298..83e901b18 100644 --- a/modules/network/fantom.ts +++ b/modules/network/fantom.ts @@ -76,10 +76,6 @@ export const fantomNetworkConfig: NetworkConfig = { name: 'sync-new-pools-from-subgraph', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(6, 'minutes') : every(2, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/fraxtal.ts b/modules/network/fraxtal.ts index 675455e8a..0c5504d57 100644 --- a/modules/network/fraxtal.ts +++ b/modules/network/fraxtal.ts @@ -69,10 +69,6 @@ export const fraxtalNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/gnosis.ts b/modules/network/gnosis.ts index d8ba23d6d..f65844451 100644 --- a/modules/network/gnosis.ts +++ b/modules/network/gnosis.ts @@ -69,10 +69,6 @@ export const gnosisNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/mainnet.ts b/modules/network/mainnet.ts index fe373f1f1..a4980e327 100644 --- a/modules/network/mainnet.ts +++ b/modules/network/mainnet.ts @@ -77,10 +77,6 @@ export const mainnetNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/mode.ts b/modules/network/mode.ts index ba02bc078..02d675d1e 100644 --- a/modules/network/mode.ts +++ b/modules/network/mode.ts @@ -68,10 +68,6 @@ export const modeNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/optimism.ts b/modules/network/optimism.ts index ee5b1a4e7..f0bd8dd2f 100644 --- a/modules/network/optimism.ts +++ b/modules/network/optimism.ts @@ -69,10 +69,6 @@ export const optimismNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/polygon.ts b/modules/network/polygon.ts index ee57bae89..dd26aa799 100644 --- a/modules/network/polygon.ts +++ b/modules/network/polygon.ts @@ -69,10 +69,6 @@ export const polygonNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/sepolia.ts b/modules/network/sepolia.ts index 6a77814c2..8b5d51c20 100644 --- a/modules/network/sepolia.ts +++ b/modules/network/sepolia.ts @@ -68,10 +68,6 @@ export const sepoliaNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: every(5, 'minutes'), diff --git a/modules/network/sonic.ts b/modules/network/sonic.ts index 1d474d964..b22899729 100644 --- a/modules/network/sonic.ts +++ b/modules/network/sonic.ts @@ -75,10 +75,6 @@ export const sonicNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/network/zkevm.ts b/modules/network/zkevm.ts index 0e4195f0d..f807afe05 100644 --- a/modules/network/zkevm.ts +++ b/modules/network/zkevm.ts @@ -69,10 +69,6 @@ export const zkevmNetworkConfig: NetworkConfig = { name: 'update-liquidity-24h-ago-v2', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), }, - { - name: 'cache-average-block-time', - interval: every(1, 'hours'), - }, { name: 'sync-staking-for-pools', interval: (env.DEPLOYMENT_ENV as DeploymentEnv) === 'canary' ? every(10, 'minutes') : every(5, 'minutes'), diff --git a/modules/pool/lib/apr-data-sources/fantom/masterchef-farm-apr.service.ts b/modules/pool/lib/apr-data-sources/fantom/masterchef-farm-apr.service.ts index d1cf923ac..9cbfb0153 100644 --- a/modules/pool/lib/apr-data-sources/fantom/masterchef-farm-apr.service.ts +++ b/modules/pool/lib/apr-data-sources/fantom/masterchef-farm-apr.service.ts @@ -3,12 +3,12 @@ import { prisma } from '../../../../../prisma/prisma-client'; import { PrismaPoolWithExpandedNesting, PrismaPoolWithTokens } from '../../../../../prisma/prisma-types'; import { prismaBulkExecuteOperations } from '../../../../../prisma/prisma-util'; import { secondsPerYear } from '../../../../common/time'; -import { blocksSubgraphService } from '../../../../subgraphs/blocks-subgraph/blocks-subgraph.service'; import { FarmFragment } from '../../../../subgraphs/masterchef-subgraph/generated/masterchef-subgraph-types'; import { tokenService } from '../../../../token/token.service'; import { PoolAprService } from '../../../pool-types'; import { networkContext } from '../../../../network/network-context.service'; import { MasterchefSubgraphService } from '../../../../subgraphs/masterchef-subgraph/masterchef.service'; +import { blockNumbers } from '../../../../block-numbers'; const FARM_EMISSIONS_PERCENT = 0.872; @@ -24,7 +24,7 @@ export class MasterchefFarmAprService implements PoolAprService { const masterchefService = new MasterchefSubgraphService(networkContext.data.subgraphs.masterchef!); const farms = await masterchefService.getAllFarms({}); - const blocksPerDay = await blocksSubgraphService.getBlocksPerDay(); + const blocksPerDay = await blockNumbers().getBlocksPerDay(chain); const blocksPerYear = blocksPerDay * 365; const tokenPrices = await tokenService.getTokenPrices(chain); const operations: any[] = []; diff --git a/modules/pool/lib/pool-snapshot.service.ts b/modules/pool/lib/pool-snapshot.service.ts index 7571705bd..6d1fda768 100644 --- a/modules/pool/lib/pool-snapshot.service.ts +++ b/modules/pool/lib/pool-snapshot.service.ts @@ -10,9 +10,9 @@ import _ from 'lodash'; import { Chain, PrismaPoolSnapshot } from '@prisma/client'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { prismaPoolWithExpandedNesting } from '../../../prisma/prisma-types'; -import { blocksSubgraphService } from '../../subgraphs/blocks-subgraph/blocks-subgraph.service'; import { networkContext } from '../../network/network-context.service'; import { CoingeckoDataService, TokenHistoricalPrices } from '../../token/lib/coingecko-data.service'; +import { blockNumbers } from '../../block-numbers'; export class PoolSnapshotService { constructor(private readonly coingeckoService: CoingeckoDataService) {} @@ -113,10 +113,10 @@ export class PoolSnapshotService { } } - const dailyBlocks = await blocksSubgraphService.getDailyBlocks(numDays); + const dailyBlocks = await blockNumbers().getDailyBlocks(this.chain, numDays); for (const block of dailyBlocks) { - const startTimestamp = parseInt(block.timestamp); + const startTimestamp = moment(block.timestamp).utc().startOf('day').unix(); const endTimestamp = startTimestamp + 86400; const swapsForDay = swaps.filter( (swap) => @@ -141,7 +141,7 @@ export class PoolSnapshotService { const { pool: poolAtBlock } = await this.balancerSubgraphService.getPool({ id: poolId, - block: { number: parseInt(block.number) }, + block: { number: block.number }, }); if (!poolAtBlock) { diff --git a/modules/pool/lib/pool-usd-data.service.ts b/modules/pool/lib/pool-usd-data.service.ts index 01ef6567d..ae24ee2b1 100644 --- a/modules/pool/lib/pool-usd-data.service.ts +++ b/modules/pool/lib/pool-usd-data.service.ts @@ -3,16 +3,12 @@ import _ from 'lodash'; 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 { networkContext } from '../../network/network-context.service'; import { capturesYield } from './pool-utils'; import * as Sentry from '@sentry/node'; export class PoolUsdDataService { - constructor( - private readonly tokenService: TokenService, - private readonly blockSubgraphService: BlocksSubgraphService, - ) {} + constructor(private readonly tokenService: TokenService) {} private get balancerSubgraphService() { return networkContext.services.balancerSubgraphService; diff --git a/modules/pool/lib/reliquary-snapshot.service.ts b/modules/pool/lib/reliquary-snapshot.service.ts index 2310239ab..830974373 100644 --- a/modules/pool/lib/reliquary-snapshot.service.ts +++ b/modules/pool/lib/reliquary-snapshot.service.ts @@ -4,7 +4,6 @@ import moment from 'moment-timezone'; import _ from 'lodash'; import { prismaBulkExecuteOperations } from '../../../prisma/prisma-util'; import { ReliquarySubgraphService } from '../../subgraphs/reliquary-subgraph/reliquary.service'; -import { blocksSubgraphService } from '../../subgraphs/blocks-subgraph/blocks-subgraph.service'; import { oneDayInMinutes } from '../../common/time'; import { Chain, @@ -13,6 +12,7 @@ import { PrismaReliquaryTokenBalanceSnapshot, } from '@prisma/client'; import { networkContext } from '../../network/network-context.service'; +import { blockNumbers } from '../../block-numbers'; export class ReliquarySnapshotService { constructor(private readonly reliquarySubgraphService: ReliquarySubgraphService) {} @@ -83,14 +83,14 @@ export class ReliquarySnapshotService { orderBy: { timestamp: 'desc' }, }); - const blockAtTimestamp = await blocksSubgraphService.getBlockForTimestamp(timestampForSnapshot); + const blockAtTimestamp = await blockNumbers().getBlock(chain, timestampForSnapshot); const relicsInFarm = await this.reliquarySubgraphService.getAllRelicsWithPaging({ where: { pid: farmId }, - block: { number: parseFloat(blockAtTimestamp.number) }, + block: { number: blockAtTimestamp }, }); const levelsAtBlock = await this.reliquarySubgraphService.getPoolLevels({ where: { pool_: { pid: farmId } }, - block: { number: parseFloat(blockAtTimestamp.number) }, + block: { number: blockAtTimestamp }, }); const sharePercentage = parseFloat(snapshot.totalBalance) / mostRecentPoolSnapshot.totalSharesNum; diff --git a/modules/pool/pool.service.ts b/modules/pool/pool.service.ts index edb8ef5b3..03f2eab25 100644 --- a/modules/pool/pool.service.ts +++ b/modules/pool/pool.service.ts @@ -17,7 +17,6 @@ import { QueryPoolGetPoolsArgs, QueryPoolGetSwapsArgs, } from '../../apps/api/gql/generated-schema'; -import { blocksSubgraphService } from '../subgraphs/blocks-subgraph/blocks-subgraph.service'; import { tokenService } from '../token/token.service'; import { userService } from '../user/user.service'; import { PoolAprUpdaterService } from './lib/pool-apr-updater.service'; @@ -248,7 +247,7 @@ const optionsResolverForPoolOnChainDataService: () => PoolOnChainDataServiceOpti export const poolService = new PoolService( new PoolOnChainDataService(optionsResolverForPoolOnChainDataService), - new PoolUsdDataService(tokenService, blocksSubgraphService), + new PoolUsdDataService(tokenService), new PoolGqlLoaderService(), new PoolAprUpdaterService(), new PoolSwapService(tokenService), diff --git a/modules/sources/enrichers/get-liquidity-and-shares-at-timestamp.ts b/modules/sources/enrichers/get-liquidity-and-shares-at-timestamp.ts index 2c7077b28..374990b4e 100644 --- a/modules/sources/enrichers/get-liquidity-and-shares-at-timestamp.ts +++ b/modules/sources/enrichers/get-liquidity-and-shares-at-timestamp.ts @@ -1,16 +1,18 @@ -import { BlockNumbersSubgraphClient, V3VaultSubgraphClient } from '../subgraphs'; +import { V3VaultSubgraphClient } from '../subgraphs'; import { V2SubgraphClient } from '../../subgraphs/balancer-subgraph'; import { prisma } from '../../../prisma/prisma-client'; import { daysAgo, roundToHour, roundToMidnight } from '../../common/time'; import { DAYS_OF_HOURLY_PRICES } from '../../../config'; +import { blockNumbers } from '../../block-numbers'; +import { Chain } from '@prisma/client'; export const getLiquidityAndSharesAtTimestamp = async ( + chain: Chain, ids: string[], vaultClient: V2SubgraphClient | V3VaultSubgraphClient, - blockNumbersClient: BlockNumbersSubgraphClient, timestamp = daysAgo(1), // 24 hours ago ) => { - const blockNumber = await blockNumbersClient.fetchBlockByTime(timestamp); + const blockNumber = await blockNumbers().getBlock(chain, timestamp); // If ids count is >= 1000 just get all const where = ids.length >= 1000 ? {} : { id_in: ids }; diff --git a/modules/sources/subgraphs/block-numbers/index.ts b/modules/sources/subgraphs/block-numbers/index.ts deleted file mode 100644 index 24bce23f3..000000000 --- a/modules/sources/subgraphs/block-numbers/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -const query = (timestamp: number) => `{ - blocks(first: 1, orderBy: timestamp, orderDirection: asc, where: { timestamp_gt: ${timestamp} }) { - number - } -}`; - -interface BlockNumberSubgraphResponse { - data: { - blocks: [ - { - number: string; - }, - ]; - }; -} - -export interface BlockNumbersSubgraphClient { - fetchBlockByTime: (timestamp: number) => Promise; -} - -export const getBlockNumbersSubgraphClient = (url: string): BlockNumbersSubgraphClient => ({ - fetchBlockByTime: (timestamp: number) => fetchBlockByTime(url, timestamp), -}); - -const fetchBlockByTime = async (endpoint: string, timestamp: number): Promise => { - const payload = { - query: query(timestamp), - }; - - const response = await fetch(endpoint, { - method: 'POST', - body: JSON.stringify(payload), - headers: { 'Content-Type': 'application/json' }, - }); - - const { - data: { blocks }, - } = (await response.json()) as BlockNumberSubgraphResponse; - - return BigInt(blocks[0].number); -}; diff --git a/modules/sources/subgraphs/index.ts b/modules/sources/subgraphs/index.ts index c54c19fea..c28ffb8f7 100644 --- a/modules/sources/subgraphs/index.ts +++ b/modules/sources/subgraphs/index.ts @@ -1,5 +1,4 @@ export * from './balancer-v3-vault'; export * from './balancer-v3-pools'; export * from './joined-client'; -export * from './block-numbers'; export * from './cow-amm'; diff --git a/modules/subgraphs/blocks-subgraph/block-subgraph-queries.graphql b/modules/subgraphs/blocks-subgraph/block-subgraph-queries.graphql deleted file mode 100644 index 6ac375907..000000000 --- a/modules/subgraphs/blocks-subgraph/block-subgraph-queries.graphql +++ /dev/null @@ -1,25 +0,0 @@ -query Blocks( - $skip: Int - $first: Int - $orderBy: Block_orderBy - $orderDirection: OrderDirection - $where: Block_filter - $block: Block_height -) { - blocks( - skip: $skip - first: $first - orderBy: $orderBy - orderDirection: $orderDirection - where: $where - block: $block - ) { - ...Block - } -} - -fragment Block on Block { - id - number - timestamp -} \ No newline at end of file diff --git a/modules/subgraphs/blocks-subgraph/blocks-subgraph.service.ts b/modules/subgraphs/blocks-subgraph/blocks-subgraph.service.ts deleted file mode 100644 index abcc76919..000000000 --- a/modules/subgraphs/blocks-subgraph/blocks-subgraph.service.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { GraphQLClient } from 'graphql-request'; -import { - Block_OrderBy, - BlockFragment, - BlocksQuery, - BlocksQueryVariables, - getSdk, - OrderDirection, -} from './generated/blocks-subgraph-types'; -import { - fiveMinutesInSeconds, - getDailyTimestampsForDays, - getDailyTimestampsWithBuffer, - oneDayInMinutes, - secondsPerDay, - secondsPerYear, -} from '../../common/time'; -import { subgraphLoadAll } from '../subgraph-util'; -import moment from 'moment-timezone'; -import { Cache, CacheClass } from 'memory-cache'; -import { networkContext } from '../../network/network-context.service'; - -const DAILY_BLOCKS_CACHE_KEY = `block-subgraph_daily-blocks`; -const AVG_BLOCK_TIME_CACHE_PREFIX = `block-subgraph:average-block-time`; -const BLOCK_24H_AGO = `block-subgraph:block-24h-ago`; - -/*const BLOCK_TIME_MAP: { [chainId: string]: number } = { - '250': 1, - '4': 15, -};*/ - -export class BlocksSubgraphService { - private cache: CacheClass; - - constructor() { - this.cache = new Cache(); - } - - public async getAverageBlockTime(): Promise { - const avgBlockTime = await this.cache.get(`${AVG_BLOCK_TIME_CACHE_PREFIX}:${networkContext.chainId}`); - - if (avgBlockTime !== null) { - return parseFloat(avgBlockTime); - } - - return this.cacheAverageBlockTime(); - } - - public async cacheAverageBlockTime(): Promise { - let blocks: BlockFragment[] = []; - - for (let i = 0; i < 6; i++) { - const result = await this.sdk.Blocks({ - first: 1000, - skip: i * 1000, - orderBy: Block_OrderBy.Number, - orderDirection: OrderDirection.Desc, - }); - - if (result.blocks.length === 0) { - break; - } - - blocks = [...blocks, ...result.blocks]; - } - - if (blocks.length === 0) { - console.error('Unable to retrieve the blocks, returning a default value of 1 second per block'); - return 1; - } - - const timeDifference = parseInt(blocks[0].timestamp) - parseInt(blocks[blocks.length - 1].timestamp); - const averageBlockTime = timeDifference / blocks.length; - - await this.cache.put(`${AVG_BLOCK_TIME_CACHE_PREFIX}:${networkContext.chainId}`, `${averageBlockTime}`); - - return averageBlockTime; - } - - public async getBlocks(args: BlocksQueryVariables): Promise { - return this.sdk.Blocks(args); - } - - public async getLatestBlock(): Promise { - const { blocks } = await this.getBlocks({ - first: 1, - orderBy: Block_OrderBy.Number, - orderDirection: OrderDirection.Desc, - }); - - return blocks.length > 0 ? parseInt(blocks[0].number) : 0; - } - - public async getAllBlocks(args: BlocksQueryVariables): Promise { - return subgraphLoadAll(this.sdk.Blocks, 'blocks', args); - } - - /*public async getHourlyBlocks(numDays: number): Promise { - const timestampsWithBuffer = getHourlyTimestampsWithBuffer(numDays); - const timestamps = getHourlyTimestampsForDays(numDays); - const blocks: BlockFragment[] = []; - - const allBlocks = await this.getAllBlocks({ - orderDirection: OrderDirection.Desc, - orderBy: Block_OrderBy.Timestamp, - where: { - timestamp_in: timestampsWithBuffer.map((timestamp) => `${timestamp}`), - }, - }); - - for (const timestamp of timestamps) { - const closest = allBlocks.reduce((a, b) => { - return Math.abs(parseInt(b.timestamp) - timestamp) < Math.abs(parseInt(a.timestamp) - timestamp) - ? b - : a; - }); - - //filter out any matches that are further than 5 minutes away.e - if (Math.abs(timestamp - parseInt(closest.timestamp)) < fiveMinutesInSeconds) { - blocks.push({ ...closest, timestamp: `${timestamp}` }); - } - } - - return blocks; - }*/ - - public async getBlockFrom24HoursAgo(): Promise { - const cached = this.cache.get(`${BLOCK_24H_AGO}:${networkContext.chainId}`); - - if (cached) { - return cached; - } - - return this.cacheBlockFrom24HoursAgo(); - } - - public async cacheBlockFrom24HoursAgo(): Promise { - const blockTime = networkContext.data.avgBlockSpeed; - - const args: BlocksQueryVariables = { - orderDirection: OrderDirection.Desc, - orderBy: Block_OrderBy.Timestamp, - where: { - timestamp_gte: `${moment - .tz('GMT') - .subtract(1, 'day') - .subtract(10 * blockTime, 'seconds') - .unix()}`, - timestamp_lte: `${moment - .tz('GMT') - .subtract(1, 'day') - .add(10 * blockTime, 'seconds') - .unix()}`, - }, - }; - - const allBlocks = await this.getAllBlocks(args); - - if (allBlocks.length > 0) { - this.cache.put(`${BLOCK_24H_AGO}:${networkContext.chainId}`, allBlocks[0], 15 * 1000); - } - - return allBlocks[0]; - } - - public async getBlockForTimestamp(timestamp: number): Promise { - const blockTime = networkContext.data.avgBlockSpeed; - - const args: BlocksQueryVariables = { - orderDirection: OrderDirection.Desc, - orderBy: Block_OrderBy.Timestamp, - where: { - timestamp_gt: `${timestamp - 50 * blockTime}`, - timestamp_lt: `${timestamp + 50 * blockTime}`, - }, - }; - - const allBlocks = await this.getAllBlocks(args); - - const closest = allBlocks.reduce((a, b) => { - return Math.abs(parseFloat(b.timestamp) - timestamp) < Math.abs(parseFloat(a.timestamp) - timestamp) - ? b - : a; - }); - return closest; - } - - public async getDailyBlocks(numDays: number): Promise { - const today = moment.tz('GMT').format('YYYY-MM-DD'); - const maxDays = moment.tz('GMT').diff(moment.tz(networkContext.data.subgraphs.startDate, 'GMT'), 'days'); - numDays = maxDays < numDays ? maxDays : numDays; - - const timestampsWithBuffer = getDailyTimestampsWithBuffer(numDays); - - const timestamps = getDailyTimestampsForDays(numDays); - const blocks: BlockFragment[] = []; - const args = { - orderDirection: OrderDirection.Desc, - orderBy: Block_OrderBy.Timestamp, - where: { - timestamp_in: timestampsWithBuffer.map((timestamp) => `${timestamp}`), - }, - }; - - const cacheResult: BlockFragment[] = await this.cache.get( - `${DAILY_BLOCKS_CACHE_KEY}:${networkContext.chainId}:${today}:${numDays}`, - ); - - if (cacheResult) { - return cacheResult; - } - - const allBlocks = await this.getAllBlocks(args); - - for (const timestamp of timestamps) { - const closest = allBlocks.reduce((a, b) => { - return Math.abs(parseInt(b.timestamp) - timestamp) < Math.abs(parseInt(a.timestamp) - timestamp) - ? b - : a; - }); - - //filter out any matches that are further than 5 minutes away.e - if (Math.abs(timestamp - parseInt(closest.timestamp)) < fiveMinutesInSeconds) { - blocks.push({ ...closest, timestamp: `${timestamp}` }); - } - } - - await this.cache.put( - `${DAILY_BLOCKS_CACHE_KEY}:${networkContext.chainId}:${today}:${numDays}`, - blocks, - oneDayInMinutes, - ); - - return blocks; - } - - public async getBlocksPerDay() { - const blockTime = await this.getAverageBlockTime(); - - return secondsPerDay / blockTime; - } - - public async getBlocksPerYear() { - const blockTime = await this.getAverageBlockTime(); - - return secondsPerYear / blockTime; - } - - public get sdk() { - const client = new GraphQLClient(networkContext.data.subgraphs.blocks); - - return getSdk(client); - } -} - -export const blocksSubgraphService = new BlocksSubgraphService(); diff --git a/modules/subgraphs/blocks-subgraph/generated/blocks-subgraph-types.ts b/modules/subgraphs/blocks-subgraph/generated/blocks-subgraph-types.ts deleted file mode 100644 index 651c08324..000000000 --- a/modules/subgraphs/blocks-subgraph/generated/blocks-subgraph-types.ts +++ /dev/null @@ -1,431 +0,0 @@ -import { GraphQLClient } from 'graphql-request'; -import * as Dom from 'graphql-request/dist/types.dom'; -import gql from 'graphql-tag'; -export type Maybe = T | null; -export type InputMaybe = Maybe; -export type Exact = { [K in keyof T]: T[K] }; -export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; -export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; -/** All built-in and custom scalars, mapped to their actual values */ -export type Scalars = { - ID: string; - String: string; - Boolean: boolean; - Int: number; - Float: number; - BigDecimal: string; - BigInt: string; - Bytes: string; - Int8: any; - Timestamp: any; -}; - -export enum Aggregation_Interval { - Day = 'day', - Hour = 'hour', -} - -export type Block = { - __typename?: 'Block'; - author?: Maybe; - difficulty?: Maybe; - gasLimit?: Maybe; - gasUsed?: Maybe; - id: Scalars['ID']; - number: Scalars['BigInt']; - parentHash?: Maybe; - receiptsRoot?: Maybe; - size?: Maybe; - stateRoot?: Maybe; - timestamp: Scalars['BigInt']; - totalDifficulty?: Maybe; - transactionsRoot?: Maybe; - unclesHash?: Maybe; -}; - -export type BlockChangedFilter = { - number_gte: Scalars['Int']; -}; - -export type Block_Filter = { - /** Filter for the block changed event. */ - _change_block?: InputMaybe; - and?: InputMaybe>>; - author?: InputMaybe; - author_contains?: InputMaybe; - author_contains_nocase?: InputMaybe; - author_ends_with?: InputMaybe; - author_ends_with_nocase?: InputMaybe; - author_gt?: InputMaybe; - author_gte?: InputMaybe; - author_in?: InputMaybe>; - author_lt?: InputMaybe; - author_lte?: InputMaybe; - author_not?: InputMaybe; - author_not_contains?: InputMaybe; - author_not_contains_nocase?: InputMaybe; - author_not_ends_with?: InputMaybe; - author_not_ends_with_nocase?: InputMaybe; - author_not_in?: InputMaybe>; - author_not_starts_with?: InputMaybe; - author_not_starts_with_nocase?: InputMaybe; - author_starts_with?: InputMaybe; - author_starts_with_nocase?: InputMaybe; - difficulty?: InputMaybe; - difficulty_gt?: InputMaybe; - difficulty_gte?: InputMaybe; - difficulty_in?: InputMaybe>; - difficulty_lt?: InputMaybe; - difficulty_lte?: InputMaybe; - difficulty_not?: InputMaybe; - difficulty_not_in?: InputMaybe>; - gasLimit?: InputMaybe; - gasLimit_gt?: InputMaybe; - gasLimit_gte?: InputMaybe; - gasLimit_in?: InputMaybe>; - gasLimit_lt?: InputMaybe; - gasLimit_lte?: InputMaybe; - gasLimit_not?: InputMaybe; - gasLimit_not_in?: InputMaybe>; - gasUsed?: InputMaybe; - gasUsed_gt?: InputMaybe; - gasUsed_gte?: InputMaybe; - gasUsed_in?: InputMaybe>; - gasUsed_lt?: InputMaybe; - gasUsed_lte?: InputMaybe; - gasUsed_not?: InputMaybe; - gasUsed_not_in?: InputMaybe>; - id?: InputMaybe; - id_gt?: InputMaybe; - id_gte?: InputMaybe; - id_in?: InputMaybe>; - id_lt?: InputMaybe; - id_lte?: InputMaybe; - id_not?: InputMaybe; - id_not_in?: InputMaybe>; - number?: InputMaybe; - number_gt?: InputMaybe; - number_gte?: InputMaybe; - number_in?: InputMaybe>; - number_lt?: InputMaybe; - number_lte?: InputMaybe; - number_not?: InputMaybe; - number_not_in?: InputMaybe>; - or?: InputMaybe>>; - parentHash?: InputMaybe; - parentHash_contains?: InputMaybe; - parentHash_contains_nocase?: InputMaybe; - parentHash_ends_with?: InputMaybe; - parentHash_ends_with_nocase?: InputMaybe; - parentHash_gt?: InputMaybe; - parentHash_gte?: InputMaybe; - parentHash_in?: InputMaybe>; - parentHash_lt?: InputMaybe; - parentHash_lte?: InputMaybe; - parentHash_not?: InputMaybe; - parentHash_not_contains?: InputMaybe; - parentHash_not_contains_nocase?: InputMaybe; - parentHash_not_ends_with?: InputMaybe; - parentHash_not_ends_with_nocase?: InputMaybe; - parentHash_not_in?: InputMaybe>; - parentHash_not_starts_with?: InputMaybe; - parentHash_not_starts_with_nocase?: InputMaybe; - parentHash_starts_with?: InputMaybe; - parentHash_starts_with_nocase?: InputMaybe; - receiptsRoot?: InputMaybe; - receiptsRoot_contains?: InputMaybe; - receiptsRoot_contains_nocase?: InputMaybe; - receiptsRoot_ends_with?: InputMaybe; - receiptsRoot_ends_with_nocase?: InputMaybe; - receiptsRoot_gt?: InputMaybe; - receiptsRoot_gte?: InputMaybe; - receiptsRoot_in?: InputMaybe>; - receiptsRoot_lt?: InputMaybe; - receiptsRoot_lte?: InputMaybe; - receiptsRoot_not?: InputMaybe; - receiptsRoot_not_contains?: InputMaybe; - receiptsRoot_not_contains_nocase?: InputMaybe; - receiptsRoot_not_ends_with?: InputMaybe; - receiptsRoot_not_ends_with_nocase?: InputMaybe; - receiptsRoot_not_in?: InputMaybe>; - receiptsRoot_not_starts_with?: InputMaybe; - receiptsRoot_not_starts_with_nocase?: InputMaybe; - receiptsRoot_starts_with?: InputMaybe; - receiptsRoot_starts_with_nocase?: InputMaybe; - size?: InputMaybe; - size_gt?: InputMaybe; - size_gte?: InputMaybe; - size_in?: InputMaybe>; - size_lt?: InputMaybe; - size_lte?: InputMaybe; - size_not?: InputMaybe; - size_not_in?: InputMaybe>; - stateRoot?: InputMaybe; - stateRoot_contains?: InputMaybe; - stateRoot_contains_nocase?: InputMaybe; - stateRoot_ends_with?: InputMaybe; - stateRoot_ends_with_nocase?: InputMaybe; - stateRoot_gt?: InputMaybe; - stateRoot_gte?: InputMaybe; - stateRoot_in?: InputMaybe>; - stateRoot_lt?: InputMaybe; - stateRoot_lte?: InputMaybe; - stateRoot_not?: InputMaybe; - stateRoot_not_contains?: InputMaybe; - stateRoot_not_contains_nocase?: InputMaybe; - stateRoot_not_ends_with?: InputMaybe; - stateRoot_not_ends_with_nocase?: InputMaybe; - stateRoot_not_in?: InputMaybe>; - stateRoot_not_starts_with?: InputMaybe; - stateRoot_not_starts_with_nocase?: InputMaybe; - stateRoot_starts_with?: InputMaybe; - stateRoot_starts_with_nocase?: InputMaybe; - timestamp?: InputMaybe; - timestamp_gt?: InputMaybe; - timestamp_gte?: InputMaybe; - timestamp_in?: InputMaybe>; - timestamp_lt?: InputMaybe; - timestamp_lte?: InputMaybe; - timestamp_not?: InputMaybe; - timestamp_not_in?: InputMaybe>; - totalDifficulty?: InputMaybe; - totalDifficulty_gt?: InputMaybe; - totalDifficulty_gte?: InputMaybe; - totalDifficulty_in?: InputMaybe>; - totalDifficulty_lt?: InputMaybe; - totalDifficulty_lte?: InputMaybe; - totalDifficulty_not?: InputMaybe; - totalDifficulty_not_in?: InputMaybe>; - transactionsRoot?: InputMaybe; - transactionsRoot_contains?: InputMaybe; - transactionsRoot_contains_nocase?: InputMaybe; - transactionsRoot_ends_with?: InputMaybe; - transactionsRoot_ends_with_nocase?: InputMaybe; - transactionsRoot_gt?: InputMaybe; - transactionsRoot_gte?: InputMaybe; - transactionsRoot_in?: InputMaybe>; - transactionsRoot_lt?: InputMaybe; - transactionsRoot_lte?: InputMaybe; - transactionsRoot_not?: InputMaybe; - transactionsRoot_not_contains?: InputMaybe; - transactionsRoot_not_contains_nocase?: InputMaybe; - transactionsRoot_not_ends_with?: InputMaybe; - transactionsRoot_not_ends_with_nocase?: InputMaybe; - transactionsRoot_not_in?: InputMaybe>; - transactionsRoot_not_starts_with?: InputMaybe; - transactionsRoot_not_starts_with_nocase?: InputMaybe; - transactionsRoot_starts_with?: InputMaybe; - transactionsRoot_starts_with_nocase?: InputMaybe; - unclesHash?: InputMaybe; - unclesHash_contains?: InputMaybe; - unclesHash_contains_nocase?: InputMaybe; - unclesHash_ends_with?: InputMaybe; - unclesHash_ends_with_nocase?: InputMaybe; - unclesHash_gt?: InputMaybe; - unclesHash_gte?: InputMaybe; - unclesHash_in?: InputMaybe>; - unclesHash_lt?: InputMaybe; - unclesHash_lte?: InputMaybe; - unclesHash_not?: InputMaybe; - unclesHash_not_contains?: InputMaybe; - unclesHash_not_contains_nocase?: InputMaybe; - unclesHash_not_ends_with?: InputMaybe; - unclesHash_not_ends_with_nocase?: InputMaybe; - unclesHash_not_in?: InputMaybe>; - unclesHash_not_starts_with?: InputMaybe; - unclesHash_not_starts_with_nocase?: InputMaybe; - unclesHash_starts_with?: InputMaybe; - unclesHash_starts_with_nocase?: InputMaybe; -}; - -export type Block_Height = { - hash?: InputMaybe; - number?: InputMaybe; - number_gte?: InputMaybe; -}; - -export enum Block_OrderBy { - Author = 'author', - Difficulty = 'difficulty', - GasLimit = 'gasLimit', - GasUsed = 'gasUsed', - Id = 'id', - Number = 'number', - ParentHash = 'parentHash', - ReceiptsRoot = 'receiptsRoot', - Size = 'size', - StateRoot = 'stateRoot', - Timestamp = 'timestamp', - TotalDifficulty = 'totalDifficulty', - TransactionsRoot = 'transactionsRoot', - UnclesHash = 'unclesHash', -} - -/** Defines the order direction, either ascending or descending */ -export enum OrderDirection { - Asc = 'asc', - Desc = 'desc', -} - -export type Query = { - __typename?: 'Query'; - /** Access to subgraph metadata */ - _meta?: Maybe<_Meta_>; - block?: Maybe; - blocks: Array; -}; - -export type Query_MetaArgs = { - block?: InputMaybe; -}; - -export type QueryBlockArgs = { - block?: InputMaybe; - id: Scalars['ID']; - subgraphError?: _SubgraphErrorPolicy_; -}; - -export type QueryBlocksArgs = { - block?: InputMaybe; - first?: InputMaybe; - orderBy?: InputMaybe; - orderDirection?: InputMaybe; - skip?: InputMaybe; - subgraphError?: _SubgraphErrorPolicy_; - where?: InputMaybe; -}; - -export type Subscription = { - __typename?: 'Subscription'; - /** Access to subgraph metadata */ - _meta?: Maybe<_Meta_>; - block?: Maybe; - blocks: Array; -}; - -export type Subscription_MetaArgs = { - block?: InputMaybe; -}; - -export type SubscriptionBlockArgs = { - block?: InputMaybe; - id: Scalars['ID']; - subgraphError?: _SubgraphErrorPolicy_; -}; - -export type SubscriptionBlocksArgs = { - block?: InputMaybe; - first?: InputMaybe; - orderBy?: InputMaybe; - orderDirection?: InputMaybe; - skip?: InputMaybe; - subgraphError?: _SubgraphErrorPolicy_; - where?: InputMaybe; -}; - -export type _Block_ = { - __typename?: '_Block_'; - /** The hash of the block */ - hash?: Maybe; - /** The block number */ - number: Scalars['Int']; - /** The hash of the parent block */ - parentHash?: Maybe; - /** Integer representation of the timestamp stored in blocks for the chain */ - timestamp?: Maybe; -}; - -/** The type for the top-level _meta field */ -export type _Meta_ = { - __typename?: '_Meta_'; - /** - * Information about a specific subgraph block. The hash of the block - * will be null if the _meta field has a block constraint that asks for - * a block number. It will be filled if the _meta field has no block constraint - * and therefore asks for the latest block - * - */ - block: _Block_; - /** The deployment ID */ - deployment: Scalars['String']; - /** If `true`, the subgraph encountered indexing errors at some past block */ - hasIndexingErrors: Scalars['Boolean']; -}; - -export enum _SubgraphErrorPolicy_ { - /** Data will be returned even if the subgraph has indexing errors */ - Allow = 'allow', - /** If the subgraph has indexing errors, data will be omitted. The default. */ - Deny = 'deny', -} - -export type BlocksQueryVariables = Exact<{ - skip?: InputMaybe; - first?: InputMaybe; - orderBy?: InputMaybe; - orderDirection?: InputMaybe; - where?: InputMaybe; - block?: InputMaybe; -}>; - -export type BlocksQuery = { - __typename?: 'Query'; - blocks: Array<{ __typename?: 'Block'; id: string; number: string; timestamp: string }>; -}; - -export type BlockFragment = { __typename?: 'Block'; id: string; number: string; timestamp: string }; - -export const BlockFragmentDoc = gql` - fragment Block on Block { - id - number - timestamp - } -`; -export const BlocksDocument = gql` - query Blocks( - $skip: Int - $first: Int - $orderBy: Block_orderBy - $orderDirection: OrderDirection - $where: Block_filter - $block: Block_height - ) { - blocks( - skip: $skip - first: $first - orderBy: $orderBy - orderDirection: $orderDirection - where: $where - block: $block - ) { - ...Block - } - } - ${BlockFragmentDoc} -`; - -export type SdkFunctionWrapper = ( - action: (requestHeaders?: Record) => Promise, - operationName: string, - operationType?: string, -) => Promise; - -const defaultWrapper: SdkFunctionWrapper = (action, _operationName, _operationType) => action(); - -export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = defaultWrapper) { - return { - Blocks(variables?: BlocksQueryVariables, requestHeaders?: Dom.RequestInit['headers']): Promise { - return withWrapper( - (wrappedRequestHeaders) => - client.request(BlocksDocument, variables, { - ...requestHeaders, - ...wrappedRequestHeaders, - }), - 'Blocks', - 'query', - ); - }, - }; -} -export type Sdk = ReturnType; diff --git a/package.json b/package.json index 839850e4e..896d325df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "backend", - "version": "1.30.0", + "version": "1.31.0", "description": "Backend service for Beethoven X and Balancer", "repository": "https://github.com/balancer/backend", "author": "Beethoven X", diff --git a/stellate/api/stellate.js b/stellate/api/stellate.js index b6242debf..145654720 100644 --- a/stellate/api/stellate.js +++ b/stellate/api/stellate.js @@ -54,9 +54,6 @@ const config = { 'tokenGetTokens', 'contentGetNewsItems', 'protocolMetricsChain', - 'blocksGetBlocksPerDay', - 'blocksGetBlocksPerSecond', - 'blocksGetAverageBlockTime', 'poolGetFeaturedPoolGroups', 'protocolMetricsAggregated', ], diff --git a/stellate/backend-canary/stellate.js b/stellate/backend-canary/stellate.js index 189aff8d8..154198cec 100644 --- a/stellate/backend-canary/stellate.js +++ b/stellate/backend-canary/stellate.js @@ -53,9 +53,6 @@ const config = { 'beetsGetFbeetsRatio', 'contentGetNewsItems', 'protocolMetricsChain', - 'blocksGetBlocksPerDay', - 'blocksGetBlocksPerSecond', - 'blocksGetAverageBlockTime', 'poolGetFeaturedPoolGroups', 'protocolMetricsAggregated', 'tokenGetProtocolTokenPrice', diff --git a/stellate/backend/stellate.js b/stellate/backend/stellate.js index 8758c6fc4..c8df11257 100644 --- a/stellate/backend/stellate.js +++ b/stellate/backend/stellate.js @@ -53,9 +53,6 @@ const config = { 'beetsGetFbeetsRatio', 'contentGetNewsItems', 'protocolMetricsChain', - 'blocksGetBlocksPerDay', - 'blocksGetBlocksPerSecond', - 'blocksGetAverageBlockTime', 'poolGetFeaturedPoolGroups', 'protocolMetricsAggregated', 'tokenGetProtocolTokenPrice', diff --git a/stellate/test-api/stellate.js b/stellate/test-api/stellate.js index 4544d4bd0..045ebabe6 100644 --- a/stellate/test-api/stellate.js +++ b/stellate/test-api/stellate.js @@ -53,9 +53,6 @@ const config = { 'tokenGetTokens', 'contentGetNewsItems', 'protocolMetricsChain', - 'blocksGetBlocksPerDay', - 'blocksGetBlocksPerSecond', - 'blocksGetAverageBlockTime', 'poolGetFeaturedPoolGroups', 'protocolMetricsAggregated', ],