@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.
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.d.ts +1 -6
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js +21 -43
- package/dist/cjs/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/cjs/clients/HubPoolClient.d.ts +2 -1
- package/dist/cjs/clients/HubPoolClient.js +6 -3
- package/dist/cjs/clients/HubPoolClient.js.map +1 -1
- package/dist/cjs/clients/SpokePoolClient.js +48 -20
- package/dist/cjs/clients/SpokePoolClient.js.map +1 -1
- package/dist/cjs/utils/EventUtils.d.ts +1 -0
- package/dist/cjs/utils/EventUtils.js +5 -1
- package/dist/cjs/utils/EventUtils.js.map +1 -1
- package/dist/esm/clients/BundleDataClient/BundleDataClient.d.ts +1 -6
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js +23 -47
- package/dist/esm/clients/BundleDataClient/BundleDataClient.js.map +1 -1
- package/dist/esm/clients/HubPoolClient.d.ts +2 -1
- package/dist/esm/clients/HubPoolClient.js +6 -3
- package/dist/esm/clients/HubPoolClient.js.map +1 -1
- package/dist/esm/clients/SpokePoolClient.js +55 -23
- package/dist/esm/clients/SpokePoolClient.js.map +1 -1
- package/dist/esm/utils/EventUtils.d.ts +1 -0
- package/dist/esm/utils/EventUtils.js +3 -0
- package/dist/esm/utils/EventUtils.js.map +1 -1
- package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts +1 -6
- package/dist/types/clients/BundleDataClient/BundleDataClient.d.ts.map +1 -1
- package/dist/types/clients/HubPoolClient.d.ts +2 -1
- package/dist/types/clients/HubPoolClient.d.ts.map +1 -1
- package/dist/types/clients/SpokePoolClient.d.ts.map +1 -1
- package/dist/types/utils/EventUtils.d.ts +1 -0
- package/dist/types/utils/EventUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/clients/BundleDataClient/BundleDataClient.ts +20 -49
- package/src/clients/HubPoolClient.ts +20 -11
- package/src/clients/SpokePoolClient.ts +29 -0
- package/src/utils/EventUtils.ts +4 -0
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
Deposit,
|
|
20
20
|
DepositWithBlock,
|
|
21
21
|
} from "../../interfaces";
|
|
22
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
782
|
-
(
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
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(
|
|
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;
|
package/src/utils/EventUtils.ts
CHANGED
|
@@ -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
|
+
}
|