@across-protocol/sdk 4.1.9 → 4.1.10

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 (34) hide show
  1. package/dist/cjs/clients/BundleDataClient/BundleDataClient.d.ts +1 -6
  2. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +21 -43
  3. package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  4. package/dist/cjs/clients/HubPoolClient.d.ts +2 -1
  5. package/dist/cjs/clients/HubPoolClient.js +6 -3
  6. package/dist/cjs/clients/HubPoolClient.js.map +1 -1
  7. package/dist/cjs/clients/SpokePoolClient.js +48 -20
  8. package/dist/cjs/clients/SpokePoolClient.js.map +1 -1
  9. package/dist/cjs/utils/EventUtils.d.ts +1 -0
  10. package/dist/cjs/utils/EventUtils.js +5 -1
  11. package/dist/cjs/utils/EventUtils.js.map +1 -1
  12. package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +1 -6
  13. package/dist/esm/clients/BundleDataClient/BundleDataClient.js +23 -47
  14. package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
  15. package/dist/esm/clients/HubPoolClient.d.ts +2 -1
  16. package/dist/esm/clients/HubPoolClient.js +6 -3
  17. package/dist/esm/clients/HubPoolClient.js.map +1 -1
  18. package/dist/esm/clients/SpokePoolClient.js +55 -23
  19. package/dist/esm/clients/SpokePoolClient.js.map +1 -1
  20. package/dist/esm/utils/EventUtils.d.ts +1 -0
  21. package/dist/esm/utils/EventUtils.js +3 -0
  22. package/dist/esm/utils/EventUtils.js.map +1 -1
  23. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +1 -6
  24. package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
  25. package/dist/types/clients/HubPoolClient.d.ts +2 -1
  26. package/dist/types/clients/HubPoolClient.d.ts.map +1 -1
  27. package/dist/types/clients/SpokePoolClient.d.ts.map +1 -1
  28. package/dist/types/utils/EventUtils.d.ts +1 -0
  29. package/dist/types/utils/EventUtils.d.ts.map +1 -1
  30. package/package.json +1 -1
  31. package/src/clients/BundleDataClient/BundleDataClient.ts +20 -49
  32. package/src/clients/HubPoolClient.ts +20 -11
  33. package/src/clients/SpokePoolClient.ts +29 -0
  34. package/src/utils/EventUtils.ts +4 -0
@@ -19,7 +19,7 @@ import {
19
19
  Deposit,
20
20
  DepositWithBlock,
21
21
  } from "../../interfaces";
