@across-protocol/sdk 4.0.2 → 4.0.3-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/cjs/clients/BundleDataClient/BundleDataClient.d.ts +2 -3
  2. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +22 -18
  3. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  4. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.d.ts +3 -0
  5. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +20 -10
  6. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  7. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.d.ts +9 -0
  8. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.js +3 -1
  9. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.js.map +1 -1
  10. package/dist/cjs/clients/SpokePoolClient.js +67 -47
  11. package/dist/cjs/clients/SpokePoolClient.js.map +1 -1
  12. package/dist/cjs/clients/mocks/MockSpokePoolClient.d.ts +5 -5
  13. package/dist/cjs/clients/mocks/MockSpokePoolClient.js +2 -2
  14. package/dist/cjs/clients/mocks/MockSpokePoolClient.js.map +1 -1
  15. package/dist/cjs/interfaces/SpokePool.d.ts +2 -0
  16. package/dist/cjs/interfaces/SpokePool.js.map +1 -1
  17. package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.d.ts +3 -3
  18. package/dist/cjs/relayFeeCalculator/chain-queries/baseQuery.js.map +1 -1
  19. package/dist/cjs/relayFeeCalculator/relayFeeCalculator.d.ts +1 -1
  20. package/dist/cjs/utils/SpokeUtils.d.ts +4 -1
  21. package/dist/cjs/utils/SpokeUtils.js +21 -1
  22. package/dist/cjs/utils/SpokeUtils.js.map +1 -1
  23. package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +2 -3
  24. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +26 -24
  25. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  26. package/dist/esm/clients/BundleDataClient/utils/FillUtils.d.ts +3 -0
  27. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +20 -11
  28. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  29. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.d.ts +9 -0
  30. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.js +2 -0
  31. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.js.map +1 -1
  32. package/dist/esm/clients/SpokePoolClient.js +78 -48
  33. package/dist/esm/clients/SpokePoolClient.js.map +1 -1
  34. package/dist/esm/clients/mocks/MockSpokePoolClient.d.ts +5 -5
  35. package/dist/esm/clients/mocks/MockSpokePoolClient.js +2 -2
  36. package/dist/esm/clients/mocks/MockSpokePoolClient.js.map +1 -1
  37. package/dist/esm/interfaces/SpokePool.d.ts +2 -0
  38. package/dist/esm/interfaces/SpokePool.js.map +1 -1
  39. package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.d.ts +3 -3
  40. package/dist/esm/relayFeeCalculator/chain-queries/baseQuery.js.map +1 -1
  41. package/dist/esm/relayFeeCalculator/relayFeeCalculator.d.ts +1 -1
  42. package/dist/esm/utils/SpokeUtils.d.ts +11 -1
  43. package/dist/esm/utils/SpokeUtils.js +26 -0
  44. package/dist/esm/utils/SpokeUtils.js.map +1 -1
  45. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +2 -3
  46. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
  47. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts +3 -0
  48. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
  49. package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts +9 -0
  50. package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts.map +1 -1
  51. package/dist/types/clients/SpokePoolClient.d.ts.map +1 -1
  52. package/dist/types/clients/mocks/MockSpokePoolClient.d.ts +5 -5
  53. package/dist/types/clients/mocks/MockSpokePoolClient.d.ts.map +1 -1
  54. package/dist/types/interfaces/SpokePool.d.ts +2 -0
  55. package/dist/types/interfaces/SpokePool.d.ts.map +1 -1
  56. package/dist/types/relayFeeCalculator/chain-queries/baseQuery.d.ts +3 -3
  57. package/dist/types/relayFeeCalculator/chain-queries/baseQuery.d.ts.map +1 -1
  58. package/dist/types/relayFeeCalculator/relayFeeCalculator.d.ts +1 -1
  59. package/dist/types/relayFeeCalculator/relayFeeCalculator.d.ts.map +1 -1
  60. package/dist/types/utils/SpokeUtils.d.ts +11 -1
  61. package/dist/types/utils/SpokeUtils.d.ts.map +1 -1
  62. package/package.json +1 -1
  63. package/src/clients/BundleDataClient/BundleDataClient.ts +29 -29
  64. package/src/clients/BundleDataClient/utils/FillUtils.ts +26 -13
  65. package/src/clients/BundleDataClient/utils/SuperstructUtils.ts +3 -0
  66. package/src/clients/SpokePoolClient.ts +58 -24
  67. package/src/clients/mocks/MockSpokePoolClient.ts +10 -8
  68. package/src/interfaces/SpokePool.ts +2 -0
  69. package/src/relayFeeCalculator/chain-queries/baseQuery.ts +6 -3
  70. package/src/relayFeeCalculator/relayFeeCalculator.ts +1 -1
  71. package/src/utils/SpokeUtils.ts +28 -1
  72. package/dist/cjs/package.json +0 -1
  73. package/dist/esm/package.json +0 -1
