@across-protocol/sdk 4.3.46 → 4.3.47

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/arch/evm/SpokeUtils.js +30 -28
  2. package/dist/cjs/arch/evm/SpokeUtils.js.map +1 -1
  3. package/dist/cjs/arch/svm/SpokeUtils.js +1 -1
  4. package/dist/cjs/arch/svm/SpokeUtils.js.map +1 -1
  5. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js +4 -6
  6. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
  7. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +0 -5
  8. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  9. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js +0 -1
  10. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  11. package/dist/cjs/clients/BundleDataClient/utils/SuperstructUtils.d.ts +58 -58
  12. package/dist/cjs/clients/HubPoolClient.d.ts +9 -3
  13. package/dist/cjs/clients/HubPoolClient.js +81 -56
  14. package/dist/cjs/clients/HubPoolClient.js.map +1 -1
  15. package/dist/cjs/clients/SpokePoolClient/EVMSpokePoolClient.js +7 -5
  16. package/dist/cjs/clients/SpokePoolClient/EVMSpokePoolClient.js.map +1 -1
  17. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js +13 -16
  18. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
  19. package/dist/cjs/clients/mocks/MockHubPoolClient.d.ts +2 -2
  20. package/dist/cjs/clients/mocks/MockHubPoolClient.js +1 -1
  21. package/dist/cjs/clients/mocks/MockHubPoolClient.js.map +1 -1
  22. package/dist/cjs/constants.d.ts +3 -0
  23. package/dist/cjs/constants.js +10 -2
  24. package/dist/cjs/constants.js.map +1 -1
  25. package/dist/esm/arch/evm/SpokeUtils.js +33 -29
  26. package/dist/esm/arch/evm/SpokeUtils.js.map +1 -1
  27. package/dist/esm/arch/svm/SpokeUtils.js +1 -1
  28. package/dist/esm/arch/svm/SpokeUtils.js.map +1 -1
  29. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js +5 -7
  30. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
  31. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +1 -6
  32. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  33. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js +0 -1
  34. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  35. package/dist/esm/clients/BundleDataClient/utils/SuperstructUtils.d.ts +58 -58
  36. package/dist/esm/clients/HubPoolClient.d.ts +9 -3
  37. package/dist/esm/clients/HubPoolClient.js +87 -60
  38. package/dist/esm/clients/HubPoolClient.js.map +1 -1
  39. package/dist/esm/clients/SpokePoolClient/EVMSpokePoolClient.js +8 -6
  40. package/dist/esm/clients/SpokePoolClient/EVMSpokePoolClient.js.map +1 -1
  41. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js +13 -18
  42. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
  43. package/dist/esm/clients/mocks/MockHubPoolClient.d.ts +2 -2
  44. package/dist/esm/clients/mocks/MockHubPoolClient.js +1 -1
  45. package/dist/esm/clients/mocks/MockHubPoolClient.js.map +1 -1
  46. package/dist/esm/constants.d.ts +3 -0
  47. package/dist/esm/constants.js +12 -1
  48. package/dist/esm/constants.js.map +1 -1
  49. package/dist/types/arch/evm/SpokeUtils.d.ts.map +1 -1
  50. package/dist/types/arch/svm/SpokeUtils.d.ts.map +1 -1
  51. package/dist/types/clients/BundleDataClient/utils/DataworkerUtils.d.ts.map +1 -1
  52. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
  53. package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts.map +1 -1
  54. package/dist/types/clients/BundleDataClient/utils/SuperstructUtils.d.ts +58 -58
  55. package/dist/types/clients/HubPoolClient.d.ts +9 -3
  56. package/dist/types/clients/HubPoolClient.d.ts.map +1 -1
  57. package/dist/types/clients/SpokePoolClient/EVMSpokePoolClient.d.ts.map +1 -1
  58. package/dist/types/clients/SpokePoolClient/SpokePoolClient.d.ts.map +1 -1
  59. package/dist/types/clients/mocks/MockHubPoolClient.d.ts +2 -2
  60. package/dist/types/clients/mocks/MockHubPoolClient.d.ts.map +1 -1
  61. package/dist/types/constants.d.ts +3 -0
  62. package/dist/types/constants.d.ts.map +1 -1
  63. package/package.json +2 -2
  64. package/src/arch/evm/SpokeUtils.ts +16 -9
  65. package/src/arch/svm/SpokeUtils.ts +12 -7
  66. package/src/clients/BundleDataClient/utils/DataworkerUtils.ts +20 -14
  67. package/src/clients/BundleDataClient/utils/FillUtils.ts +1 -7
  68. package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +0 -2
  69. package/src/clients/HubPoolClient.ts +79 -50
  70. package/src/clients/SpokePoolClient/EVMSpokePoolClient.ts +22 -8
  71. package/src/clients/SpokePoolClient/SpokePoolClient.ts +31 -39
  72. package/src/clients/mocks/MockHubPoolClient.ts +3 -3
  73. package/src/constants.ts +12 -0
