@across-protocol/sdk 4.3.58 → 4.3.59

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 (66) hide show
  1. package/dist/cjs/clients/BundleDataClient/BundleDataClient.d.ts +2 -15
  2. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +45 -332
  3. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  4. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js +6 -4
  5. package/dist/cjs/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
  6. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js +5 -0
  7. package/dist/cjs/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  8. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
  9. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js +4 -3
  10. package/dist/cjs/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  11. package/dist/cjs/clients/HubPoolClient.d.ts +3 -9
  12. package/dist/cjs/clients/HubPoolClient.js +44 -68
  13. package/dist/cjs/clients/HubPoolClient.js.map +1 -1
  14. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js +4 -3
  15. package/dist/cjs/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
  16. package/dist/cjs/clients/mocks/MockHubPoolClient.d.ts +2 -2
  17. package/dist/cjs/clients/mocks/MockHubPoolClient.js +1 -1
  18. package/dist/cjs/clients/mocks/MockHubPoolClient.js.map +1 -1
  19. package/dist/cjs/providers/retryProvider.js +6 -4
  20. package/dist/cjs/providers/retryProvider.js.map +1 -1
  21. package/dist/cjs/providers/utils.js +1 -1
  22. package/dist/cjs/providers/utils.js.map +1 -1
  23. package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +2 -15
  24. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +47 -373
  25. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  26. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js +6 -4
  27. package/dist/esm/clients/BundleDataClient/utils/DataworkerUtils.js.map +1 -1
  28. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js +6 -1
  29. package/dist/esm/clients/BundleDataClient/utils/FillUtils.js.map +1 -1
  30. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
  31. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js +3 -2
  32. package/dist/esm/clients/BundleDataClient/utils/PoolRebalanceUtils.js.map +1 -1
  33. package/dist/esm/clients/HubPoolClient.d.ts +3 -9
  34. package/dist/esm/clients/HubPoolClient.js +48 -74
  35. package/dist/esm/clients/HubPoolClient.js.map +1 -1
  36. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js +4 -3
  37. package/dist/esm/clients/SpokePoolClient/SpokePoolClient.js.map +1 -1
  38. package/dist/esm/clients/mocks/MockHubPoolClient.d.ts +2 -2
  39. package/dist/esm/clients/mocks/MockHubPoolClient.js +1 -1
  40. package/dist/esm/clients/mocks/MockHubPoolClient.js.map +1 -1
  41. package/dist/esm/providers/retryProvider.js +6 -4
  42. package/dist/esm/providers/retryProvider.js.map +1 -1
  43. package/dist/esm/providers/utils.js +2 -2
  44. package/dist/esm/providers/utils.js.map +1 -1
  45. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +2 -15
  46. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
  47. package/dist/types/clients/BundleDataClient/utils/DataworkerUtils.d.ts.map +1 -1
  48. package/dist/types/clients/BundleDataClient/utils/FillUtils.d.ts.map +1 -1
  49. package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts +1 -1
  50. package/dist/types/clients/BundleDataClient/utils/PoolRebalanceUtils.d.ts.map +1 -1
  51. package/dist/types/clients/HubPoolClient.d.ts +3 -9
  52. package/dist/types/clients/HubPoolClient.d.ts.map +1 -1
  53. package/dist/types/clients/SpokePoolClient/SpokePoolClient.d.ts.map +1 -1
  54. package/dist/types/clients/mocks/MockHubPoolClient.d.ts +2 -2
  55. package/dist/types/clients/mocks/MockHubPoolClient.d.ts.map +1 -1
  56. package/dist/types/providers/retryProvider.d.ts.map +1 -1
  57. package/package.json +2 -2
  58. package/src/clients/BundleDataClient/BundleDataClient.ts +12 -358
  59. package/src/clients/BundleDataClient/utils/DataworkerUtils.ts +13 -20
  60. package/src/clients/BundleDataClient/utils/FillUtils.ts +7 -1
  61. package/src/clients/BundleDataClient/utils/PoolRebalanceUtils.ts +8 -2
  62. package/src/clients/HubPoolClient.ts +49 -80
  63. package/src/clients/SpokePoolClient/SpokePoolClient.ts +15 -11
  64. package/src/clients/mocks/MockHubPoolClient.ts +3 -3
  65. package/src/providers/retryProvider.ts +6 -4
  66. package/src/providers/utils.ts +2 -2