@@ -53,6 +53,30 @@ export function getRepaymentChainId(fill: Fill, matchedDeposit: Deposit): number
53
53
  return matchedDeposit.fromLiteChain ? matchedDeposit.originChainId : fill.repaymentChainId;
54
54
  }
55
55
 
56
+ export function willOverwriteRepaymentChain(
57
+ repaymentChainId: number,
58
+ matchedDeposit: Deposit & { quoteBlockNumber: number },
59
+ hubPoolClient: HubPoolClient
60
+ ): boolean {
61
+ if (!matchedDeposit.fromLiteChain) {
62
+ try {
63
+ const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
64
+ matchedDeposit.inputToken,
65
+ matchedDeposit.originChainId,
66
+ matchedDeposit.quoteBlockNumber
67
+ );
68
+ hubPoolClient.getL2TokenForL1TokenAtBlock(l1TokenCounterpart, repaymentChainId, matchedDeposit.quoteBlockNumber);
69
+ // Repayment token could be found, this is a valid repayment chain.
70
+ return false;
71
+ } catch {
72
+ // Repayment token doesn't exist on repayment chain via PoolRebalanceRoutes, impossible to repay filler there.
73
+ return true;
74
+ }
75
+ } else {
76
+ return false;
77
+ }
78
+ }
79
+
56
80
  // Verify that a fill sent to an EVM chain has a 20 byte address. If the fill does not, then attempt
57
81
  // to repay the `msg.sender` of the relay transaction. Otherwise, return undefined.