22
- import { AcrossConfigStoreClient, SpokePoolClient } from "..";
22
+ import { SpokePoolClient } from "..";
23
23
  import {
24
24
  BigNumber,
25
25
  bnZero,
@@ -41,10 +41,10 @@ import {
41
41
  isZeroValueFillOrSlowFillRequest,
42
42
  chainIsEvm,
43
43
  isValidEvmAddress,
44
+ duplicateEvent,
44
45
  } from "../../utils";
45
46
  import winston from "winston";
46
47
  import {
47
- _buildPoolRebalanceRoot,
48
48
  BundleData,
49
49
  BundleDataSS,
50
50
  getEndBlockBuffers,
@@ -52,7 +52,6 @@ import {
52
52
  getRefundsFromBundle,
53
53
  getWidestPossibleExpectedBlockRange,
54
54
  isChainDisabled,
55
- PoolRebalanceRoot,
56
55
  prettyPrintV3SpokePoolEvents,
57
56
  V3DepositWithBlock,
58
57
  V3FillWithBlock,
@@ -431,52 +430,6 @@ export class BundleDataClient {
431
430
  }, toBN(0));
432
431
  }
433
432
 
434
- private async getLatestProposedBundleData(): Promise<{ bundleData: LoadDataReturnValue; blockRanges: number[][] }> {
435
- const hubPoolClient = this.clients.hubPoolClient;
436
- // Determine which bundle we should fetch from arweave, either the pending bundle or the latest
437
- // executed one. Both should have arweave data but if for some reason the arweave data is missing,
438
- // this function will have to compute the bundle data from scratch which will be slow. We have to fallback
439
- // to computing the bundle from scratch since this function needs to return the full bundle data so that
440
- // it can be used to get the running balance proposed using its data.
441
- const bundleBlockRanges = getImpliedBundleBlockRanges(
442
- hubPoolClient,
443
- this.clients.configStoreClient,
444
- hubPoolClient.hasPendingProposal()
445
- ? hubPoolClient.getLatestProposedRootBundle()
446
- : hubPoolClient.getLatestFullyExecutedRootBundle(hubPoolClient.latestBlockSearched)! // ! because we know there is a bundle
447
- );
448
- return {
449
- blockRanges: bundleBlockRanges,
450
- bundleData: await this.loadData(
451
- bundleBlockRanges,
452
- this.spokePoolClients,
453
- true // this bundle data should have been published to arweave
454
- ),
455
- };
456
- }
457
-
458
- async getLatestPoolRebalanceRoot(): Promise<{ root: PoolRebalanceRoot; blockRanges: number[][] }> {
459
- const { bundleData, blockRanges } = await this.getLatestProposedBundleData();
460
- const hubPoolClient = this.clients.hubPoolClient;
461
- const root = _buildPoolRebalanceRoot(
462
- hubPoolClient.latestBlockSearched,
463
- blockRanges[0][1],
464
- bundleData.bundleDepositsV3,
465
- bundleData.bundleFillsV3,
466
- bundleData.bundleSlowFillsV3,
467
- bundleData.unexecutableSlowFills,
468
- bundleData.expiredDepositsToRefundV3,
469
- {
470
- hubPoolClient,
471
- configStoreClient: hubPoolClient.configStoreClient as AcrossConfigStoreClient,
472
- }
473
- );
474
- return {
475
- root,
476
- blockRanges,
477
- };
478
- }
479
-
480
433
  // @dev This function should probably be moved to the InventoryClient since it bypasses loadData completely now.
481
434
  // Return refunds from the next valid bundle. This will contain any refunds that have been sent but are not included
482
435
  // in a valid bundle with all of its leaves executed. This contains refunds from:
@@ -867,6 +820,14 @@ export class BundleDataClient {
867
820
  "Not using correct bundle deposit hash key"
868
821
  );
869
822
  if (deposit.blockNumber >= originChainBlockRange[0]) {
823
+ if (bundleDepositsV3?.[originChainId]?.[deposit.inputToken]?.find((d) => duplicateEvent(deposit, d))) {
824
+ this.logger.debug({
825
+ at: "BundleDataClient#loadData",
826
+ message: "Duplicate deposit detected",
827
+ deposit,
828
+ });
829
+ throw new Error("Duplicate deposit detected");
830
+ }
870
831
  bundleDepositHashes.push(newBundleDepositHash);
871
832
  updateBundleDepositsV3(bundleDepositsV3, deposit);
872
833
  } else if (deposit.blockNumber < originChainBlockRange[0]) {
@@ -978,6 +939,11 @@ export class BundleDataClient {
978
939
  }
979
940
  }
980
941
  } else {
942
+ this.logger.debug({
943
+ at: "BundleDataClient#loadData",
944
+ message: "Duplicate fill detected",
945
+ fill,
946
+ });
981
947
  throw new Error("Duplicate fill detected");
982
948
  }
983
949
  return;
@@ -1099,6 +1065,11 @@ export class BundleDataClient {
1099
1065
  validatedBundleSlowFills.push(matchedDeposit);
1100
1066
  }
1101
1067
  } else {
1068
+ this.logger.debug({
1069
+ at: "BundleDataClient#loadData",
1070
+ message: "Duplicate slow fill request detected",
1071
+ slowFillRequest,
1072
+ });
1102
1073
  throw new Error("Duplicate slow fill request detected.");
1103
1074
  }
1104
1075
  return;
@@ -776,22 +776,31 @@ export class HubPoolClient extends BaseAbstractClient {
776
776
  return endBlock > 0 ? endBlock + 1 : 0;
777
777
  }
778
778
 
