From 68d656d621fba85fe3e799b7e31a10d0e7b6410a Mon Sep 17 00:00:00 2001 From: "James Morris, MS" <96435344+james-a-morris@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:39:52 -0400 Subject: [PATCH] improve: reduce remove direct contract/rpc calls in bundle client (#723) Signed-off-by: james-a-morris --- .../BundleDataClient/BundleDataClient.ts | 8 +++---- src/clients/SpokePoolClient.ts | 22 +++++++++++++++++- test/SpokePoolClient.ValidateFill.ts | 23 +++++++++++++++---- test/SpokePoolClient.fills.ts | 7 +++--- 4 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/clients/BundleDataClient/BundleDataClient.ts b/src/clients/BundleDataClient/BundleDataClient.ts index 2971f928..5a62d49a 100644 --- a/src/clients/BundleDataClient/BundleDataClient.ts +++ b/src/clients/BundleDataClient/BundleDataClient.ts @@ -29,7 +29,6 @@ import { getImpliedBundleBlockRanges, isSlowFill, mapAsync, - relayFillStatus, bnUint32Max, } from "../../utils"; import { BigNumber } from "ethers"; @@ -1125,8 +1124,7 @@ export class BundleDataClient { ) { // If we haven't seen a fill matching this deposit, then we need to rule out that it was filled a long time ago // by checkings its on-chain fill status. - const fillStatus = await relayFillStatus( - spokePoolClients[destinationChainId].spokePool, + const fillStatus = await spokePoolClients[destinationChainId].relayFillStatus( deposit, // We can assume that in production // the block ranges passed into this function would never contain blocks where the spoke pool client @@ -1313,8 +1311,8 @@ export class BundleDataClient { const startBlockForChain = Math.min(_startBlockForChain, spokePoolClient.latestBlockSearched); const endBlockForChain = Math.min(_endBlockForChain, spokePoolClient.latestBlockSearched); const [startTime, endTime] = [ - Number((await spokePoolClient.spokePool.provider.getBlock(startBlockForChain)).timestamp), - Number((await spokePoolClient.spokePool.provider.getBlock(endBlockForChain)).timestamp), + await spokePoolClient.getTimestampForBlock(startBlockForChain), + await spokePoolClient.getTimestampForBlock(endBlockForChain), ]; // Sanity checks: assert(endTime >= startTime, "End time should be greater than start time."); diff --git a/src/clients/SpokePoolClient.ts b/src/clients/SpokePoolClient.ts index f82490c3..5bccb3a5 100644 --- a/src/clients/SpokePoolClient.ts +++ b/src/clients/SpokePoolClient.ts @@ -25,6 +25,7 @@ import { Deposit, DepositWithBlock, Fill, + FillStatus, FillWithBlock, FilledV3RelayEvent, RealizedLpFee, @@ -38,7 +39,7 @@ import { } from "../interfaces"; import { SpokePool } from "../typechain"; import { getNetworkName } from "../utils/NetworkUtils"; -import { getBlockRangeForDepositId, getDepositIdAtBlock } from "../utils/SpokeUtils"; +import { getBlockRangeForDepositId, getDepositIdAtBlock, relayFillStatus } from "../utils/SpokeUtils"; import { BaseAbstractClient, isUpdateFailureReason, UpdateFailureReason } from "./BaseAbstractClient"; import { HubPoolClient } from "./HubPoolClient"; import { AcrossConfigStoreClient } from "./AcrossConfigStoreClient"; @@ -883,4 +884,23 @@ export class SpokePoolClient extends BaseAbstractClient { this.configStoreClient?.isChainLiteChainAtTimestamp(deposit.destinationChainId, deposit.quoteTimestamp) ?? false ); } + + public async getTimestampForBlock(blockTag: number): Promise { + const block = await this.spokePool.provider.getBlock(blockTag); + return Number(block.timestamp); + } + + /** + * Find the amount filled for a deposit at a particular block. + * @param relayData Deposit information that is used to complete a fill. + * @param blockTag Block tag (numeric or "latest") to query at. + * @returns The amount filled for the specified deposit at the requested block (or latest). + */ + public relayFillStatus( + relayData: RelayData, + blockTag?: number | "latest", + destinationChainId?: number + ): Promise { + return relayFillStatus(this.spokePool, relayData, blockTag, destinationChainId); + } } diff --git a/test/SpokePoolClient.ValidateFill.ts b/test/SpokePoolClient.ValidateFill.ts index 51e21edc..dd8267f9 100644 --- a/test/SpokePoolClient.ValidateFill.ts +++ b/test/SpokePoolClient.ValidateFill.ts @@ -7,6 +7,7 @@ import { relayFillStatus, validateFillForDeposit, queryHistoricalDepositForFill, + DepositSearchResult, } from "../src/utils"; import { CHAIN_ID_TEST_LIST, originChainId, destinationChainId, repaymentChainId } from "./constants"; import { @@ -129,9 +130,17 @@ describe("SpokePoolClient: Fill Validation", function () { let filled = await relayFillStatus(spokePool_2, deposit); expect(filled).to.equal(FillStatus.Unfilled); + // Also test spoke client variant + filled = await spokePoolClient2.relayFillStatus(deposit); + expect(filled).to.equal(FillStatus.Unfilled); + await fillV3Relay(spokePool_2, deposit, relayer); filled = await relayFillStatus(spokePool_2, deposit); expect(filled).to.equal(FillStatus.Filled); + + // Also test spoke client variant + filled = await spokePoolClient2.relayFillStatus(deposit); + expect(filled).to.equal(FillStatus.Filled); }); it("Tracks bulk v3 fill status", async function () { @@ -439,7 +448,9 @@ describe("SpokePoolClient: Fill Validation", function () { const historicalDeposit = await queryHistoricalDepositForFill(spokePoolClient1, fill); assert.equal(historicalDeposit.found, true, "Test is broken"); // Help tsc to narrow the discriminated union. - expect(historicalDeposit.deposit.depositId).to.deep.equal(deposit.depositId); + expect((historicalDeposit as Extract).deposit.depositId).to.deep.equal( + deposit.depositId + ); }); it("Can fetch younger deposit matching fill", async function () { @@ -473,7 +484,9 @@ describe("SpokePoolClient: Fill Validation", function () { const historicalDeposit = await queryHistoricalDepositForFill(spokePoolClient1, fill); assert.equal(historicalDeposit.found, true, "Test is broken"); // Help tsc to narrow the discriminated union. - expect(historicalDeposit.deposit.depositId).to.deep.equal(deposit.depositId); + expect((historicalDeposit as Extract).deposit.depositId).to.deep.equal( + deposit.depositId + ); }); it("Loads fills from memory with deposit ID > spoke pool client's earliest deposit ID queried", async function () { @@ -547,7 +560,7 @@ describe("SpokePoolClient: Fill Validation", function () { const search = await queryHistoricalDepositForFill(spokePoolClient1, fill); assert.equal(search.found, false, "Test is broken"); // Help tsc to narrow the discriminated union. - expect(search.code).to.equal(InvalidFill.DepositIdInvalid); + expect((search as Extract).code).to.equal(InvalidFill.DepositIdInvalid); expect(lastSpyLogIncludes(spy, "Queried RPC for deposit")).is.not.true; }); @@ -572,7 +585,7 @@ describe("SpokePoolClient: Fill Validation", function () { const search = await queryHistoricalDepositForFill(spokePoolClient1, fill); assert.equal(search.found, false, "Test is broken"); // Help tsc to narrow the discriminated union. - expect(search.code).to.equal(InvalidFill.DepositIdInvalid); + expect((search as Extract).code).to.equal(InvalidFill.DepositIdInvalid); expect(lastSpyLogIncludes(spy, "Queried RPC for deposit")).is.not.true; }); @@ -594,7 +607,7 @@ describe("SpokePoolClient: Fill Validation", function () { const search = await queryHistoricalDepositForFill(spokePoolClient1, fill); assert.equal(search.found, false, "Test is broken"); // Help tsc to narrow the discriminated union. - expect(search.code).to.equal(InvalidFill.FillMismatch); + expect((search as Extract).code).to.equal(InvalidFill.FillMismatch); }); it("Returns sped up deposit matched with fill", async function () { diff --git a/test/SpokePoolClient.fills.ts b/test/SpokePoolClient.fills.ts index 0703a720..ff924a77 100644 --- a/test/SpokePoolClient.fills.ts +++ b/test/SpokePoolClient.fills.ts @@ -1,6 +1,6 @@ import hre from "hardhat"; import { SpokePoolClient } from "../src/clients"; -import { V3Deposit } from "../src/interfaces"; +import { Deposit } from "../src/interfaces"; import { bnOne, findFillBlock, getNetworkName } from "../src/utils"; import { EMPTY_MESSAGE, ZERO_ADDRESS } from "../src/constants"; import { originChainId, destinationChainId } from "./constants"; @@ -24,7 +24,7 @@ describe("SpokePoolClient: Fills", function () { let depositor: SignerWithAddress, relayer1: SignerWithAddress, relayer2: SignerWithAddress; let spokePoolClient: SpokePoolClient; let deploymentBlock: number; - let deposit: V3Deposit; + let deposit: Deposit; beforeEach(async function () { [, depositor, relayer1, relayer2] = await ethers.getSigners(); @@ -57,12 +57,13 @@ describe("SpokePoolClient: Fills", function () { inputAmount: outputAmount.add(bnOne), outputToken: destErc20.address, outputAmount: toBNWei("1"), - relayerFeePct: toBNWei("0.01"), quoteTimestamp: spokePoolTime - 60, message: EMPTY_MESSAGE, fillDeadline: spokePoolTime + 600, exclusivityDeadline: 0, exclusiveRelayer: ZERO_ADDRESS, + fromLiteChain: false, + toLiteChain: false, }; });