@across-protocol/sdk 4.0.0-beta.0 → 4.0.0-beta.1

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 (86) hide show
  1. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +4 -2
  2. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  3. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.d.ts +12 -10
  4. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.js +3 -3
  5. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.js.map +1 -1
  6. package/dist/cjs/clients/SpokePoolClient.d.ts +12 -12
  7. package/dist/cjs/clients/SpokePoolClient.js +17 -15
  8. package/dist/cjs/clients/SpokePoolClient.js.map +1 -1
  9. package/dist/cjs/clients/mocks/MockSpokePoolClient.d.ts +5 -4
  10. package/dist/cjs/clients/mocks/MockSpokePoolClient.js +6 -6
  11. package/dist/cjs/clients/mocks/MockSpokePoolClient.js.map +1 -1
  12. package/dist/cjs/constants.d.ts +3 -2
  13. package/dist/cjs/constants.js +4 -3
  14. package/dist/cjs/constants.js.map +1 -1
  15. package/dist/cjs/interfaces/SpokePool.d.ts +2 -2
  16. package/dist/cjs/utils/BigNumberUtils.d.ts +1 -0
  17. package/dist/cjs/utils/BigNumberUtils.js +5 -1
  18. package/dist/cjs/utils/BigNumberUtils.js.map +1 -1
  19. package/dist/cjs/utils/DepositUtils.d.ts +2 -0
  20. package/dist/cjs/utils/DepositUtils.js +11 -3
  21. package/dist/cjs/utils/DepositUtils.js.map +1 -1
  22. package/dist/cjs/utils/EventUtils.js +4 -0
  23. package/dist/cjs/utils/EventUtils.js.map +1 -1
  24. package/dist/cjs/utils/SpokeUtils.d.ts +5 -3
  25. package/dist/cjs/utils/SpokeUtils.js +15 -8
  26. package/dist/cjs/utils/SpokeUtils.js.map +1 -1
  27. package/dist/cjs/utils/ValidatorUtils.js +1 -1
  28. package/dist/cjs/utils/ValidatorUtils.js.map +1 -1
  29. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +5 -3
  30. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  31. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.d.ts +12 -10
  32. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.js +4 -4
  33. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.js.map +1 -1
  34. package/dist/esm/clients/SpokePoolClient.d.ts +12 -12
  35. package/dist/esm/clients/SpokePoolClient.js +18 -16
  36. package/dist/esm/clients/SpokePoolClient.js.map +1 -1
  37. package/dist/esm/clients/mocks/MockSpokePoolClient.d.ts +5 -4
  38. package/dist/esm/clients/mocks/MockSpokePoolClient.js +7 -7
  39. package/dist/esm/clients/mocks/MockSpokePoolClient.js.map +1 -1
  40. package/dist/esm/constants.d.ts +3 -2
  41. package/dist/esm/constants.js +3 -2
  42. package/dist/esm/constants.js.map +1 -1
  43. package/dist/esm/interfaces/SpokePool.d.ts +2 -2
  44. package/dist/esm/utils/BigNumberUtils.d.ts +8 -0
  45. package/dist/esm/utils/BigNumberUtils.js +10 -0
  46. package/dist/esm/utils/BigNumberUtils.js.map +1 -1
  47. package/dist/esm/utils/DepositUtils.d.ts +2 -0
  48. package/dist/esm/utils/DepositUtils.js +9 -3
  49. package/dist/esm/utils/DepositUtils.js.map +1 -1
  50. package/dist/esm/utils/EventUtils.js +8 -0
  51. package/dist/esm/utils/EventUtils.js.map +1 -1
  52. package/dist/esm/utils/SpokeUtils.d.ts +5 -3
  53. package/dist/esm/utils/SpokeUtils.js +17 -9
  54. package/dist/esm/utils/SpokeUtils.js.map +1 -1
  55. package/dist/esm/utils/ValidatorUtils.js +1 -1
  56. package/dist/esm/utils/ValidatorUtils.js.map +1 -1
  57. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
  58. package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts +12 -10
  59. package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts.map +1 -1
  60. package/dist/types/clients/SpokePoolClient.d.ts +12 -12
  61. package/dist/types/clients/SpokePoolClient.d.ts.map +1 -1
  62. package/dist/types/clients/mocks/MockSpokePoolClient.d.ts +5 -4
  63. package/dist/types/clients/mocks/MockSpokePoolClient.d.ts.map +1 -1
  64. package/dist/types/constants.d.ts +3 -2
  65. package/dist/types/constants.d.ts.map +1 -1
  66. package/dist/types/interfaces/SpokePool.d.ts +2 -2
  67. package/dist/types/interfaces/SpokePool.d.ts.map +1 -1
  68. package/dist/types/utils/BigNumberUtils.d.ts +8 -0
  69. package/dist/types/utils/BigNumberUtils.d.ts.map +1 -1
  70. package/dist/types/utils/DepositUtils.d.ts +2 -0
  71. package/dist/types/utils/DepositUtils.d.ts.map +1 -1
  72. package/dist/types/utils/EventUtils.d.ts.map +1 -1
  73. package/dist/types/utils/SpokeUtils.d.ts +5 -3
  74. package/dist/types/utils/SpokeUtils.d.ts.map +1 -1
  75. package/package.json +2 -2
  76. package/src/clients/BundleDataClient/BundleDataClient.ts +8 -2
  77. package/src/clients/BundleDataClient/utils/SuperstructUtils.ts +4 -2
  78. package/src/clients/SpokePoolClient.ts +27 -23
  79. package/src/clients/mocks/MockSpokePoolClient.ts +10 -10
  80. package/src/constants.ts +4 -2
  81. package/src/interfaces/SpokePool.ts +2 -2
  82. package/src/utils/BigNumberUtils.ts +11 -0
  83. package/src/utils/DepositUtils.ts +11 -3
  84. package/src/utils/EventUtils.ts +8 -0
  85. package/src/utils/SpokeUtils.ts +25 -14
  86. package/src/utils/ValidatorUtils.ts +1 -1
