@across-protocol/sdk 3.4.14 → 3.4.16

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 (67) hide show
  1. package/dist/cjs/clients/BundleDataClient/BundleDataClient.d.ts +1 -1
  2. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +179 -111
  3. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  4. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.d.ts +3 -1
  5. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +33 -1
  6. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  7. package/dist/cjs/providers/index.d.ts +1 -0
  8. package/dist/cjs/providers/index.js +2 -0
  9. package/dist/cjs/providers/index.js.map +1 -1
  10. package/dist/cjs/providers/mockProvider.d.ts +19 -0
  11. package/dist/cjs/providers/mockProvider.js +70 -0
  12. package/dist/cjs/providers/mockProvider.js.map +1 -0
  13. package/dist/cjs/utils/AddressUtils.d.ts +1 -0
  14. package/dist/cjs/utils/AddressUtils.js +14 -1
  15. package/dist/cjs/utils/AddressUtils.js.map +1 -1
  16. package/dist/cjs/utils/DepositUtils.d.ts +2 -1
  17. package/dist/cjs/utils/DepositUtils.js +9 -0
  18. package/dist/cjs/utils/DepositUtils.js.map +1 -1
  19. package/dist/cjs/utils/NetworkUtils.d.ts +1 -0
  20. package/dist/cjs/utils/NetworkUtils.js +6 -1
  21. package/dist/cjs/utils/NetworkUtils.js.map +1 -1
  22. package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +1 -1
  23. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +213 -137
  24. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  25. package/dist/esm/clients/BundleDataClient/utils/FillUtils.d.ts +3 -1
  26. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +42 -1
  27. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  28. package/dist/esm/providers/index.d.ts +1 -0
  29. package/dist/esm/providers/index.js +2 -0
  30. package/dist/esm/providers/index.js.map +1 -1
  31. package/dist/esm/providers/mockProvider.d.ts +23 -0
  32. package/dist/esm/providers/mockProvider.js +73 -0
  33. package/dist/esm/providers/mockProvider.js.map +1 -0
  34. package/dist/esm/utils/AddressUtils.d.ts +1 -0
  35. package/dist/esm/utils/AddressUtils.js +16 -0
  36. package/dist/esm/utils/AddressUtils.js.map +1 -1
  37. package/dist/esm/utils/DepositUtils.d.ts +2 -1
  38. package/dist/esm/utils/DepositUtils.js +9 -0
  39. package/dist/esm/utils/DepositUtils.js.map +1 -1
  40. package/dist/esm/utils/NetworkUtils.d.ts +6 -0
  41. package/dist/esm/utils/NetworkUtils.js +10 -0
  42. package/dist/esm/utils/NetworkUtils.js.map +1 -1
  43. package/dist/esm/utils/SpokeUtils.js +1 -1
  44. package/dist/esm/utils/SpokeUtils.js.map +1 -1
  45. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +1 -1
  46. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
  47. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts +3 -1
  48. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
  49. package/dist/types/providers/index.d.ts +1 -0
  50. package/dist/types/providers/index.d.ts.map +1 -1
  51. package/dist/types/providers/mockProvider.d.ts +24 -0
  52. package/dist/types/providers/mockProvider.d.ts.map +1 -0
  53. package/dist/types/utils/AddressUtils.d.ts +1 -0
  54. package/dist/types/utils/AddressUtils.d.ts.map +1 -1
  55. package/dist/types/utils/DepositUtils.d.ts +2 -1
  56. package/dist/types/utils/DepositUtils.d.ts.map +1 -1
  57. package/dist/types/utils/NetworkUtils.d.ts +6 -0
  58. package/dist/types/utils/NetworkUtils.d.ts.map +1 -1
  59. package/package.json +1 -1
  60. package/src/clients/BundleDataClient/BundleDataClient.ts +109 -57
  61. package/src/clients/BundleDataClient/utils/FillUtils.ts +47 -2
  62. package/src/providers/index.ts +1 -0
  63. package/src/providers/mockProvider.ts +77 -0
  64. package/src/utils/AddressUtils.ts +16 -0
  65. package/src/utils/DepositUtils.ts +9 -0
  66. package/src/utils/NetworkUtils.ts +11 -0
  67. package/src/utils/SpokeUtils.ts +1 -1
@@ -5,4 +5,5 @@ export * from "./speedProvider";
5
5
  export * from "./constants";
6
6
  export * from "./types";
7
7
  export * from "./utils";
8
+ export * as mocks from "./mockProvider";
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { BigNumber, providers } from "ethers";
2
+ import { Block, BlockTag, FeeData, TransactionResponse } from "@ethersproject/abstract-provider";
3
+ /**
4
+ * @notice Class used to test GasPriceOracle which makes ethers provider calls to the following implemented
5
+ * methods.
6
+ */
7
+ export declare class MockedProvider extends providers.StaticJsonRpcProvider {
8
+ readonly stdLastBaseFeePerGas: BigNumber;
9
+ readonly stdMaxPriorityFeePerGas: BigNumber;
10
+ readonly defaultChainId: number;
11
+ private transactions;
12
+ constructor(stdLastBaseFeePerGas: BigNumber, stdMaxPriorityFeePerGas: BigNumber, defaultChainId?: number);
13
+ getBlock(_blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>): Promise<Block>;
14
+ send(method: string, _params: Array<any>): Promise<any>;
15
+ getFeeData(): Promise<FeeData>;
16
+ getTransaction(hash: string): Promise<TransactionResponse>;
17
+ getGasPrice(): Promise<BigNumber>;
18
+ getNetwork(): Promise<{
19
+ chainId: number;
20
+ name: string;
21
+ }>;
22
+ _setTransaction(hash: string, transaction: TransactionResponse): void;
23
+ }
24
+ //# sourceMappingURL=mockProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/mockProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAGjG;;;GAGG;AACH,qBAAa,cAAe,SAAQ,SAAS,CAAC,qBAAqB;IAI/D,QAAQ,CAAC,oBAAoB,EAAE,SAAS;IACxC,QAAQ,CAAC,uBAAuB,EAAE,SAAS;IAC3C,QAAQ,CAAC,cAAc;IALzB,OAAO,CAAC,YAAY,CAA+C;gBAGxD,oBAAoB,EAAE,SAAS,EAC/B,uBAAuB,EAAE,SAAS,EAClC,cAAc,SAAI;IAK7B,QAAQ,CAAC,oBAAoB,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;IAoB9F,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IASvD,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAU9B,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI1D,WAAW,IAAI,OAAO,CAAC,SAAS,CAAC;IAIjC,UAAU,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAOxD,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB;CAG/D"}
@@ -8,4 +8,5 @@ import { providers } from "ethers";
8
8
  export declare function isContractDeployedToAddress(address: string, provider: providers.Provider): Promise<boolean>;
9
9
  export declare function compareAddresses(addressA: string, addressB: string): 1 | -1 | 0;
10
10
  export declare function compareAddressesSimple(addressA?: string, addressB?: string): boolean;
11
+ export declare function isValidEvmAddress(address: string): boolean;
11
12
  //# sourceMappingURL=AddressUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AddressUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/AddressUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAS,MAAM,QAAQ,CAAC;AAG1C;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CASjH;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAY/E;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAKpF"}
1
+ {"version":3,"file":"AddressUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/AddressUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAS,MAAM,QAAQ,CAAC;AAG1C;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CASjH;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAY/E;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAKpF;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAc1D"}
@@ -3,7 +3,8 @@ import { CachingMechanismInterface, Deposit, DepositWithBlock, Fill, SlowFillReq
3
3
  export declare enum InvalidFill {
4
4
  DepositIdInvalid = 0,
5
5
  DepositIdNotFound = 1,
6
- FillMismatch = 2
6
+ FillMismatch = 2,
7
+ DepositIdOutOfRange = 3
7
8
  }
8
9
  export type DepositSearchResult = {
9
10
  found: true;
@@ -1 +1 @@
1
- {"version":3,"file":"DepositUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/DepositUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,yBAAyB,EAAE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAY5G,oBAAY,WAAW;IACrB,gBAAgB,IAAI;IACpB,iBAAiB,IAAA;IACjB,YAAY,IAAA;CACb;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC1C;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,wBAAsB,6BAA6B,CACjD,eAAe,EAAE,eAAe,EAChC,IAAI,EAAE,IAAI,GAAG,eAAe,EAC5B,KAAK,CAAC,EAAE,yBAAyB,GAChC,OAAO,CAAC,mBAAmB,CAAC,CAoF9B;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,CAAC,GAAG,OAAO,CAE7F;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,SAAgB,GAAG,OAAO,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAI9D"}
1
+ {"version":3,"file":"DepositUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/DepositUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,yBAAyB,EAAE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAa5G,oBAAY,WAAW;IACrB,gBAAgB,IAAI;IACpB,iBAAiB,IAAA;IACjB,YAAY,IAAA;IACZ,mBAAmB,IAAA;CACpB;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC1C;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,wBAAsB,6BAA6B,CACjD,eAAe,EAAE,eAAe,EAChC,IAAI,EAAE,IAAI,GAAG,eAAe,EAC5B,KAAK,CAAC,EAAE,yBAAyB,GAChC,OAAO,CAAC,mBAAmB,CAAC,CA2F9B;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,CAAC,GAAG,OAAO,CAE7F;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,SAAgB,GAAG,OAAO,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAI9D"}
@@ -76,6 +76,12 @@ export declare function chainIsLinea(chainId: number): boolean;
76
76
  * @returns True if chain corresponding to chainId has a hub pool implementation.
77
77
  */
78
78
  export declare function chainIsL1(chainId: number): boolean;
79
+ /**
80
+ * Determines whether a chain ID runs on an EVM-like execution layer.
81
+ * @param chainId Chain ID to evaluate.
82
+ * @returns True if chain corresponding to chainId has an EVM-like execution layer.
83
+ */
84
+ export declare function chainIsEvm(chainId: number): boolean;
79
85
  /**
80
86
  * Determines whether a chain ID has the capacity for having its USDC bridged via CCTP.
81
87
  * @param chainId Chain ID to evaluate.
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/NetworkUtils.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAGjE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAErE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAa3D;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMpD"}
1
+ {"version":3,"file":"NetworkUtils.d.ts","sourceRoot":"","sources":["../../../src/utils/NetworkUtils.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAGjE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAErE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAInD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAa3D;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMpD"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@across-protocol/sdk",
3
3
  "author": "UMA Team",
4
- "version": "3.4.14",
4
+ "version": "3.4.16",
5
5
  "license": "AGPL-3.0",
6
6
  "homepage": "https://docs.across.to/reference/sdk",
7
7
  "files": [
@@ -30,8 +30,11 @@ import {
30
30
  getImpliedBundleBlockRanges,
31
31
  isSlowFill,
32
32
  mapAsync,
33
+ filterAsync,
33
34
  bnUint32Max,
34
35
  isZeroValueDeposit,
36
+ chainIsEvm,
37
+ isValidEvmAddress,
35
38
  } from "../../utils";
36
39
  import winston from "winston";
37
40
  import {
@@ -46,6 +49,7 @@ import {
46
49
  prettyPrintV3SpokePoolEvents,
47
50
  V3DepositWithBlock,
48
51
  V3FillWithBlock,
52
+ verifyFillRepayment,
49
53
  } from "./utils";
50
54
 
51
55
  // max(uint256) - 1
@@ -55,6 +59,10 @@ type DataCache = Record<string, Promise<LoadDataReturnValue>>;
55
59
 
56
60
  // V3 dictionary helper functions
57
61
  function updateExpiredDepositsV3(dict: ExpiredDepositsToRefundV3, deposit: V3DepositWithBlock): void {
62
+ // A deposit refund for a deposit is invalid if the depositor has a bytes32 address input for an EVM chain. It is valid otherwise.
63
+ if (chainIsEvm(deposit.originChainId) && !isValidEvmAddress(deposit.depositor)) {
64
+ return;
65
+ }
58
66
  const { originChainId, inputToken } = deposit;
59
67
  if (!dict?.[originChainId]?.[inputToken]) {
60
68
  assign(dict, [originChainId, inputToken], []);
@@ -75,8 +83,13 @@ function updateBundleFillsV3(
75
83
  fill: V3FillWithBlock,
76
84
  lpFeePct: BigNumber,
77
85
  repaymentChainId: number,
78
- repaymentToken: string
86
+ repaymentToken: string,
87
+ repaymentAddress: string
79
88
  ): void {
89
+ // It is impossible to refund a deposit if the repayment chain is EVM and the relayer is a non-evm address.
90
+ if (chainIsEvm(repaymentChainId) && !isValidEvmAddress(repaymentAddress)) {
91
+ return;
92
+ }
80
93
  if (!dict?.[repaymentChainId]?.[repaymentToken]) {
81
94
  assign(dict, [repaymentChainId, repaymentToken], {
82
95
  fills: [],
@@ -86,19 +99,19 @@ function updateBundleFillsV3(
86
99
  });
87
100
  }
88
101
 
89
- const bundleFill: BundleFillV3 = { ...fill, lpFeePct };
102
+ const bundleFill: BundleFillV3 = { ...fill, lpFeePct, relayer: repaymentAddress };
90
103
 
91
104
  // Add all fills, slow and fast, to dictionary.
92
105
  assign(dict, [repaymentChainId, repaymentToken, "fills"], [bundleFill]);
93
106
 
94
107
  // All fills update the bundle LP fees.
95
108
  const refundObj = dict[repaymentChainId][repaymentToken];
96
- const realizedLpFee = fill.inputAmount.mul(bundleFill.lpFeePct).div(fixedPointAdjustment);
109
+ const realizedLpFee = bundleFill.inputAmount.mul(bundleFill.lpFeePct).div(fixedPointAdjustment);
97
110
  refundObj.realizedLpFees = refundObj.realizedLpFees ? refundObj.realizedLpFees.add(realizedLpFee) : realizedLpFee;
98
111
 
99
112
  // Only fast fills get refunded.
100
- if (!isSlowFill(fill)) {
101
- const refundAmount = fill.inputAmount.mul(fixedPointAdjustment.sub(lpFeePct)).div(fixedPointAdjustment);
113
+ if (!isSlowFill(bundleFill)) {
114
+ const refundAmount = bundleFill.inputAmount.mul(fixedPointAdjustment.sub(lpFeePct)).div(fixedPointAdjustment);
102
115
  refundObj.totalRefundAmount = refundObj.totalRefundAmount
103
116
  ? refundObj.totalRefundAmount.add(refundAmount)
104
117
  : refundAmount;
@@ -106,10 +119,10 @@ function updateBundleFillsV3(
106
119
  // Instantiate dictionary if it doesn't exist.
107
120
  refundObj.refunds ??= {};
108
121
 
109
- if (refundObj.refunds[fill.relayer]) {
110
- refundObj.refunds[fill.relayer] = refundObj.refunds[fill.relayer].add(refundAmount);
122
+ if (refundObj.refunds[bundleFill.relayer]) {
123
+ refundObj.refunds[bundleFill.relayer] = refundObj.refunds[bundleFill.relayer].add(refundAmount);
111
124
  } else {
112
- refundObj.refunds[fill.relayer] = refundAmount;
125
+ refundObj.refunds[bundleFill.relayer] = refundAmount;
113
126
  }
114
127
  }
115
128
  }
@@ -277,7 +290,7 @@ export class BundleDataClient {
277
290
  // so as not to affect this approximate refund count.
278
291
  const arweaveData = await this.loadArweaveData(bundleEvaluationBlockRanges);
279
292
  if (arweaveData === undefined) {
280
- combinedRefunds = this.getApproximateRefundsForBlockRange(chainIds, bundleEvaluationBlockRanges);
293
+ combinedRefunds = await this.getApproximateRefundsForBlockRange(chainIds, bundleEvaluationBlockRanges);
281
294
  } else {
282
295
  const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
283
296
  combinedRefunds = getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3);
@@ -298,50 +311,63 @@ export class BundleDataClient {
298
311
  }
299
312
 
300
313
  // @dev This helper function should probably be moved to the InventoryClient
301
- getApproximateRefundsForBlockRange(chainIds: number[], blockRanges: number[][]): CombinedRefunds {
314
+ async getApproximateRefundsForBlockRange(chainIds: number[], blockRanges: number[][]): Promise<CombinedRefunds> {
302
315
  const refundsForChain: CombinedRefunds = {};
303
316
  for (const chainId of chainIds) {
304
317
  if (this.spokePoolClients[chainId] === undefined) {
305
318
  continue;
306
319
  }
307
320
  const chainIndex = chainIds.indexOf(chainId);
308
- this.spokePoolClients[chainId]
309
- .getFills()
310
- .filter((fill) => {
311
- if (fill.blockNumber < blockRanges[chainIndex][0] || fill.blockNumber > blockRanges[chainIndex][1]) {
312
- return false;
313
- }
321
+ const fillsToCount = await filterAsync(this.spokePoolClients[chainId].getFills(), async (fill) => {
322
+ if (fill.blockNumber < blockRanges[chainIndex][0] || fill.blockNumber > blockRanges[chainIndex][1]) {
323
+ return false;
324
+ }
314
325
 
315
- // If origin spoke pool client isn't defined, we can't validate it.
316
- if (this.spokePoolClients[fill.originChainId] === undefined) {
317
- return false;
318
- }
319
- const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
320
- const hasMatchingDeposit =
321
- matchingDeposit !== undefined &&
322
- this.getRelayHashFromEvent(fill) === this.getRelayHashFromEvent(matchingDeposit);
323
- return hasMatchingDeposit;
324
- })
325
- .forEach((fill) => {
326
- const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
327
- assert(isDefined(matchingDeposit), "Deposit not found for fill.");
328
- const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill(
326
+ // If origin spoke pool client isn't defined, we can't validate it.
327
+ if (this.spokePoolClients[fill.originChainId] === undefined) {
328
+ return false;
329
+ }
330
+ const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
331
+ const hasMatchingDeposit =
332
+ matchingDeposit !== undefined &&
333
+ this.getRelayHashFromEvent(fill) === this.getRelayHashFromEvent(matchingDeposit);
334
+ if (hasMatchingDeposit) {
335
+ const validRepayment = await verifyFillRepayment(
329
336
  fill,
330
- this.clients.hubPoolClient,
331
- blockRanges,
332
- this.chainIdListForBundleEvaluationBlockNumbers,
333
- matchingDeposit!.fromLiteChain // Use ! because we've already asserted that matchingDeposit is defined.
337
+ this.spokePoolClients[fill.destinationChainId].spokePool.provider,
338
+ matchingDeposit,
339
+ // @dev: to get valid repayment chain ID's, get all chain IDs for the bundle block range and remove
340
+ // disabled block ranges.
341
+ this.clients.configStoreClient
342
+ .getChainIdIndicesForBlock(blockRanges[0][1])
343
+ .filter((_chainId, i) => !isChainDisabled(blockRanges[i]))
334
344
  );
335
- // Assume that lp fees are 0 for the sake of speed. In the future we could batch compute
336
- // these or make hardcoded assumptions based on the origin-repayment chain direction. This might result
337
- // in slight over estimations of refunds, but its not clear whether underestimating or overestimating is
338
- // worst from the relayer's perspective.
339
- const { relayer, inputAmount: refundAmount } = fill;
340
- refundsForChain[chainToSendRefundTo] ??= {};
341
- refundsForChain[chainToSendRefundTo][repaymentToken] ??= {};
342
- const existingRefundAmount = refundsForChain[chainToSendRefundTo][repaymentToken][relayer] ?? bnZero;
343
- refundsForChain[chainToSendRefundTo][repaymentToken][relayer] = existingRefundAmount.add(refundAmount);
344
- });
345
+ if (!isDefined(validRepayment)) {
346
+ return false;
347
+ }
348
+ }
349
+ return hasMatchingDeposit;
350
+ });
351
+ fillsToCount.forEach((fill) => {
352
+ const matchingDeposit = this.spokePoolClients[fill.originChainId].getDeposit(fill.depositId);
353
+ assert(isDefined(matchingDeposit), "Deposit not found for fill.");
354
+ const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill(
355
+ fill,
356
+ this.clients.hubPoolClient,
357
+ blockRanges,
358
+ this.chainIdListForBundleEvaluationBlockNumbers,
359
+ matchingDeposit!.fromLiteChain // Use ! because we've already asserted that matchingDeposit is defined.
360
+ );
361
+ // Assume that lp fees are 0 for the sake of speed. In the future we could batch compute
362
+ // these or make hardcoded assumptions based on the origin-repayment chain direction. This might result
363
+ // in slight over estimations of refunds, but its not clear whether underestimating or overestimating is
364
+ // worst from the relayer's perspective.
365
+ const { relayer, inputAmount: refundAmount } = fill;
366
+ refundsForChain[chainToSendRefundTo] ??= {};
367
+ refundsForChain[chainToSendRefundTo][repaymentToken] ??= {};
368
+ const existingRefundAmount = refundsForChain[chainToSendRefundTo][repaymentToken][relayer] ?? bnZero;
369
+ refundsForChain[chainToSendRefundTo][repaymentToken][relayer] = existingRefundAmount.add(refundAmount);
370
+ });
345
371
  }
346
372
  return refundsForChain;
347
373
  }
@@ -468,7 +494,7 @@ export class BundleDataClient {
468
494
  // ok for this use case.
469
495
  const arweaveData = await this.loadArweaveData(pendingBundleBlockRanges);
470
496
  if (arweaveData === undefined) {
471
- combinedRefunds.push(this.getApproximateRefundsForBlockRange(chainIds, pendingBundleBlockRanges));
497
+ combinedRefunds.push(await this.getApproximateRefundsForBlockRange(chainIds, pendingBundleBlockRanges));
472
498
  } else {
473
499
  const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
474
500
  combinedRefunds.push(getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3));
@@ -483,7 +509,7 @@ export class BundleDataClient {
483
509
  // - Only look up fills sent after the pending bundle's end blocks
484
510
  // - Skip LP fee computations and just assume the relayer is being refunded the full deposit.inputAmount
485
511
  const start = performance.now();
486
- combinedRefunds.push(this.getApproximateRefundsForBlockRange(chainIds, widestBundleBlockRanges));
512
+ combinedRefunds.push(await this.getApproximateRefundsForBlockRange(chainIds, widestBundleBlockRanges));
487
513
  this.logger.debug({
488
514
  at: "BundleDataClient#getNextBundleRefunds",
489
515
  message: `Loading approximate refunds for next bundle in ${Math.round(performance.now() - start) / 1000}s.`,
@@ -807,6 +833,8 @@ export class BundleDataClient {
807
833
 
808
834
  // If deposit block is within origin chain bundle block range, then save as bundle deposit.
809
835
  // If deposit is in bundle and it has expired, additionally save it as an expired deposit.
836
+ // Note: if the `depositor` field in the expired deposit is an invalid address, e.g. a bytes32 address on an EVM
837
+ // chain, then the deposit refund is invalid and ignored.
810
838
  // If deposit is not in the bundle block range, then save it as an older deposit that
811
839
  // may have expired.
812
840
  if (deposit.blockNumber >= originChainBlockRange[0] && deposit.blockNumber <= originChainBlockRange[1]) {
@@ -856,16 +884,28 @@ export class BundleDataClient {
856
884
  // tokens to the filler. We can't remove non-empty message deposit here in case there is a slow fill
857
885
  // request for the deposit, we'd want to see the fill took place.
858
886
  .filter((fill) => fill.blockNumber <= destinationChainBlockRange[1] && !isZeroValueDeposit(fill)),
859
- async (fill) => {
860
- const relayDataHash = this.getRelayHashFromEvent(fill);
887
+ async (_fill) => {
861
888
  fillCounter++;
862
-
889
+ const relayDataHash = this.getRelayHashFromEvent(_fill);
863
890
  if (v3RelayHashes[relayDataHash]) {
864
891
  if (!v3RelayHashes[relayDataHash].fill) {
865
892
  assert(
866
893
  isDefined(v3RelayHashes[relayDataHash].deposit),
867
894
  "Deposit should exist in relay hash dictionary."
868
895
  );
896
+ // `fill` will only possibly differ from `_fill` in the `relayer` field, which does not affect the
897
+ // relay hash, so it is safe to modify.
898
+ const fill = await verifyFillRepayment(
899
+ _fill,
900
+ destinationClient.spokePool.provider,
901
+ v3RelayHashes[relayDataHash].deposit!,
902
+ allChainIds
903
+ );
904
+ if (!isDefined(fill)) {
905
+ bundleInvalidFillsV3.push(_fill);
906
+ return;
907
+ }
908
+
869
909
  // At this point, the v3RelayHashes entry already existed meaning that there is a matching deposit,
870
910
  // so this fill is validated.
871
911
  v3RelayHashes[relayDataHash].fill = fill;
@@ -891,10 +931,10 @@ export class BundleDataClient {
891
931
  }
892
932
 
893
933
  // At this point, there is no relay hash dictionary entry for this fill, so we need to
894
- // instantiate the entry.
934
+ // instantiate the entry. We won't modify the fill.relayer until we match it with a deposit.
895
935
  v3RelayHashes[relayDataHash] = {
896
936
  deposit: undefined,
897
- fill: fill,
937
+ fill: _fill,
898
938
  slowFillRequest: undefined,
899
939
  };
900
940
 
@@ -906,22 +946,34 @@ export class BundleDataClient {
906
946
  // older deposit in case the spoke pool client's lookback isn't old enough to find the matching deposit.
907
947
  // We can skip this step if the fill's fill deadline is not infinite, because we can assume that the
908
948
  // spoke pool clients have loaded deposits old enough to cover all fills with a non-infinite fill deadline.
909
- if (fill.blockNumber >= destinationChainBlockRange[0]) {
949
+ if (_fill.blockNumber >= destinationChainBlockRange[0]) {
910
950
  // Fill has a non-infinite expiry, and we can assume our spoke pool clients have old enough deposits
911
951
  // to conclude that this fill is invalid if we haven't found a matching deposit in memory, so
912
952
  // skip the historical query.
913
- if (!INFINITE_FILL_DEADLINE.eq(fill.fillDeadline)) {
914
- bundleInvalidFillsV3.push(fill);
953
+ if (!INFINITE_FILL_DEADLINE.eq(_fill.fillDeadline)) {
954
+ bundleInvalidFillsV3.push(_fill);
915
955
  return;
916
956
  }
917
957
  // If deposit is using the deterministic relay hash feature, then the following binary search-based
918
958
  // algorithm will not work. However, it is impossible to emit an infinite fill deadline using
919
959
  // the unsafeDepositV3 function so there is no need to catch the special case.
920
- const historicalDeposit = await queryHistoricalDepositForFill(originClient, fill);
960
+ const historicalDeposit = await queryHistoricalDepositForFill(originClient, _fill);
921
961
  if (!historicalDeposit.found) {
922
- bundleInvalidFillsV3.push(fill);
962
+ bundleInvalidFillsV3.push(_fill);
923
963
  } else {
924
964
  const matchedDeposit = historicalDeposit.deposit;
965
+ const fill = await verifyFillRepayment(
966
+ _fill,
967
+ destinationClient.spokePool.provider,
968
+ matchedDeposit,
969
+ allChainIds
970
+ );
971
+ if (!isDefined(fill)) {
972
+ bundleInvalidFillsV3.push(_fill);
973
+ return;
974
+ }
975
+ v3RelayHashes[relayDataHash].fill = fill;
976
+
925
977
  // @dev Since queryHistoricalDepositForFill validates the fill by checking individual
926
978
  // object property values against the deposit's, we
927
979
  // sanity check it here by comparing the full relay hashes. If there's an error here then the
@@ -1262,7 +1314,7 @@ export class BundleDataClient {
1262
1314
  chainIds,
1263
1315
  associatedDeposit!.fromLiteChain
1264
1316
  );
1265
- updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken);
1317
+ updateBundleFillsV3(bundleFillsV3, fill, realizedLpFeePct, chainToSendRefundTo, repaymentToken, fill.relayer);
1266
1318
  });
1267
1319
  v3SlowFillLpFees.forEach(({ realizedLpFeePct: lpFeePct }, idx) => {
1268
1320
  const deposit = validatedBundleSlowFills[idx];
@@ -1,5 +1,7 @@
1
- import { Fill } from "../../../interfaces";
2
- import { getBlockRangeForChain, isSlowFill } from "../../../utils";
1
+ import _ from "lodash";
2
+ import { providers } from "ethers";
3
+ import { DepositWithBlock, Fill, FillWithBlock } from "../../../interfaces";
4
+ import { getBlockRangeForChain, isSlowFill, chainIsEvm, isValidEvmAddress, isDefined } from "../../../utils";
3
5
  import { HubPoolClient } from "../../HubPoolClient";
4
6
 
5
7
  export function getRefundInformationFromFill(
@@ -44,3 +46,46 @@ export function getRefundInformationFromFill(
44
46
  repaymentToken,
45
47
  };
46
48
  }
49
+
50
+ // Verify that a fill sent to an EVM chain has a 20 byte address. If the fill does not, then attempt
51
+ // to repay the `msg.sender` of the relay transaction. Otherwise, return undefined.
52
+ export async function verifyFillRepayment(
53
+ fill: FillWithBlock,
54
+ destinationChainProvider: providers.Provider,
55
+ matchedDeposit: DepositWithBlock,
56
+ possibleRepaymentChainIds: number[]
57
+ ): Promise<FillWithBlock | undefined> {
58
+ // Slow fills don't result in repayments so they're always valid.
59
+ if (isSlowFill(fill)) {
60
+ return fill;
61
+ }
62
+ // Lite chain deposits force repayment on origin chain.
63
+ const repaymentChainId = matchedDeposit.fromLiteChain ? fill.originChainId : fill.repaymentChainId;
64
+ // Return undefined if the requested repayment chain ID is not recognized by the hub pool.
65
+ if (!possibleRepaymentChainIds.includes(repaymentChainId)) {
66
+ return undefined;
67
+ }
68
+ const updatedFill = _.cloneDeep(fill);
69
+
70
+ // If the fill requests repayment on a chain where the repayment address is not valid, attempt to find a valid
71
+ // repayment address, otherwise return undefined.
72
+
73
+ // Case 1: repayment chain is an EVM chain but repayment address is not a valid EVM address.
74
+ if (chainIsEvm(repaymentChainId) && !isValidEvmAddress(updatedFill.relayer)) {
75
+ // TODO: Handle case where fill was sent on non-EVM chain, in which case the following call would fail
76
+ // or return something unexpected. We'd want to return undefined here.
77
+ const fillTransaction = await destinationChainProvider.getTransaction(updatedFill.transactionHash);
78
+ const destinationRelayer = fillTransaction?.from;
79
+ // Repayment chain is still an EVM chain, but the msg.sender is a bytes32 address, so the fill is invalid.
80
+ if (!isDefined(destinationRelayer) || !isValidEvmAddress(destinationRelayer)) {
81
+ return undefined;
82
+ }
83
+ // Otherwise, assume the relayer to be repaid is the msg.sender. We don't need to modify the repayment chain since
84
+ // the getTransaction() call would only succeed if the fill was sent on an EVM chain and therefore the msg.sender
85
+ // is a valid EVM address and the repayment chain is an EVM chain.
86
+ updatedFill.relayer = destinationRelayer;
87
+ }
88
+
89
+ // Case 2: TODO repayment chain is an SVM chain and repayment address is not a valid SVM address.
90
+ return updatedFill;
91
+ }
@@ -5,3 +5,4 @@ export * from "./speedProvider";
5
5
  export * from "./constants";
6
6
  export * from "./types";
7
7
  export * from "./utils";
8
+ export * as mocks from "./mockProvider";
@@ -0,0 +1,77 @@
1
+ import { BigNumber, providers } from "ethers";
2
+ import { Block, BlockTag, FeeData, TransactionResponse } from "@ethersproject/abstract-provider";
3
+ import { bnZero } from "../utils/BigNumberUtils";
4
+
5
+ /**
6
+ * @notice Class used to test GasPriceOracle which makes ethers provider calls to the following implemented
7
+ * methods.
8
+ */
9
+ export class MockedProvider extends providers.StaticJsonRpcProvider {
10
+ private transactions: { [hash: string]: TransactionResponse } = {};
11
+
12
+ constructor(
13
+ readonly stdLastBaseFeePerGas: BigNumber,
14
+ readonly stdMaxPriorityFeePerGas: BigNumber,
15
+ readonly defaultChainId = 1
16
+ ) {
17
+ super(undefined, defaultChainId);
18
+ }
19
+
20
+ getBlock(_blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>): Promise<Block> {
21
+ const mockBlock: Block = {
22
+ transactions: [],
23
+ hash: "0x",
24
+ parentHash: "0x",
25
+ number: 0,
26
+ nonce: "0",
27
+ difficulty: 0,
28
+ _difficulty: bnZero,
29
+ timestamp: 0,
30
+ gasLimit: bnZero,
31
+ gasUsed: bnZero,
32
+ baseFeePerGas: this.stdLastBaseFeePerGas,
33
+ miner: "0x",
34
+ extraData: "0x",
35
+ };
36
+ return Promise.resolve(mockBlock);
37
+ }
38
+
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ send(method: string, _params: Array<any>): Promise<any> {
41
+ switch (method) {
42
+ case "eth_maxPriorityFeePerGas":
43
+ return Promise.resolve(this.stdMaxPriorityFeePerGas);
44
+ default:
45
+ throw new Error(`MockedProvider#Unimplemented method: ${method}`);
46
+ }
47
+ }
48
+
49
+ getFeeData(): Promise<FeeData> {
50
+ return Promise.resolve({
51
+ lastBaseFeePerGas: this.stdLastBaseFeePerGas,
52
+ maxPriorityFeePerGas: this.stdMaxPriorityFeePerGas,
53
+ // Following fields unused in GasPrice oracle
54
+ maxFeePerGas: null,
55
+ gasPrice: null,
56
+ });
57
+ }
58
+
59
+ getTransaction(hash: string): Promise<TransactionResponse> {
60
+ return Promise.resolve(this.transactions[hash]);
61
+ }
62
+
63
+ getGasPrice(): Promise<BigNumber> {
64
+ return Promise.resolve(this.stdLastBaseFeePerGas.add(this.stdMaxPriorityFeePerGas));
65
+ }
66
+
67
+ getNetwork(): Promise<{ chainId: number; name: string }> {
68
+ return Promise.resolve({
69
+ name: "mocknetwork",
70
+ chainId: this.defaultChainId,
71
+ });
72
+ }
73
+
74
+ _setTransaction(hash: string, transaction: TransactionResponse) {
75
+ this.transactions[hash] = transaction;
76
+ }
77
+ }
@@ -38,3 +38,19 @@ export function compareAddressesSimple(addressA?: string, addressB?: string): bo
38
38
  }
39
39
  return addressA.toLowerCase() === addressB.toLowerCase();
40
40
  }
41
+
42
+ export function isValidEvmAddress(address: string): boolean {
43
+ if (utils.isAddress(address)) {
44
+ return true;
45
+ }
46
+ // We may throw an error here if hexZeroPadFails. This will happen if the address to pad is greater than 20 bytes long, indicating
47
+ // that the address had less than 12 leading zero bytes.
48
+ // We may also throw at getAddress if the input cannot be converted into a checksummed EVM address for some reason.
49
+ // For both cases, this indicates that the address cannot be casted as a bytes20 EVM address, so we should return false.
50
+ try {
51
+ const evmAddress = utils.hexZeroPad(utils.hexStripZeros(address), 20);
52
+ return utils.isAddress(utils.getAddress(evmAddress));
53
+ } catch (_e) {
54
+ return false;
55
+ }
56
+ }
@@ -5,6 +5,7 @@ import { CachingMechanismInterface, Deposit, DepositWithBlock, Fill, SlowFillReq
5
5
  import { getNetworkName } from "./NetworkUtils";
6
6
  import { getDepositInCache, getDepositKey, setDepositInCache } from "./CachingUtils";
7
7
  import { validateFillForDeposit } from "./FlowUtils";
8
+ import { isUnsafeDepositId } from "./SpokeUtils";
8
9
  import { getCurrentTime } from "./TimeUtils";
9
10
  import { isDefined } from "./TypeGuards";
10
11
  import { isDepositFormedCorrectly } from "./ValidatorUtils";
@@ -17,6 +18,7 @@ export enum InvalidFill {
17
18
  DepositIdInvalid = 0, // Deposit ID seems invalid for origin SpokePool
18
19
  DepositIdNotFound, // Deposit ID not found (bad RPC data?)
19
20
  FillMismatch, // Fill does not match deposit parameters for deposit ID.
21
+ DepositIdOutOfRange, // Fill is for a deterministic deposit.
20
22
  }
21
23
 
22
24
  export type DepositSearchResult =
@@ -40,6 +42,13 @@ export async function queryHistoricalDepositForFill(
40
42
  fill: Fill | SlowFillRequest,
41
43
  cache?: CachingMechanismInterface
42
44
  ): Promise<DepositSearchResult> {
45
+ if (isUnsafeDepositId(fill.depositId)) {
46
+ return {
47
+ found: false,
48
+ code: InvalidFill.DepositIdOutOfRange,
49
+ reason: `Cannot find historical deposit for fill with unsafe deposit ID ${fill.depositId}.`,
50
+ };
51
+ }
43
52
  if (fill.originChainId !== spokePoolClient.chainId) {
44
53
  throw new Error(`OriginChainId mismatch (${fill.originChainId} != ${spokePoolClient.chainId})`);
45
54
  }
@@ -123,6 +123,17 @@ export function chainIsL1(chainId: number): boolean {
123
123
  return [CHAIN_IDs.MAINNET, CHAIN_IDs.SEPOLIA].includes(chainId);
124
124
  }
125
125
 
126
+ /**
127
+ * Determines whether a chain ID runs on an EVM-like execution layer.
128
+ * @param chainId Chain ID to evaluate.
129
+ * @returns True if chain corresponding to chainId has an EVM-like execution layer.
130
+ */
131
+ export function chainIsEvm(chainId: number): boolean {
132
+ chainId;
133
+ // TODO: Fix when we support non-EVM chains.
134
+ return true;
135
+ }
136
+
126
137
  /**
127
138
  * Determines whether a chain ID has the capacity for having its USDC bridged via CCTP.
128
139
  * @param chainId Chain ID to evaluate.
@@ -208,7 +208,7 @@ export async function getBlockRangeForDepositId(
208
208
  export async function getDepositIdAtBlock(contract: Contract, blockTag: number): Promise<BigNumber> {
209
209
  const _depositIdAtBlock = await contract.numberOfDeposits({ blockTag });
210
210
  const depositIdAtBlock = toBN(_depositIdAtBlock);
211
- // Sanity check to ensure that the deposit ID is an integer and is greater than or equal to zero.
211
+ // Sanity check to ensure that the deposit ID is greater than or equal to zero.
212
212
  if (depositIdAtBlock.lt(bnZero)) {
213
213
  throw new Error("Invalid deposit count");
214
214
  }