779
- getRunningBalanceBeforeBlockForChain(block: number, chain: number, l1Token: string): TokenRunningBalance {
779
+ getLatestExecutedRootBundleContainingL1Token(
780
+ block: number,
781
+ chain: number,
782
+ l1Token: string
783
+ ): ExecutedRootBundle | undefined {
780
784
  // Search ExecutedRootBundles in descending block order to find the most recent event before the target block.
781
- const executedRootBundle = sortEventsDescending(this.executedRootBundles).find(
782
- (executedLeaf: ExecutedRootBundle) => {
783
- return (
784
- executedLeaf.blockNumber <= block &&
785
- executedLeaf.chainId === chain &&
786
- executedLeaf.l1Tokens.map((l1Token) => l1Token.toLowerCase()).includes(l1Token.toLowerCase())
787
- );
788
- }
789
- ) as ExecutedRootBundle;
785
+ return sortEventsDescending(this.executedRootBundles).find((executedLeaf: ExecutedRootBundle) => {
786
+ return (
787
+ executedLeaf.blockNumber <= block &&
788
+ executedLeaf.chainId === chain &&
789
+ executedLeaf.l1Tokens.some((token) => token.toLowerCase() === l1Token.toLowerCase())
790
+ );
791
+ });
792
+ }
793
+
794
+ getRunningBalanceBeforeBlockForChain(block: number, chain: number, l1Token: string): TokenRunningBalance {
795
+ const executedRootBundle = this.getLatestExecutedRootBundleContainingL1Token(block, chain, l1Token);
790
796
 
791
797
  return this.getRunningBalanceForToken(l1Token, executedRootBundle);
792
798
  }
793
799
 
794
- public getRunningBalanceForToken(l1Token: string, executedRootBundle: ExecutedRootBundle): TokenRunningBalance {
800
+ public getRunningBalanceForToken(
801
+ l1Token: string,
802
+ executedRootBundle: ExecutedRootBundle | undefined
803
+ ): TokenRunningBalance {
795
804
  let runningBalance = toBN(0);
796
805
  if (executedRootBundle) {
797
806
  const indexOfL1Token = executedRootBundle.l1Tokens
@@ -23,6 +23,7 @@ import {
23
23
  toAddress,
24
24
  } from "../utils";
25
25
  import {
26
+ duplicateEvent,
26
27
  paginatedEventQuery,
27
28
  sortEventsAscendingInPlace,
28
29
  spreadEvent,
@@ -585,6 +586,7 @@ export class SpokePoolClient extends BaseAbstractClient {
585
586
  * @see _update
586
587
  */
587
588
  public async update(eventsToQuery = this.queryableEventNames): Promise<void> {
589
+ const duplicateEvents: Log[] = [];
588
590
  if (this.hubPoolClient !== null && !this.hubPoolClient.isUpdated) {
589
591
  throw new Error("HubPoolClient not updated");
590
592
  }
@@ -654,6 +656,12 @@ export class SpokePoolClient extends BaseAbstractClient {
654
656
  }
655
657
 
656
658
  if (this.depositHashes[getRelayEventKey(deposit)] !== undefined) {
659
+ // Sanity check that this event is not a duplicate, even though the relay data hash is a duplicate.
660
+ const allDeposits = this._getDuplicateDeposits(deposit).concat(this.depositHashes[getRelayEventKey(deposit)]);
661
+ if (allDeposits.some((e) => duplicateEvent(deposit, e))) {
662
+ duplicateEvents.push(event);
663
+ continue;
664
+ }
657
665
  assign(this.duplicateDepositHashes, [getRelayEventKey(deposit)], [deposit]);
658
666
  continue;
659
667
  }
@@ -716,6 +724,13 @@ export class SpokePoolClient extends BaseAbstractClient {
716
724
  }
717
725
 
718
726
  const depositHash = getRelayEventKey({ ...slowFillRequest, destinationChainId: this.chainId });
727
+
728
+ // Sanity check that this event is not a duplicate.
729
+ if (this.slowFillRequests[depositHash] !== undefined) {
730
+ duplicateEvents.push(event);
731
+ continue;
732
+ }
733
+
719
734
  this.slowFillRequests[depositHash] ??= slowFillRequest;
720
735
  }
721
736
  };
@@ -749,6 +764,13 @@ export class SpokePoolClient extends BaseAbstractClient {
749
764
  fill.relayExecutionInfo.updatedMessageHash = getMessageHash(event.args.relayExecutionInfo.updatedMessage);
750
765
  }
751
766
 
767
+ // Sanity check that this event is not a duplicate.
768
+ const duplicateFill = this.fills[fill.originChainId]?.find((f) => duplicateEvent(fill, f));
769
+ if (duplicateFill) {
770
+ duplicateEvents.push(event);
771
+ continue;
772
+ }
773
+
752
774
  assign(this.fills, [fill.originChainId], [fill]);
753
775
  assign(this.depositHashesToFills, [this.getDepositHash(fill)], [fill]);
754
776
  }
@@ -793,6 +815,13 @@ export class SpokePoolClient extends BaseAbstractClient {
793
815
  }
794
816
  }
795
817
 
818
+ if (duplicateEvents.length > 0) {
819
+ this.log("debug", "Duplicate events listed", {
820
+ duplicateEvents,
821
+ });
822
+ this.log("error", "Duplicate events detected, check debug logs");
823
+ }
824
+
796
825
  // Next iteration should start off from where this one ended.
797
826
  this.currentTime = currentTime;
798
827
  this.firstDepositIdForSpokePool = update.firstDepositId;
@@ -266,3 +266,7 @@ export function isEventOlder<T extends SortableEvent>(ex: T, ey: T): boolean {
266
266
  export function getTransactionHashes(events: SortableEvent[]): string[] {
267
267
  return [...Array.from(new Set(events.map((e) => e.transactionHash)))];
268
268
  }
269
+
270
+ export function duplicateEvent(a: SortableEvent, b: SortableEvent): boolean {
271
+ return a.transactionHash === b.transactionHash && a.logIndex === b.logIndex;
272
+ }