@@ -12,6 +12,8 @@ import {
12
12
  getRelayDataHash,
13
13
  isDefined,
14
14
  toBN,
15
+ bnOne,
16
+ isUnsafeDepositId,
15
17
  } from "../utils";
16
18
  import {
17
19
  paginatedEventQuery,
@@ -46,8 +48,8 @@ type SpokePoolUpdateSuccess = {
46
48
  success: true;
47
49
  currentTime: number;
48
50
  oldestTime: number;
49
- firstDepositId: number;
50
- latestDepositId: number;
51
+ firstDepositId: BigNumber;
52
+ latestDepositId: BigNumber;
51
53
  events: Log[][];
52
54
  searchEndBlock: number;
53
55
  };
@@ -67,7 +69,7 @@ export class SpokePoolClient extends BaseAbstractClient {
67
69
  protected depositHashes: { [depositHash: string]: DepositWithBlock } = {};
68
70
  protected duplicateDepositHashes: { [depositHash: string]: DepositWithBlock[] } = {};
69
71
  protected depositHashesToFills: { [depositHash: string]: FillWithBlock[] } = {};
70
- protected speedUps: { [depositorAddress: string]: { [depositId: number]: SpeedUpWithBlock[] } } = {};
72
+ protected speedUps: { [depositorAddress: string]: { [depositId: string]: SpeedUpWithBlock[] } } = {};
71
73
  protected slowFillRequests: { [relayDataHash: string]: SlowFillRequestWithBlock } = {};
72
74
  protected depositRoutes: { [originToken: string]: { [DestinationChainId: number]: boolean } } = {};
73
75
  protected tokensBridged: TokensBridged[] = [];
@@ -75,10 +77,10 @@ export class SpokePoolClient extends BaseAbstractClient {
75
77
  protected relayerRefundExecutions: RelayerRefundExecutionWithBlock[] = [];
76
78
  protected queryableEventNames: string[] = [];
77
79
  protected configStoreClient: AcrossConfigStoreClient | undefined;
78
- public earliestDepositIdQueried = Number.MAX_SAFE_INTEGER;
79
- public latestDepositIdQueried = 0;
80
- public firstDepositIdForSpokePool = Number.MAX_SAFE_INTEGER;
81
- public lastDepositIdForSpokePool = Number.MAX_SAFE_INTEGER;
80
+ public earliestDepositIdQueried = MAX_BIG_INT;
81
+ public latestDepositIdQueried = bnZero;
82
+ public firstDepositIdForSpokePool = MAX_BIG_INT;
83
+ public lastDepositIdForSpokePool = MAX_BIG_INT;
82
84
  public fills: { [OriginChainId: number]: FillWithBlock[] } = {};
83
85
 
84
86
  /**
@@ -248,7 +250,7 @@ export class SpokePoolClient extends BaseAbstractClient {
248
250
  */
249
251
  public appendMaxSpeedUpSignatureToDeposit(deposit: DepositWithBlock): DepositWithBlock {
250
252
  const { depositId, depositor } = deposit;
251
- const speedups = this.speedUps[depositor]?.[depositId];
253
+ const speedups = this.speedUps[depositor]?.[depositId.toString()];
252
254
  if (!isDefined(speedups) || speedups.length === 0) {
253
255
  return deposit;
254
256
  }
@@ -281,7 +283,7 @@ export class SpokePoolClient extends BaseAbstractClient {
281
283
  * @param depositId The unique ID of the deposit being queried.
282
284
  * @returns The corresponding deposit if found, undefined otherwise.
283
285
  */
284
- public getDeposit(depositId: number): DepositWithBlock | undefined {
286
+ public getDeposit(depositId: BigNumber): DepositWithBlock | undefined {
285
287
  const depositHash = this.getDepositHash({ depositId, originChainId: this.chainId });
286
288
  return this.depositHashes[depositHash];
287
289
  }
@@ -311,7 +313,7 @@ export class SpokePoolClient extends BaseAbstractClient {
311
313
  * Retrieves speed up requests grouped by depositor and depositId.
312
314
  * @returns A mapping of depositor addresses to deposit ids with their corresponding speed up requests.
313
315
  */
314
- public getSpeedUps(): { [depositorAddress: string]: { [depositId: number]: SpeedUpWithBlock[] } } {
316
+ public getSpeedUps(): { [depositorAddress: string]: { [depositId: string]: SpeedUpWithBlock[] } } {
315
317
  return this.speedUps;
316
318
  }
317
319
 
@@ -381,7 +383,7 @@ export class SpokePoolClient extends BaseAbstractClient {
381
383
  );
382
384
 
383
385
  // Log any invalid deposits with same deposit id but different params.
384
- const invalidFillsForDeposit = invalidFills.filter((x) => x.depositId === deposit.depositId);
386
+ const invalidFillsForDeposit = invalidFills.filter((x) => x.depositId.eq(deposit.depositId));
385
387
  if (invalidFillsForDeposit.length > 0) {
386
388
  this.logger.warn({
387
389
  at: "SpokePoolClient",
@@ -412,7 +414,7 @@ export class SpokePoolClient extends BaseAbstractClient {
412
414
  * @note This hash is used to match deposits and fills together.
413
415
  * @note This hash takes the form of: `${depositId}-${originChainId}`.
414
416
  */
415
- public getDepositHash(event: { depositId: number; originChainId: number }): string {
417
+ public getDepositHash(event: { depositId: BigNumber; originChainId: number }): string {
416
418
  return `${event.depositId}-${event.originChainId}`;
417
419
  }
418
420
 
@@ -421,7 +423,7 @@ export class SpokePoolClient extends BaseAbstractClient {
421
423
  * @param blockTag The block number to search for the deposit ID at.
422
424
  * @returns The deposit ID.
423
425
  */
424
- public _getDepositIdAtBlock(blockTag: number): Promise<number> {
426
+ public _getDepositIdAtBlock(blockTag: number): Promise<BigNumber> {
425
427
  return getDepositIdAtBlock(this.spokePool as SpokePool, blockTag);
426
428
  }
427
429
 
@@ -454,10 +456,11 @@ export class SpokePoolClient extends BaseAbstractClient {
454
456
  */
455
457
  protected async _update(eventsToQuery: string[]): Promise<SpokePoolUpdate> {
456
458
  // Find the earliest known depositId. This assumes no deposits were placed in the deployment block.
457
- let firstDepositId: number = this.firstDepositIdForSpokePool;
458
- if (firstDepositId === Number.MAX_SAFE_INTEGER) {
459
+ let firstDepositId = this.firstDepositIdForSpokePool;
460
+ if (firstDepositId.eq(MAX_BIG_INT)) {
459
461
  firstDepositId = await this.spokePool.numberOfDeposits({ blockTag: this.deploymentBlock });
460
- if (isNaN(firstDepositId) || firstDepositId < 0) {
462
+ firstDepositId = BigNumber.from(firstDepositId); // Cast input to a big number.
463
+ if (!BigNumber.isBigNumber(firstDepositId) || firstDepositId.lt(bnZero)) {
461
464
  throw new Error(`SpokePoolClient::update: Invalid first deposit id (${firstDepositId})`);
462
465
  }
463
466
  }
@@ -507,9 +510,10 @@ export class SpokePoolClient extends BaseAbstractClient {
507
510
  ]);
508
511
  this.log("debug", `Time to query new events from RPC for ${this.chainId}: ${Date.now() - timerStart} ms`);
509
512
 
510
- const [currentTime, numberOfDeposits] = multicallFunctions.map(
513
+ const [currentTime, _numberOfDeposits] = multicallFunctions.map(
511
514
  (fn, idx) => spokePool.interface.decodeFunctionResult(fn, multicallOutput[idx])[0]
512
515
  );
516
+ const _latestDepositId = BigNumber.from(_numberOfDeposits).sub(bnOne);
513
517
 
514
518
  if (!BigNumber.isBigNumber(currentTime) || currentTime.lt(this.currentTime)) {
515
519
  const errMsg = BigNumber.isBigNumber(currentTime)
@@ -526,7 +530,7 @@ export class SpokePoolClient extends BaseAbstractClient {
526
530
  currentTime: currentTime.toNumber(), // uint32
527
531
  oldestTime: oldestTime.toNumber(),
528
532
  firstDepositId,
529
- latestDepositId: Math.max(numberOfDeposits - 1, 0),
533
+ latestDepositId: _latestDepositId.gt(bnZero) ? _latestDepositId : bnZero,
530
534
  searchEndBlock: searchConfig.toBlock,
531
535
  events,
532
536
  };
@@ -596,10 +600,10 @@ export class SpokePoolClient extends BaseAbstractClient {
596
600
  }
597
601
  assign(this.depositHashes, [this.getDepositHash(deposit)], deposit);
598
602
 
599
- if (deposit.depositId < this.earliestDepositIdQueried) {
603
+ if (deposit.depositId.lt(this.earliestDepositIdQueried) && !isUnsafeDepositId(deposit.depositId)) {
600
604
  this.earliestDepositIdQueried = deposit.depositId;
601
605
  }
602
- if (deposit.depositId > this.latestDepositIdQueried) {
606
+ if (deposit.depositId.gt(this.latestDepositIdQueried) && !isUnsafeDepositId(deposit.depositId)) {
603
607
  this.latestDepositIdQueried = deposit.depositId;
604
608
  }
605
609
  }
@@ -611,7 +615,7 @@ export class SpokePoolClient extends BaseAbstractClient {
611
615
 
612
616
  for (const event of speedUpEvents) {
613
617
  const speedUp = { ...spreadEventWithBlockNumber(event), originChainId: this.chainId } as SpeedUpWithBlock;
614
- assign(this.speedUps, [speedUp.depositor, speedUp.depositId], [speedUp]);
618
+ assign(this.speedUps, [speedUp.depositor, speedUp.depositId.toString()], [speedUp]);
615
619
 
616
620
  // Find deposit hash matching this speed up event and update the deposit data associated with the hash,
617
621
  // if the hash+data exists.
@@ -795,7 +799,7 @@ export class SpokePoolClient extends BaseAbstractClient {
795
799
  return this.oldestTime;
796
800
  }
797
801
 
798
- async findDeposit(depositId: number, destinationChainId: number): Promise<DepositWithBlock> {
802
+ async findDeposit(depositId: BigNumber, destinationChainId: number): Promise<DepositWithBlock> {
799
803
  // Binary search for event search bounds. This way we can get the blocks before and after the deposit with
800
804
  // deposit ID = fill.depositId and use those blocks to optimize the search for that deposit.
801
805
  // Stop searches after a maximum # of searches to limit number of eth_call requests. Make an
@@ -824,7 +828,7 @@ export class SpokePoolClient extends BaseAbstractClient {
824
828
  );
825
829
  const tStop = Date.now();
826
830
 
827
- const event = query.find(({ args }) => args["depositId"] === depositId);
831
+ const event = query.find(({ args }) => args["depositId"].eq(depositId));
828
832
  if (event === undefined) {
829
833
  const srcChain = getNetworkName(this.chainId);
830
834
  const dstChain = getNetworkName(destinationChainId);
@@ -14,7 +14,7 @@ import {
14
14
  SlowFillLeaf,
15
15
  SpeedUp,
16
16
  } from "../../interfaces";
17
- import { toBN, toBNWei, getCurrentTime, randomAddress } from "../../utils";
17
+ import { toBN, toBNWei, getCurrentTime, randomAddress, BigNumber, bnZero, bnOne, bnMax } from "../../utils";
18
18
  import { SpokePoolClient, SpokePoolUpdate } from "../SpokePoolClient";
19
19
  import { HubPoolClient } from "../HubPoolClient";
20
20
  import { EventManager, EventOverrides, getEventManager } from "./MockEvents";
@@ -26,8 +26,8 @@ export class MockSpokePoolClient extends SpokePoolClient {
26
26
  public eventManager: EventManager;
27
27
  private destinationTokenForChainOverride: Record<number, string> = {};
28
28
  // Allow tester to set the numberOfDeposits() returned by SpokePool at a block height.
29
- public depositIdAtBlock: number[] = [];
30
- public numberOfDeposits = 0;
29
+ public depositIdAtBlock: BigNumber[] = [];
30
+ public numberOfDeposits = bnZero;
31
31
 
32
32
  constructor(
33
33
  logger: winston.Logger,
@@ -57,21 +57,21 @@ export class MockSpokePoolClient extends SpokePoolClient {
57
57
  this.latestBlockSearched = blockNumber;
58
58
  }
59
59
 
60
- setDepositIds(_depositIds: number[]): void {
60
+ setDepositIds(_depositIds: BigNumber[]): void {
61
61
  this.depositIdAtBlock = [];
62
62
  if (_depositIds.length === 0) {
63
63
  return;
64
64
  }
65
65
  let lastDepositId = _depositIds[0];
66
66
  for (let i = 0; i < _depositIds.length; i++) {
67
- if (_depositIds[i] < lastDepositId) {
67
+ if (_depositIds[i].lt(lastDepositId)) {
68
68
  throw new Error("deposit ID must be equal to or greater than previous");
69
69
  }
70
70
  this.depositIdAtBlock[i] = _depositIds[i];
71
71
  lastDepositId = _depositIds[i];
72
72
  }
73
73
  }
74
- _getDepositIdAtBlock(blockTag: number): Promise<number> {
74
+ _getDepositIdAtBlock(blockTag: number): Promise<BigNumber> {
75
75
  return Promise.resolve(this.depositIdAtBlock[blockTag]);
76
76
  }
77
77
 
@@ -96,13 +96,13 @@ export class MockSpokePoolClient extends SpokePoolClient {
96
96
  // Update latestDepositIdQueried.
97
97
  const idx = eventsToQuery.indexOf("V3FundsDeposited");
98
98
  const latestDepositId = (events[idx] ?? []).reduce(
99
- (depositId, event) => Math.max(depositId, (event.args["depositId"] ?? 0) as number),
99
+ (depositId, event) => bnMax(depositId, event.args["depositId"] ?? bnZero),
100
100
  this.latestDepositIdQueried
101
101
  );
102
102
 
103
103
  return Promise.resolve({
104
104
  success: true,
105
- firstDepositId: 0,
105
+ firstDepositId: bnZero,
106
106
  latestDepositId,
107
107
  currentTime,
108
108
  oldestTime: 0,
@@ -122,7 +122,7 @@ export class MockSpokePoolClient extends SpokePoolClient {
122
122
  const { blockNumber, transactionIndex } = deposit;
123
123
  let { depositId, depositor, destinationChainId, inputToken, inputAmount, outputToken, outputAmount } = deposit;
124
124
  depositId ??= this.numberOfDeposits;
125
- this.numberOfDeposits = depositId + 1;
125
+ this.numberOfDeposits = depositId.add(bnOne);
126
126
 
127
127
  destinationChainId ??= random(1, 42161, false);
128
128
  depositor ??= randomAddress();
@@ -167,7 +167,7 @@ export class MockSpokePoolClient extends SpokePoolClient {
167
167
  const { blockNumber, transactionIndex } = fill;
168
168
  let { originChainId, depositId, inputToken, inputAmount, outputAmount, fillDeadline, relayer } = fill;
169
169
  originChainId ??= random(1, 42161, false);
170
- depositId ??= random(1, 100_000, false);
170
+ depositId ??= BigNumber.from(random(1, 100_000, false));
171
171
  inputToken ??= randomAddress();
172
172
  inputAmount ??= toBNWei(random(1, 1000, false));
173
173
  outputAmount ??= inputAmount;
package/src/constants.ts CHANGED
@@ -10,7 +10,7 @@ export {
10
10
  TOKEN_SYMBOLS_MAP,
11
11
  } from "@across-protocol/constants";
12
12
 
13
- export const { AddressZero: ZERO_ADDRESS } = ethersConstants;
13
+ export const { AddressZero: ZERO_ADDRESS, HashZero: ZERO_BYTES } = ethersConstants;
14
14
 
15
15
  // 2^96 - 1 is a conservative erc20 max allowance.
16
16
  export const MAX_SAFE_ALLOWANCE = "79228162514264337593543950335";
@@ -33,7 +33,7 @@ export const TRANSFER_THRESHOLD_MAX_CONFIG_STORE_VERSION = 1;
33
33
  export const ARWEAVE_TAG_APP_NAME = "across-protocol";
34
34
 
35
35
  // A hardcoded version number used, by default, to tag all Arweave records.
36
- export const ARWEAVE_TAG_APP_VERSION = 2;
36
+ export const ARWEAVE_TAG_APP_VERSION = 3;
37
37
 
38
38
  /**
39
39
  * A default list of chain Ids that the protocol supports. This is outlined
@@ -55,6 +55,8 @@ export const DEFAULT_ARWEAVE_STORAGE_ADDRESS = "Z6hjBM8FHu90lYWB8o5jR1dfX92FlV2W
55
55
 
56
56
  export const EMPTY_MESSAGE = "0x";
57
57
 
58
+ export const EMPTY_MESSAGE_HASH = ethersConstants.HashZero;
59
+
58
60
  export const BRIDGED_USDC_SYMBOLS = [
59
61
  TOKEN_SYMBOLS_MAP["USDC.e"].symbol,
60
62
  TOKEN_SYMBOLS_MAP.USDbC.symbol,
@@ -10,7 +10,7 @@ export interface RelayData {
10
10
  originChainId: number;
11
11
  depositor: string;
12
12
  recipient: string;
13
- depositId: number;
13
+ depositId: BigNumber;
14
14
  inputToken: string;
15
15
  inputAmount: BigNumber;
16
16
  outputToken: string;
@@ -67,7 +67,7 @@ export interface FillWithBlock extends Fill, SortableEvent {}
67
67
  export interface SpeedUp {
68
68
  depositor: string;
69
69
  depositorSignature: string;
70
- depositId: number;
70
+ depositId: BigNumber;
71
71
  originChainId: number;
72
72
  updatedRecipient: string;
73
73
  updatedOutputAmount: BigNumber;
@@ -62,3 +62,14 @@ export const toBN = (num: BigNumberish, rounding: "floor" | "round" | "ceil" = "
62
62
  // Otherwise, it is a string int and we can parse it directly.
63
63
  return BigNumber.from(num.toString());
64
64
  };
65
+
66
+ /**
67
+ * Compares two BigNumbers and returns the maximum. Order does not matter.
68
+ *
69
+ * @param val The first BigNumber to compare.
70
+ * @param cmp The second BigNumber to compare.
71
+ * @returns The greater of the two BigNumbers.
72
+ */
73
+ export const bnMax = (val: BigNumber, cmp: BigNumber) => {
74
+ return val.gt(cmp) ? val : cmp;
75
+ };
@@ -1,6 +1,6 @@
1
1
  import assert from "assert";
2
2
  import { SpokePoolClient } from "../clients";
3
- import { DEFAULT_CACHING_TTL, EMPTY_MESSAGE } from "../constants";
3
+ import { DEFAULT_CACHING_TTL, EMPTY_MESSAGE, EMPTY_MESSAGE_HASH } from "../constants";
4
4
  import { CachingMechanismInterface, Deposit, DepositWithBlock, Fill, SlowFillRequest } from "../interfaces";
5
5
  import { getNetworkName } from "./NetworkUtils";
6
6
  import { getDepositInCache, getDepositKey, setDepositInCache } from "./CachingUtils";
@@ -52,7 +52,7 @@ export async function queryHistoricalDepositForFill(
52
52
 
53
53
  const { depositId } = fill;
54
54
  let { firstDepositIdForSpokePool: lowId, lastDepositIdForSpokePool: highId } = spokePoolClient;
55
- if (depositId < lowId || depositId > highId) {
55
+ if (depositId.lt(lowId) || depositId.gt(highId)) {
56
56
  return {
57
57
  found: false,
58
58
  code: InvalidFill.DepositIdInvalid,
@@ -61,7 +61,7 @@ export async function queryHistoricalDepositForFill(
61
61
  }
62
62
 
63
63
  ({ earliestDepositIdQueried: lowId, latestDepositIdQueried: highId } = spokePoolClient);
64
- if (depositId >= lowId && depositId <= highId) {
64
+ if (depositId.gte(lowId) && depositId.lte(highId)) {
65
65
  const originChain = getNetworkName(fill.originChainId);
66
66
  const deposit = spokePoolClient.getDeposit(depositId);
67
67
  if (isDefined(deposit)) {
@@ -137,6 +137,10 @@ export function isZeroValueDeposit(deposit: Pick<Deposit, "inputAmount" | "messa
137
137
  return deposit.inputAmount.eq(0) && isMessageEmpty(deposit.message);
138
138
  }
139
139
 
140
+ export function isZeroValueFillOrSlowFillRequest(e: Pick<Fill | SlowFillRequest, "inputAmount" | "message">): boolean {
141
+ return e.inputAmount.eq(0) && isFillOrSlowFillRequestMessageEmpty(e.message);
142
+ }
143
+
140
144
  /**
141
145
  * Determines if a message is empty or not.
142
146
  * @param message The message to check.
@@ -146,6 +150,10 @@ export function isMessageEmpty(message = EMPTY_MESSAGE): boolean {
146
150
  return message === "" || message === "0x";
147
151
  }
148
152
 
153
+ export function isFillOrSlowFillRequestMessageEmpty(message: string): boolean {
154
+ return message === EMPTY_MESSAGE_HASH;
155
+ }
156
+
149
157
  /**
150
158
  * Determines if a deposit was updated via a speed-up transaction.
151
159
  * @param deposit Deposit to evaluate.
@@ -3,6 +3,7 @@ import { Result } from "@ethersproject/abi";
3
3
  import { Contract, Event, EventFilter } from "ethers";
4
4
  import { Log, SortableEvent } from "../interfaces";
5
5
  import { delay } from "./common";
6
+ import { isDefined, toBN, BigNumberish } from "./";
6
7
 
7
8
  const maxRetries = 3;
8
9
  const retrySleepTime = 10;
@@ -58,6 +59,13 @@ export function spreadEvent(args: Result | Record<string, unknown>): { [key: str
58
59
  if (returnedObject.rootBundleId) {
59
60
  returnedObject.rootBundleId = Number(returnedObject.rootBundleId);
60
61
  }
62
+ // If depositId is included in the event, cast it to a BigNumber. Need to check if it is defined since the deposit ID can
63
+ // be 0, which would still make this evaluate as false.
64
+ if (isDefined(returnedObject.depositId)) {
65
+ // Assuming a numeric output, we can safely cast the unknown to BigNumberish since the depositId will either be a uint32 (and therefore a TypeScript `number`),
66
+ // or a uint256 (and therefore an ethers BigNumber).
67
+ returnedObject.depositId = toBN(returnedObject.depositId as BigNumberish);
68
+ }
61
69
 
62
70
  return returnedObject;
63
71
  }
@@ -1,10 +1,10 @@
1
1
  import assert from "assert";
2
2
  import { BytesLike, Contract, PopulatedTransaction, providers, utils as ethersUtils } from "ethers";
3
- import { CHAIN_IDs, MAX_SAFE_DEPOSIT_ID, ZERO_ADDRESS } from "../constants";
3
+ import { CHAIN_IDs, MAX_SAFE_DEPOSIT_ID, ZERO_ADDRESS, ZERO_BYTES } from "../constants";
4
4
  import { Deposit, Fill, FillStatus, FillWithBlock, RelayData, SlowFillRequest } from "../interfaces";
5
5
  import { SpokePoolClient } from "../clients";
6
6
  import { chunk } from "./ArrayUtils";
7
- import { BigNumber, toBN } from "./BigNumberUtils";
7
+ import { BigNumber, toBN, bnOne, bnZero } from "./BigNumberUtils";
8
8
  import { isDefined } from "./TypeGuards";
9
9
  import { getNetworkName } from "./NetworkUtils";
10
10
  import { paginatedEventQuery, spreadEventWithBlockNumber } from "./EventUtils";
@@ -71,7 +71,7 @@ export function populateV3Relay(
71
71
  * // where the deposit with deposit ID = targetDepositId was created.
72
72
  */
73
73
  export async function getBlockRangeForDepositId(
74
- targetDepositId: number,
74
+ targetDepositId: BigNumber,
75
75
  initLow: number,
76
76
  initHigh: number,
77
77
  maxSearches: number,
@@ -80,6 +80,12 @@ export async function getBlockRangeForDepositId(
80
80
  low: number;
81
81
  high: number;
82
82
  }> {
83
+ // We can only perform this search when we have a safe deposit ID.
84
+ if (isUnsafeDepositId(targetDepositId))
85
+ throw new Error(
86
+ `Target deposit ID ${targetDepositId} is deterministic and therefore unresolvable via a binary search.`
87
+ );
88
+
83
89
  // Resolve the deployment block number.
84
90
  const deploymentBlock = spokePool.deploymentBlock;
85
91
 
@@ -110,13 +116,13 @@ export async function getBlockRangeForDepositId(
110
116
  });
111
117
 
112
118
  // Define a mapping of block numbers to number of deposits at that block. This saves repeated lookups.
113
- const queriedIds: Record<number, number> = {};
119
+ const queriedIds: Record<number, BigNumber> = {};
114
120
 
115
121
  // Define a llambda function to get the deposit ID at a block number. This function will first check the
116
122
  // queriedIds cache to see if the deposit ID at the block number has already been queried. If not, it will
117
123
  // make an eth_call request to get the deposit ID at the block number. It will then cache the deposit ID
118
124
  // in the queriedIds cache.
119
- const _getDepositIdAtBlock = async (blockNumber: number): Promise<number> => {
125
+ const _getDepositIdAtBlock = async (blockNumber: number): Promise<BigNumber> => {
120
126
  queriedIds[blockNumber] ??= await spokePool._getDepositIdAtBlock(blockNumber);
121
127
  return queriedIds[blockNumber];
122
128
  };
@@ -129,7 +135,7 @@ export async function getBlockRangeForDepositId(
129
135
 
130
136
  // If the deposit ID at the initial high block is less than the target deposit ID, then we know that
131
137
  // the target deposit ID must be greater than the initial high block, so we can throw an error.
132
- if (highestDepositIdInRange <= targetDepositId) {
138
+ if (highestDepositIdInRange.lte(targetDepositId)) {
133
139
  // initLow = 5: Deposits Num: 10
134
140
  // // targetId = 11 <- fail (triggers this error) // 10 <= 11
135
141
  // // targetId = 10 <- fail (triggers this error) // 10 <= 10
@@ -141,7 +147,7 @@ export async function getBlockRangeForDepositId(
141
147
 
142
148
  // If the deposit ID at the initial low block is greater than the target deposit ID, then we know that
143
149
  // the target deposit ID must be less than the initial low block, so we can throw an error.
144
- if (lowestDepositIdInRange > targetDepositId) {
150
+ if (lowestDepositIdInRange.gt(targetDepositId)) {
145
151
  // initLow = 5: Deposits Num: 10
146
152
  // initLow-1 = 4: Deposits Num: 2
147
153
  // // targetId = 1 <- fail (triggers this error)
@@ -155,7 +161,6 @@ export async function getBlockRangeForDepositId(
155
161
  // Define the low and high block numbers for the binary search.
156
162
  let low = initLow;
157
163
  let high = initHigh;
158
-
159
164
  // Define the number of searches performed so far.
160
165
  let searches = 0;
161
166
 
@@ -167,12 +172,12 @@ export async function getBlockRangeForDepositId(
167
172
  const midDepositId = await _getDepositIdAtBlock(mid);
168
173
 
169
174
  // Let's define the latest ID of the current midpoint block.
170
- const accountedIdByMidBlock = midDepositId - 1;
175
+ const accountedIdByMidBlock = midDepositId.sub(bnOne);
171
176
 
172
177
  // If our target deposit ID is less than the smallest range of our
173
178
  // midpoint deposit ID range, then we know that the target deposit ID
174
179
  // must be in the lower half of the block range.
175
- if (targetDepositId <= accountedIdByMidBlock) {
180
+ if (targetDepositId.lte(accountedIdByMidBlock)) {
176
181
  high = mid;
177
182
  }
178
183
  // If our target deposit ID is greater than the largest range of our
@@ -201,10 +206,11 @@ export async function getBlockRangeForDepositId(
201
206
  * @param blockTag The block number to search for the deposit ID at.
202
207
  * @returns The deposit ID.
203
208
  */
204
- export async function getDepositIdAtBlock(contract: Contract, blockTag: number): Promise<number> {
205
- const depositIdAtBlock = await contract.numberOfDeposits({ blockTag });
209
+ export async function getDepositIdAtBlock(contract: Contract, blockTag: number): Promise<BigNumber> {
210
+ const _depositIdAtBlock = await contract.numberOfDeposits({ blockTag });
211
+ const depositIdAtBlock = toBN(_depositIdAtBlock);
206
212
  // Sanity check to ensure that the deposit ID is an integer and is greater than or equal to zero.
207
- if (!Number.isInteger(depositIdAtBlock) || depositIdAtBlock < 0) {
213
+ if (depositIdAtBlock.lt(bnZero)) {
208
214
  throw new Error("Invalid deposit count");
209
215
  }
210
216
  return depositIdAtBlock;
@@ -245,7 +251,7 @@ export function getRelayHashFromEvent(e: Deposit | Fill | SlowFillRequest): stri
245
251
  return getRelayDataHash(e, e.destinationChainId);
246
252
  }
247
253
 
248
- export function isUnsafeDepositId(depositId: number): boolean {
254
+ export function isUnsafeDepositId(depositId: BigNumber): boolean {
249
255
  // SpokePool.unsafeDepositV3() produces a uint256 depositId by hashing the msg.sender, depositor and input
250
256
  // uint256 depositNonce. There is a possibility that this resultant uint256 is less than the maxSafeDepositId (i.e.
251
257
  // the maximum uint32 value) which makes it possible that an unsafeDepositV3's depositId can collide with a safe
@@ -415,3 +421,8 @@ export async function findFillEvent(
415
421
  } as FillWithBlock;
416
422
  return fill;
417
423
  }
424
+
425
+ // Determines if the input address (either a bytes32 or bytes20) is the zero address.
426
+ export function isZeroAddress(address: string): boolean {
427
+ return address === ZERO_ADDRESS || address === ZERO_BYTES;
428
+ }
@@ -8,7 +8,7 @@ const HexValidator = define<string>("HexValidator", (v) => ethersUtils.isHexStri
8
8
  const BigNumberValidator = define<BigNumber>("BigNumberValidator", (v) => BigNumber.isBigNumber(v));
9
9
 
10
10
  const V3DepositSchema = object({
11
- depositId: Min(integer(), 0),
11
+ depositId: BigNumberValidator,
12
12
  depositor: AddressValidator,
13
13
  recipient: AddressValidator,
14
14
  inputToken: AddressValidator,