From bb96d2e2bdbbdb787549e5289131cf327cd6c851 Mon Sep 17 00:00:00 2001 From: Ihor Farion Date: Wed, 16 Jul 2025 17:59:24 -0700 Subject: [PATCH 1/6] fix 1 test Signed-off-by: Ihor Farion --- test/Dataworker.loadData.unexecutableSlowFill.ts | 6 ++++-- test/utils/utils.ts | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/test/Dataworker.loadData.unexecutableSlowFill.ts b/test/Dataworker.loadData.unexecutableSlowFill.ts index 1e60d6dc64..08ed502496 100644 --- a/test/Dataworker.loadData.unexecutableSlowFill.ts +++ b/test/Dataworker.loadData.unexecutableSlowFill.ts @@ -238,8 +238,10 @@ describe("Dataworker: Load bundle data: Computing unexecutable slow fills", asyn await spokePoolClient_1.update(); const deposits = spokePoolClient_1.getDeposits(); expect(deposits.length).to.equal(3); - const eligibleSlowFills = depositsWithSlowFillRequests.filter((x) => erc20_2.address === x.outputToken); - const ineligibleSlowFills = depositsWithSlowFillRequests.filter((x) => erc20_2.address !== x.outputToken); + const eligibleSlowFills = depositsWithSlowFillRequests.filter((x) => erc20_2.address === x.outputToken.toNative()); + const ineligibleSlowFills = depositsWithSlowFillRequests.filter( + (x) => erc20_2.address !== x.outputToken.toNative() + ); // Generate slow fill requests for the slow fill-eligible deposits await requestSlowFill(spokePool_2, relayer, eligibleSlowFills[0]); diff --git a/test/utils/utils.ts b/test/utils/utils.ts index 1831df01a6..9f55070a09 100644 --- a/test/utils/utils.ts +++ b/test/utils/utils.ts @@ -21,6 +21,7 @@ import { ZERO_ADDRESS, getMessageHash, toBytes32, + toAddressType, } from "../../src/utils"; import { DEFAULT_BLOCK_RANGE_FOR_CHAIN, @@ -328,19 +329,20 @@ export async function depositV3( const { blockNumber, transactionHash: txnRef, transactionIndex: txnIndex } = txnReceipt; const { logIndex } = eventLog; - const depositObject = { + const depositArgs = spreadEvent(args); + const depositObject: DepositWithBlock = { blockNumber, txnRef, txnIndex, logIndex, - ...(spreadEvent(args) as Deposit), + ...(depositArgs as Deposit), originChainId: Number(originChainId), quoteBlockNumber: 0, messageHash: args.messageHash ?? getMessageHash(args.message), }; - if (isLegacyDeposit) { - depositObject.outputToken = outputToken; - } + + depositObject.outputToken = toAddressType(depositArgs.outputToken, depositArgs.destinationChainId); + return depositObject; } From 9f022cb51771ce112fc10165e05b32a8f3b3021c Mon Sep 17 00:00:00 2001 From: Ihor Farion Date: Sat, 19 Jul 2025 14:39:30 -0700 Subject: [PATCH 2/6] complete fixing tests Signed-off-by: Ihor Farion --- test/Dataworker.loadData.slowFill.ts | 33 ++------ test/Relayer.BasicFill.ts | 34 ++++---- test/Relayer.SlowFill.ts | 9 +- test/Relayer.UnfilledDeposits.ts | 51 ++++------- test/utils/SpokePoolUtils.ts | 19 +++-- test/utils/utils.ts | 121 ++++++++++++++++++++++++--- 6 files changed, 159 insertions(+), 108 deletions(-) diff --git a/test/Dataworker.loadData.slowFill.ts b/test/Dataworker.loadData.slowFill.ts index 22037845d8..e195972b22 100644 --- a/test/Dataworker.loadData.slowFill.ts +++ b/test/Dataworker.loadData.slowFill.ts @@ -576,7 +576,7 @@ describe("Dataworker: Load bundle data: Computing slow fills", async function () it("Slow fill request for deposit that isn't eligible for slow fill", async function () { const invalidOutputToken = erc20_1; - const _depositObject = await depositV3( + const depositObject = await depositV3( spokePool_1, destinationChainId, depositor, @@ -585,14 +585,7 @@ describe("Dataworker: Load bundle data: Computing slow fills", async function () invalidOutputToken.address, amountToDeposit ); - const depositObject = { - ..._depositObject, - inputToken: toAddressType(_depositObject.inputToken, originChainId), - outputToken: toAddressType(_depositObject.outputToken, destinationChainId), - depositor: toAddressType(_depositObject.depositor, originChainId), - recipient: toAddressType(_depositObject.recipient, destinationChainId), - exclusiveRelayer: toAddressType(_depositObject.exclusiveRelayer, destinationChainId), - }; + await spokePoolClient_1.update(); await requestSlowFill(spokePool_2, relayer, depositObject); @@ -621,7 +614,7 @@ describe("Dataworker: Load bundle data: Computing slow fills", async function () await mockConfigStore.update(); (spokePoolClient_1 as any).configStoreClient = mockConfigStore; (spokePoolClient_2 as any).configStoreClient = mockConfigStore; - const _depositObject = await depositV3( + const depositObject = await depositV3( spokePool_1, destinationChainId, depositor, @@ -630,14 +623,7 @@ describe("Dataworker: Load bundle data: Computing slow fills", async function () erc20_2.address, amountToDeposit ); - const depositObject = { - ..._depositObject, - inputToken: toAddressType(_depositObject.inputToken, originChainId), - outputToken: toAddressType(_depositObject.outputToken, destinationChainId), - depositor: toAddressType(_depositObject.depositor, originChainId), - recipient: toAddressType(_depositObject.recipient, destinationChainId), - exclusiveRelayer: toAddressType(_depositObject.exclusiveRelayer, destinationChainId), - }; + await spokePoolClient_1.update(); expect(mockConfigStore.liteChainIndicesUpdates.length).to.equal(1); expect(mockConfigStore.liteChainIndicesUpdates[0].timestamp).to.be.lt(depositObject.quoteTimestamp); @@ -667,7 +653,7 @@ describe("Dataworker: Load bundle data: Computing slow fills", async function () await mockConfigStore.update(); (spokePoolClient_1 as any).configStoreClient = mockConfigStore; (spokePoolClient_2 as any).configStoreClient = mockConfigStore; - const _depositObject = await depositV3( + const depositObject = await depositV3( spokePool_1, destinationChainId, depositor, @@ -676,14 +662,7 @@ describe("Dataworker: Load bundle data: Computing slow fills", async function () erc20_2.address, amountToDeposit ); - const depositObject = { - ..._depositObject, - inputToken: toAddressType(_depositObject.inputToken, originChainId), - outputToken: toAddressType(_depositObject.outputToken, destinationChainId), - depositor: toAddressType(_depositObject.depositor, originChainId), - recipient: toAddressType(_depositObject.recipient, destinationChainId), - exclusiveRelayer: toAddressType(_depositObject.exclusiveRelayer, destinationChainId), - }; + await spokePoolClient_1.update(); expect(mockConfigStore.liteChainIndicesUpdates.length).to.equal(1); expect(mockConfigStore.liteChainIndicesUpdates[0].timestamp).to.be.lt(depositObject.quoteTimestamp); diff --git a/test/Relayer.BasicFill.ts b/test/Relayer.BasicFill.ts index 737d234bc8..b9e68cf21f 100644 --- a/test/Relayer.BasicFill.ts +++ b/test/Relayer.BasicFill.ts @@ -442,7 +442,7 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { // Make two deposits - one with the relayer as exclusiveRelayer, and one with a random address. // Verify that the relayer can immediately fill the first deposit, and both after the exclusivity window. - for (const exclusiveRelayer of [randomAddress(), relayerAddress]) { + for (const exclusiveRelayer of [randomAddress(), relayerAddress.toNative()]) { const deposit = await depositV3( spokePool_1, destinationChainId, @@ -464,7 +464,7 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { deposits.forEach((deposit) => { const depositHash = spokePoolClients[deposit.destinationChainId].getDepositHash(deposit); const status = - deposit.exclusiveRelayer === relayerAddress.toEvmAddress() ? FillStatus.Filled : FillStatus.Unfilled; + deposit.exclusiveRelayer.toString() === relayerAddress.toString() ? FillStatus.Filled : FillStatus.Unfilled; expect(fillStatus[depositHash] ?? FillStatus.Unfilled).to.equal(status); }); @@ -473,7 +473,7 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { expect(lastSpyLogIncludes(spy, "0 unfilled deposits found")).to.be.true; const exclusiveDeposit = deposits.find( - ({ exclusiveRelayer }) => exclusiveRelayer !== relayerAddress.toEvmAddress() + ({ exclusiveRelayer }) => exclusiveRelayer.toString() !== relayerAddress.toString() ); expect(exclusiveDeposit).to.exist; await spokePool_2.setCurrentTime(exclusiveDeposit!.exclusivityDeadline + 1); @@ -593,7 +593,7 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { ); const fillAmount = profitClient.getFillAmountInUsd({ ...deposit1, - outputToken: toAddressType(deposit1.outputToken, destinationChainId), + outputToken: deposit1.outputToken, })!; expect(fillAmount).to.exist; @@ -644,14 +644,8 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { await updateAllClients(); originChainCommitment = relayerInstance.computeOriginChainCommitment(originChainId, 0, Number.MAX_SAFE_INTEGER); - expect( - originChainCommitment.eq( - getFillAmount( - { ...deposit1, outputToken: toAddressType(deposit1.outputToken, destinationChainId) }, - tokenPrice - ) - ) - ).to.be.true; + expect(originChainCommitment.eq(getFillAmount({ ...deposit1, outputToken: deposit1.outputToken }, tokenPrice))).to + .be.true; let originChainLimits = relayerInstance.computeOriginChainLimits(originChainId); expect(isChainOvercommitted(originChainLimits)).to.be.false; @@ -955,7 +949,7 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { spokePool_1, { ...deposit, - updatedRecipient: update.recipient, + updatedRecipient: toAddressType(update.recipient, destinationChainId), updatedOutputAmount: update.outputAmount, updatedMessage: update.message, }, @@ -1022,7 +1016,12 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { const updatedRecipient = randomAddress(); await updateDeposit( spokePool_1, - { ...deposit, updatedRecipient, updatedOutputAmount, updatedMessage }, + { + ...deposit, + updatedRecipient: toAddressType(updatedRecipient, destinationChainId), + updatedOutputAmount, + updatedMessage, + }, depositor ); @@ -1039,7 +1038,12 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { updatedMessage = EMPTY_MESSAGE; await updateDeposit( spokePool_1, - { ...deposit, updatedRecipient, updatedOutputAmount, updatedMessage }, + { + ...deposit, + updatedRecipient: toAddressType(updatedRecipient, destinationChainId), + updatedOutputAmount, + updatedMessage, + }, depositor ); diff --git a/test/Relayer.SlowFill.ts b/test/Relayer.SlowFill.ts index 16ae5cc9b7..82a5697901 100644 --- a/test/Relayer.SlowFill.ts +++ b/test/Relayer.SlowFill.ts @@ -241,14 +241,7 @@ describe("Relayer: Initiates slow fill requests", async function () { // Verify that the slowFill request was received by the destination SpokePoolClient. await Promise.all([spokePoolClient_1.update(), spokePoolClient_2.update(), hubPoolClient.update()]); - const slowFillRequest = spokePoolClient_2.getSlowFillRequest({ - ...deposit, - inputToken: toAddressType(inputToken, originChainId), - outputToken: toAddressType(outputToken, destinationChainId), - depositor: toAddressType(deposit.depositor, originChainId), - recipient: toAddressType(deposit.recipient, destinationChainId), - exclusiveRelayer: toAddressType(deposit.exclusiveRelayer, destinationChainId), - }); + const slowFillRequest = spokePoolClient_2.getSlowFillRequest(deposit); expect(slowFillRequest).to.exist; const txnReceipts = await relayerInstance.checkForUnfilledDepositsAndFill(); diff --git a/test/Relayer.UnfilledDeposits.ts b/test/Relayer.UnfilledDeposits.ts index e84f4f7c11..0f74c7b1ea 100644 --- a/test/Relayer.UnfilledDeposits.ts +++ b/test/Relayer.UnfilledDeposits.ts @@ -43,6 +43,8 @@ import { randomAddress, setupTokensForWallet, deployMulticall3, + depositV3IntoPrimitiveEvm, + fillIntoPrimitiveEvm, } from "./utils"; // Tested import { Relayer } from "../src/relayer/Relayer"; @@ -233,14 +235,7 @@ describe("Relayer: Unfilled Deposits", async function () { unfilledDeposits.map((unfilledDeposit) => { return { ...unfilledDeposit, - deposit: { - ...unfilledDeposit.deposit, - inputToken: unfilledDeposit.deposit.inputToken.toEvmAddress(), - outputToken: unfilledDeposit.deposit.outputToken.toEvmAddress(), - depositor: unfilledDeposit.deposit.depositor.toEvmAddress(), - recipient: unfilledDeposit.deposit.recipient.toEvmAddress(), - exclusiveRelayer: unfilledDeposit.deposit.exclusiveRelayer.toEvmAddress(), - }, + deposit: depositV3IntoPrimitiveEvm(unfilledDeposit.deposit), }; }) ) @@ -249,7 +244,7 @@ describe("Relayer: Unfilled Deposits", async function () { [...deposits] .sort((a, b) => (a.destinationChainId > b.destinationChainId ? 1 : -1)) .map((deposit) => ({ - deposit, + deposit: depositV3IntoPrimitiveEvm(deposit), unfilledAmount: deposit.outputAmount, invalidFills: [], version: configStoreClient.configStoreVersion, @@ -287,14 +282,7 @@ describe("Relayer: Unfilled Deposits", async function () { unfilledDeposits.map((unfilledDeposit) => { return { ...unfilledDeposit, - deposit: { - ...unfilledDeposit.deposit, - inputToken: unfilledDeposit.deposit.inputToken.toEvmAddress(), - outputToken: unfilledDeposit.deposit.outputToken.toEvmAddress(), - depositor: unfilledDeposit.deposit.depositor.toEvmAddress(), - recipient: unfilledDeposit.deposit.recipient.toEvmAddress(), - exclusiveRelayer: unfilledDeposit.deposit.exclusiveRelayer.toEvmAddress(), - }, + deposit: depositV3IntoPrimitiveEvm(unfilledDeposit.deposit), }; }) ) @@ -303,7 +291,7 @@ describe("Relayer: Unfilled Deposits", async function () { deposits .filter(({ depositId }) => depositId !== filledDeposit!.depositId) .map((deposit) => ({ - deposit, + deposit: depositV3IntoPrimitiveEvm(deposit), unfilledAmount: deposit.outputAmount, invalidFills: [], version: configStoreClient.configStoreVersion, @@ -333,15 +321,12 @@ describe("Relayer: Unfilled Deposits", async function () { unfilledDeposits = _getAllUnfilledDeposits(); expect( unfilledDeposits.map((unfilledDeposit) => { + const depositV3PrimitiveEvmArgs = depositV3IntoPrimitiveEvm(unfilledDeposit.deposit); return { ...unfilledDeposit, deposit: { ...unfilledDeposit.deposit, - inputToken: unfilledDeposit.deposit.inputToken.toEvmAddress(), - outputToken: unfilledDeposit.deposit.outputToken.toEvmAddress(), - depositor: unfilledDeposit.deposit.depositor.toEvmAddress(), - recipient: unfilledDeposit.deposit.recipient.toEvmAddress(), - exclusiveRelayer: unfilledDeposit.deposit.exclusiveRelayer.toEvmAddress(), + ...depositV3PrimitiveEvmArgs, }, invalidFills: [ { @@ -366,12 +351,14 @@ describe("Relayer: Unfilled Deposits", async function () { { deposit: { ...deposit, + ...depositV3IntoPrimitiveEvm(deposit), depositId: sdkUtils.toBN(deposit.depositId), }, unfilledAmount: deposit.outputAmount, invalidFills: [ { ...invalidFill, + ...fillIntoPrimitiveEvm(invalidFill), depositId: sdkUtils.toBN(invalidFill.depositId), }, ], @@ -516,14 +503,7 @@ describe("Relayer: Unfilled Deposits", async function () { outputAmount, { quoteTimestamp } ); - deposits.push({ - ...deposit, - inputToken: toAddressType(deposit.inputToken, originChainId), - outputToken: toAddressType(deposit.outputToken, destinationChainId), - depositor: toAddressType(deposit.depositor, originChainId), - recipient: toAddressType(deposit.recipient, destinationChainId), - exclusiveRelayer: toAddressType(deposit.exclusiveRelayer, destinationChainId), - }); + deposits.push(deposit); // Modify the HubPool LP balance to ensure that subsequent deposits will receive a different LP fee. const lpTokenBalance = await lpToken.balanceOf(owner.address); @@ -621,11 +601,7 @@ describe("Relayer: Unfilled Deposits", async function () { ...unfilledDeposit, deposit: { ...unfilledDeposit.deposit, - inputToken: unfilledDeposit.deposit.inputToken.toEvmAddress(), - outputToken: unfilledDeposit.deposit.outputToken.toEvmAddress(), - depositor: unfilledDeposit.deposit.depositor.toEvmAddress(), - recipient: unfilledDeposit.deposit.recipient.toEvmAddress(), - exclusiveRelayer: unfilledDeposit.deposit.exclusiveRelayer.toEvmAddress(), + ...depositV3IntoPrimitiveEvm(unfilledDeposit.deposit), }, invalidFills: [ { @@ -649,13 +625,14 @@ describe("Relayer: Unfilled Deposits", async function () { .to.deep.equal([ { deposit: { - ...deposit, + ...depositV3IntoPrimitiveEvm(deposit), depositId: sdkUtils.toBN(deposit.depositId), }, unfilledAmount: deposit.outputAmount, invalidFills: [ { ...invalidFill, + ...fillIntoPrimitiveEvm(invalidFill), depositId: sdkUtils.toBN(invalidFill.depositId), }, ], diff --git a/test/utils/SpokePoolUtils.ts b/test/utils/SpokePoolUtils.ts index 5ca6daa8af..cadc7900a6 100644 --- a/test/utils/SpokePoolUtils.ts +++ b/test/utils/SpokePoolUtils.ts @@ -1,5 +1,5 @@ import assert from "assert"; -import { Contract, bnZero, spreadEvent, toBytes32 } from "../../src/utils"; +import { Contract, bnZero, spreadEvent, toAddressType, toBytes32 } from "../../src/utils"; import { Deposit, DepositWithBlock, @@ -8,7 +8,7 @@ import { SlowFillRequest, SlowFillRequestWithBlock, } from "../../src/interfaces"; -import { SignerWithAddress } from "./utils"; +import { SignerWithAddress, slowFillRequestFromArgs } from "./utils"; export function V3FillFromDeposit( deposit: DepositWithBlock, @@ -19,7 +19,7 @@ export function V3FillFromDeposit( const { blockNumber, txnRef, logIndex, txnIndex, quoteTimestamp, ...relayData } = deposit; const fill: Fill = { ...relayData, - relayer, + relayer: toAddressType(relayer, deposit.destinationChainId), realizedLpFeePct: deposit.realizedLpFeePct ?? bnZero, repaymentChainId: repaymentChainId ?? deposit.destinationChainId, relayExecutionInfo: { @@ -40,11 +40,11 @@ export async function requestSlowFill( await spokePool .connect(relayer) .requestSlowFill([ - toBytes32(deposit.depositor), - toBytes32(deposit.recipient), - toBytes32(deposit.exclusiveRelayer), - toBytes32(deposit.inputToken), - toBytes32(deposit.outputToken), + deposit.depositor.toBytes32(), + deposit.recipient.toBytes32(), + deposit.exclusiveRelayer.toBytes32(), + deposit.inputToken.toBytes32(), + deposit.outputToken.toBytes32(), deposit.inputAmount, deposit.outputAmount, deposit.originChainId, @@ -59,8 +59,9 @@ export async function requestSlowFill( ]); const lastEvent = events.at(-1); assert(lastEvent); + const slowFillRequest = slowFillRequestFromArgs(spreadEvent(lastEvent.args!)); const requestObject: SlowFillRequestWithBlock = { - ...(spreadEvent(lastEvent.args!) as SlowFillRequest), + ...slowFillRequest, destinationChainId, blockNumber: lastEvent.blockNumber, txnRef: lastEvent.transactionHash, diff --git a/test/utils/utils.ts b/test/utils/utils.ts index 9f55070a09..0d2d0ebc31 100644 --- a/test/utils/utils.ts +++ b/test/utils/utils.ts @@ -9,7 +9,15 @@ import chaiExclude from "chai-exclude"; import sinon from "sinon"; import winston from "winston"; import { GLOBAL_CONFIG_STORE_KEYS } from "../../src/clients"; -import { Deposit, DepositWithBlock, Fill, FillWithBlock, SlowFillLeaf } from "../../src/interfaces"; +import { + Deposit, + DepositWithBlock, + Fill, + FillWithBlock, + RelayData, + SlowFillLeaf, + SlowFillRequest, +} from "../../src/interfaces"; import { BigNumber, isDefined, @@ -228,8 +236,8 @@ export async function deployNewTokenMapping( // Give signer initial balance and approve hub pool and spoke pool to pull funds from it await addLiquidity(l1TokenHolder, hubPool, l1Token, amountToSeedLpPool); - await setupTokensForWallet(spokePool, l2TokenHolder, [l2Token, l2TokenDestination], null, 100); - await setupTokensForWallet(spokePoolDestination, l2TokenHolder, [l2TokenDestination, l2Token], null, 100); + await setupTokensForWallet(spokePool, l2TokenHolder, [l2Token, l2TokenDestination], undefined, 100); + await setupTokensForWallet(spokePoolDestination, l2TokenHolder, [l2TokenDestination, l2Token], undefined, 100); // Set time to provider time so blockfinder can find block for deposit quote time. await spokePool.setCurrentTime(await getLastBlockTime(spokePool.provider)); @@ -335,13 +343,15 @@ export async function depositV3( txnRef, txnIndex, logIndex, - ...(depositArgs as Deposit), + ...depositFromArgs(depositArgs), originChainId: Number(originChainId), quoteBlockNumber: 0, messageHash: args.messageHash ?? getMessageHash(args.message), }; - depositObject.outputToken = toAddressType(depositArgs.outputToken, depositArgs.destinationChainId); + if (isLegacyDeposit) { + depositObject.outputToken = toAddressType(outputToken, originChainId); + } return depositObject; } @@ -352,7 +362,9 @@ export async function updateDeposit( depositor: SignerWithAddress ): Promise { const { updatedRecipient: updatedRecipientAddress, updatedOutputAmount, updatedMessage } = deposit; - const updatedRecipient = sdkUtils.toBytes32(updatedRecipientAddress!); + if (updatedRecipientAddress === undefined) + throw `updateDeposit cannot have updatedRecipientAddress undefined ${depositV3IntoPrimitiveEvm(deposit)}`; + const updatedRecipient = updatedRecipientAddress.toBytes32(); assert.ok(isDefined(updatedRecipient)); assert.ok(isDefined(updatedOutputAmount)); assert.ok(isDefined(updatedMessage)); @@ -389,11 +401,11 @@ export async function fillV3Relay( await spokePool.connect(signer).fillRelay( { ...deposit, - depositor: toBytes32(deposit.depositor), - recipient: toBytes32(deposit.recipient), - inputToken: toBytes32(deposit.inputToken), - outputToken: toBytes32(deposit.outputToken), - exclusiveRelayer: toBytes32(deposit.exclusiveRelayer), + depositor: deposit.depositor.toBytes32(), + recipient: deposit.recipient.toBytes32(), + inputToken: deposit.inputToken.toBytes32(), + outputToken: deposit.outputToken.toBytes32(), + exclusiveRelayer: deposit.exclusiveRelayer.toBytes32(), }, repaymentChainId ?? destinationChainId, toBytes32(await signer.getAddress()) @@ -414,7 +426,7 @@ export async function fillV3Relay( txnRef: transactionHash, txnIndex: transactionIndex, logIndex, - ...(parsedEvent as Fill), + ...fillFromArgs(parsedEvent), messageHash: args.messageHash ?? getMessageHash(args.message), relayExecutionInfo: { ...parsedEvent.relayExecutionInfo, @@ -493,3 +505,88 @@ export function createRefunds( }, }; } + +// A helper function to parse key - value map into a Deposit object +export function fillFromArgs(fillArgs: { [key: string]: any }): Fill { + const obj = { ...fillArgs }; + + obj.relayExecutionInfo.updatedRecipient = toAddressType( + fillArgs.relayExecutionInfo.updatedRecipient, + fillArgs.destinationChainId + ); + + obj.relayer = toAddressType(fillArgs.relayer, fillArgs.destinationChainId); + + obj.depositor = toAddressType(fillArgs.depositor, fillArgs.originChainId); + obj.recipient = toAddressType(fillArgs.recipient, fillArgs.destinationChainId); + obj.inputToken = toAddressType(fillArgs.inputToken, fillArgs.originChainId); + obj.outputToken = toAddressType(fillArgs.outputToken, fillArgs.destinationChainId); + obj.exclusiveRelayer = toAddressType(fillArgs.exclusiveRelayer, fillArgs.destinationChainId); + + return obj as Fill; +} + +// decomposes Fill into primitive types suitable for === comparions +export function fillIntoPrimitiveEvm(fill: Fill) { + return { + ...fill, + inputToken: fill.inputToken.toEvmAddress(), + outputToken: fill.outputToken.toEvmAddress(), + depositor: fill.depositor.toEvmAddress(), + recipient: fill.recipient.toEvmAddress(), + exclusiveRelayer: fill.exclusiveRelayer.toEvmAddress(), + relayer: fill.relayer.toEvmAddress(), // todo? consider using .toNative() and dropping the `...Evm` suffix + relayExecutionInfo: { + ...fill.relayExecutionInfo, + updatedRecipient: fill.relayExecutionInfo.updatedRecipient?.toEvmAddress(), + }, + }; +} + +export function relayDataFromArgs(relayDataArgs: { [key: string]: any }): RelayData { + const obj = { ...relayDataArgs }; + + obj.depositor = toAddressType(relayDataArgs.depositor, relayDataArgs.originChainId); + obj.recipient = toAddressType(relayDataArgs.recipient, relayDataArgs.destinationChainId); + obj.inputToken = toAddressType(relayDataArgs.inputToken, relayDataArgs.originChainId); + obj.outputToken = toAddressType(relayDataArgs.outputToken, relayDataArgs.destinationChainId); + obj.exclusiveRelayer = toAddressType(relayDataArgs.exclusiveRelayer, relayDataArgs.destinationChainId); + + return obj as RelayData; +} + +export function slowFillRequestFromArgs(slowFillRequestArgs: { [key: string]: any }): SlowFillRequest { + const obj = { ...slowFillRequestArgs, ...(relayDataFromArgs(slowFillRequestArgs) as any) }; + + return obj as SlowFillRequest; +} + +// A helper function to parse key - value map into a Deposit object with correct types (e.g. Address) +export function depositFromArgs(depositArgs: { [key: string]: any }): Deposit { + const obj = { ...depositArgs }; + + obj.depositor = toAddressType(depositArgs.depositor, depositArgs.originChainId); + obj.recipient = toAddressType(depositArgs.recipient, depositArgs.destinationChainId); + obj.inputToken = toAddressType(depositArgs.inputToken, depositArgs.originChainId); + obj.outputToken = toAddressType(depositArgs.outputToken, depositArgs.destinationChainId); + obj.exclusiveRelayer = toAddressType(depositArgs.exclusiveRelayer, depositArgs.destinationChainId); + + if (depositArgs.updatedRecipient !== undefined) { + obj.updatedRecipient = toAddressType(depositArgs.updatedRecipient, depositArgs.destinationChainId); + } + + return obj as Deposit; +} + +// decomposes Deposit into primitive types suitable for === comparions +export function depositV3IntoPrimitiveEvm(deposit: Deposit) { + return { + ...deposit, + inputToken: deposit.inputToken.toEvmAddress(), + outputToken: deposit.outputToken.toEvmAddress(), + depositor: deposit.depositor.toEvmAddress(), + recipient: deposit.recipient.toEvmAddress(), + exclusiveRelayer: deposit.exclusiveRelayer.toEvmAddress(), + updatedRecipient: deposit.updatedRecipient?.toEvmAddress(), + }; +} From faf727352647928c00c15f483908f5c3710e2428 Mon Sep 17 00:00:00 2001 From: Ihor Farion Date: Sat, 19 Jul 2025 14:51:59 -0700 Subject: [PATCH 3/6] fix lint Signed-off-by: Ihor Farion --- test/Relayer.SlowFill.ts | 2 +- test/utils/SpokePoolUtils.ts | 11 ++--------- test/utils/utils.ts | 3 ++- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/test/Relayer.SlowFill.ts b/test/Relayer.SlowFill.ts index 82a5697901..6d496a8243 100644 --- a/test/Relayer.SlowFill.ts +++ b/test/Relayer.SlowFill.ts @@ -38,7 +38,7 @@ import { winston, deployMulticall3, } from "./utils"; -import { SvmAddress, EvmAddress, toAddressType } from "../src/utils"; +import { SvmAddress, EvmAddress } from "../src/utils"; import { Relayer } from "../src/relayer/Relayer"; import { RelayerConfig } from "../src/relayer/RelayerConfig"; // Tested diff --git a/test/utils/SpokePoolUtils.ts b/test/utils/SpokePoolUtils.ts index cadc7900a6..270b56e074 100644 --- a/test/utils/SpokePoolUtils.ts +++ b/test/utils/SpokePoolUtils.ts @@ -1,13 +1,6 @@ import assert from "assert"; -import { Contract, bnZero, spreadEvent, toAddressType, toBytes32 } from "../../src/utils"; -import { - Deposit, - DepositWithBlock, - Fill, - FillType, - SlowFillRequest, - SlowFillRequestWithBlock, -} from "../../src/interfaces"; +import { Contract, bnZero, spreadEvent, toAddressType } from "../../src/utils"; +import { Deposit, DepositWithBlock, Fill, FillType, SlowFillRequestWithBlock } from "../../src/interfaces"; import { SignerWithAddress, slowFillRequestFromArgs } from "./utils"; export function V3FillFromDeposit( diff --git a/test/utils/utils.ts b/test/utils/utils.ts index 0d2d0ebc31..df16481d3e 100644 --- a/test/utils/utils.ts +++ b/test/utils/utils.ts @@ -362,8 +362,9 @@ export async function updateDeposit( depositor: SignerWithAddress ): Promise { const { updatedRecipient: updatedRecipientAddress, updatedOutputAmount, updatedMessage } = deposit; - if (updatedRecipientAddress === undefined) + if (updatedRecipientAddress === undefined) { throw `updateDeposit cannot have updatedRecipientAddress undefined ${depositV3IntoPrimitiveEvm(deposit)}`; + } const updatedRecipient = updatedRecipientAddress.toBytes32(); assert.ok(isDefined(updatedRecipient)); assert.ok(isDefined(updatedOutputAmount)); From 565c4d9e95328c1ecbc261e94bb16fa1b9fb4e70 Mon Sep 17 00:00:00 2001 From: Ihor Farion Date: Mon, 21 Jul 2025 10:23:45 -0700 Subject: [PATCH 4/6] pr comments Signed-off-by: Ihor Farion --- test/Relayer.BasicFill.ts | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/test/Relayer.BasicFill.ts b/test/Relayer.BasicFill.ts index 47dd2844d0..d01cd42c42 100644 --- a/test/Relayer.BasicFill.ts +++ b/test/Relayer.BasicFill.ts @@ -463,8 +463,7 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { deposits.forEach((deposit) => { const depositHash = spokePoolClients[deposit.destinationChainId].getDepositHash(deposit); - const status = - deposit.exclusiveRelayer.toString() === relayerAddress.toString() ? FillStatus.Filled : FillStatus.Unfilled; + const status = deposit.exclusiveRelayer.eq(relayerAddress) ? FillStatus.Filled : FillStatus.Unfilled; expect(fillStatus[depositHash] ?? FillStatus.Unfilled).to.equal(status); }); @@ -472,9 +471,7 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { expect((await txnReceipts[destinationChainId]).length).to.equal(0); expect(lastSpyLogIncludes(spy, "0 unfilled deposits found")).to.be.true; - const exclusiveDeposit = deposits.find( - ({ exclusiveRelayer }) => exclusiveRelayer.toString() !== relayerAddress.toString() - ); + const exclusiveDeposit = deposits.find(({ exclusiveRelayer }) => exclusiveRelayer.eq(relayerAddress)); expect(exclusiveDeposit).to.exist; await spokePool_2.setCurrentTime(exclusiveDeposit!.exclusivityDeadline + 1); await updateAllClients(); @@ -591,10 +588,7 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { outputToken, outputAmount ); - const fillAmount = profitClient.getFillAmountInUsd({ - ...deposit1, - outputToken: deposit1.outputToken, - })!; + const fillAmount = profitClient.getFillAmountInUsd(deposit1)!; expect(fillAmount).to.exist; // Simple escalating confirmation requirements; cap off with a default upper limit. @@ -644,8 +638,7 @@ describe("Relayer: Check for Unfilled Deposits and Fill", async function () { await updateAllClients(); originChainCommitment = relayerInstance.computeOriginChainCommitment(originChainId, 0, Number.MAX_SAFE_INTEGER); - expect(originChainCommitment.eq(getFillAmount({ ...deposit1, outputToken: deposit1.outputToken }, tokenPrice))).to - .be.true; + expect(originChainCommitment.eq(getFillAmount(deposit1, tokenPrice))).to.be.true; let originChainLimits = relayerInstance.computeOriginChainLimits(originChainId); expect(isChainOvercommitted(originChainLimits)).to.be.false; From 573d8fc60b0eaf137c39b8605f345c7b8cb6d021 Mon Sep 17 00:00:00 2001 From: Ihor Farion Date: Mon, 21 Jul 2025 14:33:07 -0700 Subject: [PATCH 5/6] adjust test utility fns to be more explicit Signed-off-by: Ihor Farion --- src/interfaces/index.ts | 1 + test/Relayer.UnfilledDeposits.ts | 24 +++--- test/utils/utils.ts | 137 +++++++++++++++++-------------- 3 files changed, 88 insertions(+), 74 deletions(-) diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index 9d3f8a3ed5..8d0163045f 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -56,6 +56,7 @@ export type RelayData = interfaces.RelayData; export type Deposit = interfaces.Deposit; export type DepositWithBlock = interfaces.DepositWithBlock; export type Fill = interfaces.Fill; +export type RelayExecutionEventInfo = interfaces.RelayExecutionEventInfo; export type FillWithBlock = interfaces.FillWithBlock; export type SpeedUp = interfaces.SpeedUp; export type SlowFillRequest = interfaces.SlowFillRequest; diff --git a/test/Relayer.UnfilledDeposits.ts b/test/Relayer.UnfilledDeposits.ts index 0f74c7b1ea..3233829612 100644 --- a/test/Relayer.UnfilledDeposits.ts +++ b/test/Relayer.UnfilledDeposits.ts @@ -43,8 +43,8 @@ import { randomAddress, setupTokensForWallet, deployMulticall3, - depositV3IntoPrimitiveEvm, - fillIntoPrimitiveEvm, + depositIntoPrimitiveTypes, + fillIntoPrimitiveTypes, } from "./utils"; // Tested import { Relayer } from "../src/relayer/Relayer"; @@ -235,7 +235,7 @@ describe("Relayer: Unfilled Deposits", async function () { unfilledDeposits.map((unfilledDeposit) => { return { ...unfilledDeposit, - deposit: depositV3IntoPrimitiveEvm(unfilledDeposit.deposit), + deposit: depositIntoPrimitiveTypes(unfilledDeposit.deposit), }; }) ) @@ -244,7 +244,7 @@ describe("Relayer: Unfilled Deposits", async function () { [...deposits] .sort((a, b) => (a.destinationChainId > b.destinationChainId ? 1 : -1)) .map((deposit) => ({ - deposit: depositV3IntoPrimitiveEvm(deposit), + deposit: depositIntoPrimitiveTypes(deposit), unfilledAmount: deposit.outputAmount, invalidFills: [], version: configStoreClient.configStoreVersion, @@ -282,7 +282,7 @@ describe("Relayer: Unfilled Deposits", async function () { unfilledDeposits.map((unfilledDeposit) => { return { ...unfilledDeposit, - deposit: depositV3IntoPrimitiveEvm(unfilledDeposit.deposit), + deposit: depositIntoPrimitiveTypes(unfilledDeposit.deposit), }; }) ) @@ -291,7 +291,7 @@ describe("Relayer: Unfilled Deposits", async function () { deposits .filter(({ depositId }) => depositId !== filledDeposit!.depositId) .map((deposit) => ({ - deposit: depositV3IntoPrimitiveEvm(deposit), + deposit: depositIntoPrimitiveTypes(deposit), unfilledAmount: deposit.outputAmount, invalidFills: [], version: configStoreClient.configStoreVersion, @@ -321,7 +321,7 @@ describe("Relayer: Unfilled Deposits", async function () { unfilledDeposits = _getAllUnfilledDeposits(); expect( unfilledDeposits.map((unfilledDeposit) => { - const depositV3PrimitiveEvmArgs = depositV3IntoPrimitiveEvm(unfilledDeposit.deposit); + const depositV3PrimitiveEvmArgs = depositIntoPrimitiveTypes(unfilledDeposit.deposit); return { ...unfilledDeposit, deposit: { @@ -351,14 +351,14 @@ describe("Relayer: Unfilled Deposits", async function () { { deposit: { ...deposit, - ...depositV3IntoPrimitiveEvm(deposit), + ...depositIntoPrimitiveTypes(deposit), depositId: sdkUtils.toBN(deposit.depositId), }, unfilledAmount: deposit.outputAmount, invalidFills: [ { ...invalidFill, - ...fillIntoPrimitiveEvm(invalidFill), + ...fillIntoPrimitiveTypes(invalidFill), depositId: sdkUtils.toBN(invalidFill.depositId), }, ], @@ -601,7 +601,7 @@ describe("Relayer: Unfilled Deposits", async function () { ...unfilledDeposit, deposit: { ...unfilledDeposit.deposit, - ...depositV3IntoPrimitiveEvm(unfilledDeposit.deposit), + ...depositIntoPrimitiveTypes(unfilledDeposit.deposit), }, invalidFills: [ { @@ -625,14 +625,14 @@ describe("Relayer: Unfilled Deposits", async function () { .to.deep.equal([ { deposit: { - ...depositV3IntoPrimitiveEvm(deposit), + ...depositIntoPrimitiveTypes(deposit), depositId: sdkUtils.toBN(deposit.depositId), }, unfilledAmount: deposit.outputAmount, invalidFills: [ { ...invalidFill, - ...fillIntoPrimitiveEvm(invalidFill), + ...fillIntoPrimitiveTypes(invalidFill), depositId: sdkUtils.toBN(invalidFill.depositId), }, ], diff --git a/test/utils/utils.ts b/test/utils/utils.ts index df16481d3e..9c7d6253c6 100644 --- a/test/utils/utils.ts +++ b/test/utils/utils.ts @@ -15,6 +15,7 @@ import { Fill, FillWithBlock, RelayData, + RelayExecutionEventInfo, SlowFillLeaf, SlowFillRequest, } from "../../src/interfaces"; @@ -363,7 +364,7 @@ export async function updateDeposit( ): Promise { const { updatedRecipient: updatedRecipientAddress, updatedOutputAmount, updatedMessage } = deposit; if (updatedRecipientAddress === undefined) { - throw `updateDeposit cannot have updatedRecipientAddress undefined ${depositV3IntoPrimitiveEvm(deposit)}`; + throw `updateDeposit cannot have updatedRecipientAddress undefined ${depositIntoPrimitiveTypes(deposit)}`; } const updatedRecipient = updatedRecipientAddress.toBytes32(); assert.ok(isDefined(updatedRecipient)); @@ -422,17 +423,11 @@ export async function fillV3Relay( const parsedEvent = spreadEvent(args); return { - destinationChainId, blockNumber, txnRef: transactionHash, txnIndex: transactionIndex, logIndex, - ...fillFromArgs(parsedEvent), - messageHash: args.messageHash ?? getMessageHash(args.message), - relayExecutionInfo: { - ...parsedEvent.relayExecutionInfo, - updatedMessageHash: getMessageHash(parsedEvent.relayExecutionInfo.updatedMessage), - }, + ...fillFromArgs({ ...parsedEvent, destinationChainId }), }; } @@ -449,7 +444,7 @@ export async function addLiquidity( await hubPool.connect(signer).addLiquidity(l1Token.address, amount); } -export function buildV3SlowRelayLeaves(deposits: interfaces.Deposit[], lpFeePct: BigNumber): SlowFillLeaf[] { +export function buildV3SlowRelayLeaves(deposits: Deposit[], lpFeePct: BigNumber): SlowFillLeaf[] { const chainId = deposits[0].destinationChainId; assert.isTrue(deposits.every(({ destinationChainId }) => chainId === destinationChainId)); return deposits @@ -507,87 +502,105 @@ export function createRefunds( }; } -// A helper function to parse key - value map into a Deposit object +// A helper function to parse key - value map into a Fill object export function fillFromArgs(fillArgs: { [key: string]: any }): Fill { - const obj = { ...fillArgs }; - - obj.relayExecutionInfo.updatedRecipient = toAddressType( - fillArgs.relayExecutionInfo.updatedRecipient, - fillArgs.destinationChainId - ); - - obj.relayer = toAddressType(fillArgs.relayer, fillArgs.destinationChainId); - - obj.depositor = toAddressType(fillArgs.depositor, fillArgs.originChainId); - obj.recipient = toAddressType(fillArgs.recipient, fillArgs.destinationChainId); - obj.inputToken = toAddressType(fillArgs.inputToken, fillArgs.originChainId); - obj.outputToken = toAddressType(fillArgs.outputToken, fillArgs.destinationChainId); - obj.exclusiveRelayer = toAddressType(fillArgs.exclusiveRelayer, fillArgs.destinationChainId); - - return obj as Fill; + const { message, ...relayData } = relayDataFromArgs(fillArgs); + const { relayExecutionInfo: relayExecutionInfoArgs } = fillArgs; + const relayExecutionInfo: RelayExecutionEventInfo = { + updatedRecipient: toAddressType(relayExecutionInfoArgs.updatedRecipient, fillArgs.destinationChainId), + updatedOutputAmount: relayExecutionInfoArgs.updatedOutputAmount, + updatedMessageHash: relayExecutionInfoArgs.updatedMessageHash, + fillType: relayExecutionInfoArgs.fillType, + }; + if (relayExecutionInfoArgs.updatedMessage) { + relayExecutionInfo.updatedMessage = relayExecutionInfoArgs.updatedMessage; + } + return { + ...relayData, + messageHash: fillArgs.messageHash, + destinationChainId: fillArgs.destinationChainId, + relayer: toAddressType(fillArgs.relayer, fillArgs.destinationChainId), + repaymentChainId: fillArgs.repaymentChainId, + relayExecutionInfo, + }; } // decomposes Fill into primitive types suitable for === comparions -export function fillIntoPrimitiveEvm(fill: Fill) { +export function fillIntoPrimitiveTypes(fill: Fill) { return { ...fill, - inputToken: fill.inputToken.toEvmAddress(), - outputToken: fill.outputToken.toEvmAddress(), - depositor: fill.depositor.toEvmAddress(), - recipient: fill.recipient.toEvmAddress(), - exclusiveRelayer: fill.exclusiveRelayer.toEvmAddress(), - relayer: fill.relayer.toEvmAddress(), // todo? consider using .toNative() and dropping the `...Evm` suffix + inputToken: fill.inputToken.toNative(), + outputToken: fill.outputToken.toNative(), + depositor: fill.depositor.toNative(), + recipient: fill.recipient.toNative(), + exclusiveRelayer: fill.exclusiveRelayer.toNative(), + relayer: fill.relayer.toNative(), relayExecutionInfo: { ...fill.relayExecutionInfo, - updatedRecipient: fill.relayExecutionInfo.updatedRecipient?.toEvmAddress(), + updatedRecipient: fill.relayExecutionInfo.updatedRecipient?.toNative(), }, }; } export function relayDataFromArgs(relayDataArgs: { [key: string]: any }): RelayData { - const obj = { ...relayDataArgs }; - - obj.depositor = toAddressType(relayDataArgs.depositor, relayDataArgs.originChainId); - obj.recipient = toAddressType(relayDataArgs.recipient, relayDataArgs.destinationChainId); - obj.inputToken = toAddressType(relayDataArgs.inputToken, relayDataArgs.originChainId); - obj.outputToken = toAddressType(relayDataArgs.outputToken, relayDataArgs.destinationChainId); - obj.exclusiveRelayer = toAddressType(relayDataArgs.exclusiveRelayer, relayDataArgs.destinationChainId); - - return obj as RelayData; + return { + originChainId: relayDataArgs.originChainId, + depositor: toAddressType(relayDataArgs.depositor, relayDataArgs.originChainId), + recipient: toAddressType(relayDataArgs.recipient, relayDataArgs.destinationChainId), + depositId: relayDataArgs.depositId, + inputToken: toAddressType(relayDataArgs.inputToken, relayDataArgs.originChainId), + inputAmount: relayDataArgs.inputAmount, + outputToken: toAddressType(relayDataArgs.outputToken, relayDataArgs.destinationChainId), + outputAmount: relayDataArgs.outputAmount, + message: relayDataArgs.message, + fillDeadline: relayDataArgs.fillDeadline, + exclusiveRelayer: toAddressType(relayDataArgs.exclusiveRelayer, relayDataArgs.destinationChainId), + exclusivityDeadline: relayDataArgs.exclusivityDeadline, + }; } export function slowFillRequestFromArgs(slowFillRequestArgs: { [key: string]: any }): SlowFillRequest { - const obj = { ...slowFillRequestArgs, ...(relayDataFromArgs(slowFillRequestArgs) as any) }; - - return obj as SlowFillRequest; + const { message, ...relayData } = relayDataFromArgs(slowFillRequestArgs); + return { + ...relayData, + destinationChainId: slowFillRequestArgs.destinationChainId, + messageHash: slowFillRequestArgs.messageHash ?? getMessageHash(slowFillRequestArgs.message), + }; } // A helper function to parse key - value map into a Deposit object with correct types (e.g. Address) export function depositFromArgs(depositArgs: { [key: string]: any }): Deposit { - const obj = { ...depositArgs }; + const deposit: Deposit = { + ...relayDataFromArgs(depositArgs), + destinationChainId: depositArgs.destinationChainId, + messageHash: depositArgs.messageHash, + quoteTimestamp: depositArgs.quoteTimestamp, + fromLiteChain: depositArgs.fromLiteChain, + toLiteChain: depositArgs.toLiteChain, + }; - obj.depositor = toAddressType(depositArgs.depositor, depositArgs.originChainId); - obj.recipient = toAddressType(depositArgs.recipient, depositArgs.destinationChainId); - obj.inputToken = toAddressType(depositArgs.inputToken, depositArgs.originChainId); - obj.outputToken = toAddressType(depositArgs.outputToken, depositArgs.destinationChainId); - obj.exclusiveRelayer = toAddressType(depositArgs.exclusiveRelayer, depositArgs.destinationChainId); + if (depositArgs.speedUpSignature) { + deposit.speedUpSignature = depositArgs.speedUpSignature; + } - if (depositArgs.updatedRecipient !== undefined) { - obj.updatedRecipient = toAddressType(depositArgs.updatedRecipient, depositArgs.destinationChainId); + if (depositArgs.updatedRecipient) { + deposit.updatedRecipient = toAddressType(depositArgs.updatedRecipient, depositArgs.destinationChainId); + deposit.updatedOutputAmount = depositArgs.updatedOutputAmount; + deposit.updatedMessage = depositArgs.updatedMessage; } - return obj as Deposit; + return deposit; } // decomposes Deposit into primitive types suitable for === comparions -export function depositV3IntoPrimitiveEvm(deposit: Deposit) { +export function depositIntoPrimitiveTypes(deposit: Deposit) { return { ...deposit, - inputToken: deposit.inputToken.toEvmAddress(), - outputToken: deposit.outputToken.toEvmAddress(), - depositor: deposit.depositor.toEvmAddress(), - recipient: deposit.recipient.toEvmAddress(), - exclusiveRelayer: deposit.exclusiveRelayer.toEvmAddress(), - updatedRecipient: deposit.updatedRecipient?.toEvmAddress(), + inputToken: deposit.inputToken.toNative(), + outputToken: deposit.outputToken.toNative(), + depositor: deposit.depositor.toNative(), + recipient: deposit.recipient.toNative(), + exclusiveRelayer: deposit.exclusiveRelayer.toNative(), + updatedRecipient: deposit.updatedRecipient?.toNative(), }; } From db2bcdbe4efb5c2166eb920a30f890611d1ee7ed Mon Sep 17 00:00:00 2001 From: Ihor Farion Date: Mon, 21 Jul 2025 15:59:37 -0700 Subject: [PATCH 6/6] init commit Signed-off-by: Ihor Farion --- test/utils/SpokePoolUtils.ts | 6 +- test/utils/utils.ts | 120 ++++++++++++++++++++++++++++++----- 2 files changed, 107 insertions(+), 19 deletions(-) diff --git a/test/utils/SpokePoolUtils.ts b/test/utils/SpokePoolUtils.ts index 270b56e074..cdd187582d 100644 --- a/test/utils/SpokePoolUtils.ts +++ b/test/utils/SpokePoolUtils.ts @@ -52,10 +52,12 @@ export async function requestSlowFill( ]); const lastEvent = events.at(-1); assert(lastEvent); - const slowFillRequest = slowFillRequestFromArgs(spreadEvent(lastEvent.args!)); + const slowFillRequest = slowFillRequestFromArgs({ + ...spreadEvent(lastEvent.args!), + destinationChainId: Number(destinationChainId), + }); const requestObject: SlowFillRequestWithBlock = { ...slowFillRequest, - destinationChainId, blockNumber: lastEvent.blockNumber, txnRef: lastEvent.transactionHash, logIndex: lastEvent.logIndex, diff --git a/test/utils/utils.ts b/test/utils/utils.ts index 9c7d6253c6..a0061085b9 100644 --- a/test/utils/utils.ts +++ b/test/utils/utils.ts @@ -40,6 +40,7 @@ import { } from "../constants"; import { SpokePoolDeploymentResult, SpyLoggerResult } from "../types"; import { INFINITE_FILL_DEADLINE } from "../../src/common"; +import { assert as ssAssert, number, string, boolean, optional, any, type } from "superstruct"; export { SpyTransport, @@ -280,6 +281,8 @@ export async function depositV3( fillDeadline?: number; exclusivityDeadline?: number; exclusiveRelayer?: string; + fromLiteChain?: boolean; + toLiteChain?: boolean; } = {} ): Promise { const depositor = signer.address; @@ -344,10 +347,14 @@ export async function depositV3( txnRef, txnIndex, logIndex, - ...depositFromArgs(depositArgs), - originChainId: Number(originChainId), + ...depositFromArgs({ + ...depositArgs, + originChainId: Number(originChainId), + messageHash: args.messageHash ?? getMessageHash(args.message), + fromLiteChain: opts.fromLiteChain ?? false, + toLiteChain: opts.toLiteChain ?? false, + }), quoteBlockNumber: 0, - messageHash: args.messageHash ?? getMessageHash(args.message), }; if (isLegacyDeposit) { @@ -502,9 +509,95 @@ export function createRefunds( }; } +// Superstruct validation schemas to ensure expected properties exist in argument maps. +const RelayDataFields = { + originChainId: number(), + depositor: string(), + recipient: string(), + depositId: any(), + inputToken: string(), + inputAmount: any(), + outputToken: string(), + outputAmount: any(), + message: string(), + fillDeadline: any(), + exclusiveRelayer: string(), + exclusivityDeadline: any(), +}; + +// This one isn't from the SDK, but a requirement for the test util helpers +const DestinationChainIdField = { + destinationChainId: number(), +}; + +// The raw args for relay data need destinationChainId for creating Address types +const RelayDataArgsStruct = type({ ...RelayDataFields, ...DestinationChainIdField }); + +// Now for the specific event types +const { message, ...OmittedMessageRelayDataFields } = RelayDataFields; + +const BaseRelayArgsStruct = type({ + ...OmittedMessageRelayDataFields, + ...DestinationChainIdField, +}); + +const DepositArgsStruct = type({ + ...RelayDataFields, + ...DestinationChainIdField, + messageHash: string(), + quoteTimestamp: number(), + fromLiteChain: boolean(), + toLiteChain: boolean(), + speedUpSignature: optional(string()), + updatedRecipient: optional(string()), + updatedOutputAmount: optional(any()), + updatedMessage: optional(string()), +}); + +const RelayExecutionEventInfoStruct = type({ + updatedRecipient: string(), + updatedOutputAmount: any(), // BigNumber + updatedMessage: optional(string()), + updatedMessageHash: string(), + fillType: any(), // enum FillType +}); + +const FillArgsStruct = type({ + ...OmittedMessageRelayDataFields, + ...DestinationChainIdField, + messageHash: string(), + relayer: string(), + repaymentChainId: number(), + relayExecutionInfo: RelayExecutionEventInfoStruct, +}); + +const SlowFillRequestArgsStruct = type({ + ...OmittedMessageRelayDataFields, + ...DestinationChainIdField, + messageHash: string(), +}); + +function _getRelayDataFields(relayDataArgs: { [key: string]: any }): Omit { + ssAssert(relayDataArgs, BaseRelayArgsStruct); + return { + originChainId: relayDataArgs.originChainId, + depositor: toAddressType(relayDataArgs.depositor, relayDataArgs.originChainId), + recipient: toAddressType(relayDataArgs.recipient, relayDataArgs.destinationChainId), + depositId: relayDataArgs.depositId, + inputToken: toAddressType(relayDataArgs.inputToken, relayDataArgs.originChainId), + inputAmount: relayDataArgs.inputAmount, + outputToken: toAddressType(relayDataArgs.outputToken, relayDataArgs.destinationChainId), + outputAmount: relayDataArgs.outputAmount, + fillDeadline: relayDataArgs.fillDeadline, + exclusiveRelayer: toAddressType(relayDataArgs.exclusiveRelayer, relayDataArgs.destinationChainId), + exclusivityDeadline: relayDataArgs.exclusivityDeadline, + }; +} + // A helper function to parse key - value map into a Fill object export function fillFromArgs(fillArgs: { [key: string]: any }): Fill { - const { message, ...relayData } = relayDataFromArgs(fillArgs); + ssAssert(fillArgs, FillArgsStruct); + const relayData = _getRelayDataFields(fillArgs); const { relayExecutionInfo: relayExecutionInfoArgs } = fillArgs; const relayExecutionInfo: RelayExecutionEventInfo = { updatedRecipient: toAddressType(relayExecutionInfoArgs.updatedRecipient, fillArgs.destinationChainId), @@ -543,33 +636,26 @@ export function fillIntoPrimitiveTypes(fill: Fill) { } export function relayDataFromArgs(relayDataArgs: { [key: string]: any }): RelayData { + ssAssert(relayDataArgs, RelayDataArgsStruct); return { - originChainId: relayDataArgs.originChainId, - depositor: toAddressType(relayDataArgs.depositor, relayDataArgs.originChainId), - recipient: toAddressType(relayDataArgs.recipient, relayDataArgs.destinationChainId), - depositId: relayDataArgs.depositId, - inputToken: toAddressType(relayDataArgs.inputToken, relayDataArgs.originChainId), - inputAmount: relayDataArgs.inputAmount, - outputToken: toAddressType(relayDataArgs.outputToken, relayDataArgs.destinationChainId), - outputAmount: relayDataArgs.outputAmount, + ..._getRelayDataFields(relayDataArgs), message: relayDataArgs.message, - fillDeadline: relayDataArgs.fillDeadline, - exclusiveRelayer: toAddressType(relayDataArgs.exclusiveRelayer, relayDataArgs.destinationChainId), - exclusivityDeadline: relayDataArgs.exclusivityDeadline, }; } export function slowFillRequestFromArgs(slowFillRequestArgs: { [key: string]: any }): SlowFillRequest { - const { message, ...relayData } = relayDataFromArgs(slowFillRequestArgs); + ssAssert(slowFillRequestArgs, SlowFillRequestArgsStruct); + const relayData = _getRelayDataFields(slowFillRequestArgs); return { ...relayData, destinationChainId: slowFillRequestArgs.destinationChainId, - messageHash: slowFillRequestArgs.messageHash ?? getMessageHash(slowFillRequestArgs.message), + messageHash: slowFillRequestArgs.messageHash, }; } // A helper function to parse key - value map into a Deposit object with correct types (e.g. Address) export function depositFromArgs(depositArgs: { [key: string]: any }): Deposit { + ssAssert(depositArgs, DepositArgsStruct); const deposit: Deposit = { ...relayDataFromArgs(depositArgs), destinationChainId: depositArgs.destinationChainId,