58
82
  export async function verifyFillRepayment(
@@ -72,19 +96,8 @@ export async function verifyFillRepayment(
72
96
 
73
97
  // If repayment chain doesn't have a Pool Rebalance Route for the input token, then change the repayment
74
98
  // chain to the destination chain.
75
- if (!isSlowFill(fill) && !matchedDeposit.fromLiteChain) {
76
- try {
77
- const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
78
- fill.inputToken,
79
- fill.originChainId,
80
- matchedDeposit.quoteBlockNumber
81
- );
82
- hubPoolClient.getL2TokenForL1TokenAtBlock(l1TokenCounterpart, repaymentChainId, matchedDeposit.quoteBlockNumber);
83
- // Repayment token could be found, this is a valid repayment chain.
84
- } catch {
85
- // Repayment token doesn't exist on repayment chain via PoolRebalanceRoutes, impossible to repay filler there.
86
- repaymentChainId = fill.destinationChainId;
87
- }
99
+ if (!isSlowFill(fill) && willOverwriteRepaymentChain(repaymentChainId, matchedDeposit, hubPoolClient)) {
100
+ repaymentChainId = fill.destinationChainId;
88
101
  }
89
102
 
90
103
  if (!isValidEvmAddress(fill.relayer)) {
@@ -15,6 +15,8 @@ import {
15
15
  } from "superstruct";
16
16
  import { BigNumber } from "../../../utils";
17
17
 
18
+ export const UNDEFINED_MESSAGE_HASH = "";
19
+
18
20
  const PositiveIntegerStringSS = pattern(string(), /\d+/);
19
21
  const Web3AddressSS = pattern(string(), /^0x[a-fA-F0-9]{40}$/);
20
22
 
@@ -54,6 +56,7 @@ const SortableEventSS = {
54
56
  };
55
57
 
56
58
  const V3DepositSS = {
59
+ messageHash: defaulted(string(), UNDEFINED_MESSAGE_HASH),
57
60
  fromLiteChain: defaulted(boolean(), false),
58
61
  toLiteChain: defaulted(boolean(), false),
59
62
  destinationChainId: number(),
@@ -9,11 +9,14 @@ import {
9
9
  MAX_BIG_INT,
10
10
  MakeOptional,
11
11
  assign,
12
- getRelayDataHash,
12
+ getRelayEventKey,
13
13
  isDefined,
14
14
  toBN,
15
15
  bnOne,
16
+ getMessageHash,
16
17
  isUnsafeDepositId,
18
+ isSlowFill,
19
+ isValidEvmAddress,
17
20
  } from "../utils";
18
21
  import {
19
22
  paginatedEventQuery,
@@ -43,6 +46,7 @@ import { getBlockRangeForDepositId, getDepositIdAtBlock, relayFillStatus } from
43
46
  import { BaseAbstractClient, isUpdateFailureReason, UpdateFailureReason } from "./BaseAbstractClient";
44
47
  import { HubPoolClient } from "./HubPoolClient";
45
48
  import { AcrossConfigStoreClient } from "./AcrossConfigStoreClient";
49
+ import { getRepaymentChainId, overwriteRepaymentChain, willOverwriteRepaymentChain } from "./BundleDataClient/utils/FillUtils";
46
50
 
47
51
  type SpokePoolUpdateSuccess = {
48
52
  success: true;
@@ -143,7 +147,7 @@ export class SpokePoolClient extends BaseAbstractClient {
143
147
  * unless the original deposit is a duplicate.
144
148
  */
145
149
  private _getDuplicateDeposits(deposit: DepositWithBlock): DepositWithBlock[] {
146
- const depositHash = this.getDepositHash(deposit);
150
+ const depositHash = getRelayEventKey(deposit);
147
151
  return this.duplicateDepositHashes[depositHash] ?? [];
148
152
  }
149
153
 
@@ -297,8 +301,7 @@ export class SpokePoolClient extends BaseAbstractClient {
297
301
  * @returns The corresponding deposit if found, undefined otherwise.
298
302
  */
299
303
  public getDeposit(depositId: BigNumber): DepositWithBlock | undefined {
300
- const depositHash = this.getDepositHash({ depositId, originChainId: this.chainId });
301
- return this.depositHashes[depositHash];
304
+ return Object.values(this.depositHashes).find(({ depositId: _depositId }) => _depositId.eq(depositId));
302
305
  }
303
306
 
304
307
  /**
@@ -307,7 +310,7 @@ export class SpokePoolClient extends BaseAbstractClient {
307
310
  * @returns The corresponding SlowFIllRequest event if found, otherwise undefined.
308
311
  */
309
312
  public getSlowFillRequest(relayData: RelayData): SlowFillRequestWithBlock | undefined {
310
- const hash = getRelayDataHash(relayData, this.chainId);
313
+ const hash = getRelayEventKey({ ...relayData, destinationChainId: this.chainId });
311
314
  return this.slowFillRequests[hash];
312
315
  }
313
316
 
@@ -336,7 +339,7 @@ export class SpokePoolClient extends BaseAbstractClient {
336
339
  * @returns The corresponding deposit if found, undefined otherwise.
337
340
  */
338
341
  public getDepositForFill(fill: Fill): DepositWithBlock | undefined {
339
- const deposit = this.depositHashes[this.getDepositHash(fill)];
342
+ const deposit = this.depositHashes[getRelayEventKey(fill)];
340
343
  const match = validateFillForDeposit(fill, deposit);
341
344
  if (match.valid) {
342
345
  return deposit;
@@ -359,7 +362,7 @@ export class SpokePoolClient extends BaseAbstractClient {
359
362
  * @returns A valid fill for the deposit, or undefined.
360
363
  */
361
364
  public getFillForDeposit(deposit: Deposit): FillWithBlock | undefined {
362
- const fills = this.depositHashesToFills[this.getDepositHash(deposit)];
365
+ const fills = this.depositHashesToFills[getRelayEventKey(deposit)];
363
366
  return fills?.find((fill) => validateFillForDeposit(fill, deposit));
364
367
  }
365
368
 
@@ -376,23 +379,44 @@ export class SpokePoolClient extends BaseAbstractClient {
376
379
  invalidFills: Fill[];
377
380
  } {
378
381
  const { outputAmount } = deposit;
379
- const fillsForDeposit = this.depositHashesToFills[this.getDepositHash(deposit)];
382
+ const fillsForDeposit = this.depositHashesToFills[getRelayEventKey(deposit)];
380
383
 
381
384
  // If no fills then the full amount is remaining.
382
385
  if (fillsForDeposit === undefined || fillsForDeposit.length === 0) {
383
386
  return { unfilledAmount: outputAmount, fillCount: 0, invalidFills: [] };
384
387
  }
385
388
 
386
- const { validFills, invalidFills } = fillsForDeposit.reduce(
387
- (groupedFills: { validFills: Fill[]; invalidFills: Fill[] }, fill: Fill) => {
389
+ const { validFills, invalidFills, unrepayableFills } = fillsForDeposit.reduce(
390
+ (groupedFills: { validFills: Fill[]; invalidFills: Fill[]; unrepayableFills: Fill[] }, fill: Fill) => {
388
391
  if (validateFillForDeposit(fill, deposit).valid) {
392
+ const repaymentChainId = getRepaymentChainId(fill, deposit);
393
+ // In order to keep this function sync, we can't call verifyFillRepayment so we'll log any fills that
394
+ // we'll have to overwrite repayment information for. This includes fills for lite chains where the
395
+ // repayment address is invalid, and fills for non-lite chains where the repayment address is valid or
396
+ // the repayment chain is invalid. We don't check that the origin chain is a valid EVM chain for
397
+ // lite chain deposits yet because only EVM chains are supported on Across...for now. This means
398
+ // this logic will have to be revisited when we add SVM to log properly.
399
+ if (
400
+ this.hubPoolClient &&
401
+ !isSlowFill(fill) &&
402
+ (!isValidEvmAddress(fill.relayer) ||
403
+ willOverwriteRepaymentChain(
404
+ repaymentChainId,
405
+ { ...deposit, quoteBlockNumber: this.hubPoolClient!.latestBlockSearched },
406
+ this.hubPoolClient
407
+ ))
408
+ ) {
409
+ groupedFills.unrepayableFills.push(fill);
410
+ }
411
+ // This fill is still valid and means that the deposit cannot be filled on-chain anymore, but it
412
+ // also can be unrepayable which we should want to log.
389
413
  groupedFills.validFills.push(fill);
390
414
  } else {
391
415
  groupedFills.invalidFills.push(fill);
392
416
  }
393
417
  return groupedFills;
394
418
  },
395
- { validFills: [], invalidFills: [] }
419
+ { validFills: [], invalidFills: [], unrepayableFills: [] }
396
420
  );
397
421
 
398
422
  // Log any invalid deposits with same deposit id but different params.
@@ -407,6 +431,17 @@ export class SpokePoolClient extends BaseAbstractClient {
407
431
  notificationPath: "across-invalid-fills",
408
432
  });
409
433
  }
434
+ const unrepayableFillsForDeposit = unrepayableFills.filter((x) => x.depositId.eq(deposit.depositId));
435
+ if (unrepayableFillsForDeposit.length > 0) {
436
+ this.logger.warn({
437
+ at: "SpokePoolClient",
438
+ chainId: this.chainId,
439
+ message: "Unrepayable fills found where we need to switch repayment address and or chain",
440
+ deposit,
441
+ unrepayableFills: Object.fromEntries(unrepayableFillsForDeposit.map((x) => [x.relayer, x])),
442
+ notificationPath: "across-unrepayable-fills",
443
+ });
444
+ }
410
445
 
411
446
  // If all fills are invalid we can consider this unfilled.
412
447
  if (validFills.length === 0) {
@@ -593,6 +628,7 @@ export class SpokePoolClient extends BaseAbstractClient {
593
628
  // Derive and append the common properties that are not part of the onchain event.
594
629
  const deposit = {
595
630
  ...spreadEventWithBlockNumber(event),
631
+ messageHash: getMessageHash(event.args["message"]),
596
632
  quoteBlockNumber,
597
633
  originChainId: this.chainId,
598
634
  // The following properties are placeholders to be updated immediately.
@@ -607,11 +643,11 @@ export class SpokePoolClient extends BaseAbstractClient {
607
643
  deposit.outputToken = this.getDestinationTokenForDeposit(deposit);
608
644
  }
609
645
 
610
- if (this.depositHashes[this.getDepositHash(deposit)] !== undefined) {
611
- assign(this.duplicateDepositHashes, [this.getDepositHash(deposit)], [deposit]);
646
+ if (this.depositHashes[getRelayEventKey(deposit)] !== undefined) {
647
+ assign(this.duplicateDepositHashes, [getRelayEventKey(deposit)], [deposit]);
612
648
  continue;
613
649
  }
614
- assign(this.depositHashes, [this.getDepositHash(deposit)], deposit);
650
+ assign(this.depositHashes, [getRelayEventKey(deposit)], deposit);
615
651
 
616
652
  if (deposit.depositId.lt(this.earliestDepositIdQueried) && !isUnsafeDepositId(deposit.depositId)) {
617
653
  this.earliestDepositIdQueried = deposit.depositId;
@@ -632,13 +668,13 @@ export class SpokePoolClient extends BaseAbstractClient {
632
668
 
633
669
  // Find deposit hash matching this speed up event and update the deposit data associated with the hash,
634
670
  // if the hash+data exists.
635
- const depositHash = this.getDepositHash(speedUp);
671
+ const deposit = this.getDeposit(speedUp.depositId);
636
672
 
637
673
  // We can assume all deposits in this lookback window are loaded in-memory already so if the depositHash
638
674
  // is not mapped to a deposit, then we can throw away the speedup as it can't be applied to anything.
639
- const depositDataAssociatedWithSpeedUp = this.depositHashes[depositHash];
640
- if (isDefined(depositDataAssociatedWithSpeedUp)) {
641
- this.depositHashes[depositHash] = this.appendMaxSpeedUpSignatureToDeposit(depositDataAssociatedWithSpeedUp);
675
+ if (isDefined(deposit)) {
676
+ const eventKey = getRelayEventKey(deposit);
677
+ this.depositHashes[eventKey] = this.appendMaxSpeedUpSignatureToDeposit(deposit);
642
678
  }
643
679
  }
644
680
  }
@@ -648,14 +684,12 @@ export class SpokePoolClient extends BaseAbstractClient {
648
684
  for (const event of slowFillRequests) {
649
685
  const slowFillRequest = {
650
686
  ...spreadEventWithBlockNumber(event),
687
+ messageHash: getMessageHash(event.args["message"]),
651
688
  destinationChainId: this.chainId,
652
689
  } as SlowFillRequestWithBlock;
653
690
 
654
- const relayDataHash = getRelayDataHash(slowFillRequest, this.chainId);
655
- if (this.slowFillRequests[relayDataHash] !== undefined) {
656
- continue;
657
- }
658
- this.slowFillRequests[relayDataHash] = slowFillRequest;
691
+ const depositHash = getRelayEventKey({ ...slowFillRequest, destinationChainId: this.chainId });
692
+ this.slowFillRequests[depositHash] ??= slowFillRequest;
659
693
  }
660
694
  }
661
695
 
@@ -677,7 +711,7 @@ export class SpokePoolClient extends BaseAbstractClient {
677
711
  } as FillWithBlock;
678
712
 
679
713
  assign(this.fills, [fill.originChainId], [fill]);
680
- assign(this.depositHashesToFills, [this.getDepositHash(fill)], [fill]);
714
+ assign(this.depositHashesToFills, [getRelayEventKey(fill)], [fill]);
681
715
  }
682
716
  }
683
717
 
@@ -5,10 +5,12 @@ import winston from "winston";
5
5
  import { ZERO_ADDRESS } from "../../constants";
6
6
  import {
7
7
  Log,
8
+ Deposit,
8
9
  DepositWithBlock,
9
10
  FillType,
10
- RelayerRefundExecutionWithBlock,
11
- SlowFillRequestWithBlock,
11
+ RelayerRefundExecution,
12
+ SlowFillRequest,
13
+ SortableEvent,
12
14
  Fill,
13
15
  FillWithBlock,
14
16
  SlowFillLeaf,
@@ -117,7 +119,7 @@ export class MockSpokePoolClient extends SpokePoolClient {
117
119
  EnabledDepositRoute: "address,uint256,bool",
118
120
  };
119
121
 
120
- depositV3(deposit: DepositWithBlock): Log {
122
+ depositV3(deposit: Omit<Deposit, "messageHash"> & Partial<SortableEvent>): Log {
121
123
  const event = "V3FundsDeposited";
122
124
 
123
125
  const { blockNumber, transactionIndex } = deposit;
@@ -132,7 +134,7 @@ export class MockSpokePoolClient extends SpokePoolClient {
132
134
  inputAmount ??= toBNWei(random(1, 1000, false));
133
135
  outputAmount ??= inputAmount.mul(toBN("0.95"));
134
136
 
135
- const message = deposit["message"] ?? `${event} event at block ${blockNumber}, index ${transactionIndex}.`;
137
+ const message = deposit["message"] ?? "0x";
136
138
  const topics = [destinationChainId, depositId, depositor];
137
139
  const quoteTimestamp = deposit.quoteTimestamp ?? getCurrentTime();
138
140
  const args = {
@@ -162,7 +164,7 @@ export class MockSpokePoolClient extends SpokePoolClient {
162
164
  });
163
165
  }
164
166
 
165
- fillV3Relay(fill: FillWithBlock): Log {
167
+ fillV3Relay(fill: Omit<Fill, "messageHash"> & Partial<SortableEvent>): Log {
166
168
  const event = "FilledV3Relay";
167
169
 
168
170
  const { blockNumber, transactionIndex } = fill;
@@ -177,7 +179,7 @@ export class MockSpokePoolClient extends SpokePoolClient {
177
179
 
178
180
  const topics = [originChainId, depositId, relayer];
179
181
  const recipient = fill.recipient ?? randomAddress();
180
- const message = fill["message"] ?? `${event} event at block ${blockNumber}, index ${transactionIndex}.`;
182
+ const message = fill["message"] ?? "0x";
181
183
 
182
184
  const args = {
183
185
  inputToken,
@@ -238,7 +240,7 @@ export class MockSpokePoolClient extends SpokePoolClient {
238
240
  });
239
241
  }
240
242
 
241
- requestV3SlowFill(request: SlowFillRequestWithBlock): Log {
243
+ requestV3SlowFill(request: Omit<SlowFillRequest, "messageHash"> & Partial<SortableEvent>): Log {
242
244
  const event = "RequestedV3SlowFill";
243
245
 
244
246
  const { originChainId, depositId } = request;
@@ -274,7 +276,7 @@ export class MockSpokePoolClient extends SpokePoolClient {
274
276
  return this.fillV3Relay(fill as FillWithBlock);
275
277
  }
276
278
 
277
- executeRelayerRefundLeaf(refund: RelayerRefundExecutionWithBlock): Log {
279
+ executeRelayerRefundLeaf(refund: RelayerRefundExecution & Partial<SortableEvent>): Log {
278
280
  const event = "ExecutedRelayerRefundRoot";
279
281
 
280
282
  const chainId = refund.chainId ?? this.chainId;
@@ -22,6 +22,7 @@ export interface RelayData {
22
22
  }
23
23
 
24
24
  export interface Deposit extends RelayData {
25
+ messageHash: string;
25
26
  destinationChainId: number;
26
27
  quoteTimestamp: number;
27
28
  speedUpSignature?: string;
@@ -77,6 +78,7 @@ export interface SpeedUp {
77
78
  export interface SpeedUpWithBlock extends SpeedUp, SortableEvent {}
78
79
 
79
80
  export interface SlowFillRequest extends RelayData {
81
+ messageHash: string;
80
82
  destinationChainId: number;
81
83
  }
82
84
  export interface SlowFillRequestWithBlock extends SlowFillRequest, SortableEvent {}
@@ -71,7 +71,7 @@ export class QueryBase implements QueryInterface {
71
71
  * @returns The gas estimate for this function call (multiplied with the optional buffer).
72
72
  */
73
73
  async getGasCosts(
74
- deposit: Deposit,
74
+ deposit: Omit<Deposit, "messageHash">,
75
75
  relayer = DEFAULT_SIMULATED_RELAYER_ADDRESS,
76
76
  options: Partial<{
77
77
  gasPrice: BigNumberish;
@@ -121,7 +121,7 @@ export class QueryBase implements QueryInterface {
121
121
  * @returns PopulatedTransaction
122
122
  */
123
123
  getUnsignedTxFromDeposit(
124
- deposit: Deposit,
124
+ deposit: Omit<Deposit, "messageHash">,
125
125
  relayer = DEFAULT_SIMULATED_RELAYER_ADDRESS
126
126
  ): Promise<PopulatedTransaction> {
127
127
  return populateV3Relay(this.spokePool, deposit, relayer);
@@ -133,7 +133,10 @@ export class QueryBase implements QueryInterface {
133
133
  * @param relayer Sender of PopulatedTransaction
134
134
  * @returns Estimated gas cost based on ethers.VoidSigner's gas estimation
135
135
  */
136
- async getNativeGasCost(deposit: Deposit, relayer = DEFAULT_SIMULATED_RELAYER_ADDRESS): Promise<BigNumber> {
136
+ async getNativeGasCost(
137
+ deposit: Omit<Deposit, "messageHash">,
138
+ relayer = DEFAULT_SIMULATED_RELAYER_ADDRESS
139
+ ): Promise<BigNumber> {
137
140
  const unsignedTx = await this.getUnsignedTxFromDeposit(deposit, relayer);
138
141
  const voidSigner = new VoidSigner(relayer, this.provider);
139
142
  return voidSigner.estimateGas(unsignedTx);
@@ -22,7 +22,7 @@ import { Transport } from "viem";
22
22
  // This needs to be implemented for every chain and passed into RelayFeeCalculator
23
23
  export interface QueryInterface {
24
24
  getGasCosts: (
25
- deposit: Deposit,
25
+ deposit: Omit<Deposit, "messageHash">,
26
26
  relayer: string,
27
27
  options?: Partial<{
28
28
  gasPrice: BigNumberish;
@@ -21,7 +21,7 @@ type BlockTag = providers.BlockTag;
21
21
  */
22
22
  export function populateV3Relay(
23
23
  spokePool: Contract,
24
- deposit: Deposit,
24
+ deposit: Omit<Deposit, "messageHash">,
25
25
  relayer: string,
26
26
  repaymentChainId = deposit.destinationChainId
27
27
  ): Promise<PopulatedTransaction> {
@@ -57,6 +57,33 @@ export function populateV3Relay(
57
57
  return spokePool.populateTransaction.fillV3Relay(v3RelayData, repaymentChainId, { from: relayer });
58
58
  }
59
59
 
60
+ /**
61
+ * Concatenate all fields from a Deposit, Fill or SlowFillRequest into a single string.
62
+ * This can be used to identify a bridge event in a mapping. This is used instead of the actual keccak256 hash
63
+ * (getRelayDataHash()) for two reasons: performance and the fact that only Deposit includes the `message` field, which
64
+ * is required to compute a complete RelayData hash.
65
+ * note: This function should _not_ be used to query the SpokePool.fillStatuses mapping.
66
+ */
67
+ export function getRelayEventKey(data: RelayData & { destinationChainId: number }): string {
68
+ return [
69
+ data.depositor,
70
+ data.recipient,
71
+ data.exclusiveRelayer,
72
+ data.inputToken,
73
+ data.outputToken,
74
+ data.inputAmount,
75
+ data.outputAmount,
76
+ data.originChainId,
77
+ data.destinationChainId,
78
+ data.depositId,
79
+ data.fillDeadline,
80
+ data.exclusivityDeadline,
81
+ data.message,
82
+ ]
83
+ .map(String)
84
+ .join("-");
85
+ }
86
+
60
87
  /**
61
88
  * Find the block range that contains the deposit ID. This is a binary search that searches for the block range
62
89
  * that contains the deposit ID.
@@ -1 +0,0 @@
1
- {"type":"commonjs"}
@@ -1 +0,0 @@
1
- {"type":"module","sideEffects":false}