@@ -1,7 +1,6 @@
1
1
  import assert from "assert";
2
2
  import _ from "lodash";
3
3
  import {
4
- ProposedRootBundle,
5
4
  SlowFillRequestWithBlock,
6
5
  SpokePoolClientsByChain,
7
6
  FillType,
@@ -14,7 +13,6 @@ import {
14
13
  BundleSlowFills,
15
14
  ExpiredDepositsToRefundV3,
16
15
  Clients,
17
- CombinedRefunds,
18
16
  FillWithBlock,
19
17
  Deposit,
20
18
  DepositWithBlock,
@@ -29,10 +27,8 @@ import {
29
27
  assign,
30
28
  fixedPointAdjustment,
31
29
  isDefined,
32
- toBN,
33
30
  forEachAsync,
34
31
  getBlockRangeForChain,
35
- getImpliedBundleBlockRanges,
36
32
  getRelayEventKey,
37
33
  isSlowFill,
38
34
  mapAsync,
@@ -42,7 +38,6 @@ import {
42
38
  duplicateEvent,
43
39
  invalidOutputToken,
44
40
  Address,
45
- getNetworkName,
46
41
  toBytes32,
47
42
  convertRelayDataParamsToBytes32,
48
43
  convertFillParamsToBytes32,
@@ -50,11 +45,8 @@ import {
50
45
  import winston from "winston";
51
46
  import {
52
47
  BundleDataSS,
53
- getEndBlockBuffers,
54
48
  getRefundInformationFromFill,
55
- getRefundsFromBundle,
56
- getWidestPossibleExpectedBlockRange,
57
- isChainDisabled,
49
+ isChainDisabledAtBlock,
58
50
  prettyPrintV3SpokePoolEvents,
59
51
  V3DepositWithBlock,
60
52
  V3FillWithBlock,
@@ -370,346 +362,6 @@ export class BundleDataClient {
370
362
  return bundleData;
371
363
  }
372
364
 
373
- // @dev This function should probably be moved to the InventoryClient since it bypasses loadData completely now.
374
- async getPendingRefundsFromValidBundles(): Promise<CombinedRefunds[]> {
375
- const refunds = [];
376
- if (!this.clients.hubPoolClient.isUpdated) {
377
- throw new Error("BundleDataClient::getPendingRefundsFromValidBundles HubPoolClient not updated.");
378
- }
379
-
380
- const bundle = this.clients.hubPoolClient.getLatestFullyExecutedRootBundle(
381
- this.clients.hubPoolClient.latestHeightSearched
382
- );
383
- if (bundle !== undefined) {
384
- refunds.push(await this.getPendingRefundsFromBundle(bundle));
385
- } // No more valid bundles in history!
386
- return refunds;
387
- }
388
-
389
- // @dev This function should probably be moved to the InventoryClient since it bypasses loadData completely now.
390
- // Return refunds from input bundle.
391
- async getPendingRefundsFromBundle(bundle: ProposedRootBundle): Promise<CombinedRefunds> {
392
- const nextBundleMainnetStartBlock = this.clients.hubPoolClient.getNextBundleStartBlockNumber(
393
- this.chainIdListForBundleEvaluationBlockNumbers,
394
- this.clients.hubPoolClient.latestHeightSearched,
395
- this.clients.hubPoolClient.chainId
396
- );
397
- const chainIds = this.clients.configStoreClient.getChainIdIndicesForBlock(nextBundleMainnetStartBlock);
398
-
399
- // Reconstruct latest bundle block range.
400
- const bundleEvaluationBlockRanges = getImpliedBundleBlockRanges(
401
- this.clients.hubPoolClient,
402
- this.clients.configStoreClient,
403
- bundle
404
- );
405
- let combinedRefunds: CombinedRefunds;
406
- // Here we don't call loadData because our fallback is to approximate refunds if we don't have arweave data, rather
407
- // than use the much slower loadData to compute all refunds. We don't need to consider slow fills or deposit
408
- // expiries here so we can skip some steps. We also don't need to compute LP fees as they should be small enough
409
- // so as not to affect this approximate refund count.
410
- const arweaveData = await this.loadArweaveData(bundleEvaluationBlockRanges);
411
- if (!isDefined(arweaveData)) {
412
- combinedRefunds = await this.getApproximateRefundsForBlockRange(chainIds, bundleEvaluationBlockRanges);
413
- } else {
414
- const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
415
- combinedRefunds = getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3);
416
- // If we don't have a spoke pool client for a chain, then we won't be able to deduct refunds correctly for this
417
- // chain. For most of the pending bundle's liveness period, these past refunds are already executed so this is
418
- // a reasonable assumption. This empty refund chain also matches what the alternative
419
- // `getApproximateRefundsForBlockRange` would return.
420
- Object.keys(combinedRefunds).forEach((chainId) => {
421
- if (!this.spokePoolClientManager.getClient(Number(chainId))) {
422
- delete combinedRefunds[Number(chainId)];
423
- }
424
- });
425
- }
426
-
427
- // The latest proposed bundle's refund leaves might have already been partially or entirely executed.
428
- // We have to deduct the executed amounts from the total refund amounts.
429
- return this.deductExecutedRefunds(combinedRefunds, bundle);
430
- }
431
-
432
- // @dev This helper function should probably be moved to the InventoryClient
433
- async getApproximateRefundsForBlockRange(chainIds: number[], blockRanges: number[][]): Promise<CombinedRefunds> {
434
- const refundsForChain: CombinedRefunds = {};
435
- const bundleEndBlockForMainnet = blockRanges[0][1];
436
- for (const chainId of chainIds) {
437
- const spokePoolClient = this.spokePoolClientManager.getClient(chainId);
438
- if (!isDefined(spokePoolClient)) {
439
- continue;
440
- }
441
- const chainIndex = chainIds.indexOf(chainId);
442
- // @dev This function does not account for pre-fill refunds as it is optimized for speed. The way to detect
443
- // pre-fill refunds is to load all deposits that are unmatched by fills in the spoke pool client's memory
444
- // and then query the FillStatus on-chain, but that might slow this function down too much. For now, we
445
- // will live with this expected inaccuracy as it should be small. The pre-fill would have to precede the deposit
446
- // by more than the caller's event lookback window which is expected to be unlikely.
447
- const fillsToCount = spokePoolClient.getFills().filter((fill) => {
448
- if (
449
- fill.blockNumber < blockRanges[chainIndex][0] ||
450
- fill.blockNumber > blockRanges[chainIndex][1] ||
451
- isZeroValueFillOrSlowFillRequest(fill) ||
452
- invalidOutputToken(fill)
453
- ) {
454
- return false;
455
- }
456
-
457
- const originSpokePoolClient = this.spokePoolClientManager.getClient(fill.originChainId);
458
- // If origin spoke pool client isn't defined, we can't validate it.
459
- if (!isDefined(originSpokePoolClient)) {
460
- return false;
461
- }
462
- const matchingDeposit = originSpokePoolClient.getDeposit(fill.depositId);
463
- const hasMatchingDeposit =
464
- matchingDeposit !== undefined && getRelayEventKey(fill) === getRelayEventKey(matchingDeposit);
465
- return hasMatchingDeposit;
466
- });
467
- await forEachAsync(fillsToCount, async (_fill) => {
468
- const originChain = getNetworkName(_fill.originChainId);
469
- const originSpokePoolClient = this.spokePoolClientManager.getClient(_fill.originChainId);
470
- assert(isDefined(originSpokePoolClient), `No SpokePoolClient for chain ${originChain}`);
471
- const matchingDeposit = originSpokePoolClient.getDeposit(_fill.depositId);
472
- assert(
473
- isDefined(matchingDeposit),
474
- `No ${originChain} deposit found for ${getNetworkName(_fill.destinationChainId)} fill ${_fill.depositId}`
475
- );
476
-
477
- const spokeClient = this.spokePoolClientManager.getClient(_fill.destinationChainId);
478
- assert(
479
- isDefined(spokeClient),
480
- `SpokePoolClient for ${getNetworkName(_fill.destinationChainId)} not found for fill.`
481
- );
482
-
483
- let provider;
484
- if (isEVMSpokePoolClient(spokeClient)) {
485
- provider = spokeClient.spokePool.provider;
486
- } else if (isSVMSpokePoolClient(spokeClient)) {
487
- provider = spokeClient.svmEventsClient.getRpc();
488
- }
489
- const fill = await verifyFillRepayment(
490
- _fill,
491
- provider!,
492
- matchingDeposit,
493
- this.clients.hubPoolClient,
494
- bundleEndBlockForMainnet
495
- );
496
- if (!isDefined(fill)) {
497
- return;
498
- }
499
- const { chainToSendRefundTo, repaymentToken } = getRefundInformationFromFill(
500
- {
501
- ...fill,
502
- fromLiteChain: matchingDeposit.fromLiteChain,
503
- },
504
- this.clients.hubPoolClient,
505
- bundleEndBlockForMainnet
506
- );
507
- // Assume that lp fees are 0 for the sake of speed. In the future we could batch compute
508
- // these or make hardcoded assumptions based on the origin-repayment chain direction. This might result
509
- // in slight over estimations of refunds, but its not clear whether underestimating or overestimating is
510
- // worst from the relayer's perspective.
511
- const { relayer, inputAmount: refundAmount } = fill;
512
- refundsForChain[chainToSendRefundTo] ??= {};
513
- refundsForChain[chainToSendRefundTo][repaymentToken.toBytes32()] ??= {};
514
- const existingRefundAmount =
515
- refundsForChain[chainToSendRefundTo][repaymentToken.toBytes32()][relayer.toBytes32()] ?? bnZero;
516
- refundsForChain[chainToSendRefundTo][repaymentToken.toBytes32()][relayer.toBytes32()] =
517
- existingRefundAmount.add(refundAmount);
518
- });
519
- }
520
- return refundsForChain;
521
- }
522
-
523
- getUpcomingDepositAmount(chainId: number, l2Token: Address, latestBlockToSearch: number): BigNumber {
524
- const spokePoolClient = this.spokePoolClientManager.getClient(chainId);
525
- if (!isDefined(spokePoolClient)) {
526
- return toBN(0);
527
- }
528
- return spokePoolClient
529
- .getDeposits()
530
- .filter((deposit) => deposit.blockNumber > latestBlockToSearch && deposit.inputToken.eq(l2Token))
531
- .reduce((acc, deposit) => {
532
- return acc.add(deposit.inputAmount);
533
- }, toBN(0));
534
- }
535
-
536
- // @dev This function should probably be moved to the InventoryClient since it bypasses loadData completely now.
537
- // Return refunds from the next valid bundle. This will contain any refunds that have been sent but are not included
538
- // in a valid bundle with all of its leaves executed. This contains refunds from:
539
- // - Bundles that passed liveness but have not had all of their pool rebalance leaves executed.
540
- // - Bundles that are pending liveness
541
- // - Fills sent after the pending, but not validated, bundle
542
- async getNextBundleRefunds(): Promise<CombinedRefunds[]> {
543
- const hubPoolClient = this.clients.hubPoolClient;
544
- const nextBundleMainnetStartBlock = hubPoolClient.getNextBundleStartBlockNumber(
545
- this.chainIdListForBundleEvaluationBlockNumbers,
546
- hubPoolClient.latestHeightSearched,
547
- hubPoolClient.chainId
548
- );
549
- const chainIds = this.clients.configStoreClient.getChainIdIndicesForBlock(nextBundleMainnetStartBlock);
550
- const combinedRefunds: CombinedRefunds[] = [];
551
-
552
- // @dev: If spoke pool client is undefined for a chain, then the end block will be null or undefined, which
553
- // should be handled gracefully and effectively cause this function to ignore refunds for the chain.
554
- let widestBundleBlockRanges = await getWidestPossibleExpectedBlockRange(
555
- chainIds,
556
- this.spokePoolClientManager.getSpokePoolClients(),
557
- getEndBlockBuffers(chainIds, this.blockRangeEndBlockBuffer),
558
- this.clients,
559
- this.clients.hubPoolClient.latestHeightSearched,
560
- this.clients.configStoreClient.getEnabledChains(this.clients.hubPoolClient.latestHeightSearched)
561
- );
562
- // Return block ranges for blocks after _pendingBlockRanges and up to widestBlockRanges.
563
- // If a chain is disabled or doesn't have a spoke pool client, return a range of 0
564
- function getBlockRangeDelta(_pendingBlockRanges: number[][]): number[][] {
565
- return widestBundleBlockRanges.map((blockRange, index) => {
566
- // If pending block range doesn't have an entry for the widest range, which is possible when a new chain
567
- // is added to the CHAIN_ID_INDICES list, then simply set the initial block range to the widest block range.
568
- // This will produce a block range delta of 0 where the returned range for this chain is [widest[1], widest[1]].
569
- const initialBlockRange = _pendingBlockRanges[index] ?? blockRange;
570
- // If chain is disabled, return disabled range
571
- if (initialBlockRange[0] === initialBlockRange[1]) {
572
- return initialBlockRange;
573
- }
574
- // If pending bundle end block exceeds widest end block or if widest end block is undefined
575
- // (which is possible if the spoke pool client for the chain is not defined), return an empty range since there are no
576
- // "new" events to consider for this chain.
577
- if (!isDefined(blockRange[1]) || initialBlockRange[1] >= blockRange[1]) {
578
- return [initialBlockRange[1], initialBlockRange[1]];
579
- }
580
- // If initialBlockRange][0] > widestBlockRange[0], then we'll ignore any blocks
581
- // between initialBlockRange[0] and widestBlockRange[0] (inclusive) for simplicity reasons. In practice
582
- // this should not happen.
583
- return [initialBlockRange[1] + 1, blockRange[1]];
584
- });
585
- }
586
-
587
- // If there is a pending bundle that has not been fully executed, then it should have arweave
588
- // data so we can load it from there.
589
- if (hubPoolClient.hasPendingProposal()) {
590
- const pendingBundleBlockRanges = getImpliedBundleBlockRanges(
591
- hubPoolClient,
592
- this.clients.configStoreClient,
593
- hubPoolClient.getLatestProposedRootBundle()
594
- );
595
- // Similar to getAppoximateRefundsForBlockRange, we'll skip the full bundle reconstruction if the arweave
596
- // data is undefined and use the much faster approximation method which doesn't consider LP fees which is
597
- // ok for this use case.
598
- const arweaveData = await this.loadArweaveData(pendingBundleBlockRanges);
599
- if (!isDefined(arweaveData)) {
600
- combinedRefunds.push(await this.getApproximateRefundsForBlockRange(chainIds, pendingBundleBlockRanges));
601
- } else {
602
- const { bundleFillsV3, expiredDepositsToRefundV3 } = arweaveData;
603
- combinedRefunds.push(getRefundsFromBundle(bundleFillsV3, expiredDepositsToRefundV3));
604
- }
605
-
606
- // Shorten the widestBundleBlockRanges now to not double count the pending bundle blocks.
607
- widestBundleBlockRanges = getBlockRangeDelta(pendingBundleBlockRanges);
608
- }
609
-
610
- // Next, load all refunds sent after the last bundle proposal. This can be expensive so we'll skip the full
611
- // bundle reconstruction and make some simplifying assumptions:
612
- // - Only look up fills sent after the pending bundle's end blocks
613
- // - Skip LP fee computations and just assume the relayer is being refunded the full deposit.inputAmount
614
- const start = performance.now();
615
- combinedRefunds.push(await this.getApproximateRefundsForBlockRange(chainIds, widestBundleBlockRanges));
616
- this.logger.debug({
617
- at: "BundleDataClient#getNextBundleRefunds",
618
- message: `Loading approximate refunds for next bundle in ${Math.round(performance.now() - start) / 1000}s.`,
619
- blockRanges: JSON.stringify(widestBundleBlockRanges),
620
- });
621
- return combinedRefunds;
622
- }
623
-
624
- // @dev This helper function should probably be moved to the InventoryClient
625
- getExecutedRefunds(
626
- spokePoolClient: SpokePoolClient,
627
- relayerRefundRoot: string
628
- ): {
629
- [tokenAddress: string]: {
630
- [relayer: string]: BigNumber;
631
- };
632
- } {
633
- if (!isDefined(spokePoolClient)) {
634
- return {};
635
- }
636
- // @dev Search from right to left since there can be multiple root bundles with the same relayer refund root.
637
- // The caller should take caution if they're trying to use this function to find matching refunds for older
638
- // root bundles as opposed to more recent ones.
639
- const bundle = _.findLast(
640
- spokePoolClient.getRootBundleRelays(),
641
- (bundle) => bundle.relayerRefundRoot === relayerRefundRoot
642
- );
643
- if (bundle === undefined) {
644
- return {};
645
- }
646
-
647
- const executedRefundLeaves = spokePoolClient
648
- .getRelayerRefundExecutions()
649
- .filter((leaf) => leaf.rootBundleId === bundle.rootBundleId);
650
- const executedRefunds: { [tokenAddress: string]: { [relayer: string]: BigNumber } } = {};
651
- for (const refundLeaf of executedRefundLeaves) {
652
- const tokenAddress = refundLeaf.l2TokenAddress.toBytes32();
653
- const executedTokenRefunds = (executedRefunds[tokenAddress] ??= {});
654
-
655
- for (let i = 0; i < refundLeaf.refundAddresses.length; i++) {
656
- const relayer = refundLeaf.refundAddresses[i].toBytes32();
657
- const refundAmount = refundLeaf.refundAmounts[i];
658
-
659
- executedTokenRefunds[relayer] ??= bnZero;
660
- executedTokenRefunds[relayer] = executedTokenRefunds[relayer].add(refundAmount);
661
- }
662
- }
663
- return executedRefunds;
664
- }
665
-
666
- // @dev This helper function should probably be moved to the InventoryClient
667
- private deductExecutedRefunds(
668
- allRefunds: CombinedRefunds,
669
- bundleContainingRefunds: ProposedRootBundle
670
- ): CombinedRefunds {
671
- for (const chainIdStr of Object.keys(allRefunds)) {
672
- const chainId = Number(chainIdStr);
673
- const spokePoolClient = this.spokePoolClientManager.getClient(chainId);
674
- if (!isDefined(spokePoolClient)) {
675
- continue;
676
- }
677
- const executedRefunds = this.getExecutedRefunds(spokePoolClient, bundleContainingRefunds.relayerRefundRoot);
678
-
679
- for (const tokenAddress of Object.keys(allRefunds[chainId])) {
680
- const refunds = allRefunds[chainId][tokenAddress];
681
- if (executedRefunds[tokenAddress] === undefined || refunds === undefined) {
682
- continue;
683
- }
684
-
685
- for (const relayer of Object.keys(refunds)) {
686
- const executedAmount = executedRefunds[tokenAddress][relayer];
687
- if (executedAmount === undefined) {
688
- continue;
689
- }
690
- // Since there should only be a single executed relayer refund leaf for each relayer-token-chain combination,
691
- // we can deduct this refund and mark it as executed if the executed amount is > 0.
692
- refunds[relayer] = bnZero;
693
- }
694
- }
695
- }
696
- return allRefunds;
697
- }
698
-
699
- getRefundsFor(bundleRefunds: CombinedRefunds, relayer: Address, chainId: number, token: Address): BigNumber {
700
- if (!bundleRefunds[chainId] || !bundleRefunds[chainId][token.toBytes32()]) {
701
- return BigNumber.from(0);
702
- }
703
- const allRefunds = bundleRefunds[chainId][token.toBytes32()];
704
- return allRefunds && allRefunds[relayer.toBytes32()] ? allRefunds[relayer.toBytes32()] : BigNumber.from(0);
705
- }
706
-
707
- getTotalRefund(refunds: CombinedRefunds[], relayer: Address, chainId: number, refundToken: Address): BigNumber {
708
- return refunds.reduce((totalRefund, refunds) => {
709
- return totalRefund.add(this.getRefundsFor(refunds, relayer, chainId, refundToken));
710
- }, bnZero);
711
- }
712
-
713
365
  private async loadArweaveData(blockRangesForChains: number[][]): Promise<LoadDataReturnValue> {
714
366
  const arweaveKey = this.getArweaveBundleDataClientKey(blockRangesForChains);
715
367
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
@@ -761,8 +413,8 @@ export class BundleDataClient {
761
413
  throw new Error("HubPoolClient not updated");
762
414
  }
763
415
 
764
- const chainIds = this.clients.configStoreClient.getChainIdIndicesForBlock(blockRangesForChains[0][0]);
765
- const bundleEndBlockForMainnet = blockRangesForChains[0][1];
416
+ const [bundleStartBlockForMainnet, bundleEndBlockForMainnet] = blockRangesForChains[0];
417
+ const chainIds = this.clients.configStoreClient.getChainIdIndicesForBlock(bundleStartBlockForMainnet);
766
418
 
767
419
  if (blockRangesForChains.length > chainIds.length) {
768
420
  throw new Error(
@@ -786,11 +438,6 @@ export class BundleDataClient {
786
438
  // (2) the fill deadline has passed. We'll need to decrement running balances for these deposits on the
787
439
  // destination chain where the slow fill would have been executed.
788
440
 
789
- const _isChainDisabled = (chainId: number): boolean => {
790
- const blockRangeForChain = getBlockRangeForChain(blockRangesForChains, chainId, chainIds);
791
- return isChainDisabled(blockRangeForChain);
792
- };
793
-
794
441
  const _canCreateSlowFillLeaf = (deposit: DepositWithBlock): boolean => {
795
442
  return (
796
443
  // Cannot slow fill when input and output tokens are not equivalent.
@@ -826,7 +473,11 @@ export class BundleDataClient {
826
473
  // Infer chain ID's to load from number of block ranges passed in.
827
474
  const allChainIds = blockRangesForChains
828
475
  .map((_blockRange, index) => chainIds[index])
829
- .filter((chainId) => !_isChainDisabled(chainId) && spokePoolClients[chainId] !== undefined);
476
+ .filter(
477
+ (chainId) =>
478
+ !isChainDisabledAtBlock(chainId, bundleStartBlockForMainnet, this.clients.configStoreClient) &&
479
+ spokePoolClients[chainId] !== undefined
480
+ );
830
481
  allChainIds.forEach((chainId) => {
831
482
  const spokePoolClient = spokePoolClients[chainId];
832
483
  if (!spokePoolClient.isUpdated) {
@@ -1676,7 +1327,10 @@ export class BundleDataClient {
1676
1327
  (
1677
1328
  await mapAsync(chainIds, async (chainId, index) => {
1678
1329
  const blockRangeForChain = blockRangesForChains[index];
1679
- if (!isDefined(blockRangeForChain) || isChainDisabled(blockRangeForChain)) {
1330
+ if (
1331
+ !isDefined(blockRangeForChain) ||
1332
+ isChainDisabledAtBlock(chainId, blockRangesForChains[0][0], this.clients.configStoreClient)
1333
+ ) {
1680
1334
  return;
1681
1335
  }
1682
1336
  const [_startBlockForChain, _endBlockForChain] = blockRangeForChain;
@@ -399,21 +399,15 @@ export function _getMarginalRunningBalances(
399
399
  ([l2TokenAddress, { realizedLpFees: totalRealizedLpFee, totalRefundAmount }]) => {
400
400
  // If the repayment token and repayment chain ID do not map to a PoolRebalanceRoute graph, then
401
401
  // there are no relevant L1 running balances.
402
- if (
403
- !clients.hubPoolClient.l2TokenHasPoolRebalanceRoute(
404
- toAddressType(l2TokenAddress, repaymentChainId),
405
- repaymentChainId,
406
- mainnetBundleEndBlock
407
- )
408
- ) {
409
- chainWithRefundsOnly.add(repaymentChainId);
410
- return;
411
- }
412
402
  const l1Token = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
413
403
  toAddressType(l2TokenAddress, repaymentChainId),
414
404
  repaymentChainId,
415
405
  mainnetBundleEndBlock
416
406
  );
407
+ if (!l1Token) {
408
+ chainWithRefundsOnly.add(repaymentChainId);
409
+ return;
410
+ }
417
411
  const l1TokenAddr = l1Token.toNative();
418
412
  assert(l1Token.isEVM(), `Expected an EVM address: ${l1TokenAddr}`);
419
413
 
@@ -439,6 +433,9 @@ export function _getMarginalRunningBalances(
439
433
  destinationChainId,
440
434
  mainnetBundleEndBlock
441
435
  );
436
+
437
+ assert(isDefined(l1TokenCounterpart), "getRefundInformationFromFill: l1TokenCounterpart is undefined");
438
+
442
439
  const lpFee = deposit.lpFeePct.mul(deposit.inputAmount).div(fixedPointAdjustment);
443
440
  updateRunningBalance(
444
441
  runningBalances,
@@ -468,6 +465,8 @@ export function _getMarginalRunningBalances(
468
465
  destinationChainId,
469
466
  mainnetBundleEndBlock
470
467
  );
468
+ assert(isDefined(l1TokenCounterpart), "getRefundInformationFromFill: l1TokenCounterpart is undefined");
469
+
471
470
  const lpFee = deposit.lpFeePct.mul(deposit.inputAmount).div(fixedPointAdjustment);
472
471
  updateRunningBalance(
473
472
  runningBalances,
@@ -523,21 +522,15 @@ export function _getMarginalRunningBalances(
523
522
  deposits.forEach((deposit) => {
524
523
  // If the repayment token and repayment chain ID do not map to a PoolRebalanceRoute graph, then
525
524
  // there are no relevant L1 running balances.
526
- if (
527
- !clients.hubPoolClient.l2TokenHasPoolRebalanceRoute(
528
- deposit.inputToken,
529
- deposit.originChainId,
530
- mainnetBundleEndBlock
531
- )
532
- ) {
533
- chainWithRefundsOnly.add(deposit.originChainId);
534
- return;
535
- }
536
525
  const l1TokenCounterpart = clients.hubPoolClient.getL1TokenForL2TokenAtBlock(
537
526
  toAddressType(inputToken, originChainId),
538
527
  originChainId,
539
528
  mainnetBundleEndBlock
540
529
  );
530
+ if (!l1TokenCounterpart) {
531
+ chainWithRefundsOnly.add(deposit.originChainId);
532
+ return;
533
+ }
541
534
  updateRunningBalance(runningBalances, originChainId, l1TokenCounterpart.toEvmAddress(), deposit.inputAmount);
542
535
  });
543
536
  });
@@ -37,18 +37,21 @@ 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 succeed.
40
+ // call and we would have returned already, so the following call should always return a valid L1 token.
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
+
47
49
  const repaymentToken = hubPoolClient.getL2TokenForL1TokenAtBlock(
48
50
  l1TokenCounterpart,
49
51
  chainToSendRefundTo,
50
52
  bundleEndBlockForMainnet
51
53
  );
54
+ assert(isDefined(repaymentToken), "getRefundInformationFromFill: repaymentToken is undefined");
52
55
 
53
56
  return {
54
57
  chainToSendRefundTo,
@@ -183,6 +186,9 @@ function _repaymentChainTokenIsValid(
183
186
  relayData.originChainId,
184
187
  bundleEndBlockForMainnet
185
188
  );
189
+ if (!l1TokenCounterpart) {
190
+ return false;
191
+ }
186
192
  if (
187
193
  !hubPoolClient.l2TokenEnabledForL1TokenAtBlock(
188
194
  l1TokenCounterpart,
@@ -98,8 +98,12 @@ export async function getWidestPossibleExpectedBlockRange(
98
98
  });
99
99
  }
100
100
 
101
- export function isChainDisabled(blockRangeForChain: number[]): boolean {
102
- return blockRangeForChain[0] === blockRangeForChain[1];
101
+ export function isChainDisabledAtBlock(
102
+ chainId: number,
103
+ mainnetBlock: number,
104
+ configStoreClient: AcrossConfigStoreClient
105
+ ): boolean {
106
+ return configStoreClient.getDisabledChainsForBlock(mainnetBlock).includes(chainId);
103
107
  }
104
108
 
105
109
  // Note: this function computes the intended transfer amount before considering the transfer threshold.
@@ -202,6 +206,8 @@ export function updateRunningBalanceForDeposit(
202
206
  deposit.originChainId,
203
207
  mainnetBundleEndBlock
204
208
  );
209
+ assert(isDefined(l1TokenCounterpart), "updateRunningBalanceForDeposit: l1TokenCounterpart is undefined");
210
+
205
211
  updateRunningBalance(runningBalances, deposit.originChainId, l1TokenCounterpart.toEvmAddress(), updateAmount);
206
212
  }
207
213