From 0d4872b657715c6ebb122c3c1087996cb36323d1 Mon Sep 17 00:00:00 2001 From: nigiri <168690269+0xnigir1@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:34:15 -0300 Subject: [PATCH] feat: dummy pricing provider (#32) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 🤖 Linear Closes GIT-136 GIT-144 ## Description - DummyPricingProvider for testing, dev environments to avoid rate limiting - write a Factory to instantiate a pricing provider from Env config - makes `timestampEnd` optional for `IPricingProvider` ## Checklist before requesting a review - [x] I have conducted a self-review of my code. - [x] I have conducted a QA. - [x] If it is a core feature, I have included comprehensive tests. --- apps/processing/.env.example | 2 + apps/processing/README.md | 2 + apps/processing/src/config/env.ts | 31 +++++++++- .../services/sharedDependencies.service.ts | 10 +--- packages/pricing/src/exceptions/index.ts | 2 + .../src/exceptions/invalidSource.exception.ts | 5 ++ .../missingDependencies.exception.ts | 5 ++ packages/pricing/src/external.ts | 13 ++++- packages/pricing/src/factory/index.ts | 56 +++++++++++++++++++ packages/pricing/src/interfaces/index.ts | 1 + .../src/interfaces/pricing.interface.ts | 5 +- .../src/interfaces/pricingConfig.interface.ts | 18 ++++++ packages/pricing/src/internal.ts | 1 + .../src/providers/coingecko.provider.ts | 9 ++- .../pricing/src/providers/dummy.provider.ts | 24 ++++++++ packages/pricing/src/providers/index.ts | 1 + .../test/factory/pricingFactory.spec.ts | 56 +++++++++++++++++++ .../test/providers/coingecko.provider.spec.ts | 19 +++++++ .../test/providers/dummy.provider.spec.ts | 18 ++++++ packages/processors/src/helpers/pricing.ts | 9 ++- .../allo/handlers/poolCreated.handler.ts | 9 +-- .../dvmdDirectTransfer.handler.ts | 9 +-- .../src/schemas/matchingDistribution.ts | 4 +- .../allo/handlers/poolCreated.handler.spec.ts | 6 +- 24 files changed, 273 insertions(+), 42 deletions(-) create mode 100644 packages/pricing/src/exceptions/invalidSource.exception.ts create mode 100644 packages/pricing/src/exceptions/missingDependencies.exception.ts create mode 100644 packages/pricing/src/factory/index.ts create mode 100644 packages/pricing/src/interfaces/pricingConfig.interface.ts create mode 100644 packages/pricing/src/providers/dummy.provider.ts create mode 100644 packages/pricing/test/factory/pricingFactory.spec.ts create mode 100644 packages/pricing/test/providers/dummy.provider.spec.ts diff --git a/apps/processing/.env.example b/apps/processing/.env.example index f5e89c9..3e9bba5 100644 --- a/apps/processing/.env.example +++ b/apps/processing/.env.example @@ -13,5 +13,7 @@ INDEXER_ADMIN_SECRET=testing IPFS_GATEWAYS_URL=["https://ipfs.io","https://gateway.pinata.cloud","https://dweb.link", "https://ipfs.eth.aragon.network"] +PRICING_SOURCE= #coingecko | dummy + COINGECKO_API_KEY={{YOUR_KEY}} COINGECKO_API_TYPE=demo \ No newline at end of file diff --git a/apps/processing/README.md b/apps/processing/README.md index 6460df1..7547863 100644 --- a/apps/processing/README.md +++ b/apps/processing/README.md @@ -35,6 +35,8 @@ Available options: | `INDEXER_GRAPHQL_URL` | GraphQL endpoint for the indexer | N/A | Yes | | | `INDEXER_ADMIN_SECRET` | Admin secret for indexer authentication | N/A | Yes | | | `IPFS_GATEWAYS_URL` | Array of IPFS gateway URLs | N/A | Yes | Multiple gateways for redundancy | +| `PRICING_SOURCE` | Pricing source (coingecko or dummy) | coingecko | No | | +| `DUMMY_PRICE` | Dummy price | 1 | No | Only if PRICING_SOURCE is dummy | | `COINGECKO_API_KEY` | API key for CoinGecko service | N/A | Yes | | | `COINGECKO_API_TYPE` | CoinGecko API tier (demo or pro) | pro | No | | diff --git a/apps/processing/src/config/env.ts b/apps/processing/src/config/env.ts index 0275a03..638d1af 100644 --- a/apps/processing/src/config/env.ts +++ b/apps/processing/src/config/env.ts @@ -14,7 +14,7 @@ const stringToJSONSchema = z.string().transform((str, ctx): z.infer { + if (val.PRICING_SOURCE === "dummy") { + return { pricingSource: val.PRICING_SOURCE, dummyPrice: val.DUMMY_PRICE, ...val }; + } + + return { + pricingSource: val.PRICING_SOURCE, + apiKey: val.COINGECKO_API_KEY, + apiType: val.COINGECKO_API_TYPE, + ...val, + }; + }); + const env = validationSchema.safeParse(process.env); if (!env.success) { diff --git a/apps/processing/src/services/sharedDependencies.service.ts b/apps/processing/src/services/sharedDependencies.service.ts index 32ceec6..9b41999 100644 --- a/apps/processing/src/services/sharedDependencies.service.ts +++ b/apps/processing/src/services/sharedDependencies.service.ts @@ -5,7 +5,7 @@ import { } from "@grants-stack-indexer/data-flow"; import { EnvioIndexerClient } from "@grants-stack-indexer/indexer-client"; import { IpfsProvider } from "@grants-stack-indexer/metadata"; -import { CoingeckoProvider } from "@grants-stack-indexer/pricing"; +import { PricingProviderFactory } from "@grants-stack-indexer/pricing"; import { createKyselyDatabase, KyselyApplicationRepository, @@ -50,13 +50,7 @@ export class SharedDependenciesService { kyselyDatabase, env.DATABASE_SCHEMA, ); - const pricingProvider = new CoingeckoProvider( - { - apiKey: env.COINGECKO_API_KEY, - apiType: env.COINGECKO_API_TYPE, - }, - logger, - ); + const pricingProvider = PricingProviderFactory.create(env, { logger }); const metadataProvider = new IpfsProvider(env.IPFS_GATEWAYS_URL, logger); diff --git a/packages/pricing/src/exceptions/index.ts b/packages/pricing/src/exceptions/index.ts index 1ea09ef..c4c30df 100644 --- a/packages/pricing/src/exceptions/index.ts +++ b/packages/pricing/src/exceptions/index.ts @@ -2,3 +2,5 @@ export * from "./network.exception.js"; export * from "./unsupportedChain.exception.js"; export * from "./unknownPricing.exception.js"; export * from "./unsupportedToken.exception.js"; +export * from "./invalidSource.exception.js"; +export * from "./missingDependencies.exception.js"; diff --git a/packages/pricing/src/exceptions/invalidSource.exception.ts b/packages/pricing/src/exceptions/invalidSource.exception.ts new file mode 100644 index 0000000..7b11b15 --- /dev/null +++ b/packages/pricing/src/exceptions/invalidSource.exception.ts @@ -0,0 +1,5 @@ +export class InvalidPricingSource extends Error { + constructor() { + super(`Invalid pricing source`); + } +} diff --git a/packages/pricing/src/exceptions/missingDependencies.exception.ts b/packages/pricing/src/exceptions/missingDependencies.exception.ts new file mode 100644 index 0000000..cbc4600 --- /dev/null +++ b/packages/pricing/src/exceptions/missingDependencies.exception.ts @@ -0,0 +1,5 @@ +export class MissingDependencies extends Error { + constructor() { + super(`Missing dependencies`); + } +} diff --git a/packages/pricing/src/external.ts b/packages/pricing/src/external.ts index ef38d90..abbfedd 100644 --- a/packages/pricing/src/external.ts +++ b/packages/pricing/src/external.ts @@ -1,9 +1,20 @@ export type { TokenPrice, IPricingProvider } from "./internal.js"; -export { CoingeckoProvider } from "./internal.js"; +export { CoingeckoProvider, DummyPricingProvider } from "./internal.js"; + +export { PricingProviderFactory } from "./internal.js"; +export type { + PricingConfig, + PricingProvider, + DummyPricingConfig, + CoingeckoPricingConfig, +} from "./internal.js"; + export { UnsupportedChainException, NetworkException, UnknownPricingException, UnsupportedToken, + InvalidPricingSource, + MissingDependencies, } from "./internal.js"; diff --git a/packages/pricing/src/factory/index.ts b/packages/pricing/src/factory/index.ts new file mode 100644 index 0000000..7050d95 --- /dev/null +++ b/packages/pricing/src/factory/index.ts @@ -0,0 +1,56 @@ +import { ILogger } from "@grants-stack-indexer/shared"; + +import { + CoingeckoProvider, + DummyPricingProvider, + InvalidPricingSource, + IPricingProvider, + MissingDependencies, + PricingConfig, + PricingProvider, +} from "../internal.js"; + +/** + * Factory class for creating pricing providers. + */ +export class PricingProviderFactory { + /** + * Creates a pricing provider based on the provided configuration. + * @param options - The pricing configuration. + * @param deps - dependencies to inject into the pricing provider. + * @returns The created pricing provider. + * @throws {InvalidPricingSource} if the pricing source is invalid. + * @throws {MissingDependencies} if the dependencies are missing. + */ + static create( + options: PricingConfig, + deps?: { + logger?: ILogger; + }, + ): IPricingProvider { + let pricingProvider: IPricingProvider; + + switch (options.pricingSource) { + case "dummy": + pricingProvider = new DummyPricingProvider(options.dummyPrice); + break; + case "coingecko": + if (!deps?.logger) { + throw new MissingDependencies(); + } + + pricingProvider = new CoingeckoProvider( + { + apiKey: options.apiKey, + apiType: options.apiType, + }, + deps.logger, + ); + break; + default: + throw new InvalidPricingSource(); + } + + return pricingProvider; + } +} diff --git a/packages/pricing/src/interfaces/index.ts b/packages/pricing/src/interfaces/index.ts index 13271cd..6cd31b7 100644 --- a/packages/pricing/src/interfaces/index.ts +++ b/packages/pricing/src/interfaces/index.ts @@ -1 +1,2 @@ export * from "./pricing.interface.js"; +export * from "./pricingConfig.interface.js"; diff --git a/packages/pricing/src/interfaces/pricing.interface.ts b/packages/pricing/src/interfaces/pricing.interface.ts index c9f22d1..dca4dad 100644 --- a/packages/pricing/src/interfaces/pricing.interface.ts +++ b/packages/pricing/src/interfaces/pricing.interface.ts @@ -2,6 +2,9 @@ import { TokenCode } from "@grants-stack-indexer/shared"; import { TokenPrice } from "../internal.js"; +// available pricing providers +export type PricingProvider = "coingecko" | "dummy"; + /** * Represents a pricing service that retrieves token prices. * @dev is service responsibility to map token code to their internal platform ID @@ -20,6 +23,6 @@ export interface IPricingProvider { getTokenPrice( tokenCode: TokenCode, startTimestampMs: number, - endTimestampMs: number, + endTimestampMs?: number, ): Promise; } diff --git a/packages/pricing/src/interfaces/pricingConfig.interface.ts b/packages/pricing/src/interfaces/pricingConfig.interface.ts new file mode 100644 index 0000000..ce9c608 --- /dev/null +++ b/packages/pricing/src/interfaces/pricingConfig.interface.ts @@ -0,0 +1,18 @@ +import { PricingProvider } from "./index.js"; + +export type DummyPricingConfig = { + pricingSource: "dummy"; + dummyPrice?: number; +}; + +export type CoingeckoPricingConfig = { + pricingSource: "coingecko"; + apiKey: string; + apiType: "demo" | "pro"; +}; + +export type PricingConfig = Source extends "dummy" + ? DummyPricingConfig + : Source extends "coingecko" + ? CoingeckoPricingConfig + : never; diff --git a/packages/pricing/src/internal.ts b/packages/pricing/src/internal.ts index 74118ac..e1d4daa 100644 --- a/packages/pricing/src/internal.ts +++ b/packages/pricing/src/internal.ts @@ -2,3 +2,4 @@ export * from "./types/index.js"; export * from "./interfaces/index.js"; export * from "./providers/index.js"; export * from "./exceptions/index.js"; +export * from "./factory/index.js"; diff --git a/packages/pricing/src/providers/coingecko.provider.ts b/packages/pricing/src/providers/coingecko.provider.ts index 4c3d562..029c67e 100644 --- a/packages/pricing/src/providers/coingecko.provider.ts +++ b/packages/pricing/src/providers/coingecko.provider.ts @@ -51,6 +51,9 @@ const TokenMapping: { [key: string]: CoingeckoTokenId | undefined } = { WSEI: "wrapped-sei" as CoingeckoTokenId, }; +// sometimes coingecko returns no prices for 1 hour range, 2 hours works better +const TIME_DELTA = 2 * 60 * 60 * 1000; + /** * The Coingecko provider is a pricing provider that uses the Coingecko API to get the price of a token. */ @@ -83,13 +86,17 @@ export class CoingeckoProvider implements IPricingProvider { async getTokenPrice( tokenCode: TokenCode, startTimestampMs: number, - endTimestampMs: number, + endTimestampMs?: number, ): Promise { const tokenId = TokenMapping[tokenCode]; if (!tokenId) { throw new UnsupportedToken(tokenCode); } + if (!endTimestampMs) { + endTimestampMs = startTimestampMs + TIME_DELTA; + } + if (startTimestampMs > endTimestampMs) { return undefined; } diff --git a/packages/pricing/src/providers/dummy.provider.ts b/packages/pricing/src/providers/dummy.provider.ts new file mode 100644 index 0000000..df6b045 --- /dev/null +++ b/packages/pricing/src/providers/dummy.provider.ts @@ -0,0 +1,24 @@ +import { TokenCode } from "@grants-stack-indexer/shared"; + +import { IPricingProvider, TokenPrice } from "../internal.js"; + +/** + * DummyPricingProvider class that implements the IPricingProvider interface. + * This provider returns a configurable fixed price (defaults to 1) for any token code. + * Used primarily for testing purposes when actual token prices are not needed. + */ +export class DummyPricingProvider implements IPricingProvider { + constructor(private readonly dummyPrice: number = 1) {} + + /* @inheritdoc */ + async getTokenPrice( + _tokenCode: TokenCode, + startTimestampMs: number, + _endTimestampMs?: number, + ): Promise { + return Promise.resolve({ + priceUsd: this.dummyPrice, + timestampMs: startTimestampMs, + }); + } +} diff --git a/packages/pricing/src/providers/index.ts b/packages/pricing/src/providers/index.ts index 7172e08..9c05289 100644 --- a/packages/pricing/src/providers/index.ts +++ b/packages/pricing/src/providers/index.ts @@ -1 +1,2 @@ export * from "./coingecko.provider.js"; +export * from "./dummy.provider.js"; diff --git a/packages/pricing/test/factory/pricingFactory.spec.ts b/packages/pricing/test/factory/pricingFactory.spec.ts new file mode 100644 index 0000000..8d466c3 --- /dev/null +++ b/packages/pricing/test/factory/pricingFactory.spec.ts @@ -0,0 +1,56 @@ +import { describe, expect, it } from "vitest"; + +import { ILogger } from "@grants-stack-indexer/shared"; + +import { CoingeckoProvider, PricingConfig } from "../../src/external.js"; +import { PricingProviderFactory } from "../../src/factory/index.js"; +import { InvalidPricingSource, MissingDependencies } from "../../src/internal.js"; +import { DummyPricingProvider } from "../../src/providers/dummy.provider.js"; + +describe("PricingProviderFactory", () => { + it("create a DummyPricingProvider", () => { + const options: PricingConfig<"dummy"> = { + pricingSource: "dummy", + dummyPrice: 1, + }; + + const pricingProvider = PricingProviderFactory.create(options); + expect(pricingProvider).toBeInstanceOf(DummyPricingProvider); + const dummyProvider = pricingProvider as DummyPricingProvider; + expect(dummyProvider["dummyPrice"]).toBe(1); + }); + + it("create a CoingeckoProvider", () => { + const options: PricingConfig<"coingecko"> = { + pricingSource: "coingecko", + apiKey: "some-api-key", + apiType: "pro", + }; + + const pricingProvider = PricingProviderFactory.create(options, { + logger: {} as unknown as ILogger, + }); + + expect(pricingProvider).toBeInstanceOf(CoingeckoProvider); + }); + + it("throws if logger instance is not provided for CoingeckoProvider", () => { + const options: PricingConfig<"coingecko"> = { + pricingSource: "coingecko", + apiKey: "some-api-key", + apiType: "demo", + }; + + expect(() => PricingProviderFactory.create(options)).toThrowError(MissingDependencies); + }); + + it("should throw an error for invalid pricing source", () => { + const options = { + source: "invalid", + }; + + expect(() => { + PricingProviderFactory.create(options as unknown as PricingConfig<"dummy">); + }).toThrowError(InvalidPricingSource); + }); +}); diff --git a/packages/pricing/test/providers/coingecko.provider.spec.ts b/packages/pricing/test/providers/coingecko.provider.spec.ts index 2b750ac..4525278 100644 --- a/packages/pricing/test/providers/coingecko.provider.spec.ts +++ b/packages/pricing/test/providers/coingecko.provider.spec.ts @@ -73,6 +73,25 @@ describe("CoingeckoProvider", () => { ); }); + it("uses default endTimestampMs if not provided", async () => { + const mockResponse = { + prices: [[1609459200000, 100]], + }; + mock.get.mockResolvedValueOnce({ status: 200, data: mockResponse }); + + const result = await provider.getTokenPrice("ETH" as TokenCode, 1609459200000); + + const expectedPrice: TokenPrice = { + timestampMs: 1609459200000, + priceUsd: 100, + }; + + expect(result).toEqual(expectedPrice); + expect(mock.get).toHaveBeenCalledWith( + "/coins/ethereum/market_chart/range?vs_currency=usd&from=1609459200000&to=1609466400000&precision=full", + ); + }); + it("return undefined if no price data is available for timerange", async () => { const mockResponse = { prices: [], diff --git a/packages/pricing/test/providers/dummy.provider.spec.ts b/packages/pricing/test/providers/dummy.provider.spec.ts new file mode 100644 index 0000000..160361b --- /dev/null +++ b/packages/pricing/test/providers/dummy.provider.spec.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from "vitest"; + +import { TokenCode } from "@grants-stack-indexer/shared"; + +import { DummyPricingProvider } from "../../src/providers/dummy.provider.js"; + +describe("DummyPricingProvider", () => { + it("return 1 for all token prices", async () => { + const provider = new DummyPricingProvider(); + + const response = await provider.getTokenPrice("ETH" as TokenCode, 11111111); + + expect(response).toEqual({ + priceUsd: 1, + timestampMs: 11111111, + }); + }); +}); diff --git a/packages/processors/src/helpers/pricing.ts b/packages/processors/src/helpers/pricing.ts index 351927f..1fac089 100644 --- a/packages/processors/src/helpers/pricing.ts +++ b/packages/processors/src/helpers/pricing.ts @@ -4,9 +4,6 @@ import { Token } from "@grants-stack-indexer/shared"; import { TokenPriceNotFoundError } from "../internal.js"; import { calculateAmountInToken, calculateAmountInUsd } from "./index.js"; -// sometimes coingecko returns no prices for 1 hour range, 2 hours works better -const TIMESTAMP_DELTA_RANGE = 2 * 60 * 60 * 1000; - /** * Get the amount in USD for a given amount in the token * @param pricingProvider - The pricing provider to use @@ -21,11 +18,12 @@ export const getTokenAmountInUsd = async ( token: Token, amount: bigint, timestamp: number, + timestampEnd?: number, ): Promise<{ amountInUsd: string; timestamp: number }> => { const tokenPrice = await pricingProvider.getTokenPrice( token.priceSourceCode, timestamp, - timestamp + TIMESTAMP_DELTA_RANGE, + timestampEnd, ); if (!tokenPrice) { @@ -52,11 +50,12 @@ export const getUsdInTokenAmount = async ( token: Token, amountInUSD: string, timestamp: number, + timestampEnd?: number, ): Promise<{ amount: bigint; price: number; timestamp: Date }> => { const closestPrice = await pricingProvider.getTokenPrice( token.priceSourceCode, timestamp, - timestamp + TIMESTAMP_DELTA_RANGE, + timestampEnd, ); if (!closestPrice) { diff --git a/packages/processors/src/processors/allo/handlers/poolCreated.handler.ts b/packages/processors/src/processors/allo/handlers/poolCreated.handler.ts index aed83db..9979c72 100644 --- a/packages/processors/src/processors/allo/handlers/poolCreated.handler.ts +++ b/packages/processors/src/processors/allo/handlers/poolCreated.handler.ts @@ -14,9 +14,6 @@ type Dependencies = Pick< "evmProvider" | "pricingProvider" | "metadataProvider" | "roundRepository" >; -// sometimes coingecko returns no prices for 1 hour range, 2 hours works better -export const TIMESTAMP_DELTA_RANGE = 2 * 60 * 60 * 1000; - /** /** * Handles the PoolCreated event for the Allo protocol. @@ -198,11 +195,7 @@ export class PoolCreatedHandler implements IEventHandler<"Allo", "PoolCreated"> timestamp: number, ): Promise { const { pricingProvider } = this.dependencies; - const tokenPrice = await pricingProvider.getTokenPrice( - token.priceSourceCode, - timestamp, - timestamp + TIMESTAMP_DELTA_RANGE, - ); + const tokenPrice = await pricingProvider.getTokenPrice(token.priceSourceCode, timestamp); if (!tokenPrice) { throw new TokenPriceNotFoundError(token.address, timestamp); diff --git a/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.ts b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.ts index c39bc09..d480ead 100644 --- a/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.ts +++ b/packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/dvmdDirectTransfer.handler.ts @@ -40,9 +40,6 @@ type Dependencies = Pick< const STRATEGY_NAME = "allov2.DonationVotingMerkleDistributionDirectTransferStrategy"; -// sometimes coingecko returns no prices for 1 hour range, 2 hours works better -export const TIMESTAMP_DELTA_RANGE = 2 * 60 * 60 * 1000; - /** * This handler is responsible for processing events related to the * Donation Voting Merkle Distribution Direct Transfer strategy. @@ -199,11 +196,7 @@ export class DVMDDirectTransferStrategyHandler extends BaseStrategyHandler { timestamp: number, ): Promise { const { pricingProvider } = this.dependencies; - const tokenPrice = await pricingProvider.getTokenPrice( - token.priceSourceCode, - timestamp, - timestamp + TIMESTAMP_DELTA_RANGE, - ); + const tokenPrice = await pricingProvider.getTokenPrice(token.priceSourceCode, timestamp); if (!tokenPrice) { throw new TokenPriceNotFoundError(token.address, timestamp); diff --git a/packages/processors/src/schemas/matchingDistribution.ts b/packages/processors/src/schemas/matchingDistribution.ts index a70bce7..9295dd3 100644 --- a/packages/processors/src/schemas/matchingDistribution.ts +++ b/packages/processors/src/schemas/matchingDistribution.ts @@ -15,8 +15,8 @@ export const MatchingDistributionSchema = z.object({ projectPayoutAddress: z.string(), projectId: z.string(), projectName: z.string(), - matchPoolPercentage: z.number().or(z.string().min(1)).pipe(z.coerce.number()), - contributionsCount: z.number().or(z.string().min(1)).pipe(z.coerce.number()), + matchPoolPercentage: z.coerce.number(), + contributionsCount: z.coerce.number(), originalMatchAmountInToken: BigIntSchema.default("0"), matchAmountInToken: BigIntSchema.default("0"), }), diff --git a/packages/processors/test/allo/handlers/poolCreated.handler.spec.ts b/packages/processors/test/allo/handlers/poolCreated.handler.spec.ts index a5e1dfb..6109242 100644 --- a/packages/processors/test/allo/handlers/poolCreated.handler.spec.ts +++ b/packages/processors/test/allo/handlers/poolCreated.handler.spec.ts @@ -8,10 +8,7 @@ import type { IRoundReadRepository, Round } from "@grants-stack-indexer/reposito import type { ChainId, DeepPartial, ProcessorEvent, TokenCode } from "@grants-stack-indexer/shared"; import { mergeDeep } from "@grants-stack-indexer/shared"; -import { - PoolCreatedHandler, - TIMESTAMP_DELTA_RANGE, -} from "../../../src/processors/allo/handlers/poolCreated.handler.js"; +import { PoolCreatedHandler } from "../../../src/processors/allo/handlers/poolCreated.handler.js"; // Function to create a mock event with optional overrides function createMockEvent( @@ -465,7 +462,6 @@ describe("PoolCreatedHandler", () => { expect(mockPricingProvider.getTokenPrice).toHaveBeenCalledWith( "ETH" as TokenCode, 1708369911, - 1708369911 + TIMESTAMP_DELTA_RANGE, ); });