@@ -18,7 +18,6 @@ import {
18
18
  count2DDictionaryValues,
19
19
  count3DDictionaryValues,
20
20
  toAddressType,
21
- isDefined,
22
21
  } from "../../../utils";
23
22
  import {
24
23
  addLastRunningBalance,
@@ -154,15 +153,21 @@ export function _buildPoolRebalanceRoot(
154
153
  ([l2TokenAddress, { realizedLpFees: totalRealizedLpFee, totalRefundAmount }]) => {
155
154
  // If the repayment token and repayment chain ID do not map to a PoolRebalanceRoute graph, then
156
155
  // there are no relevant L1 running balances.
156
+ if (
157
+ !clients.hubPoolClient.l2TokenHasPoolRebalanceRoute(
158
+ toAddressType(l2TokenAddress, repaymentChainId),
159
+ repaymentChainId,
160
+ mainnetBundleEndBlock
161
+ )
162
+ ) {
163
+ chainWithRefundsOnly.add(repaymentChainId);
164
+ return;
165
+ }
157
166
  const l1Token = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
158
167
  toAddressType(l2TokenAddress, repaymentChainId),
159
168
  repaymentChainId,
160
169
  mainnetBundleEndBlock
161
170
  );
162
- if (!l1Token) {
163
- chainWithRefundsOnly.add(repaymentChainId);
164
- return;
165
- }
166
171
  const l1TokenAddr = l1Token.toNative();
167
172
  assert(l1Token.isEVM(), `Expected an EVM address: ${l1TokenAddr}`);
168
173
 
@@ -188,9 +193,6 @@ export function _buildPoolRebalanceRoot(
188
193
  destinationChainId,
189
194
  mainnetBundleEndBlock
190
195
  );
191
-
192
- assert(isDefined(l1TokenCounterpart), "getRefundInformationFromFill: l1TokenCounterpart is undefined");
193
-
194
196
  const lpFee = deposit.lpFeePct.mul(deposit.inputAmount).div(fixedPointAdjustment);
195
197
  updateRunningBalance(
196
198
  runningBalances,
@@ -220,8 +222,6 @@ export function _buildPoolRebalanceRoot(
220
222
  destinationChainId,
221
223
  mainnetBundleEndBlock
222
224
  );
223
- assert(isDefined(l1TokenCounterpart), "getRefundInformationFromFill: l1TokenCounterpart is undefined");
224
-
225
225
  const lpFee = deposit.lpFeePct.mul(deposit.inputAmount).div(fixedPointAdjustment);
226
226
  updateRunningBalance(
227
227
  runningBalances,
@@ -277,15 +277,21 @@ export function _buildPoolRebalanceRoot(
277
277
  deposits.forEach((deposit) => {
278
278
  // If the repayment token and repayment chain ID do not map to a PoolRebalanceRoute graph, then
279
279
  // there are no relevant L1 running balances.
280
+ if (
281
+ !clients.hubPoolClient.l2TokenHasPoolRebalanceRoute(
282
+ deposit.inputToken,
283
+ deposit.originChainId,
284
+ mainnetBundleEndBlock
285
+ )
286
+ ) {
287
+ chainWithRefundsOnly.add(deposit.originChainId);
288
+ return;
289
+ }
280
290
  const l1TokenCounterpart = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
281
291
  toAddressType(inputToken, originChainId),
282
292
  originChainId,
283
293
  mainnetBundleEndBlock
284
294
  );
285
- if (!l1TokenCounterpart) {
286
- chainWithRefundsOnly.add(deposit.originChainId);
287
- return;
288
- }
289
295
  updateRunningBalance(runningBalances, originChainId, l1TokenCounterpart.toEvmAddress(), deposit.inputAmount);
290
296
  });
291
297
  });
@@ -37,21 +37,18 @@ export function getRefundInformationFromFill(
37
37
 
38
38
  // Now figure out the equivalent L2 token for the repayment token. If the inputToken doesn't have a
39
39
  // PoolRebalanceRoute, then the repayment chain would have been the originChainId after the getRepaymentChainId()
40
- // call and we would have returned already, so the following call should always return a valid L1 token.
40
+ // call and we would have returned already, so the following call should always succeed.
41
41
  const l1TokenCounterpart = hubPoolClient.getL1TokenForL2TokenAtBlock(
42
42
  relayData.inputToken,
43
43
  relayData.originChainId,
44
44
  bundleEndBlockForMainnet
45
45
  );
46
46
 
47
- assert(isDefined(l1TokenCounterpart), "getRefundInformationFromFill: l1TokenCounterpart is undefined");
48
-
49
47
  const repaymentToken = hubPoolClient.getL2TokenForL1TokenAtBlock(
50
48
  l1TokenCounterpart,
51
49
  chainToSendRefundTo,
52
50
  bundleEndBlockForMainnet
53
51
  );
54
- assert(isDefined(repaymentToken), "getRefundInformationFromFill: repaymentToken is undefined");
55
52
 
56
53
  return {
57
54
  chainToSendRefundTo,
@@ -186,9 +183,6 @@ function _repaymentChainTokenIsValid(
186
183
  relayData.originChainId,
187
184
  bundleEndBlockForMainnet
188
185
  );
189
- if (!l1TokenCounterpart) {
190
- return false;
191
- }
192
186
  if (
193
187
  !hubPoolClient.l2TokenEnabledForL1TokenAtBlock(
194
188
  l1TokenCounterpart,
@@ -202,8 +202,6 @@ export function updateRunningBalanceForDeposit(
202
202
  deposit.originChainId,
203
203
  mainnetBundleEndBlock
204
204
  );
205
- assert(isDefined(l1TokenCounterpart), "updateRunningBalanceForDeposit: l1TokenCounterpart is undefined");
206
-
207
205
  updateRunningBalance(runningBalances, deposit.originChainId, l1TokenCounterpart.toEvmAddress(), updateAmount);
208
206
  }
209
207
 
@@ -34,6 +34,7 @@ import {
34
34
  fetchTokenInfo,
35
35
  getCachedBlockForTimestamp,
36
36
  getCurrentTime,
37
+ getNetworkName,
37
38
  isDefined,
38
39
  mapAsync,
39
40
  paginatedEventQuery,
@@ -74,11 +75,17 @@ type HubPoolEvent =
74
75
  | "RootBundleExecuted"
75
76
  | "CrossChainContractsSet";
76
77
 
78
+ type L1TokensToDestinationTokens = {
79
+ [l1Token: string]: { [destinationChainId: number]: Address };
80
+ };
81
+
77
82
  export type LpFeeRequest = Pick<Deposit, "originChainId" | "inputToken" | "inputAmount" | "quoteTimestamp"> & {
78
83
  paymentChainId?: number;
79
84
  };
80
85
 
81
86
  export class HubPoolClient extends BaseAbstractClient {
87
+ // L1Token -> destinationChainId -> destinationToken
88
+ protected l1TokensToDestinationTokens: L1TokensToDestinationTokens = {};
82
89
  protected l1Tokens: L1TokenInfo[] = []; // L1Tokens and their associated info.
83
90
  // @dev `token` here is a 20-byte hex sting
84
91
  protected lpTokens: { [token: string]: LpToken } = {};
@@ -185,16 +192,24 @@ export class HubPoolClient extends BaseAbstractClient {
185
192
  l1Token: EvmAddress,
186
193
  destinationChainId: number,
187
194
  latestHubBlock = Number.MAX_SAFE_INTEGER
188
- ): Address | undefined {
195
+ ): Address {
189
196
  if (!this.l1TokensToDestinationTokensWithBlock?.[l1Token.toEvmAddress()]?.[destinationChainId]) {
190
- return undefined;
197
+ const chain = getNetworkName(destinationChainId);
198
+ const { symbol } = this.l1Tokens.find(({ address }) => address.eq(l1Token)) ?? { symbol: l1Token.toString() };
199
+ throw new Error(`Could not find SpokePool mapping for ${symbol} on ${chain} and L1 token ${l1Token}`);
191
200
  }
192
201
  // Find the last mapping published before the target block.
193
- const l2Token: DestinationTokenWithBlock | undefined = this.l1TokensToDestinationTokensWithBlock[
194
- l1Token.toEvmAddress()
195
- ][destinationChainId].find((mapping: DestinationTokenWithBlock) => mapping.blockNumber <= latestHubBlock);
196
-
197
- return !l2Token || l2Token.l2Token.isZeroAddress() ? undefined : l2Token.l2Token;
202
+ const l2Token: DestinationTokenWithBlock | undefined = sortEventsDescending(
203
+ this.l1TokensToDestinationTokensWithBlock[l1Token.toEvmAddress()][destinationChainId]
204
+ ).find((mapping: DestinationTokenWithBlock) => mapping.blockNumber <= latestHubBlock);
205
+ if (!l2Token) {
206
+ const chain = getNetworkName(destinationChainId);
207
+ const { symbol } = this.l1Tokens.find(({ address }) => address.eq(l1Token)) ?? { symbol: l1Token.toString() };
208
+ throw new Error(
209
+ `Could not find SpokePool mapping for ${symbol} on ${chain} at or before HubPool block ${latestHubBlock}!`
210
+ );
211
+ }
212
+ return l2Token.l2Token;
198
213
  }
199
214
 
200
215
  // Returns the latest L1 token to use for an L2 token as of the input hub block.
@@ -202,27 +217,32 @@ export class HubPoolClient extends BaseAbstractClient {
202
217
  l2Token: Address,
203
218
  destinationChainId: number,
204
219
  latestHubBlock = Number.MAX_SAFE_INTEGER
205
- ): EvmAddress | undefined {
206
- const l2Tokens = Object.keys(this.l1TokensToDestinationTokensWithBlock).flatMap((l1Token) => {
207
- // Get the latest L2 token mapping for the given L1 token.
208
- // @dev Since tokens on L2s (like Solana) can have 32 byte addresses, filter on the lower 20 bytes of the token only.
209
- const sortedL2Tokens = sortEventsDescending(
210
- (this.l1TokensToDestinationTokensWithBlock[l1Token][destinationChainId] ?? []).filter(
211
- (dstTokenWithBlock) => dstTokenWithBlock.blockNumber <= latestHubBlock
212
- )
220
+ ): EvmAddress {
221
+ const l2Tokens = Object.keys(this.l1TokensToDestinationTokensWithBlock)
222
+ .filter((l1Token) => this.l2TokenEnabledForL1Token(EvmAddress.from(l1Token), destinationChainId))
223
+ .map((l1Token) => {
224
+ // Return all matching L2 token mappings that are equal to or earlier than the target block.
225
+ // @dev Since tokens on L2s (like Solana) can have 32 byte addresses, filter on the lower 20 bytes of the token only.
226
+ return this.l1TokensToDestinationTokensWithBlock[l1Token][destinationChainId].filter(
227
+ (dstTokenWithBlock) =>
228
+ dstTokenWithBlock.l2Token.truncateToBytes20() === l2Token.truncateToBytes20() &&
229
+ dstTokenWithBlock.blockNumber <= latestHubBlock
230
+ );
231
+ })
232
+ .flat();
233
+ if (l2Tokens.length === 0) {
234
+ const chain = getNetworkName(destinationChainId);
235
+ throw new Error(
236
+ `Could not find HubPool mapping for ${l2Token} on ${chain} at or before HubPool block ${latestHubBlock}!`
213
237
  );
214
- // If the latest L2 token mapping is equal to the target L2 token, return it.
215
- return sortedL2Tokens.length > 0 && sortedL2Tokens[0].l2Token.truncateToBytes20() === l2Token.truncateToBytes20()
216
- ? sortedL2Tokens[0]
217
- : [];
218
- });
219
-
220
- return l2Tokens.length === 0 ? undefined : sortEventsDescending(l2Tokens)[0].l1Token;
238
+ }
239
+ // Find the last mapping published before the target block.
240
+ return sortEventsDescending(l2Tokens)[0].l1Token;
221
241
  }
222
242
 
223
243
  protected getL1TokenForDeposit(
224
244
  deposit: Pick<DepositWithBlock, "originChainId" | "inputToken" | "quoteBlockNumber">
225
- ): EvmAddress | undefined {
245
+ ): EvmAddress {
226
246
  // L1-->L2 token mappings are set via PoolRebalanceRoutes which occur on mainnet,
227
247
  // so we use the latest token mapping. This way if a very old deposit is filled, the relayer can use the
228
248
  // latest L2 token mapping to find the L1 token counterpart.
@@ -230,7 +250,7 @@ export class HubPoolClient extends BaseAbstractClient {
230
250
  }
231
251
 
232
252
  l2TokenEnabledForL1Token(l1Token: EvmAddress, destinationChainId: number): boolean {
233
- return this.l2TokenEnabledForL1TokenAtBlock(l1Token, destinationChainId, Number.MAX_SAFE_INTEGER);
253
+ return this.l1TokensToDestinationTokens?.[l1Token.toEvmAddress()]?.[destinationChainId] != undefined;
234
254
  }
235
255
 
236
256
  l2TokenEnabledForL1TokenAtBlock(l1Token: EvmAddress, destinationChainId: number, hubBlockNumber: number): boolean {
@@ -238,12 +258,21 @@ export class HubPoolClient extends BaseAbstractClient {
238
258
  const l2Token: DestinationTokenWithBlock | undefined = sortEventsDescending(
239
259
  this.l1TokensToDestinationTokensWithBlock?.[l1Token.toEvmAddress()]?.[destinationChainId] ?? []
240
260
  ).find((mapping: DestinationTokenWithBlock) => mapping.blockNumber <= hubBlockNumber);
241
- return l2Token !== undefined && !l2Token.l2Token.isZeroAddress();
261
+ return l2Token !== undefined;
242
262
  }
243
263
 
244
264
  l2TokenHasPoolRebalanceRoute(l2Token: Address, l2ChainId: number, hubPoolBlock = this.latestHeightSearched): boolean {
245
- const l1Token = this.getL1TokenForL2TokenAtBlock(l2Token, l2ChainId, hubPoolBlock);
246
- return l1Token !== undefined;
265
+ return Object.values(this.l1TokensToDestinationTokensWithBlock).some((destinationTokenMapping) => {
266
+ return Object.entries(destinationTokenMapping).some(([_l2ChainId, setPoolRebalanceRouteEvents]) => {
267
+ return setPoolRebalanceRouteEvents.some((e) => {
268
+ return (
269
+ e.blockNumber <= hubPoolBlock &&
270
+ e.l2Token.truncateToBytes20() === l2Token.truncateToBytes20() &&
271
+ Number(_l2ChainId) === l2ChainId
272
+ );
273
+ });
274
+ });
275
+ });
247
276
  }
248
277
 
249
278
  /**
@@ -378,11 +407,9 @@ export class HubPoolClient extends BaseAbstractClient {
378
407
  const hubPoolTokens: { [k: string]: EvmAddress } = {};
379
408
  const getHubPoolToken = (deposit: LpFeeRequest, quoteBlockNumber: number): EvmAddress | undefined => {
380
409
  const tokenKey = `${deposit.originChainId}-${deposit.inputToken}`;
381
- const l1Token = this.getL1TokenForDeposit({ ...deposit, quoteBlockNumber });
382
- if (!l1Token) {
383
- return undefined;
384
- }
385
- return (hubPoolTokens[tokenKey] ??= l1Token);
410
+ if (this.l2TokenHasPoolRebalanceRoute(deposit.inputToken, deposit.originChainId, quoteBlockNumber)) {
411
+ return (hubPoolTokens[tokenKey] ??= this.getL1TokenForDeposit({ ...deposit, quoteBlockNumber }));
412
+ } else return undefined;
386
413
  };
387
414
  const getHubPoolTokens = (): EvmAddress[] => dedupArray(Object.values(hubPoolTokens).filter(isDefined));
388
415
 
@@ -521,14 +548,14 @@ export class HubPoolClient extends BaseAbstractClient {
521
548
  // Resolve both SpokePool tokens back to their respective HubPool tokens and verify that they match.
522
549
  const l1TokenA = this.getL1TokenForL2TokenAtBlock(tokenA, chainIdA, hubPoolBlock);
523
550
  const l1TokenB = this.getL1TokenForL2TokenAtBlock(tokenB, chainIdB, hubPoolBlock);
524
- if (!l1TokenA || !l1TokenB || !l1TokenA.eq(l1TokenB)) {
551
+ if (!l1TokenA.eq(l1TokenB)) {
525
552
  return false;
526
553
  }
527
554
 
528
555
  // Resolve both HubPool tokens back to a current SpokePool token and verify that they match.
529
556
  const _tokenA = this.getL2TokenForL1TokenAtBlock(l1TokenA, chainIdA, hubPoolBlock);
530
557
  const _tokenB = this.getL2TokenForL1TokenAtBlock(l1TokenB, chainIdB, hubPoolBlock);
531
- return _tokenA !== undefined && _tokenB !== undefined && tokenA.eq(_tokenA) && tokenB.eq(_tokenB);
558
+ return tokenA.eq(_tokenA) && tokenB.eq(_tokenB);
532
559
  }
533
560
 
534
561
  getSpokeActivationBlockForChain(chainId: number): number {
@@ -968,22 +995,24 @@ export class HubPoolClient extends BaseAbstractClient {
968
995
  destinationToken = svmUsdc;
969
996
  }
970
997
 
971
- const newRoute: DestinationTokenWithBlock = {
972
- l1Token: EvmAddress.from(args.l1Token),
973
- l2Token: destinationToken,
974
- blockNumber: args.blockNumber,
975
- txnIndex: args.txnIndex,
976
- logIndex: args.logIndex,
977
- txnRef: args.txnRef,
978
- };
979
- if (this.l1TokensToDestinationTokensWithBlock[args.l1Token]?.[args.destinationChainId]) {
980
- // Events are most likely coming in descending orders already but just in case we sort them again.
981
- this.l1TokensToDestinationTokensWithBlock[args.l1Token][args.destinationChainId] = sortEventsDescending([
982
- ...this.l1TokensToDestinationTokensWithBlock[args.l1Token][args.destinationChainId],
983
- newRoute,
984
- ]);
985
- } else {
986
- assign(this.l1TokensToDestinationTokensWithBlock, [args.l1Token, args.destinationChainId], [newRoute]);
998
+ // If the destination token is set to the zero address in an event, then this means Across should no longer
999
+ // rebalance to this chain.
1000
+ if (!destinationToken.isZeroAddress()) {
1001
+ assign(this.l1TokensToDestinationTokens, [args.l1Token, args.destinationChainId], destinationToken);
1002
+ assign(
1003
+ this.l1TokensToDestinationTokensWithBlock,
1004
+ [args.l1Token, args.destinationChainId],
1005
+ [
1006
+ {
1007
+ l1Token: EvmAddress.from(args.l1Token),
1008
+ l2Token: destinationToken,
1009
+ blockNumber: args.blockNumber,
1010
+ txnIndex: args.txnIndex,
1011
+ logIndex: args.logIndex,
1012
+ txnRef: args.txnRef,
1013
+ },
1014
+ ]
1015
+ );
987
1016
  }
988
1017
  }
989
1018
  }
@@ -11,6 +11,7 @@ import { DepositWithBlock, FillStatus, RelayData } from "../../interfaces";
11
11
  import {
12
12
  BigNumber,
13
13
  DepositSearchResult,
14
+ getMessageHash,
14
15
  getNetworkName,
15
16
  InvalidFill,
16
17
  MakeOptional,
@@ -194,18 +195,31 @@ export class EVMSpokePoolClient extends SpokePoolClient {
194
195
  };
195
196
  }
196
197
 
198
+ const spreadEvent = spreadEventWithBlockNumber(event) as Omit<
199
+ DepositWithBlock,
200
+ "originChainId" | "inputToken" | "outputToken" | "depositor" | "recipient" | "exclusiveRelayer"
201
+ > & {
202
+ inputToken: string;
203
+ outputToken: string;
204
+ depositor: string;
205
+ recipient: string;
206
+ exclusiveRelayer: string;
207
+ };
208
+
209
+ const originChainId = this.chainId;
197
210
  deposit = {
198
- ...spreadEventWithBlockNumber(event),
199
- inputToken: toAddressType(event.args.inputToken, event.args.originChainId),
200
- outputToken: toAddressType(event.args.outputToken, event.args.destinationChainId),
201
- depositor: toAddressType(event.args.depositor, this.chainId),
202
- recipient: toAddressType(event.args.recipient, event.args.destinationChainId),
203
- exclusiveRelayer: toAddressType(event.args.exclusiveRelayer, event.args.destinationChainId),
211
+ ...spreadEvent,
204
212
  originChainId: this.chainId,
205
- quoteBlockNumber: await this.getBlockNumber(Number(event.args["quoteTimestamp"])),
213
+ inputToken: toAddressType(spreadEvent.inputToken, originChainId),
214
+ outputToken: toAddressType(spreadEvent.outputToken, spreadEvent.destinationChainId),
215
+ depositor: toAddressType(spreadEvent.depositor, originChainId),
216
+ recipient: toAddressType(spreadEvent.recipient, spreadEvent.destinationChainId),
217
+ exclusiveRelayer: toAddressType(spreadEvent.exclusiveRelayer, spreadEvent.destinationChainId),
218
+ quoteBlockNumber: await this.getBlockNumber(spreadEvent.quoteTimestamp),
219
+ messageHash: getMessageHash(spreadEvent.message),
206
220
  fromLiteChain: true, // To be updated immediately afterwards.
207
221
  toLiteChain: true, // To be updated immediately afterwards.
208
- } as DepositWithBlock;
222
+ };
209
223
 
210
224
  if (deposit.outputToken.isZeroAddress()) {
211
225
  deposit.outputToken = this.getDestinationTokenForDeposit(deposit);
@@ -472,22 +472,18 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
472
472
  )
473
473
  ) {
474
474
  return false;
475
+ } else {
476
+ const l1Token = this.hubPoolClient?.getL1TokenForL2TokenAtBlock(
477
+ deposit.inputToken,
478
+ deposit.originChainId,
479
+ deposit.quoteBlockNumber
480
+ );
481
+ return this.hubPoolClient.l2TokenEnabledForL1TokenAtBlock(
482
+ l1Token,
483
+ deposit.destinationChainId,
484
+ deposit.quoteBlockNumber
485
+ );
475
486
  }
476
-
477
- const l1Token = this.hubPoolClient?.getL1TokenForL2TokenAtBlock(
478
- deposit.inputToken,
479
- deposit.originChainId,
480
- deposit.quoteBlockNumber
481
- );
482
- if (!l1Token) {
483
- return false;
484
- }
485
-
486
- return this.hubPoolClient.l2TokenEnabledForL1TokenAtBlock(
487
- l1Token,
488
- deposit.destinationChainId,
489
- deposit.quoteBlockNumber
490
- );
491
487
  }
492
488
 
493
489
  /**
@@ -523,11 +519,12 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
523
519
  }
524
520
 
525
521
  // Performs the indexing of a deposit-like spoke pool event.
522
+ const originChainId = this.chainId;
526
523
  const queryDepositEvents = async (eventName: string) => {
527
524
  const depositEvents = (queryResults[eventsToQuery.indexOf(eventName)] ?? []).map((_event) => {
528
525
  const event = _event as Omit<
529
526
  DepositWithBlock,
530
- "depositor" | "recipient" | "inputToken" | "outputToken" | "exclusiveRelayer"
527
+ "originChainId" | "depositor" | "recipient" | "inputToken" | "outputToken" | "exclusiveRelayer"
531
528
  > & {
532
529
  depositor: string;
533
530
  recipient: string;
@@ -537,12 +534,14 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
537
534
  };
538
535
  return {
539
536
  ...event,
540
- depositor: toAddressType(event.depositor, this.chainId),
537
+ originChainId,
538
+ depositor: toAddressType(event.depositor, originChainId),
541
539
  recipient: toAddressType(event.recipient, event.destinationChainId),
542
- inputToken: toAddressType(event.inputToken, this.chainId),
540
+ inputToken: toAddressType(event.inputToken, originChainId),
543
541
  outputToken: toAddressType(event.outputToken, event.destinationChainId),
544
542
  exclusiveRelayer: toAddressType(event.exclusiveRelayer, event.destinationChainId),
545
- } as DepositWithBlock;
543
+ messageHash: getMessageHash(event.message),
544
+ } satisfies Omit<DepositWithBlock, "quoteBlockNumber" | "fromLiteChain" | "toLiteChain">;
546
545
  });
547
546
  if (depositEvents.length > 0) {
548
547
  this.log(
@@ -563,17 +562,11 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
563
562
  // Derive and append the common properties that are not part of the onchain event.
564
563
  const deposit = {
565
564
  ...event,
566
- messageHash: getMessageHash(event.message),
567
565
  quoteBlockNumber,
568
- originChainId: this.chainId,
569
- // The following properties are placeholders to be updated immediately.
570
- fromLiteChain: true,
571
- toLiteChain: true,
566
+ fromLiteChain: this.isOriginLiteChain(event),
567
+ toLiteChain: this.isDestinationLiteChain(event),
572
568
  };
573
569
 
574
- deposit.fromLiteChain = this.isOriginLiteChain(deposit);
575
- deposit.toLiteChain = this.isDestinationLiteChain(deposit);
576
-
577
570
  if (deposit.outputToken.isZeroAddress()) {
578
571
  deposit.outputToken = this.getDestinationTokenForDeposit(deposit);
579
572
  }
@@ -697,10 +690,12 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
697
690
  });
698
691
 
699
692
  // Performs indexing of filled relay-like events.
693
+ const destinationChainId = this.chainId;
700
694
  const queryFilledRelayEvents = (eventName: string) => {
701
695
  const fillEvents = (queryResults[eventsToQuery.indexOf(eventName)] ?? []).map((_event) => {
702
696
  const event = _event as Omit<
703
697
  FillWithBlock,
698
+ | "destinationChainId"
704
699
  | "depositor"
705
700
  | "recipient"
706
701
  | "inputToken"
@@ -717,19 +712,21 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
717
712
  relayer: string;
718
713
  relayExecutionInfo: Omit<RelayExecutionEventInfo, "updatedRecipient"> & { updatedRecipient: string };
719
714
  };
715
+
720
716
  return {
721
717
  ...event,
718
+ destinationChainId,
722
719
  depositor: toAddressType(event.depositor, event.originChainId),
723
- recipient: toAddressType(event.recipient, this.chainId),
720
+ recipient: toAddressType(event.recipient, destinationChainId),
724
721
  inputToken: toAddressType(event.inputToken, event.originChainId),
725
- outputToken: toAddressType(event.outputToken, this.chainId),
726
- exclusiveRelayer: toAddressType(event.exclusiveRelayer, this.chainId),
727
- relayer: toAddressType(event.relayer, this.chainId),
722
+ outputToken: toAddressType(event.outputToken, destinationChainId),
723
+ exclusiveRelayer: toAddressType(event.exclusiveRelayer, destinationChainId),
724
+ relayer: toAddressType(event.relayer, event.repaymentChainId),
728
725
  relayExecutionInfo: {
729
726
  ...event.relayExecutionInfo,
730
727
  updatedRecipient: toAddressType(event.relayExecutionInfo.updatedRecipient, this.chainId),
731
728
  },
732
- } as FillWithBlock;
729
+ } satisfies FillWithBlock;
733
730
  });
734
731
 
735
732
  if (fillEvents.length > 0) {
@@ -740,16 +737,11 @@ export abstract class SpokePoolClient extends BaseAbstractClient {
740
737
 
741
738
  // @note The type assertions here suppress errors that might arise due to incomplete types. For now, verify via
742
739
  // test that the types are complete. A broader change in strategy for safely unpacking events will be introduced.
743
- for (const event of fillEvents) {
744
- const fill = {
745
- ...event,
746
- destinationChainId: this.chainId,
747
- };
748
-
740
+ for (const fill of fillEvents) {
749
741
  // Sanity check that this event is not a duplicate.
750
742
  const duplicateFill = this.fills[fill.originChainId]?.find((f) => duplicateEvent(fill, f));
751
743
  if (duplicateFill) {
752
- duplicateEvents.push(event);
744
+ duplicateEvents.push(fill);
753
745
  continue;
754
746
  }
755
747
 
@@ -118,9 +118,9 @@ export class MockHubPoolClient extends HubPoolClient {
118
118
  delete this.spokePoolTokens[l1Token]?.[chainId];
119
119
  }
120
120
 
121
- getL1TokenForL2TokenAtBlock(l2Token: Address, chainId: number, blockNumber: number): EvmAddress | undefined {
121
+ getL1TokenForL2TokenAtBlock(l2Token: Address, chainId: number, blockNumber: number): EvmAddress {
122
122
  const l1Token = Object.keys(this.spokePoolTokens).find(
123
- (l1Token) => this.spokePoolTokens[l1Token]?.[chainId]?.eq(l2Token)
123
+ (l1Token) => this.spokePoolTokens[l1Token]?.[chainId].eq(l2Token)
124
124
  );
125
125
  if (isDefined(l1Token)) {
126
126
  return EvmAddress.from(l1Token);
@@ -129,7 +129,7 @@ export class MockHubPoolClient extends HubPoolClient {
129
129
  }
130
130
  }
131
131
 
132
- getL2TokenForL1TokenAtBlock(l1Token: EvmAddress, chainId: number, blockNumber: number): Address | undefined {
132
+ getL2TokenForL1TokenAtBlock(l1Token: EvmAddress, chainId: number, blockNumber: number): Address {
133
133
  const l2Token = this.spokePoolTokens[l1Token.toEvmAddress()]?.[chainId];
134
134
  return l2Token ?? super.getL2TokenForL1TokenAtBlock(l1Token, chainId, blockNumber);
135
135
  }
package/src/constants.ts CHANGED
@@ -93,3 +93,15 @@ export const CUSTOM_GAS_TOKENS = {
93
93
  [CHAIN_IDs.LENS]: "GHO",
94
94
  [CHAIN_IDs.LENS_SEPOLIA]: "GHO",
95
95
  };
96
+
97
+ // Blocks where SpokePools were upgraded from v2 to v2.5. This is where the fillStatus mapping
98
+ // was introduced. This mapping should only be updated on subsequent upgrades where there are
99
+ // breaking changes and the exact upgrade block is required to bound certain queries.
100
+ export const SPOKEPOOL_UPGRADE_BLOCKS = {
101
+ [CHAIN_IDs.ARBITRUM]: 183082059,
102
+ [CHAIN_IDs.BASE]: 10874747,
103
+ [CHAIN_IDs.MAINNET]: 19277695,
104
+ [CHAIN_IDs.OPTIMISM]: 116469982,
105
+ [CHAIN_IDs.POLYGON]: 53793776,
106
+ [CHAIN_IDs.ZK_SYNC]: 27157340,
107
+ };