diff --git a/packages/error-handling/src/utils/assert.ts b/packages/error-handling/src/utils/assert.ts index f0910b1d..8a9ca098 100644 --- a/packages/error-handling/src/utils/assert.ts +++ b/packages/error-handling/src/utils/assert.ts @@ -8,7 +8,10 @@ import { AssertError } from "../errors/AssertError"; * @returns An assertion of `value`. * @throws {@link AssertError} if assert's validity fails */ -export function assert(value: unknown, message: string): asserts value { +export function assert( + value: unknown, + message: string, +): asserts value is NonNullable { try { return assertModule.ok(value, message); } catch (e: unknown) { diff --git a/packages/indexer-database/package.json b/packages/indexer-database/package.json index 03fc86b2..6e0fa1a7 100644 --- a/packages/indexer-database/package.json +++ b/packages/indexer-database/package.json @@ -25,7 +25,7 @@ "author": "", "license": "ISC", "dependencies": { - "@across-protocol/sdk": "^3.3.23", + "@across-protocol/sdk": "^3.4.15", "pg": "^8.4.0", "reflect-metadata": "^0.1.13", "superstruct": "2.0.3-1", diff --git a/packages/indexer-database/src/entities/HistoricPrice.ts b/packages/indexer-database/src/entities/HistoricPrice.ts new file mode 100644 index 00000000..f35ad61b --- /dev/null +++ b/packages/indexer-database/src/entities/HistoricPrice.ts @@ -0,0 +1,33 @@ +import { + Column, + CreateDateColumn, + Entity, + PrimaryGeneratedColumn, + Unique, +} from "typeorm"; + +@Entity() +@Unique("UK_hp_baseCurrency_quoteCurrency_date", [ + "baseCurrency", + "quoteCurrency", + "date", +]) +export class HistoricPrice { + @PrimaryGeneratedColumn() + id: number; + + @Column() + baseCurrency: string; + + @Column({ default: "usd" }) + quoteCurrency: string; + + @Column({ type: "date" }) + date: Date; + + @Column({ type: "decimal" }) + price: string; + + @CreateDateColumn() + createdAt: Date; +} diff --git a/packages/indexer-database/src/entities/RelayHashInfo.ts b/packages/indexer-database/src/entities/RelayHashInfo.ts index c16c383f..1af58e56 100644 --- a/packages/indexer-database/src/entities/RelayHashInfo.ts +++ b/packages/indexer-database/src/entities/RelayHashInfo.ts @@ -13,6 +13,7 @@ import { import { V3FundsDeposited } from "./evm/V3FundsDeposited"; import { FilledV3Relay } from "./evm/FilledV3Relay"; import { RequestedV3SlowFill } from "./evm/RequestedV3SlowFill"; +import { SwapBeforeBridge } from "./evm/SwapBeforeBridge"; export enum RelayStatus { Unfilled = "unfilled", @@ -24,7 +25,10 @@ export enum RelayStatus { } @Entity() -@Unique("UK_relayHashInfo_relayHash", ["relayHash"]) +@Unique("UK_relayHashInfo_relayHash_depositEvent", [ + "relayHash", + "depositEventId", +]) @Index("IX_rhi_originChainId_depositId", ["originChainId", "depositId"]) @Index("IX_rhi_depositTxHash", ["depositTxHash"]) @Index("IX_rhi_origin_deadline_status", [ @@ -40,7 +44,7 @@ export class RelayHashInfo { relayHash: string; @Column({ type: "decimal" }) - depositId: number; + depositId: string; @Column() originChainId: number; @@ -84,6 +88,16 @@ export class RelayHashInfo { }) slowFillRequestEvent: RequestedV3SlowFill; + @Column({ nullable: true }) + swapBeforeBridgeEventId: number; + + @OneToOne(() => SwapBeforeBridge, { nullable: true }) + @JoinColumn({ + name: "swapBeforeBridgeEventId", + foreignKeyConstraintName: "FK_relayHashInfo_swapBeforeBridgeEventId", + }) + swapBeforeBridgeEvent: SwapBeforeBridge; + @Column() fillDeadline: Date; @@ -93,9 +107,26 @@ export class RelayHashInfo { @Column({ nullable: true }) depositRefundTxHash: string; + // swap varas + @Column({ nullable: true, type: "decimal" }) + swapFeeInputAmount: string; + @Column({ nullable: true, type: "decimal" }) + swapFeeUsdAmount: string; + @Column({ nullable: true }) + swapInputTokenName: string; + @Column({ nullable: true }) + swapOutputTokenName: string; + @CreateDateColumn() createdAt: Date; + @Column({ nullable: true, type: "decimal" }) + bridgeFeeUsd: string; + @Column({ nullable: true, type: "decimal" }) + inputPriceUsd: string; + @Column({ nullable: true, type: "decimal" }) + outputPriceUsd: string; + @UpdateDateColumn() updatedAt: Date; } diff --git a/packages/indexer-database/src/entities/evm/FilledV3Relay.ts b/packages/indexer-database/src/entities/evm/FilledV3Relay.ts index 1e729321..d77f555f 100644 --- a/packages/indexer-database/src/entities/evm/FilledV3Relay.ts +++ b/packages/indexer-database/src/entities/evm/FilledV3Relay.ts @@ -17,7 +17,7 @@ export class FilledV3Relay { relayHash: string; @Column({ type: "decimal" }) - depositId: number; + depositId: string; @Column() originChainId: number; diff --git a/packages/indexer-database/src/entities/evm/RequestedSpeedUpV3Deposit.ts b/packages/indexer-database/src/entities/evm/RequestedSpeedUpV3Deposit.ts index 1111d042..ca24d876 100644 --- a/packages/indexer-database/src/entities/evm/RequestedSpeedUpV3Deposit.ts +++ b/packages/indexer-database/src/entities/evm/RequestedSpeedUpV3Deposit.ts @@ -21,7 +21,7 @@ export class RequestedSpeedUpV3Deposit { originChainId: number; @Column({ type: "decimal" }) - depositId: number; + depositId: string; @Column() depositor: string; diff --git a/packages/indexer-database/src/entities/evm/RequestedV3SlowFill.ts b/packages/indexer-database/src/entities/evm/RequestedV3SlowFill.ts index 7337afee..f7a3309a 100644 --- a/packages/indexer-database/src/entities/evm/RequestedV3SlowFill.ts +++ b/packages/indexer-database/src/entities/evm/RequestedV3SlowFill.ts @@ -16,7 +16,7 @@ export class RequestedV3SlowFill { relayHash: string; @Column({ type: "decimal" }) - depositId: number; + depositId: string; @Column() originChainId: number; diff --git a/packages/indexer-database/src/entities/evm/SwapBeforeBridge.ts b/packages/indexer-database/src/entities/evm/SwapBeforeBridge.ts new file mode 100644 index 00000000..de2e68e4 --- /dev/null +++ b/packages/indexer-database/src/entities/evm/SwapBeforeBridge.ts @@ -0,0 +1,60 @@ +import { + Column, + CreateDateColumn, + Entity, + PrimaryGeneratedColumn, + Unique, +} from "typeorm"; + +@Entity({ schema: "evm" }) +@Unique("UK_swapBeforeBridge_chainId_blockHash_logIndex", [ + "chainId", + "blockHash", + "logIndex", +]) +export class SwapBeforeBridge { + @PrimaryGeneratedColumn() + id: number; + + @Column() + swapToken: string; + + @Column() + acrossInputToken: string; + + @Column() + acrossOutputToken: string; + + @Column({ type: "decimal" }) + swapTokenAmount: string; + + @Column({ type: "decimal" }) + acrossInputAmount: string; + + @Column({ type: "decimal" }) + acrossOutputAmount: string; + + @Column() + exchange: string; + + @Column() + blockHash: string; + + @Column() + blockNumber: number; + + @Column() + transactionHash: string; + + @Column() + logIndex: number; + + @Column() + chainId: number; + + @Column() + finalised: boolean; + + @CreateDateColumn() + createdAt: Date; +} diff --git a/packages/indexer-database/src/entities/evm/V3FundsDeposited.ts b/packages/indexer-database/src/entities/evm/V3FundsDeposited.ts index 04a1de98..2d3c0946 100644 --- a/packages/indexer-database/src/entities/evm/V3FundsDeposited.ts +++ b/packages/indexer-database/src/entities/evm/V3FundsDeposited.ts @@ -7,9 +7,10 @@ import { } from "typeorm"; @Entity({ schema: "evm" }) -@Unique("UK_v3FundsDeposited_depositId_originChainId", [ - "depositId", - "originChainId", +@Unique("UK_v3FundsDeposited_relayHash_block_logIdx", [ + "relayHash", + "blockNumber", + "logIndex", ]) export class V3FundsDeposited { @PrimaryGeneratedColumn() @@ -19,7 +20,7 @@ export class V3FundsDeposited { relayHash: string; @Column({ type: "decimal" }) - depositId: number; + depositId: string; @Column() originChainId: number; diff --git a/packages/indexer-database/src/entities/index.ts b/packages/indexer-database/src/entities/index.ts index 82a8c2b8..47b7068e 100644 --- a/packages/indexer-database/src/entities/index.ts +++ b/packages/indexer-database/src/entities/index.ts @@ -12,6 +12,7 @@ export * from "./evm/RequestedSpeedUpV3Deposit"; export * from "./evm/RelayedRootBundle"; export * from "./evm/ExecutedRelayerRefundRoot"; export * from "./evm/TokensBridged"; +export * from "./evm/SwapBeforeBridge"; // Others export * from "./Bundle"; @@ -24,3 +25,4 @@ export * from "./WebhookRequest"; export * from "./WebhookClient"; export * from "./IndexerProgressInfo"; +export * from "./HistoricPrice"; diff --git a/packages/indexer-database/src/main.ts b/packages/indexer-database/src/main.ts index 03e00d71..0869c652 100644 --- a/packages/indexer-database/src/main.ts +++ b/packages/indexer-database/src/main.ts @@ -1,9 +1,16 @@ import "reflect-metadata"; -import { DataSource, LessThan, Not, In } from "typeorm"; +import { + DataSource, + InsertResult, + UpdateResult, + In, + LessThan, + Not, +} from "typeorm"; import * as entities from "./entities"; import { DatabaseConfig } from "./model"; -export { DataSource, LessThan, Not, In }; +export { DataSource, InsertResult, UpdateResult, In, LessThan, Not }; export const createDataSource = (config: DatabaseConfig): DataSource => { return new DataSource({ @@ -29,6 +36,7 @@ export const createDataSource = (config: DatabaseConfig): DataSource => { entities.RequestedV3SlowFill, entities.TokensBridged, entities.V3FundsDeposited, + entities.SwapBeforeBridge, // Bundle entities.Bundle, entities.BundleBlockRange, @@ -41,6 +49,8 @@ export const createDataSource = (config: DatabaseConfig): DataSource => { entities.WebhookClient, // Indexer entities.IndexerProgressInfo, + // Historic Price + entities.HistoricPrice, ], migrationsTableName: "_migrations", migrations: ["migrations/*.ts"], diff --git a/packages/indexer-database/src/migrations/1734616435674-HistoricPrice.ts b/packages/indexer-database/src/migrations/1734616435674-HistoricPrice.ts new file mode 100644 index 00000000..24d6f530 --- /dev/null +++ b/packages/indexer-database/src/migrations/1734616435674-HistoricPrice.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class HistoricPrice1734616435674 implements MigrationInterface { + name = "HistoricPrice1734616435674"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + CREATE TABLE "historic_price" ( + "id" SERIAL NOT NULL, + "baseCurrency" character varying NOT NULL, + "quoteCurrency" character varying NOT NULL DEFAULT 'usd', + "date" date NOT NULL, + "price" double precision NOT NULL, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + CONSTRAINT "UK_hp_baseCurrency_quoteCurrency_date" UNIQUE ("baseCurrency", "quoteCurrency", "date"), + CONSTRAINT "PK_77dc3f4978cdfb03f1bb3a7444b" PRIMARY KEY ("id")) + `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "historic_price"`); + } +} diff --git a/packages/indexer-database/src/migrations/1735922359359-RelayHashInfo.ts b/packages/indexer-database/src/migrations/1735922359359-RelayHashInfo.ts new file mode 100644 index 00000000..a1514ed1 --- /dev/null +++ b/packages/indexer-database/src/migrations/1735922359359-RelayHashInfo.ts @@ -0,0 +1,29 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class RelayHashInfo1735922359359 implements MigrationInterface { + name = "RelayHashInfo1735922359359"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD "bridgeFeeUsd" double precision`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD "inputPriceUsd" double precision`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD "outputPriceUsd" double precision`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP COLUMN "bridgeFeeUsd"`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP COLUMN "outputPriceUsd"`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP COLUMN "inputPriceUsd"`, + ); + } +} diff --git a/packages/indexer-database/src/migrations/1737650752958-DepositsUniqueConstraint.ts b/packages/indexer-database/src/migrations/1737650752958-DepositsUniqueConstraint.ts new file mode 100644 index 00000000..837547da --- /dev/null +++ b/packages/indexer-database/src/migrations/1737650752958-DepositsUniqueConstraint.ts @@ -0,0 +1,37 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class DepositsUniqueConstraint1737650752958 + implements MigrationInterface +{ + name = "DepositsUniqueConstraint1737650752958"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "evm"."v3_funds_deposited" DROP CONSTRAINT "UK_v3FundsDeposited_depositId_originChainId"`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP CONSTRAINT "UK_relayHashInfo_relayHash"`, + ); + await queryRunner.query( + `ALTER TABLE "evm"."v3_funds_deposited" ADD CONSTRAINT "UK_v3FundsDeposited_relayHash_block_logIdx" UNIQUE ("relayHash", "blockNumber", "logIndex")`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD CONSTRAINT "UK_relayHashInfo_relayHash_depositEvent" UNIQUE ("relayHash", "depositEventId")`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP CONSTRAINT "UK_relayHashInfo_relayHash_depositEvent"`, + ); + await queryRunner.query( + `ALTER TABLE "evm"."v3_funds_deposited" DROP CONSTRAINT "UK_v3FundsDeposited_relayHash_block_logIdx"`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD CONSTRAINT "UK_relayHashInfo_relayHash" UNIQUE ("relayHash")`, + ); + await queryRunner.query( + `ALTER TABLE "evm"."v3_funds_deposited" ADD CONSTRAINT "UK_v3FundsDeposited_depositId_originChainId" UNIQUE ("depositId", "originChainId")`, + ); + } +} diff --git a/packages/indexer-database/src/migrations/1737653335019-RelayHashInfo.ts b/packages/indexer-database/src/migrations/1737653335019-RelayHashInfo.ts new file mode 100644 index 00000000..89af607f --- /dev/null +++ b/packages/indexer-database/src/migrations/1737653335019-RelayHashInfo.ts @@ -0,0 +1,35 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class RelayHashInfo1737653335019 implements MigrationInterface { + name = "RelayHashInfo1737653335019"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD "swapFeeInputAmount" numeric NULL`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD "swapInputTokenName" character varying NULL`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD "swapOutputTokenName" character varying NULL`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD "swapFeeUsdAmount" numeric NULL`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP COLUMN "swapFeeUsdAmount"`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP COLUMN "swapFeeInputAmount"`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP COLUMN "swapInputTokenName"`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP COLUMN "swapOutputTokenName"`, + ); + } +} diff --git a/packages/indexer-database/src/migrations/1738543498015-SwapBeforeBridge.ts b/packages/indexer-database/src/migrations/1738543498015-SwapBeforeBridge.ts new file mode 100644 index 00000000..157a9d2a --- /dev/null +++ b/packages/indexer-database/src/migrations/1738543498015-SwapBeforeBridge.ts @@ -0,0 +1,32 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class SwapBeforeBridge1738543498015 implements MigrationInterface { + name = "SwapBeforeBridge1738543498015"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + CREATE TABLE "evm"."swap_before_bridge" ( + "id" SERIAL NOT NULL, + "swapToken" character varying NOT NULL, + "acrossInputToken" character varying NOT NULL, + "acrossOutputToken" character varying NOT NULL, + "swapTokenAmount" numeric NOT NULL, + "acrossInputAmount" numeric NOT NULL, + "acrossOutputAmount" numeric NOT NULL, + "exchange" character varying NOT NULL, + "blockHash" character varying NOT NULL, + "blockNumber" integer NOT NULL, + "transactionHash" character varying NOT NULL, + "logIndex" integer NOT NULL, + "chainId" integer NOT NULL, + "finalised" boolean NOT NULL DEFAULT false, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + CONSTRAINT "UK_swapBeforeBridge_chainId_blockHash_logIndex" UNIQUE ("chainId", "blockHash", "logIndex"), + CONSTRAINT "PK_4d800cfe04c9c412fb76e62e21f" PRIMARY KEY ("id")) + `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "evm"."swap_before_bridge"`); + } +} diff --git a/packages/indexer-database/src/migrations/1738544424919-RelayHashInfo.ts b/packages/indexer-database/src/migrations/1738544424919-RelayHashInfo.ts new file mode 100644 index 00000000..a76d2099 --- /dev/null +++ b/packages/indexer-database/src/migrations/1738544424919-RelayHashInfo.ts @@ -0,0 +1,31 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class RelayHashInfo1738544424919 implements MigrationInterface { + name = "RelayHashInfo1738544424919"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD "swapBeforeBridgeEventId" integer`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" ADD CONSTRAINT "UQ_0e578ee118b0d02c181f4a39c71" UNIQUE ("swapBeforeBridgeEventId")`, + ); + await queryRunner.query(` + ALTER TABLE "relay_hash_info" + ADD CONSTRAINT "FK_relayHashInfo_swapBeforeBridgeEventId" + FOREIGN KEY ("swapBeforeBridgeEventId") REFERENCES "evm"."swap_before_bridge"("id") ON DELETE NO ACTION ON UPDATE NO ACTION + `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP CONSTRAINT "FK_relayHashInfo_swapBeforeBridgeEventId"`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP CONSTRAINT "UQ_0e578ee118b0d02c181f4a39c71"`, + ); + await queryRunner.query( + `ALTER TABLE "relay_hash_info" DROP COLUMN "swapBeforeBridgeEventId"`, + ); + } +} diff --git a/packages/indexer/package.json b/packages/indexer/package.json index a5a1d16a..1a195ca1 100644 --- a/packages/indexer/package.json +++ b/packages/indexer/package.json @@ -23,17 +23,19 @@ "dependencies": { "@across-protocol/constants": "^3.1.28", "@across-protocol/contracts": "^3.0.23", - "@across-protocol/sdk": "^3.3.23", + "@across-protocol/sdk": "^3.4.15", "@repo/error-handling": "workspace:*", "@repo/webhooks": "workspace:*", "@types/express": "^4.17.21", "@types/lodash": "^4.17.7", + "@types/luxon": "^3.4.2", "bullmq": "^5.12.12", "ethers": "^5.7.2", "express": "^4.19.2", "express-bearer-token": "^3.0.0", "ioredis": "^5.4.1", "lodash": "^4.17.21", + "luxon": "^3.5.0", "redis": "^4.7.0", "superstruct": "^2.0.3-1", "winston": "^3.13.1" diff --git a/packages/indexer/src/data-indexing/service/AcrossIndexerManager.ts b/packages/indexer/src/data-indexing/service/AcrossIndexerManager.ts index b43d2d32..964b2976 100644 --- a/packages/indexer/src/data-indexing/service/AcrossIndexerManager.ts +++ b/packages/indexer/src/data-indexing/service/AcrossIndexerManager.ts @@ -23,6 +23,7 @@ import { getFinalisedBlockBufferDistance, getLoopWaitTimeSeconds, } from "./constants"; +import { SwapBeforeBridgeRepository } from "../../database/SwapBeforeBridgeRepository"; export class AcrossIndexerManager { private hubPoolIndexer?: Indexer; @@ -38,6 +39,7 @@ export class AcrossIndexerManager { private retryProvidersFactory: RetryProvidersFactory, private hubPoolRepository: HubPoolRepository, private spokePoolRepository: SpokePoolRepository, + private swapBeforeBridgeRepository: SwapBeforeBridgeRepository, private redisCache: RedisCache, private indexerQueuesService: IndexerQueuesService, private webhookWriteFn?: eventProcessorManager.WebhookWriteFn, @@ -99,6 +101,7 @@ export class AcrossIndexerManager { this.hubPoolClientFactory, this.spokePoolClientFactory, this.spokePoolRepository, + this.swapBeforeBridgeRepository, new SpokePoolProcessor( this.postgres, this.logger, diff --git a/packages/indexer/src/data-indexing/service/SpokePoolIndexerDataHandler.ts b/packages/indexer/src/data-indexing/service/SpokePoolIndexerDataHandler.ts index 455e1de0..28f6463f 100644 --- a/packages/indexer/src/data-indexing/service/SpokePoolIndexerDataHandler.ts +++ b/packages/indexer/src/data-indexing/service/SpokePoolIndexerDataHandler.ts @@ -17,10 +17,13 @@ import { IndexerDataHandler } from "./IndexerDataHandler"; import * as utils from "../../utils"; import { getIntegratorId } from "../../utils/spokePoolUtils"; import { SpokePoolRepository } from "../../database/SpokePoolRepository"; +import { SwapBeforeBridgeRepository } from "../../database/SwapBeforeBridgeRepository"; import { SpokePoolProcessor } from "../../services/spokePoolProcessor"; import { IndexerQueues, IndexerQueuesService } from "../../messaging/service"; import { IntegratorIdMessage } from "../../messaging/IntegratorIdWorker"; import { getMaxBlockLookBack } from "../../web3/constants"; +import { PriceMessage } from "../../messaging/priceWorker"; +import { EventDecoder } from "../../web3/EventDecoder"; export type FetchEventsResult = { v3FundsDepositedEvents: utils.V3FundsDepositedWithIntegradorId[]; @@ -28,7 +31,7 @@ export type FetchEventsResult = { requestedV3SlowFillEvents: across.interfaces.SlowFillRequestWithBlock[]; requestedSpeedUpV3Events: { [depositorAddress: string]: { - [depositId: number]: across.interfaces.SpeedUpWithBlock[]; + [depositId: string]: across.interfaces.SpeedUpWithBlock[]; }; }; relayedRootBundleEvents: across.interfaces.RootBundleRelayWithBlock[]; @@ -44,6 +47,11 @@ export type StoreEventsResult = { executedRefundRoots: SaveQueryResult[]; }; +export type DepositSwapPair = { + deposit: entities.V3FundsDeposited; + swapBeforeBridge: entities.SwapBeforeBridge; +}; + export class SpokePoolIndexerDataHandler implements IndexerDataHandler { private isInitialized: boolean; private configStoreClient: across.clients.AcrossConfigStoreClient; @@ -58,6 +66,7 @@ export class SpokePoolIndexerDataHandler implements IndexerDataHandler { private hubPoolFactory: utils.HubPoolClientFactory, private spokePoolFactory: utils.SpokePoolClientFactory, private spokePoolClientRepository: SpokePoolRepository, + private swapBeforeBridgeRepository: SwapBeforeBridgeRepository, private spokePoolProcessor: SpokePoolProcessor, private indexerQueuesService: IndexerQueuesService, ) { @@ -127,17 +136,25 @@ export class SpokePoolIndexerDataHandler implements IndexerDataHandler { const timeToStoreEvents = performance.now(); await this.updateNewDepositsWithIntegratorId(newInsertedDeposits); + const depositSwapPairs = await this.matchDepositEventsWithSwapEvents( + newInsertedDeposits, + lastFinalisedBlock, + ); + await this.publishSwaps(depositSwapPairs); //FIXME: Remove performance timing const timeToUpdateDepositIds = performance.now(); - await this.spokePoolProcessor.process(storedEvents); + await this.spokePoolProcessor.process(storedEvents, depositSwapPairs); //FIXME: Remove performance timing const timeToProcessDeposits = performance.now(); this.profileStoreEvents(storedEvents); + // publish new relays to workers to fill in prices + await this.publishNewRelays(storedEvents.fills); + //FIXME: Remove performance timing const finalPerfTime = performance.now(); @@ -156,6 +173,95 @@ export class SpokePoolIndexerDataHandler implements IndexerDataHandler { }); } + /** + * Function that matches the new deposit events with swap events + * 1. for all new deposits transactions, fetch the transaction receipt + * 2. for each tx receipt, get SwapBeforeBridge events + * 3. insert the swap events into the database + * 4. group the deposit events and swap events by the transaction hash + */ + private async matchDepositEventsWithSwapEvents( + deposits: entities.V3FundsDeposited[], + lastFinalisedBlock: number, + ) { + // avoid fetching the same transaction receipt multiple times + const uniqueDepositTxHashes = [ + ...new Set(deposits.map((deposit) => deposit.transactionHash)), + ]; + const transactionReceipts = await Promise.all([ + ...uniqueDepositTxHashes.map((txHash) => + this.provider.getTransactionReceipt(txHash), + ), + ]); + const swapBeforeBridgeEvents = transactionReceipts + .map((transactionReceipt) => + EventDecoder.decodeSwapBeforeBridgeEvents(transactionReceipt), + ) + .flat(); + /** + * this calls `saveAndHandleFinalisation()` from the `BlockchainEventRepository`. Not sure if this is the best way to do it + * because if the event is already in the database, it will not be returned (result: 'nothing'). + */ + const saveResult = + await this.swapBeforeBridgeRepository.formatAndSaveSwapBeforeBridgeEvents( + swapBeforeBridgeEvents, + this.chainId, + lastFinalisedBlock, + ); + const insertedSwapBeforeBridgeEvents = + indexerDatabaseUtils.filterSaveQueryResults( + saveResult, + SaveQueryResultType.Inserted, + ); + const depositsAndSwapsByTxHash = insertedSwapBeforeBridgeEvents.reduce( + (acc, swapBeforeBridge) => { + acc[swapBeforeBridge.transactionHash] = { + deposits: deposits.filter( + (d) => d.transactionHash === swapBeforeBridge.transactionHash, + ), + swapBeforeBridges: insertedSwapBeforeBridgeEvents.filter( + (s) => s.transactionHash === swapBeforeBridge.transactionHash, + ), + }; + return acc; + }, + {} as Record< + string, + { + deposits: entities.V3FundsDeposited[]; + swapBeforeBridges: entities.SwapBeforeBridge[]; + } + >, + ); + + // match the deposit with the swap before + const depositSwapMap = Object.values(depositsAndSwapsByTxHash) + .map((depositAndSwap) => { + const { deposits, swapBeforeBridges } = depositAndSwap; + const sortedDeposits = deposits.sort((a, b) => a.logIndex - b.logIndex); + const sortedSwapBeforeBridges = swapBeforeBridges.sort( + (a, b) => a.logIndex - b.logIndex, + ); + const matchedPairs: DepositSwapPair[] = []; + const usedSwaps = new Set(); // Track used swaps by their log index + + sortedDeposits.forEach((deposit) => { + const matchingSwap = sortedSwapBeforeBridges.find( + (swap) => + swap.logIndex < deposit.logIndex && !usedSwaps.has(swap.logIndex), + ); + if (matchingSwap) { + matchedPairs.push({ deposit, swapBeforeBridge: matchingSwap }); + usedSwaps.add(matchingSwap.logIndex); // Mark this swap as used + } + }); + + return matchedPairs; + }) + .flat(); + return depositSwapMap; + } + /** * Log the time that it took to store the events from the moment they were emitted onchain * @param events @@ -427,6 +533,31 @@ export class SpokePoolIndexerDataHandler implements IndexerDataHandler { }); } + private async publishNewRelays( + fills: SaveQueryResult[], + ) { + const messages: PriceMessage[] = fills + .filter((x) => x.data != undefined) + .map((fill) => ({ + fillEventId: fill.data?.id!, + })); + + await this.indexerQueuesService.publishMessagesBulk( + IndexerQueues.PriceQuery, + IndexerQueues.PriceQuery, // Use queue name as job name + messages, + ); + } + private async publishSwaps(swapDepositPairs: DepositSwapPair[]) { + const messages = swapDepositPairs.map((pair) => { + swapEventId: pair.swapBeforeBridge.id; + }); + await this.indexerQueuesService.publishMessagesBulk( + IndexerQueues.SwapMessage, + IndexerQueues.SwapMessage, // Use queue name as job name + messages, + ); + } private async publishIntegratorIdMessages( deposits: entities.V3FundsDeposited[], ) { diff --git a/packages/indexer/src/database/SpokePoolRepository.ts b/packages/indexer/src/database/SpokePoolRepository.ts index a950fa0a..31759bab 100644 --- a/packages/indexer/src/database/SpokePoolRepository.ts +++ b/packages/indexer/src/database/SpokePoolRepository.ts @@ -25,6 +25,7 @@ export class SpokePoolRepository extends dbUtils.BlockchainEventRepository { | across.interfaces.SlowFillRequestWithBlock, ) { return { + depositId: event.depositId.toString(), inputAmount: event.inputAmount.toString(), outputAmount: event.outputAmount.toString(), fillDeadline: new Date(event.fillDeadline * 1000), @@ -63,8 +64,8 @@ export class SpokePoolRepository extends dbUtils.BlockchainEventRepository { this.saveAndHandleFinalisationBatch( entities.V3FundsDeposited, eventsChunk, - ["depositId", "originChainId"], - ["relayHash", "transactionHash"], + ["relayHash", "blockNumber", "logIndex"], + [], ), ), ); @@ -143,7 +144,7 @@ export class SpokePoolRepository extends dbUtils.BlockchainEventRepository { public async formatAndSaveRequestedSpeedUpV3Events( requestedSpeedUpV3Events: { [depositorAddress: string]: { - [depositId: number]: across.interfaces.SpeedUpWithBlock[]; + [depositId: string]: across.interfaces.SpeedUpWithBlock[]; }; }, lastFinalisedBlock: number, @@ -154,6 +155,7 @@ export class SpokePoolRepository extends dbUtils.BlockchainEventRepository { events.map((event) => { return { ...event, + depositId: event.depositId.toString(), updatedOutputAmount: event.updatedOutputAmount.toString(), finalised: event.blockNumber <= lastFinalisedBlock, }; diff --git a/packages/indexer/src/database/SwapBeforeBridgeRepository.ts b/packages/indexer/src/database/SwapBeforeBridgeRepository.ts new file mode 100644 index 00000000..f0d3e30e --- /dev/null +++ b/packages/indexer/src/database/SwapBeforeBridgeRepository.ts @@ -0,0 +1,51 @@ +import winston from "winston"; +import * as across from "@across-protocol/sdk"; +import { DataSource, entities, utils as dbUtils } from "@repo/indexer-database"; +import { SwapBeforeBridgeEvent } from "../web3/model/events"; + +export class SwapBeforeBridgeRepository extends dbUtils.BlockchainEventRepository { + constructor( + postgres: DataSource, + logger: winston.Logger, + private chunkSize = 100, + ) { + super(postgres, logger); + } + + public async formatAndSaveSwapBeforeBridgeEvents( + swapBeforeBridgeEvents: SwapBeforeBridgeEvent[], + chainId: number, + lastFinalisedBlock: number, + ) { + const formattedEvents = swapBeforeBridgeEvents.map((event) => { + const entity = new entities.SwapBeforeBridge(); + entity.swapToken = event.args.swapToken; + entity.acrossInputToken = event.args.acrossInputToken; + entity.acrossOutputToken = event.args.acrossOutputToken; + entity.swapTokenAmount = event.args.swapTokenAmount.toString(); + entity.acrossInputAmount = event.args.acrossInputAmount.toString(); + entity.acrossOutputAmount = event.args.acrossOutputAmount.toString(); + entity.exchange = event.args.exchange; + entity.blockHash = event.blockHash; + entity.blockNumber = event.blockNumber; + entity.transactionHash = event.transactionHash; + entity.logIndex = event.logIndex; + entity.chainId = chainId; + entity.finalised = event.blockNumber <= lastFinalisedBlock; + return entity; + }); + const chunkedEvents = across.utils.chunk(formattedEvents, this.chunkSize); + const savedEvents = await Promise.all( + chunkedEvents.map((eventsChunk) => + this.saveAndHandleFinalisationBatch( + entities.SwapBeforeBridge, + eventsChunk, + ["chainId", "blockHash", "logIndex"], + [], + ), + ), + ); + const result = savedEvents.flat(); + return result; + } +} diff --git a/packages/indexer/src/main.ts b/packages/indexer/src/main.ts index b896f931..390cabf9 100644 --- a/packages/indexer/src/main.ts +++ b/packages/indexer/src/main.ts @@ -17,8 +17,11 @@ import { import { BundleRepository } from "./database/BundleRepository"; import { IndexerQueuesService } from "./messaging/service"; import { IntegratorIdWorker } from "./messaging/IntegratorIdWorker"; +import { PriceWorker } from "./messaging/priceWorker"; import { AcrossIndexerManager } from "./data-indexing/service/AcrossIndexerManager"; import { BundleServicesManager } from "./services/BundleServicesManager"; +import { SwapBeforeBridgeRepository } from "./database/SwapBeforeBridgeRepository"; +import { SwapWorker } from "./messaging/swapWorker"; async function initializeRedis( config: parseEnv.RedisConfig, @@ -93,6 +96,7 @@ export async function Main(config: parseEnv.Config, logger: winston.Logger) { retryProvidersFactory, new HubPoolRepository(postgres, logger), new SpokePoolRepository(postgres, logger), + new SwapBeforeBridgeRepository(postgres, logger), redisCache, indexerQueuesService, write, @@ -109,6 +113,13 @@ export async function Main(config: parseEnv.Config, logger: winston.Logger) { new BundleRepository(postgres, logger, true), ); + const swapWorker = new SwapWorker( + redis, + postgres, + retryProvidersFactory, + logger, + ); + // Set up message workers const integratorIdWorker = new IntegratorIdWorker( redis, @@ -116,6 +127,7 @@ export async function Main(config: parseEnv.Config, logger: winston.Logger) { logger, retryProvidersFactory, ); + const priceWorker = new PriceWorker(redis, postgres, logger); let exitRequested = false; process.on("SIGINT", () => { @@ -125,10 +137,13 @@ export async function Main(config: parseEnv.Config, logger: winston.Logger) { message: "Wait for shutdown, or press Ctrl+C again to forcefully exit.", }); integratorIdWorker.close(); + priceWorker.close(); + swapWorker.close(); acrossIndexerManager.stopGracefully(); bundleServicesManager.stop(); } else { integratorIdWorker.close(); + swapWorker.close(); logger.info({ at: "Indexer#Main", message: "Forcing exit..." }); redis?.quit(); postgres?.destroy(); diff --git a/packages/indexer/src/messaging/priceWorker.ts b/packages/indexer/src/messaging/priceWorker.ts new file mode 100644 index 00000000..e1c61b9e --- /dev/null +++ b/packages/indexer/src/messaging/priceWorker.ts @@ -0,0 +1,276 @@ +import Redis from "ioredis"; +import { DateTime } from "luxon"; +import winston from "winston"; +import { Job, Worker } from "bullmq"; +import { DataSource, entities } from "@repo/indexer-database"; +import { IndexerQueues } from "./service"; +import { ethers } from "ethers"; +import { findTokenByAddress, yesterday } from "../utils"; +// import { CoingeckoClient } from "../utils/coingeckoClient"; +import { RetryProvidersFactory } from "../web3/RetryProvidersFactory"; +import { assert } from "@repo/error-handling"; +import * as across from "@across-protocol/sdk"; +import * as ss from "superstruct"; + +export const PriceMessage = ss.object({ + fillEventId: ss.number(), +}); + +export type PriceMessage = ss.Infer; + +/** + * This worker listens to the `PriceQuery` queue and processes each job by: + * - Verifying the existence of the relay hash info and deposit records. + * - Determining the block time from the relay hash info and calculating the price time as the previous day's timestamp. + * - Identifying the base currency using the output token and destination chain ID. + * - Checking if a historic price for the base currency and quote currency (USD) already exists in the database. + * - If not, fetching the historic price from Coingecko and inserting it into the database. + * - Logging errors and information at various stages of the process. + */ +export class PriceWorker { + private worker: Worker; + private coingeckoClient: across.coingecko.Coingecko; + private relayHashInfoRepository; + private historicPriceRepository; + + constructor( + private redis: Redis, + private postgres: DataSource, + private logger: winston.Logger, + ) { + this.coingeckoClient = across.coingecko.Coingecko.get(logger); + this.relayHashInfoRepository = this.postgres.getRepository( + entities.RelayHashInfo, + ); + this.historicPriceRepository = this.postgres.getRepository( + entities.HistoricPrice, + ); + this.setWorker(); + } + private async getPrice( + address: string, + chainId: number, + time: Date, + quoteCurrency = "usd", + ): Promise { + const priceTime = yesterday(time); + const tokenInfo = findTokenByAddress(address, chainId); + const baseCurrency = tokenInfo.symbol; + + const cachedPrice = await this.historicPriceRepository.findOne({ + where: { + date: priceTime, + baseCurrency, + quoteCurrency, + }, + }); + // we have this price at this time in the db + if (cachedPrice) { + return Number(cachedPrice.price); + } + + const cgFormattedDate = + DateTime.fromJSDate(priceTime).toFormat("dd-LL-yyyy"); + const price = await this.coingeckoClient.getContractHistoricDayPrice( + address, + cgFormattedDate, + quoteCurrency, + chainId, + ); + assert( + price, + `Unable to fetch price for ${quoteCurrency} in ${baseCurrency}(${tokenInfo.coingeckoId}) at ${priceTime}`, + ); + // upsert to prevent conflicts with swap worker inserts + await this.historicPriceRepository.upsert( + { + date: priceTime, + baseCurrency, + quoteCurrency, + price: price.toString(), + }, + ["date", "baseCurrency", "quoteCurrency"], + ); + + return Number(price); + } + + public setWorker() { + this.worker = new Worker( + IndexerQueues.PriceQuery, + async (job: Job) => { + // validate data type + if (!ss.is(job.data, PriceMessage)) return; + try { + await this.run(job.data); + } catch (error) { + this.logger.error({ + at: "PriceWorker", + message: `Error getting price for fill on fill event id ${job.data.fillEventId}`, + error, + job, + }); + throw error; + } + }, + { connection: this.redis, concurrency: 10 }, + ); + } + // price is assumed to be a float, amount is assumed in wei and decimals is the conversion for that amount + // this outputs the difference between input and output normalized to the price which is typically usd + private static calculateBridgeFee( + inputToken: { amount: string; price: number; decimals: number }, + outputToken: { amount: string; price: number; decimals: number }, + ): string { + // Convert input token amount from string to BigInt for precise arithmetic operations + const inputAmountBigInt = BigInt(inputToken.amount); + // Convert output token amount from string to BigInt for precise arithmetic operations + const outputAmountBigInt = BigInt(outputToken.amount); + + // Convert input token price to BigInt by scaling it according to its decimals + // This involves rounding the price to the nearest integer after multiplying by 10^decimals + const inputPriceBigInt = BigInt( + Math.round(inputToken.price * Math.pow(10, 18)), + ); + // Convert output token price to BigInt by scaling it according to its decimals + // This involves rounding the price to the nearest integer after multiplying by 10^decimals + const outputPriceBigInt = BigInt( + Math.round(outputToken.price * Math.pow(10, 18)), + ); + + // Normalize the input amount by multiplying it with its price and dividing by 10^decimals + // This converts the amount to a common scale based on its price + const normalizedInputAmount = + (inputAmountBigInt * inputPriceBigInt) / + BigInt(Math.pow(10, inputToken.decimals)); + // Normalize the output amount by multiplying it with its price and dividing by 10^decimals + // This converts the amount to a common scale based on its price + const normalizedOutputAmount = + (outputAmountBigInt * outputPriceBigInt) / + BigInt(Math.pow(10, outputToken.decimals)); + + // Calculate the bridge fee by subtracting the normalized output amount from the normalized input amount + // This gives the difference in value between the input and output tokens + return ethers.utils.formatEther( + normalizedInputAmount - normalizedOutputAmount, + ); + } + private async run(params: PriceMessage) { + const { fillEventId } = params; + + const relayHashInfo = await this.relayHashInfoRepository.findOne({ + where: { fillEventId }, + relations: { + fillEvent: true, + }, + }); + + if (!relayHashInfo) { + const errorMessage = `Relay hash info not found by id ${fillEventId}`; + this.logger.error({ + at: "PriceWorker", + message: errorMessage, + ...params, + }); + // this should end the request if the entity cant be found by id. it will never be there + return; + } + + if (!relayHashInfo.fillEvent) { + const errorMessage = "Fill event not found for relay hash info."; + this.logger.error({ + at: "PriceWorker", + message: errorMessage, + ...params, + }); + return; + } + + if ( + relayHashInfo.bridgeFeeUsd && + relayHashInfo.inputPriceUsd && + relayHashInfo.outputPriceUsd + ) { + const errorMessage = "Skipping already processed relay hash"; + this.logger.error({ + at: "PriceWorker", + message: errorMessage, + ...params, + }); + return; + } + + // we are getting our price timestamp off fill event time rather than deposit, this should be pretty close to deposit, and we only look up previous 24 hour price anywyay + // if blockTimestamp doesnt exist, maybe we keep retrying till it does + const blockTime = relayHashInfo.fillEvent.blockTimestamp; + if (!blockTime) { + const errorMessage = "Block time not found for relay hash info."; + this.logger.error({ + at: "PriceWorker", + message: errorMessage, + ...params, + }); + throw new Error(errorMessage); + } + const inputTokenAddress = relayHashInfo.fillEvent.inputToken; + const outputTokenAddress = relayHashInfo.fillEvent.outputToken; + const destinationChainId = relayHashInfo.destinationChainId; + const inputTokenInfo = findTokenByAddress( + inputTokenAddress, + relayHashInfo.originChainId, + ); + const outputTokenInfo = findTokenByAddress( + outputTokenAddress, + destinationChainId, + ); + + const inputTokenPrice = await this.getPrice( + inputTokenAddress, + relayHashInfo.originChainId, + blockTime, + ); + const outputTokenPrice = await this.getPrice( + outputTokenAddress, + destinationChainId, + blockTime, + ); + + const inputToken = { + amount: relayHashInfo.fillEvent.inputAmount, + price: inputTokenPrice, + decimals: inputTokenInfo.decimals, + }; + + const outputToken = { + amount: relayHashInfo.fillEvent.outputAmount, + price: outputTokenPrice, + decimals: outputTokenInfo.decimals, + }; + + const bridgeFee = PriceWorker.calculateBridgeFee(inputToken, outputToken); + const updatedFields: Partial = {}; + + if (relayHashInfo.bridgeFeeUsd !== bridgeFee.toString()) { + updatedFields.bridgeFeeUsd = bridgeFee.toString(); + } + if (Number(relayHashInfo.inputPriceUsd) !== inputTokenPrice) { + updatedFields.inputPriceUsd = inputTokenPrice.toString(); + } + if (Number(relayHashInfo.outputPriceUsd) !== outputTokenPrice) { + updatedFields.outputPriceUsd = outputTokenPrice.toString(); + } + + if (Object.keys(updatedFields).length > 0) { + await this.relayHashInfoRepository.update({ fillEventId }, updatedFields); + this.logger.info({ + at: "PriceWorker#updateRelayHashInfo", + message: "Updated relay hash info with new fields", + params, + updatedFields, + }); + } + } + public async close() { + return this.worker.close(); + } +} diff --git a/packages/indexer/src/messaging/service.ts b/packages/indexer/src/messaging/service.ts index 9f23abfe..7597f64a 100644 --- a/packages/indexer/src/messaging/service.ts +++ b/packages/indexer/src/messaging/service.ts @@ -3,6 +3,8 @@ import { Queue, JobsOptions, BulkJobOptions } from "bullmq"; export enum IndexerQueues { IntegratorId = "IntegratorId", + PriceQuery = "PriceQuery", + SwapMessage = "SwapMessage", } export class IndexerQueuesService { diff --git a/packages/indexer/src/messaging/swapWorker.ts b/packages/indexer/src/messaging/swapWorker.ts new file mode 100644 index 00000000..62ca6e54 --- /dev/null +++ b/packages/indexer/src/messaging/swapWorker.ts @@ -0,0 +1,198 @@ +import Redis from "ioredis"; +import winston from "winston"; +import { DateTime } from "luxon"; +import { Job, Worker } from "bullmq"; +import * as across from "@across-protocol/sdk"; +import { DataSource, entities } from "@repo/indexer-database"; +import { IndexerQueues } from "./service"; +import { ethers } from "ethers"; +import { assert } from "@repo/error-handling"; +import { RetryProvidersFactory } from "../web3/RetryProvidersFactory"; +import * as s from "superstruct"; +import { findTokenByAddress, yesterday } from "../utils"; + +export const SwapMessage = s.object({ + // confusingly the deposit event entity database id is named depositEventId in relayhashinfo + // we want to point to the database id, not the on chain id + swapEventId: s.number(), +}); + +export type SwapMessage = s.Infer; + +export class SwapWorker { + private worker: Worker; + private depositRepository; + private historicPriceRepository; + private relayHashInfoRepository; + private swapBeforeBridgeRepository; + private coingeckoClient: across.coingecko.Coingecko; + + constructor( + private redis: Redis, + private postgres: DataSource, + private retryProvidersFactory: RetryProvidersFactory, + private logger: winston.Logger, + ) { + this.depositRepository = this.postgres.getRepository( + entities.V3FundsDeposited, + ); + this.historicPriceRepository = this.postgres.getRepository( + entities.HistoricPrice, + ); + this.relayHashInfoRepository = this.postgres.getRepository( + entities.RelayHashInfo, + ); + this.swapBeforeBridgeRepository = this.postgres.getRepository( + entities.SwapBeforeBridge, + ); + this.coingeckoClient = across.coingecko.Coingecko.get(logger); + this.setWorker(); + } + public setWorker() { + this.worker = new Worker( + IndexerQueues.SwapMessage, + async (job: Job) => { + const [error, data] = s.validate(job.data, SwapMessage); + if (error) { + this.logger.error({ + at: "SwapWorker", + message: "Invalid job data", + error, + }); + return; + } + try { + await this.run(data); + } catch (error) { + this.logger.error({ + at: "SwapWorker", + message: `Error getting swap infor for hash ${data.swapEventId}`, + error, + }); + throw error; + } + }, + { connection: this.redis, concurrency: 10 }, + ); + } + private async getPrice( + address: string, + chainId: number, + time: Date, + quoteCurrency = "usd", + ): Promise { + const priceTime = yesterday(time); + const tokenInfo = findTokenByAddress(address, chainId); + const baseCurrency = tokenInfo.symbol; + + const cachedPrice = await this.historicPriceRepository.findOne({ + where: { + date: priceTime, + baseCurrency, + quoteCurrency, + }, + }); + // we have this price at this time in the db + if (cachedPrice) { + return Number(cachedPrice.price); + } + + const cgFormattedDate = + DateTime.fromJSDate(priceTime).toFormat("dd-LL-yyyy"); + const price = await this.coingeckoClient.getContractHistoricDayPrice( + address, + cgFormattedDate, + quoteCurrency, + chainId, + ); + assert( + price, + `Unable to fetch price for ${quoteCurrency} in ${baseCurrency}(${tokenInfo.coingeckoId}) at ${priceTime}`, + ); + // upsert to prevent conflicts with price worker inserts + await this.historicPriceRepository.upsert( + { + date: priceTime, + baseCurrency, + quoteCurrency, + price: price.toString(), + }, + ["date", "baseCurrency", "quoteCurrency"], + ); + + return Number(price); + } + private async run(params: SwapMessage) { + const { swapEventId } = params; + const swapEvent = await this.swapBeforeBridgeRepository.findOneBy({ + id: swapEventId, + }); + + if (!swapEvent) { + this.logger.error({ + at: "SwapWorker", + message: `Swap event not found for id ${swapEventId}`, + }); + return; + } + + const { + acrossInputToken, + acrossOutputToken, + swapToken, + swapTokenAmount, + acrossInputAmount, + } = swapEvent; + const inputTokenInfo = findTokenByAddress( + acrossInputToken, + swapEvent.chainId, + ); + const outputTokenInfo = findTokenByAddress( + acrossOutputToken, + swapEvent.chainId, + ); + + const inputPriceUsd = await this.getPrice( + swapToken, + swapEvent.chainId, + swapEvent.blockTimestamp, + ); + const outputPriceUsd = await this.getPrice( + acrossInputToken, + swapEvent.chainId, + swapEvent.blockTimestamp, + ); + const swapInputTokenName = inputTokenInfo.name; + const swapOutputTokenName = outputTokenInfo.name; + // converting wei to normal float value before doing any more math + const swapInputAmountUsd = + Number( + ethers.utils.formatUnits(swapTokenAmount, inputTokenInfo.decimals), + ) * inputPriceUsd; + const swapOutputAmountUsd = + Number( + ethers.utils.formatUnits(acrossInputAmount, outputTokenInfo.decimals), + ) * outputPriceUsd; + const swapFeeUsdAmount = swapInputAmountUsd - swapOutputAmountUsd; + // this calculation is very innaccurate but gives us a ballpark of input tokens lost during swap + const swapFeeInputAmount = swapFeeUsdAmount / inputPriceUsd; + this.relayHashInfoRepository.update( + // this is deposit entity id, unique to database + { swapBeforeBridgeEventId: swapEventId }, + { + swapInputTokenName, + swapOutputTokenName, + swapFeeInputAmount: swapFeeInputAmount.toString(), + swapFeeUsdAmount: swapFeeUsdAmount.toString(), + }, + ), + this.logger.info({ + at: "SwapWorker", + message: "Updated relay hashinfo with swap data", + swapEventId, + }); + } + public async close() { + return this.worker.close(); + } +} diff --git a/packages/indexer/src/parseEnv.ts b/packages/indexer/src/parseEnv.ts index 4a61a5e4..592bdc8c 100644 --- a/packages/indexer/src/parseEnv.ts +++ b/packages/indexer/src/parseEnv.ts @@ -20,6 +20,7 @@ export type Config = { webhookConfig: WebhooksConfig; maxBlockRangeSize?: number; }; + export type RedisConfig = { host: string; port: number; @@ -30,11 +31,12 @@ export type ProviderConfig = [providerUrl: string, chainId: number]; export type Env = Record; export function parseRedisConfig(env: Env): RedisConfig { - assert(env.REDIS_HOST, "requires REDIS_HOST"); - assert(env.REDIS_PORT, "requires REDIS_PORT"); - const port = parseNumber(env.REDIS_PORT); + const { REDIS_HOST, REDIS_PORT } = env; + assert(REDIS_HOST, "requires REDIS_HOST"); + assert(REDIS_PORT, "requires REDIS_PORT"); + const port = parseNumber(REDIS_PORT); return { - host: env.REDIS_HOST, + host: REDIS_HOST, port, // @dev: this retry config is needed for bullmq workers maxRetriesPerRequest: null, diff --git a/packages/indexer/src/services/spokePoolProcessor.ts b/packages/indexer/src/services/spokePoolProcessor.ts index 323b5ecc..40ac738f 100644 --- a/packages/indexer/src/services/spokePoolProcessor.ts +++ b/packages/indexer/src/services/spokePoolProcessor.ts @@ -1,16 +1,20 @@ -import { utils } from "@across-protocol/sdk"; import winston from "winston"; import { DataSource, entities, utils as dbUtils, + InsertResult, + UpdateResult, SaveQueryResultType, } from "@repo/indexer-database"; import { WebhookTypes, eventProcessorManager } from "@repo/webhooks"; import { RelayStatus } from "../../../indexer-database/dist/src/entities"; -import { StoreEventsResult } from "../data-indexing/service/SpokePoolIndexerDataHandler"; +import { + DepositSwapPair, + StoreEventsResult, +} from "../data-indexing/service/SpokePoolIndexerDataHandler"; enum SpokePoolEvents { V3FundsDeposited = "V3FundsDeposited", @@ -19,8 +23,6 @@ enum SpokePoolEvents { } export class SpokePoolProcessor { - private queryBatchSize = 100; - constructor( private readonly postgres: DataSource, private readonly logger: winston.Logger, @@ -28,7 +30,10 @@ export class SpokePoolProcessor { private readonly webhookWriteFn?: eventProcessorManager.WebhookWriteFn, ) {} - public async process(events: StoreEventsResult) { + public async process( + events: StoreEventsResult, + depositSwapPairs: DepositSwapPair[], + ) { const newDeposits = dbUtils.filterSaveQueryResults( events.deposits, SaveQueryResultType.Inserted, @@ -38,13 +43,44 @@ export class SpokePoolProcessor { SaveQueryResultType.Updated, ); - const timeToAssignSpokeEventsStart = performance.now(); - await this.assignSpokeEventsToRelayHashInfo( - SpokePoolEvents.V3FundsDeposited, - [...newDeposits, ...updatedDeposits], + const newFills = dbUtils.filterSaveQueryResults( + events.fills, + SaveQueryResultType.Inserted, + ); + const updatedFills = dbUtils.filterSaveQueryResults( + events.fills, + SaveQueryResultType.Updated, ); - const timeToAssignSpokeEventsEnd = performance.now(); + const newSlowFillRequests = dbUtils.filterSaveQueryResults( + events.slowFillRequests, + SaveQueryResultType.Inserted, + ); + const updatedSlowFillRequests = dbUtils.filterSaveQueryResults( + events.slowFillRequests, + SaveQueryResultType.Updated, + ); + + // Assign events to relay hash info + const timeToAssignSpokeEventsToRelayHashInfoStart = performance.now(); + await this.assignSpokeEventsToRelayHashInfo({ + deposits: [...newDeposits, ...updatedDeposits], + fills: [...newFills, ...updatedFills], + slowFillRequests: [...newSlowFillRequests, ...updatedSlowFillRequests], + }); + const timeToAssignSpokeEventsToRelayHashInfoEnd = performance.now(); + + // Update expired deposits + const timeToUpdateExpiredRelaysStart = performance.now(); + const expiredDeposits = await this.updateExpiredRelays(); + const timeToUpdateExpiredRelaysEnd = performance.now(); + + // Update refunded deposits + const timeToUpdateRefundedDepositsStart = performance.now(); + const refundedDeposits = await this.updateRefundedDepositsStatus(); + const timeToUpdateRefundedDepositsEnd = performance.now(); + + // Send webhook notifications // Notify webhook of new deposits newDeposits.forEach((deposit) => { this.webhookWriteFn?.({ @@ -57,21 +93,6 @@ export class SpokePoolProcessor { }, }); }); - const newSlowFillRequests = dbUtils.filterSaveQueryResults( - events.slowFillRequests, - SaveQueryResultType.Inserted, - ); - const updatedSlowFillRequests = dbUtils.filterSaveQueryResults( - events.slowFillRequests, - SaveQueryResultType.Updated, - ); - - const timeToAssignSpokeEventsToRelayHashInfoStart = performance.now(); - await this.assignSpokeEventsToRelayHashInfo( - SpokePoolEvents.RequestedV3SlowFill, - [...newSlowFillRequests, ...updatedSlowFillRequests], - ); - const timeToAssignSpokeEventsToRelayHashInfoEnd = performance.now(); // Notify webhook of new slow fill requests newSlowFillRequests.forEach((deposit) => { @@ -86,19 +107,6 @@ export class SpokePoolProcessor { }); }); - const newFills = dbUtils.filterSaveQueryResults( - events.fills, - SaveQueryResultType.Inserted, - ); - const updatedFills = dbUtils.filterSaveQueryResults( - events.fills, - SaveQueryResultType.Updated, - ); - await this.assignSpokeEventsToRelayHashInfo(SpokePoolEvents.FilledV3Relay, [ - ...newFills, - ...updatedFills, - ]); - // Notify webhook of new fills newFills.forEach((fill) => { this.webhookWriteFn?.({ @@ -112,10 +120,6 @@ export class SpokePoolProcessor { }); }); - const timeToUpdateExpiredRelaysStart = performance.now(); - const expiredDeposits = await this.updateExpiredRelays(); - const timeToUpdateExpiredRelaysEnd = performance.now(); - // Notify webhook of expired deposits expiredDeposits.forEach((deposit) => { this.webhookWriteFn?.({ @@ -129,10 +133,6 @@ export class SpokePoolProcessor { }); }); - const timeToUpdateRefundedDepositsStart = performance.now(); - const refundedDeposits = await this.updateRefundedDepositsStatus(); - const timeToUpdateRefundedDepositsEnd = performance.now(); - // Notify webhook of refunded deposits refundedDeposits.forEach((deposit) => { this.webhookWriteFn?.({ @@ -146,12 +146,12 @@ export class SpokePoolProcessor { }); }); + await this.assignSwapEventToRelayHashInfo(depositSwapPairs); + this.logger.debug({ at: "Indexer#SpokePoolProcessor#process", message: "System Time Log for SpokePoolProcessor#process", spokeChainId: this.chainId, - timeToAssignSpokeEvents: - timeToAssignSpokeEventsEnd - timeToAssignSpokeEventsStart, timeToAssignSpokeEventsToRelayHashInfo: timeToAssignSpokeEventsToRelayHashInfoEnd - timeToAssignSpokeEventsToRelayHashInfoStart, @@ -159,66 +159,296 @@ export class SpokePoolProcessor { timeToUpdateExpiredRelaysEnd - timeToUpdateExpiredRelaysStart, timeToUpdateRefundedDeposits: timeToUpdateRefundedDepositsEnd - timeToUpdateRefundedDepositsStart, - totalTime: timeToUpdateRefundedDepositsEnd - timeToAssignSpokeEventsStart, + totalTime: + timeToUpdateRefundedDepositsEnd - + timeToAssignSpokeEventsToRelayHashInfoStart, }); } /** * Updates relayHashInfo table to include recently stored events - * @param events An array of already stored deposits, fills or slow fill requests + * @param events An object with stored deposits, fills and slow fill requests * @returns A void promise */ - private async assignSpokeEventsToRelayHashInfo( - eventType: SpokePoolEvents, - events: - | entities.V3FundsDeposited[] - | entities.FilledV3Relay[] - | entities.RequestedV3SlowFill[], + private async assignSpokeEventsToRelayHashInfo(events: { + deposits: entities.V3FundsDeposited[]; + fills: entities.FilledV3Relay[]; + slowFillRequests: entities.RequestedV3SlowFill[]; + }): Promise { + await Promise.all([ + this.assignDepositEventsToRelayHashInfo(events.deposits), + this.assignFillEventsToRelayHashInfo(events.fills), + this.assignSlowFillRequestedEventsToRelayHashInfo( + events.slowFillRequests, + ), + ]); + } + + /** + * Updates relayHashInfo table to include recently stored deposits + * @param events An array of already stored deposits + * @returns A void promise + */ + private async assignDepositEventsToRelayHashInfo( + events: entities.V3FundsDeposited[], ): Promise { - const relayHashInfoRepository = this.postgres.getRepository( - entities.RelayHashInfo, - ); - const eventTypeToField = { - [SpokePoolEvents.V3FundsDeposited]: "depositEventId", - [SpokePoolEvents.FilledV3Relay]: "fillEventId", - [SpokePoolEvents.RequestedV3SlowFill]: "requestSlowFillEventId", - }; - const data = events.map((event) => { - const eventField = eventTypeToField[eventType]; - return { - relayHash: event.relayHash, - depositId: event.depositId, - originChainId: event.originChainId, - destinationChainId: event.destinationChainId, - fillDeadline: event.fillDeadline, - [eventField]: event.id, - ...(eventType === SpokePoolEvents.V3FundsDeposited && { + const insertResults: InsertResult[] = []; + const updateResults: UpdateResult[] = []; + await Promise.all( + events.map(async (event) => { + // Format from event to relayHashInfo row + const item = { + relayHash: event.relayHash, + depositId: event.depositId, + originChainId: event.originChainId, + destinationChainId: event.destinationChainId, + fillDeadline: event.fillDeadline, + depositEventId: event.id, depositTxHash: event.transactionHash, - }), - ...(eventType === SpokePoolEvents.FilledV3Relay && { - status: RelayStatus.Filled, + }; + + // Start a transaction + const queryRunner = this.postgres.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + const relayHashInfoRepository = queryRunner.manager.getRepository( + entities.RelayHashInfo, + ); + try { + // Convert relayHash into a 32-bit integer for database lock usage + const lockKey = this.relayHashToInt32(item.relayHash); + // Acquire a lock to prevent concurrent modifications on the same relayHash. + await queryRunner.query(`SELECT pg_advisory_xact_lock($2, $1)`, [ + item.originChainId, + lockKey, + ]); + + // Retrieve an existing entry that either: + // - Matches the relayHash and has no associated depositEventId. + // - Matches both relayHash and depositEventId. + const existingRow = await relayHashInfoRepository + .createQueryBuilder() + .where('"relayHash" = :itemRelayHash', { + itemRelayHash: item.relayHash, + }) + .andWhere( + '"depositEventId" IS NULL OR "depositEventId" = :itemEventId', + { itemEventId: item.depositEventId }, + ) + .getOne(); + + // Insert a new record if no matching entry is found. + if (!existingRow) { + const insertedRow = await relayHashInfoRepository.insert(item); + insertResults.push(insertedRow); + } else { + // Update the existing row if a match is found. + const updatedRow = await relayHashInfoRepository.update( + { id: existingRow.id, relayHash: item.relayHash }, + item, + ); + updateResults.push(updatedRow); + } + await queryRunner.commitTransaction(); + } catch (error) { + await queryRunner.rollbackTransaction(); + throw error; + } finally { + // Release transaction resources; locks acquired will be automatically released. + await queryRunner.release(); + } + }), + ); + + this.logRelayHashInfoAssignmentResult( + SpokePoolEvents.V3FundsDeposited, + insertResults, + updateResults, + ); + } + + /** + * Updates relayHashInfo table to include recently stored fills + * @param events An array of already stored fills + * @returns A void promise + */ + private async assignFillEventsToRelayHashInfo( + events: entities.FilledV3Relay[], + ): Promise { + const insertResults: InsertResult[] = []; + const updateResults: UpdateResult[] = []; + await Promise.all( + events.map(async (event) => { + // Format from event to relayHashInfo row + const item = { + relayHash: event.relayHash, + depositId: event.depositId, + originChainId: event.originChainId, + destinationChainId: event.destinationChainId, + fillDeadline: event.fillDeadline, + fillEventId: event.id, + status: RelayStatus.Filled, // Mark the status as filled. fillTxHash: event.transactionHash, - }), - ...(eventType === SpokePoolEvents.RequestedV3SlowFill && { - status: RelayStatus.SlowFillRequested, - }), - }; - }); + }; - const upsertResults = []; - for (const item of data) { - upsertResults.push( - await relayHashInfoRepository.upsert(item, ["relayHash"]), - ); - } + // Start a transaction + const queryRunner = this.postgres.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + const relayHashInfoRepository = queryRunner.manager.getRepository( + entities.RelayHashInfo, + ); + + try { + // Convert relayHash into a 32-bit integer for database lock usage + const lockKey = this.relayHashToInt32(item.relayHash); + // Acquire a lock to prevent concurrent modifications on the same relayHash. + await queryRunner.query(`SELECT pg_advisory_xact_lock($2, $1)`, [ + item.originChainId, + lockKey, + ]); + + // Retrieve an existing entry based on the relayHash. + // If multiple rows exist, prioritize updating the one from the first deposit event indexed. + const existingRow = await relayHashInfoRepository + .createQueryBuilder() + .where(`"relayHash" = :itemRelayHash`, { + itemRelayHash: item.relayHash, + }) + .orderBy('"depositEventId"', "ASC") + .getOne(); + + // Insert a new record if no matching entry is found. + if (!existingRow) { + const insertedRow = await relayHashInfoRepository.insert(item); + insertResults.push(insertedRow); + } else { + // Update the existing row if a match is found. + const updatedRow = await relayHashInfoRepository.update( + { id: existingRow.id, relayHash: item.relayHash }, + item, + ); + updateResults.push(updatedRow); + } + await queryRunner.commitTransaction(); + } catch (error) { + await queryRunner.rollbackTransaction(); + throw error; + } finally { + // Release transaction resources; locks acquired will be automatically released. + await queryRunner.release(); + } + }), + ); + + this.logRelayHashInfoAssignmentResult( + SpokePoolEvents.FilledV3Relay, + insertResults, + updateResults, + ); + } + + /** + * Updates relayHashInfo table to include recently requested slow fill events + * @param events An array of already stored requested slow fills + * @returns A void promise + */ + private async assignSlowFillRequestedEventsToRelayHashInfo( + events: entities.RequestedV3SlowFill[], + ): Promise { + const insertResults: InsertResult[] = []; + const updateResults: UpdateResult[] = []; + await Promise.all( + events.map(async (event) => { + // Format from event to relayHashInfo row + const item = { + relayHash: event.relayHash, + depositId: event.depositId, + originChainId: event.originChainId, + destinationChainId: event.destinationChainId, + fillDeadline: event.fillDeadline, + slowFillRequestEventId: event.id, + }; + + // Start a transaction + const queryRunner = this.postgres.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + const relayHashInfoRepository = queryRunner.manager.getRepository( + entities.RelayHashInfo, + ); + + try { + // Convert relayHash into a 32-bit integer for database lock usage + const lockKey = this.relayHashToInt32(item.relayHash); + // Acquire a lock to prevent concurrent modifications on the same relayHash. + await queryRunner.query(`SELECT pg_advisory_xact_lock($2, $1)`, [ + item.originChainId, + lockKey, + ]); + + // Retrieve an existing entry based on the relayHash. + // If multiple rows exist, prioritize updating the one from the first deposit event indexed. + const existingRow = await relayHashInfoRepository + .createQueryBuilder() + .where(`"relayHash" = :itemRelayHash`, { + itemRelayHash: item.relayHash, + }) + .orderBy('"depositEventId"', "ASC") + .getOne(); + // Insert a new record if no matching entry is found. + if (!existingRow) { + const insertedRow = await relayHashInfoRepository.insert({ + ...item, + status: RelayStatus.SlowFillRequested, + }); + insertResults.push(insertedRow); + } else { + // Update the existing row if a match is found. + const updatedRow = await relayHashInfoRepository.update( + { id: existingRow.id, relayHash: item.relayHash }, + { + ...item, + // Update status to SlowFillRequested only if it is not already marked as Filled. + ...(existingRow.status !== RelayStatus.Filled && { + status: RelayStatus.SlowFillRequested, + }), + }, + ); + updateResults.push(updatedRow); + } + await queryRunner.commitTransaction(); + } catch (error) { + await queryRunner.rollbackTransaction(); + throw error; + } finally { + // Release transaction resources; locks acquired will be automatically released. + await queryRunner.release(); + } + }), + ); + + this.logRelayHashInfoAssignmentResult( + SpokePoolEvents.RequestedV3SlowFill, + insertResults, + updateResults, + ); + } + + private logRelayHashInfoAssignmentResult( + eventType: SpokePoolEvents, + insertResults: InsertResult[], + updateResults: UpdateResult[], + ) { this.logger.debug({ at: "Indexer#SpokePoolProcessor#assignSpokeEventsToRelayHashInfo", message: `${eventType} events associated with RelayHashInfo`, - updatedRelayHashInfoRows: upsertResults.reduce( + insertedRows: insertResults.reduce( (acc, res) => acc + res.generatedMaps.length, 0, ), + updatedRows: updateResults.reduce((acc, res) => acc + res.affected!, 0), }); } @@ -351,4 +581,52 @@ export class SpokePoolProcessor { } return updatedRows; } + + /** + * Generates a 32bit integer based on an input string + */ + private relayHashToInt32(relayHash: string): number { + let hash = 0; + let chr; + + // If the input string is empty, return 0 + if (relayHash.length === 0) return hash; + + // Loop through each character in the string + for (let i = 0; i < relayHash.length; i++) { + // Get the Unicode value of the character + chr = relayHash.charCodeAt(i); + + // Perform bitwise operations to generate a hash + // This shifts the hash left by 5 bits, subtracts itself, and adds the character code + hash = (hash << 5) - hash + chr; + + // Convert the result into a 32-bit integer by forcing it into the signed integer range + hash |= 0; + } + + // Return the final computed 32-bit integer hash + return hash; + } + + /* + * Assigns the swap event to the relay hash info + */ + private async assignSwapEventToRelayHashInfo( + depositSwapPairs: DepositSwapPair[], + ) { + const relayHashInfoRepository = this.postgres.getRepository( + entities.RelayHashInfo, + ); + await Promise.all( + depositSwapPairs.map(async (depositSwapPair) => { + await relayHashInfoRepository.update( + { depositEventId: depositSwapPair.deposit.id }, + { + swapBeforeBridgeEventId: depositSwapPair.swapBeforeBridge.id, + }, + ); + }), + ); + } } diff --git a/packages/indexer/src/test/priceWorker.test.ts b/packages/indexer/src/test/priceWorker.test.ts new file mode 100644 index 00000000..1bb8fe13 --- /dev/null +++ b/packages/indexer/src/test/priceWorker.test.ts @@ -0,0 +1,68 @@ +import { expect } from "chai"; +import { PriceWorker } from "../messaging/priceWorker"; + +describe("PriceWorker", function () { + describe("calculateBridgeFee", function () { + it("should correctly calculate the bridge fee", function () { + const inputToken = { + amount: "1000000000000000000", // 1 token in wei + price: 1, // $1 per token + decimals: 18, + }; + + const outputToken = { + amount: "500000000000000000", // 0.5 token in wei + price: 1, // $1 per token + decimals: 18, + }; + + const bridgeFee = PriceWorker["calculateBridgeFee"]( + inputToken, + outputToken, + ); + expect(bridgeFee).to.equal("0.5"); // Expecting a bridge fee of $0.5 + }); + + it("should return zero bridge fee when input and output values are equal", function () { + const inputToken = { + amount: "1000000000000000000", // 1 token in wei + price: 2, // $2 per token + decimals: 18, + }; + + const outputToken = { + amount: "1000000000000000000", // 1 token in wei + price: 2, // $2 per token + decimals: 18, + }; + + const bridgeFee = PriceWorker["calculateBridgeFee"]( + inputToken, + outputToken, + ); + expect(bridgeFee).to.equal("0.0"); // Expecting a bridge fee of $0.0 + }); + + it("should correctly calculate the bridge fee with different decimals", function () { + const inputToken = { + amount: "10000000000000000000", // 10 token in wei + price: 2, // $2 per token + decimals: 18, + }; + + const outputToken = { + amount: "5000000000", // 5 tokens in smaller unit + price: 3, // $3 per token + decimals: 9, + }; + // 10 * 2 = 20 + // 5 * 3 = 15 + // 20 - 15 = 5 + const bridgeFee = PriceWorker["calculateBridgeFee"]( + inputToken, + outputToken, + ); + expect(bridgeFee).to.equal("5.0"); // Expecting a bridge fee of $5.0 + }); + }); +}); diff --git a/packages/indexer/src/utils/currencyUtils.ts b/packages/indexer/src/utils/currencyUtils.ts new file mode 100644 index 00000000..ea85aa38 --- /dev/null +++ b/packages/indexer/src/utils/currencyUtils.ts @@ -0,0 +1,58 @@ +import * as constants from "@across-protocol/constants"; +import { DateTime } from "luxon"; +// Convert now to a consistent price timestamp yesterday for lookup purposes +export function yesterday(now: Date) { + // theres a slight wrinkle when using coingecko, if the time falls within 12-3AM we must subtract 2 days, rather than 1 + const utcHour = DateTime.fromJSDate(now).toUTC().hour; + const daysToSubtract = utcHour >= 0 && utcHour < 3 ? 2 : 1; + return DateTime.fromJSDate(now).minus({ days: daysToSubtract }).toJSDate(); +} + +export type TokenInfo = { + name: string; + symbol: string; + decimals: number; + addresses: Record; + coingeckoId: string; +}; +export type Token = { + name: string; + symbol: string; + decimals: number; + address: string; + chainId: number; + coingeckoId: string; +}; +// mapping the token constants to something easier to search +export const tokenSymbolsMap = [ + ...Object.values(constants.TOKEN_SYMBOLS_MAP), +] as TokenInfo[]; +// map to just a flat list +export const tokensList = tokenSymbolsMap.reduce((result, token) => { + Object.entries(token.addresses).forEach(([chainId, address]) => { + result.push({ + name: token.name, + symbol: token.symbol, + decimals: token.decimals, + chainId: Number(chainId), + address: address, + coingeckoId: token.coingeckoId, + }); + }); + return result; +}, [] as Token[]); + +// given an address and chain id, return the token data +export function findTokenByAddress(address: string, chainId: number): Token { + const result = tokensList.find( + (token) => + token.address.toLowerCase() === address.toLowerCase() && + token.chainId === chainId, + ); + if (!result) { + throw new Error( + `Token info not found for address: ${address} on chainId: ${chainId}`, + ); + } + return result; +} diff --git a/packages/indexer/src/utils/index.ts b/packages/indexer/src/utils/index.ts index 1faf5dc2..6cb2d1a9 100644 --- a/packages/indexer/src/utils/index.ts +++ b/packages/indexer/src/utils/index.ts @@ -2,3 +2,4 @@ export * from "./contractUtils"; export * from "./contractFactoryUtils"; export * from "./bundleBuilderUtils"; export * from "./spokePoolUtils"; +export * from "./currencyUtils"; diff --git a/packages/indexer/src/web3/EventDecoder.ts b/packages/indexer/src/web3/EventDecoder.ts new file mode 100644 index 00000000..68fe50a4 --- /dev/null +++ b/packages/indexer/src/web3/EventDecoder.ts @@ -0,0 +1,48 @@ +import { ethers } from "ethers"; +import * as abi from "./abi"; +import { SwapBeforeBridgeEvent } from "./model/events"; + +export class EventDecoder { + static decodeSwapBeforeBridgeEvents( + receipt: ethers.providers.TransactionReceipt, + ) { + const swapBeforeBridgeEventTopic = + "0x646284e396b68ff4b4f34e0aa97bcdb9c100f5b44a20da5c475f627039853841"; + const events: SwapBeforeBridgeEvent[] = this.decodeTransactionReceiptLogs( + receipt, + swapBeforeBridgeEventTopic, + abi.SwapAndBridgeAbi, + ); + + return events; + } + + static decodeTransactionReceiptLogs( + receipt: ethers.providers.TransactionReceipt, + eventTopic: string, + abi: any, + ) { + const events: (ethers.providers.Log & { args: any })[] = []; + + for (const log of receipt.logs) { + const contractInterface = new ethers.utils.Interface(abi); + + if (log.topics.length === 0) continue; + + try { + const parsedLog = contractInterface.parseLog(log); + if (parsedLog && log.topics[0] === eventTopic) { + events.push({ ...log, args: parsedLog.args }); + } + } catch (e: any) { + if (e.reason === "no matching event" && e.code === "INVALID_ARGUMENT") { + continue; + } else { + throw e; + } + } + } + + return events; + } +} diff --git a/packages/indexer/src/web3/abi/SwapAndBridge.ts b/packages/indexer/src/web3/abi/SwapAndBridge.ts new file mode 100644 index 00000000..d6b5a832 --- /dev/null +++ b/packages/indexer/src/web3/abi/SwapAndBridge.ts @@ -0,0 +1,267 @@ +export const SwapAndBridgeAbi = [ + { + inputs: [ + { + internalType: "contract V3SpokePoolInterface", + name: "_spokePool", + type: "address", + }, + { + internalType: "address", + name: "_exchange", + type: "address", + }, + { + internalType: "bytes4[]", + name: "_allowedSelectors", + type: "bytes4[]", + }, + { + internalType: "contract IERC20", + name: "_swapToken", + type: "address", + }, + { + internalType: "contract IERC20", + name: "_acrossInputToken", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "InvalidFunctionSelector", + type: "error", + }, + { + inputs: [], + name: "LeftoverSrcTokens", + type: "error", + }, + { + inputs: [], + name: "MinimumExpectedInputAmount", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "exchange", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "swapToken", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "acrossInputToken", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "swapTokenAmount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "acrossInputAmount", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "acrossOutputToken", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "acrossOutputAmount", + type: "uint256", + }, + ], + name: "SwapBeforeBridge", + type: "event", + }, + { + inputs: [], + name: "ACROSS_INPUT_TOKEN", + outputs: [ + { + internalType: "contract IERC20", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "EXCHANGE", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "SPOKE_POOL", + outputs: [ + { + internalType: "contract V3SpokePoolInterface", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "SWAP_TOKEN", + outputs: [ + { + internalType: "contract IERC20", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes4", + name: "", + type: "bytes4", + }, + ], + name: "allowedSelectors", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes[]", + name: "data", + type: "bytes[]", + }, + ], + name: "multicall", + outputs: [ + { + internalType: "bytes[]", + name: "results", + type: "bytes[]", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "routerCalldata", + type: "bytes", + }, + { + internalType: "uint256", + name: "swapTokenAmount", + type: "uint256", + }, + { + internalType: "uint256", + name: "minExpectedInputTokenAmount", + type: "uint256", + }, + { + components: [ + { + internalType: "address", + name: "outputToken", + type: "address", + }, + { + internalType: "uint256", + name: "outputAmount", + type: "uint256", + }, + { + internalType: "address", + name: "depositor", + type: "address", + }, + { + internalType: "address", + name: "recipient", + type: "address", + }, + { + internalType: "uint256", + name: "destinationChainid", + type: "uint256", + }, + { + internalType: "address", + name: "exclusiveRelayer", + type: "address", + }, + { + internalType: "uint32", + name: "quoteTimestamp", + type: "uint32", + }, + { + internalType: "uint32", + name: "fillDeadline", + type: "uint32", + }, + { + internalType: "uint32", + name: "exclusivityDeadline", + type: "uint32", + }, + { + internalType: "bytes", + name: "message", + type: "bytes", + }, + ], + internalType: "struct SwapAndBridgeBase.DepositData", + name: "depositData", + type: "tuple", + }, + ], + name: "swapAndBridge", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +]; diff --git a/packages/indexer/src/web3/abi/index.ts b/packages/indexer/src/web3/abi/index.ts new file mode 100644 index 00000000..c2783849 --- /dev/null +++ b/packages/indexer/src/web3/abi/index.ts @@ -0,0 +1 @@ +export { SwapAndBridgeAbi } from "./SwapAndBridge"; diff --git a/packages/indexer/src/web3/model/events.ts b/packages/indexer/src/web3/model/events.ts new file mode 100644 index 00000000..d6fe2e94 --- /dev/null +++ b/packages/indexer/src/web3/model/events.ts @@ -0,0 +1,13 @@ +import { BigNumber, providers } from "ethers"; + +export interface SwapBeforeBridgeEvent extends providers.Log { + args: { + swapToken: string; + acrossInputToken: string; + acrossOutputToken: string; + swapTokenAmount: BigNumber; + acrossInputAmount: BigNumber; + acrossOutputAmount: BigNumber; + exchange: string; + }; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be26746d..d69cdb0b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,8 +152,8 @@ importers: specifier: ^3.0.23 version: 3.0.23(@babel/core@7.25.2)(@ethersproject/abi@5.7.0)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) '@across-protocol/sdk': - specifier: ^3.3.23 - version: 3.3.23(@babel/core@7.25.2)(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(@ethersproject/abi@5.7.0)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) + specifier: ^3.4.15 + version: 3.4.15(@babel/core@7.25.2)(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(@ethersproject/abi@5.7.0)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) '@repo/error-handling': specifier: workspace:* version: link:../error-handling @@ -166,6 +166,9 @@ importers: '@types/lodash': specifier: ^4.17.7 version: 4.17.7 + '@types/luxon': + specifier: ^3.4.2 + version: 3.4.2 bullmq: specifier: ^5.12.12 version: 5.12.14 @@ -184,6 +187,9 @@ importers: lodash: specifier: ^4.17.21 version: 4.17.21 + luxon: + specifier: ^3.5.0 + version: 3.5.0 redis: specifier: ^4.7.0 version: 4.7.0 @@ -331,8 +337,8 @@ importers: packages/indexer-database: dependencies: '@across-protocol/sdk': - specifier: ^3.3.23 - version: 3.3.23(@babel/core@7.25.2)(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) + specifier: ^3.4.15 + version: 3.4.15(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(@ethersproject/abi@5.7.0)(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) pg: specifier: ^8.4.0 version: 8.12.0 @@ -597,6 +603,9 @@ packages: '@across-protocol/constants@3.1.28': resolution: {integrity: sha512-rnI1pQgkJ6+hPIQNomsi8eQreVfWKfFn9i9Z39U0fAnoXodZklW0eqj5N0cXlEfahp5j2u1RCs7s6fQ9megCdw==} + '@across-protocol/constants@3.1.31': + resolution: {integrity: sha512-gvVYfJkeipZaYITJruSvupZdzCro/H1jVE1m2K16/lIqH7oKfJbNhBqT5ytc3R012MtY1oUxPdCgNIVSJz3VDw==} + '@across-protocol/contracts@0.1.4': resolution: {integrity: sha512-y9FVRSFdPgEdGWBcf8rUmmzdYhzGdy0752HwpaAFtMJ1pn+HFgNaI0EZc/UudMKIPOkk+/BxPIHYPy7tKad5/A==} @@ -606,9 +615,15 @@ packages: peerDependencies: buffer-layout: ^1.2.2 - '@across-protocol/sdk@3.3.23': - resolution: {integrity: sha512-1AVVE8Z3rCjPDu/HAqAe2sErQXm+vbBz7VuVZPVmzdlLAHKAaAFOqtmWUNJg3iPYAkfAAjfoykBT48APDWRkfg==} + '@across-protocol/contracts@3.0.25': + resolution: {integrity: sha512-OwBxylXAzujUJCGbENyBki0yUryJJAb4v7i69nri+psyJr8MA8LhiiOIVhw+jIUeukBeY8uKF+AI7fzlewwFvA==} engines: {node: '>=16.18.0'} + peerDependencies: + buffer-layout: ^1.2.2 + + '@across-protocol/sdk@3.4.15': + resolution: {integrity: sha512-0ICm525mIBr+H7XrjY9M7Jo59P8Xvmu//85t0TZrcJlrn/qrDRetyst2nAFTb4CRZlJafJFKtvIieuClAqjTEg==} + engines: {node: '>=20.18.0'} '@adraffy/ens-normalize@1.11.0': resolution: {integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==} @@ -1397,6 +1412,7 @@ packages: '@pinata/sdk@2.1.0': resolution: {integrity: sha512-hkS0tcKtsjf9xhsEBs2Nbey5s+Db7x5rlOH9TaWHBXkJ7IwwOs2xnEDigNaxAHKjYAwcw+m2hzpO5QgOfeF7Zw==} + deprecated: Please install the new IPFS SDK at pinata-web3. More information at https://docs.pinata.cloud/web3/sdk '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} @@ -1815,6 +1831,9 @@ packages: '@types/lru-cache@5.1.1': resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} + '@types/luxon@3.4.2': + resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==} + '@types/markdown-it@14.1.2': resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} @@ -2063,26 +2082,26 @@ packages: resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} engines: {node: ^18.18.0 || >=20.0.0} - '@uma/common@2.37.1': - resolution: {integrity: sha512-gUZfpoBJRU4pMHnlNlcxMMRPnBlH/K4cZ8b4R6UewxvUbxbBNktV6KC4A2bkZ0AS9IQRzNGHToZJg//0cbqULw==} - '@uma/common@2.37.3': resolution: {integrity: sha512-DLcM2xtiFWDbty21r2gsL6AJbOc8G/CMqg0iMxssvkKbz8varsWS44zJF85XGxMlY8fE40w0ZS8MR92xpbsu4g==} - '@uma/contracts-frontend@0.4.23': - resolution: {integrity: sha512-x0kS05uIZbpz/DP1TjvYNLR5h/PWNbb5pNa4FisVTmDL5F/FQuLZX7Mf+rh3zBApm37U4NkvrAcIyIQ1eqSGdA==} + '@uma/contracts-frontend@0.4.25': + resolution: {integrity: sha512-LfkMw0lO+H+hUPevoAFogVu5iJTXp+Q2ChddqiynvvrwZ/lrNHrOjj0uEX1winjJXTLFs78jBK1AsIkkYK2VTQ==} '@uma/contracts-node@0.4.23': resolution: {integrity: sha512-W0mBb0pp5mXfLgsqXAIQUU3nqUMAsRKbrM6FfWAjmswe7PrMBlUq3fgpd+Fw1S6T0egKhe+zABYoU8H3ROJAUw==} + '@uma/contracts-node@0.4.25': + resolution: {integrity: sha512-WaFojX4qyMmXpy5MBS7g0M0KnWESGusdSfTmlkZpCh65TksGaJwAyOM1YBRLL3xm3xSgxPoG+n6tTilSomUmOw==} + '@uma/core@2.61.0': resolution: {integrity: sha512-bnk+CWW+uWpRilrgUny/gDXHKomG+h1Ug84OXdx+AAvj1/BtlMDOCNNt1OX8LSAz+a0hkiN9s24/zgHclTC/sg==} '@uma/logger@1.3.0': resolution: {integrity: sha512-8lCSA7kvH34kbp652toM9ZtANEW1bxT8NLyFSTZlegcHgQ1opR+GepTKerrOLU7SKdOJY1P0ZWCQN5vUKxrdHA==} - '@uma/sdk@0.34.8': - resolution: {integrity: sha512-/aYmJBS46r1LPtBXMYnzvgAaF9opy0PeKontPRUV50mU/wCAd3yHdVVNpPiq73IYfYVweJ2K8XpblVBC97rzZA==} + '@uma/sdk@0.34.10': + resolution: {integrity: sha512-Jo64XpbCxquuPIIktQCWFMNN/vCTyA1SbVXMrlmXgO7NAtPPMyPBlsKJr+N0/QrqymBQcO5wzdmo+EqJaeKIHw==} engines: {node: '>=14'} peerDependencies: '@eth-optimism/contracts': ^0.5.40 @@ -4044,10 +4063,6 @@ packages: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} engines: {node: '>= 0.12'} - form-data@2.5.1: - resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==} - engines: {node: '>= 0.12'} - form-data@2.5.2: resolution: {integrity: sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q==} engines: {node: '>= 0.12'} @@ -5133,6 +5148,7 @@ packages: lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. lodash.isarguments@3.1.0: resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} @@ -8093,11 +8109,11 @@ packages: snapshots: - '@across-protocol/across-token@1.0.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)': + '@across-protocol/across-token@1.0.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)': dependencies: '@openzeppelin/contracts': 4.9.6 - '@uma/common': 2.37.1(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) - hardhat: 2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) + '@uma/common': 2.37.3(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) + hardhat: 2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) transitivePeerDependencies: - '@babel/core' - '@codechecks/client' @@ -8114,11 +8130,11 @@ snapshots: - typescript - utf-8-validate - '@across-protocol/across-token@1.0.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)': + '@across-protocol/across-token@1.0.0(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)': dependencies: '@openzeppelin/contracts': 4.9.6 - '@uma/common': 2.37.1(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) - hardhat: 2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) + '@uma/common': 2.37.3(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + hardhat: 2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) transitivePeerDependencies: - '@babel/core' - '@codechecks/client' @@ -8137,11 +8153,13 @@ snapshots: '@across-protocol/constants@3.1.28': {} - '@across-protocol/contracts@0.1.4(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': + '@across-protocol/constants@3.1.31': {} + + '@across-protocol/contracts@0.1.4(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': dependencies: '@eth-optimism/contracts': 0.5.40(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@openzeppelin/contracts': 4.1.0 - '@uma/core': 2.61.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) + '@uma/core': 2.61.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) transitivePeerDependencies: - '@babel/core' - '@codechecks/client' @@ -8156,11 +8174,11 @@ snapshots: - typechain - utf-8-validate - '@across-protocol/contracts@0.1.4(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': + '@across-protocol/contracts@0.1.4(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10)': dependencies: '@eth-optimism/contracts': 0.5.40(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@openzeppelin/contracts': 4.1.0 - '@uma/core': 2.61.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) + '@uma/core': 2.61.0(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) transitivePeerDependencies: - '@babel/core' - '@codechecks/client' @@ -8219,9 +8237,9 @@ snapshots: - typescript - utf-8-validate - '@across-protocol/contracts@3.0.23(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)': + '@across-protocol/contracts@3.0.25(@babel/core@7.25.2)(@ethersproject/abi@5.7.0)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)': dependencies: - '@across-protocol/constants': 3.1.28 + '@across-protocol/constants': 3.1.31 '@coral-xyz/anchor': 0.30.1(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) '@defi-wonderland/smock': 2.4.0(@ethersproject/abi@5.7.0)(@ethersproject/abstract-provider@5.7.0)(@ethersproject/abstract-signer@5.7.0)(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)) '@eth-optimism/contracts': 0.5.40(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) @@ -8235,9 +8253,9 @@ snapshots: '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.4)(utf-8-validate@5.0.10) '@solana/web3.js': 1.95.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) '@types/yargs': 17.0.33 - '@uma/common': 2.37.3(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) + '@uma/common': 2.37.3(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) '@uma/contracts-node': 0.4.23 - '@uma/core': 2.61.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) + '@uma/core': 2.61.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) axios: 1.7.7 bs58: 6.0.0 buffer-layout: 1.2.2 @@ -8263,16 +8281,60 @@ snapshots: - typescript - utf-8-validate - '@across-protocol/sdk@3.3.23(@babel/core@7.25.2)(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(@ethersproject/abi@5.7.0)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)': + '@across-protocol/contracts@3.0.25(@ethersproject/abi@5.7.0)(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(typescript@5.5.4)(utf-8-validate@5.0.10)': + dependencies: + '@across-protocol/constants': 3.1.31 + '@coral-xyz/anchor': 0.30.1(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@defi-wonderland/smock': 2.4.0(@ethersproject/abi@5.7.0)(@ethersproject/abstract-provider@5.7.0)(@ethersproject/abstract-signer@5.7.0)(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)) + '@eth-optimism/contracts': 0.5.40(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@openzeppelin/contracts': 4.9.6 + '@openzeppelin/contracts-upgradeable': 4.9.6 + '@scroll-tech/contracts': 0.1.0 + '@solana-developers/helpers': 2.5.6(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.4)(utf-8-validate@5.0.10) + '@solana/spl-token': 0.4.9(@solana/web3.js@1.95.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.5.4)(utf-8-validate@5.0.10) + '@solana/web3.js': 1.95.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@types/yargs': 17.0.33 + '@uma/common': 2.37.3(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + '@uma/contracts-node': 0.4.23 + '@uma/core': 2.61.0(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + axios: 1.7.7 + bs58: 6.0.0 + buffer-layout: 1.2.2 + prettier-plugin-rust: 0.1.9 + yargs: 17.7.2 + zksync-web3: 0.14.4(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + transitivePeerDependencies: + - '@babel/core' + - '@codechecks/client' + - '@ethersproject/abi' + - '@ethersproject/hardware-wallets' + - '@nomiclabs/hardhat-ethers' + - bufferutil + - c-kzg + - debug + - encoding + - ethers + - fastestsmallesttextencoderdecoder + - hardhat + - supports-color + - ts-generator + - typechain + - typescript + - utf-8-validate + + '@across-protocol/sdk@3.4.15(@babel/core@7.25.2)(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(@ethersproject/abi@5.7.0)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)': dependencies: '@across-protocol/across-token': 1.0.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) - '@across-protocol/constants': 3.1.28 - '@across-protocol/contracts': 3.0.23(@babel/core@7.25.2)(@ethersproject/abi@5.7.0)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) + '@across-protocol/constants': 3.1.31 + '@across-protocol/contracts': 3.0.25(@babel/core@7.25.2)(@ethersproject/abi@5.7.0)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) '@eth-optimism/sdk': 3.3.2(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@ethersproject/bignumber': 5.7.0 '@pinata/sdk': 2.1.0 '@types/mocha': 10.0.7 - '@uma/sdk': 0.34.8(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + '@uma/sdk': 0.34.10(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) arweave: 1.15.1 async: 3.2.6 axios: 0.27.2 @@ -8282,7 +8344,7 @@ snapshots: lodash: 4.17.21 lodash.get: 4.4.2 superstruct: 0.15.5 - tslib: 2.7.0 + tslib: 2.8.1 viem: 2.21.53(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10) transitivePeerDependencies: - '@babel/core' @@ -8306,16 +8368,16 @@ snapshots: - utf-8-validate - zod - '@across-protocol/sdk@3.3.23(@babel/core@7.25.2)(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)': + '@across-protocol/sdk@3.4.15(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(@ethersproject/abi@5.7.0)(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)': dependencies: - '@across-protocol/across-token': 1.0.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) - '@across-protocol/constants': 3.1.28 - '@across-protocol/contracts': 3.0.23(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) + '@across-protocol/across-token': 1.0.0(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) + '@across-protocol/constants': 3.1.31 + '@across-protocol/contracts': 3.0.25(@ethersproject/abi@5.7.0)(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(buffer-layout@1.2.2)(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(typescript@5.5.4)(utf-8-validate@5.0.10) '@eth-optimism/sdk': 3.3.2(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@ethersproject/bignumber': 5.7.0 '@pinata/sdk': 2.1.0 '@types/mocha': 10.0.7 - '@uma/sdk': 0.34.8(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + '@uma/sdk': 0.34.10(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) arweave: 1.15.1 async: 3.2.6 axios: 0.27.2 @@ -8325,7 +8387,7 @@ snapshots: lodash: 4.17.21 lodash.get: 4.4.2 superstruct: 0.15.5 - tslib: 2.7.0 + tslib: 2.8.1 viem: 2.21.53(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10) transitivePeerDependencies: - '@babel/core' @@ -8615,6 +8677,23 @@ snapshots: enabled: 2.0.0 kuler: 2.0.0 + '@defi-wonderland/smock@2.4.0(@ethersproject/abi@5.7.0)(@ethersproject/abstract-provider@5.7.0)(@ethersproject/abstract-signer@5.7.0)(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))': + dependencies: + '@ethersproject/abi': 5.7.0 + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@nomicfoundation/ethereumjs-util': 9.0.4 + '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)) + diff: 5.2.0 + ethers: 5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) + hardhat: 2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) + lodash.isequal: 4.5.0 + lodash.isequalwith: 4.4.0 + rxjs: 7.8.1 + semver: 7.6.3 + transitivePeerDependencies: + - c-kzg + '@defi-wonderland/smock@2.4.0(@ethersproject/abi@5.7.0)(@ethersproject/abstract-provider@5.7.0)(@ethersproject/abstract-signer@5.7.0)(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)))(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))': dependencies: '@ethersproject/abi': 5.7.0 @@ -9656,7 +9735,7 @@ snapshots: '@pinata/sdk@2.1.0': dependencies: axios: 0.21.4(debug@4.3.7) - form-data: 2.5.1 + form-data: 2.5.2 is-ipfs: 0.6.3 path: 0.12.7 transitivePeerDependencies: @@ -10291,6 +10370,8 @@ snapshots: '@types/lru-cache@5.1.1': {} + '@types/luxon@3.4.2': {} + '@types/markdown-it@14.1.2': dependencies: '@types/linkify-it': 5.0.0 @@ -10617,9 +10698,9 @@ snapshots: '@typescript-eslint/types': 7.18.0 eslint-visitor-keys: 3.4.3 - '@uma/common@2.37.1(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': + '@uma/common@2.37.3(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': dependencies: - '@across-protocol/contracts': 0.1.4(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) + '@across-protocol/contracts': 0.1.4(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) '@ethersproject/address': 5.7.0 '@ethersproject/bignumber': 5.7.0 '@ethersproject/bytes': 5.7.0 @@ -10641,59 +10722,8 @@ snapshots: decimal.js: 10.4.3 dotenv: 9.0.2 eth-crypto: 2.6.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - hardhat-deploy: 0.9.1(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) - hardhat-gas-reporter: 1.0.10(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) - hardhat-typechain: 0.3.5(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4)) - lodash.uniqby: 4.7.0 - minimist: 1.2.8 - moment: 2.30.1 - node-fetch: 2.7.0(encoding@0.1.13) - node-metamask: https://codeload.github.com/UMAprotocol/node-metamask/tar.gz/36b33cb82558bafcd3ab0dcfbd35b26c2c0a2584(bufferutil@4.0.8)(utf-8-validate@5.0.10) - require-context: 1.1.0 - solidity-coverage: 0.7.22(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) - truffle-deploy-registry: 0.5.1 - web3: 1.10.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) - winston: 3.13.1 - transitivePeerDependencies: - - '@babel/core' - - '@codechecks/client' - - '@ethersproject/hardware-wallets' - - bufferutil - - debug - - encoding - - ethers - - hardhat - - supports-color - - ts-generator - - typechain - - utf-8-validate - - '@uma/common@2.37.1(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': - dependencies: - '@across-protocol/contracts': 0.1.4(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@google-cloud/kms': 3.8.0(encoding@0.1.13) - '@google-cloud/storage': 6.12.0(encoding@0.1.13) - '@nomicfoundation/hardhat-verify': 1.1.1(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)) - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)) - '@nomiclabs/hardhat-web3': 2.0.0(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(web3@1.10.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)) - '@truffle/contract': 4.6.17(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@truffle/hdwallet-provider': 1.5.1-alpha.1(@babel/core@7.25.2)(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@types/ethereum-protocol': 1.0.5 - '@uniswap/v3-core': 1.0.1 - abi-decoder: https://codeload.github.com/UMAprotocol/abi-decoder/tar.gz/1f18b7037985bf9b8960a6dc39dc52579ef274bb - async-retry: 1.3.3 - axios: 1.7.7 - bignumber.js: 8.1.1 - chalk-pipe: 3.0.0 - decimal.js: 10.4.3 - dotenv: 9.0.2 - eth-crypto: 2.6.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) hardhat-deploy: 0.9.1(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) - hardhat-gas-reporter: 1.0.10(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + hardhat-gas-reporter: 1.0.10(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) hardhat-typechain: 0.3.5(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4)) lodash.uniqby: 4.7.0 minimist: 1.2.8 @@ -10719,9 +10749,9 @@ snapshots: - typechain - utf-8-validate - '@uma/common@2.37.3(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': + '@uma/common@2.37.3(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10)': dependencies: - '@across-protocol/contracts': 0.1.4(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) + '@across-protocol/contracts': 0.1.4(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@ethersproject/address': 5.7.0 '@ethersproject/bignumber': 5.7.0 '@ethersproject/bytes': 5.7.0 @@ -10743,60 +10773,9 @@ snapshots: decimal.js: 10.4.3 dotenv: 9.0.2 eth-crypto: 2.6.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - hardhat-deploy: 0.9.1(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) + hardhat-deploy: 0.9.1(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) hardhat-gas-reporter: 1.0.10(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) - hardhat-typechain: 0.3.5(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4)) - lodash.uniqby: 4.7.0 - minimist: 1.2.8 - moment: 2.30.1 - node-fetch: 2.7.0(encoding@0.1.13) - node-metamask: https://codeload.github.com/UMAprotocol/node-metamask/tar.gz/36b33cb82558bafcd3ab0dcfbd35b26c2c0a2584(bufferutil@4.0.8)(utf-8-validate@5.0.10) - require-context: 1.1.0 - solidity-coverage: 0.7.22(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) - truffle-deploy-registry: 0.5.1 - web3: 1.10.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) - winston: 3.13.1 - transitivePeerDependencies: - - '@babel/core' - - '@codechecks/client' - - '@ethersproject/hardware-wallets' - - bufferutil - - debug - - encoding - - ethers - - hardhat - - supports-color - - ts-generator - - typechain - - utf-8-validate - - '@uma/common@2.37.3(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': - dependencies: - '@across-protocol/contracts': 0.1.4(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@google-cloud/kms': 3.8.0(encoding@0.1.13) - '@google-cloud/storage': 6.12.0(encoding@0.1.13) - '@nomicfoundation/hardhat-verify': 1.1.1(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)) - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)) - '@nomiclabs/hardhat-web3': 2.0.0(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(web3@1.10.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)) - '@truffle/contract': 4.6.17(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@truffle/hdwallet-provider': 1.5.1-alpha.1(@babel/core@7.25.2)(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@types/ethereum-protocol': 1.0.5 - '@uniswap/v3-core': 1.0.1 - abi-decoder: https://codeload.github.com/UMAprotocol/abi-decoder/tar.gz/1f18b7037985bf9b8960a6dc39dc52579ef274bb - async-retry: 1.3.3 - axios: 1.7.7 - bignumber.js: 8.1.1 - chalk-pipe: 3.0.0 - decimal.js: 10.4.3 - dotenv: 9.0.2 - eth-crypto: 2.6.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - hardhat-deploy: 0.9.1(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) - hardhat-gas-reporter: 1.0.10(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) - hardhat-typechain: 0.3.5(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4)) + hardhat-typechain: 0.3.5(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)) lodash.uniqby: 4.7.0 minimist: 1.2.8 moment: 2.30.1 @@ -10821,17 +10800,19 @@ snapshots: - typechain - utf-8-validate - '@uma/contracts-frontend@0.4.23': {} + '@uma/contracts-frontend@0.4.25': {} '@uma/contracts-node@0.4.23': {} - '@uma/core@2.61.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': + '@uma/contracts-node@0.4.25': {} + + '@uma/core@2.61.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': dependencies: '@gnosis.pm/safe-contracts': 1.3.0(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) '@gnosis.pm/zodiac': 3.2.0(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) '@maticnetwork/fx-portal': 1.0.5 '@openzeppelin/contracts': 4.9.6 - '@uma/common': 2.37.3(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) + '@uma/common': 2.37.3(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) '@uniswap/lib': 4.0.1-alpha '@uniswap/v2-core': 1.0.0 '@uniswap/v2-periphery': 1.1.0-beta.0 @@ -10851,13 +10832,13 @@ snapshots: - typechain - utf-8-validate - '@uma/core@2.61.0(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10)': + '@uma/core@2.61.0(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10)': dependencies: '@gnosis.pm/safe-contracts': 1.3.0(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) '@gnosis.pm/zodiac': 3.2.0(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) '@maticnetwork/fx-portal': 1.0.5 '@openzeppelin/contracts': 4.9.6 - '@uma/common': 2.37.3(@babel/core@7.25.2)(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4))(utf-8-validate@5.0.10) + '@uma/common': 2.37.3(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@uniswap/lib': 4.0.1-alpha '@uniswap/v2-core': 1.0.0 '@uniswap/v2-periphery': 1.1.0-beta.0 @@ -10898,7 +10879,7 @@ snapshots: - supports-color - utf-8-validate - '@uma/sdk@0.34.8(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10)': + '@uma/sdk@0.34.10(@eth-optimism/contracts@0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10)': dependencies: '@eth-optimism/contracts': 0.6.0(bufferutil@4.0.8)(ethers@5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@eth-optimism/core-utils': 0.7.7(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -10906,11 +10887,11 @@ snapshots: '@ethersproject/providers': 5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@google-cloud/datastore': 8.7.0(encoding@0.1.13) '@types/lodash-es': 4.17.12 - '@uma/contracts-frontend': 0.4.23 - '@uma/contracts-node': 0.4.23 + '@uma/contracts-frontend': 0.4.25 + '@uma/contracts-node': 0.4.25 axios: 1.7.7 bluebird: 3.7.2 - bn.js: 4.12.0 + bn.js: 4.12.1 decimal.js: 10.4.3 ethers: 5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) highland: 2.13.5 @@ -11242,7 +11223,7 @@ snapshots: asn1.js@5.4.1: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.1 inherits: 2.0.4 minimalistic-assert: 1.0.1 safer-buffer: 2.1.2 @@ -11272,7 +11253,7 @@ snapshots: async-mutex@0.5.0: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 async-retry@1.3.3: dependencies: @@ -11311,7 +11292,7 @@ snapshots: axios@0.27.2: dependencies: follow-redirects: 1.15.9(debug@4.3.7) - form-data: 4.0.0 + form-data: 4.0.1 transitivePeerDependencies: - debug @@ -11524,7 +11505,7 @@ snapshots: browserify-rsa: 4.1.0 create-hash: 1.2.0 create-hmac: 1.1.7 - elliptic: 6.5.7 + elliptic: 6.6.1 hash-base: 3.0.4 inherits: 2.0.4 parse-asn1: 5.1.7 @@ -12003,7 +11984,7 @@ snapshots: create-ecdh@4.0.4: dependencies: bn.js: 4.12.1 - elliptic: 6.5.7 + elliptic: 6.6.1 create-hash@1.2.0: dependencies: @@ -12418,7 +12399,7 @@ snapshots: elliptic@6.5.7: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.1 brorand: 1.1.0 hash.js: 1.1.7 hmac-drbg: 1.0.1 @@ -13068,7 +13049,7 @@ snapshots: ethereumjs-abi@0.6.8: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.1 ethereumjs-util: 6.2.1 ethereumjs-account@2.0.5: @@ -13118,9 +13099,9 @@ snapshots: ethereumjs-util@6.2.1: dependencies: '@types/bn.js': 4.11.6 - bn.js: 4.12.0 + bn.js: 4.12.1 create-hash: 1.2.0 - elliptic: 6.5.7 + elliptic: 6.6.1 ethereum-cryptography: 0.1.3 ethjs-util: 0.1.6 rlp: 2.2.7 @@ -13488,12 +13469,6 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 - form-data@2.5.1: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - form-data@2.5.2: dependencies: asynckit: 0.4.0 @@ -14023,7 +13998,7 @@ snapshots: ajv: 6.12.6 har-schema: 2.0.0 - hardhat-deploy@0.9.1(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10): + hardhat-deploy@0.9.1(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10): dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/abstract-signer': 5.7.0 @@ -14044,7 +14019,7 @@ snapshots: enquirer: 2.4.1 form-data: 4.0.1 fs-extra: 10.1.0 - hardhat: 2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) + hardhat: 2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) match-all: 1.2.6 murmur-128: 0.2.1 qs: 6.13.0 @@ -14053,7 +14028,7 @@ snapshots: - supports-color - utf-8-validate - hardhat-deploy@0.9.1(@ethersproject/hardware-wallets@5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10): + hardhat-deploy@0.9.1(bufferutil@4.0.8)(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10): dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/abstract-signer': 5.7.0 @@ -14061,7 +14036,6 @@ snapshots: '@ethersproject/bignumber': 5.7.0 '@ethersproject/bytes': 5.7.0 '@ethersproject/contracts': 5.7.0 - '@ethersproject/hardware-wallets': 5.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@ethersproject/providers': 5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@ethersproject/solidity': 5.7.0 '@ethersproject/transactions': 5.7.0 @@ -14074,7 +14048,7 @@ snapshots: enquirer: 2.4.1 form-data: 4.0.1 fs-extra: 10.1.0 - hardhat: 2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) + hardhat: 2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) match-all: 1.2.6 murmur-128: 0.2.1 qs: 6.13.0 @@ -14107,11 +14081,9 @@ snapshots: - debug - utf-8-validate - hardhat-typechain@0.3.5(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4)): + hardhat-typechain@0.3.5(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10)): dependencies: hardhat: 2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@16.18.104)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10) - ts-generator: 0.1.1 - typechain: 4.0.3(typescript@5.5.4) hardhat-typechain@0.3.5(hardhat@2.22.12(bufferutil@4.0.8)(ts-node@10.9.2(@types/node@22.7.3)(typescript@5.5.4))(typescript@5.5.4)(utf-8-validate@5.0.10))(ts-generator@0.1.1)(typechain@4.0.3(typescript@5.5.4)): dependencies: