@hyperlane-xyz/rebalancer 1.0.0 → 1.0.2
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/factories/RebalancerContextFactory.d.ts +2 -0
- package/dist/factories/RebalancerContextFactory.d.ts.map +1 -1
- package/dist/factories/RebalancerContextFactory.js +21 -9
- package/dist/factories/RebalancerContextFactory.js.map +1 -1
- package/dist/monitor/Monitor.d.ts +0 -1
- package/dist/monitor/Monitor.d.ts.map +1 -1
- package/dist/monitor/Monitor.js +2 -17
- package/dist/monitor/Monitor.js.map +1 -1
- package/dist/tracking/ActionTracker.d.ts +6 -2
- package/dist/tracking/ActionTracker.d.ts.map +1 -1
- package/dist/tracking/ActionTracker.js +19 -23
- package/dist/tracking/ActionTracker.js.map +1 -1
- package/dist/tracking/ActionTracker.test.js +105 -35
- package/dist/tracking/ActionTracker.test.js.map +1 -1
- package/dist/utils/blockTag.d.ts +14 -0
- package/dist/utils/blockTag.d.ts.map +1 -0
- package/dist/utils/blockTag.js +26 -0
- package/dist/utils/blockTag.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +7 -7
- package/src/factories/RebalancerContextFactory.ts +29 -9
- package/src/monitor/Monitor.ts +7 -30
- package/src/tracking/ActionTracker.test.ts +120 -37
- package/src/tracking/ActionTracker.ts +32 -38
- package/src/utils/blockTag.ts +42 -0
- package/src/utils/index.ts +1 -0
|
@@ -5,7 +5,6 @@ import Sinon from 'sinon';
|
|
|
5
5
|
|
|
6
6
|
import { EthJsonRpcBlockParameterTag } from '@hyperlane-xyz/sdk';
|
|
7
7
|
|
|
8
|
-
import type { ConfirmedBlockTags } from '../interfaces/IMonitor.js';
|
|
9
8
|
import type { ExplorerMessage } from '../utils/ExplorerClient.js';
|
|
10
9
|
|
|
11
10
|
import { ActionTracker, type ActionTrackerConfig } from './ActionTracker.js';
|
|
@@ -46,19 +45,19 @@ describe('ActionTracker', () => {
|
|
|
46
45
|
getInflightRebalanceActions: explorerGetInflightRebalanceActions,
|
|
47
46
|
} as any;
|
|
48
47
|
|
|
49
|
-
// Create stub for
|
|
48
|
+
// Create stub for adapter (used by MultiProtocolCore)
|
|
50
49
|
mailboxStub = {
|
|
51
|
-
|
|
50
|
+
isDelivered: Sinon.stub().resolves(false),
|
|
52
51
|
};
|
|
53
52
|
|
|
54
|
-
// Create stub for
|
|
55
|
-
const coreGetContracts = Sinon.stub().returns({ mailbox: mailboxStub });
|
|
53
|
+
// Create stub for MultiProtocolCore
|
|
56
54
|
const multiProviderGetChainName = Sinon.stub().callsFake(
|
|
57
55
|
(domain: number) => `chain${domain}`,
|
|
58
56
|
);
|
|
57
|
+
const adapterStub = Sinon.stub().returns(mailboxStub);
|
|
59
58
|
|
|
60
59
|
core = {
|
|
61
|
-
|
|
60
|
+
adapter: adapterStub,
|
|
62
61
|
multiProvider: {
|
|
63
62
|
getChainName: multiProviderGetChainName,
|
|
64
63
|
},
|
|
@@ -107,7 +106,7 @@ describe('ActionTracker', () => {
|
|
|
107
106
|
explorerClient.getInflightUserTransfers.resolves([]);
|
|
108
107
|
|
|
109
108
|
// Ensure mailbox returns false so action stays in_progress
|
|
110
|
-
mailboxStub.
|
|
109
|
+
mailboxStub.isDelivered.resolves(false);
|
|
111
110
|
|
|
112
111
|
await tracker.initialize();
|
|
113
112
|
|
|
@@ -259,7 +258,7 @@ describe('ActionTracker', () => {
|
|
|
259
258
|
});
|
|
260
259
|
|
|
261
260
|
explorerClient.getInflightUserTransfers.resolves([]);
|
|
262
|
-
mailboxStub.
|
|
261
|
+
mailboxStub.isDelivered.resolves(true);
|
|
263
262
|
|
|
264
263
|
await tracker.syncTransfers();
|
|
265
264
|
|
|
@@ -338,7 +337,7 @@ describe('ActionTracker', () => {
|
|
|
338
337
|
await rebalanceIntentStore.save(intent);
|
|
339
338
|
await rebalanceActionStore.save(action);
|
|
340
339
|
|
|
341
|
-
mailboxStub.
|
|
340
|
+
mailboxStub.isDelivered.resolves(true);
|
|
342
341
|
|
|
343
342
|
await tracker.syncRebalanceActions();
|
|
344
343
|
|
|
@@ -367,7 +366,7 @@ describe('ActionTracker', () => {
|
|
|
367
366
|
|
|
368
367
|
await rebalanceActionStore.save(action);
|
|
369
368
|
|
|
370
|
-
mailboxStub.
|
|
369
|
+
mailboxStub.isDelivered.resolves(false);
|
|
371
370
|
|
|
372
371
|
await tracker.syncRebalanceActions();
|
|
373
372
|
|
|
@@ -658,8 +657,8 @@ describe('ActionTracker', () => {
|
|
|
658
657
|
});
|
|
659
658
|
});
|
|
660
659
|
|
|
661
|
-
describe('
|
|
662
|
-
it('should
|
|
660
|
+
describe('delivery check synchronization', () => {
|
|
661
|
+
it('should check delivery status in syncTransfers using adapter', async () => {
|
|
663
662
|
await transferStore.save({
|
|
664
663
|
id: '0xmsg1',
|
|
665
664
|
status: 'in_progress',
|
|
@@ -674,21 +673,19 @@ describe('ActionTracker', () => {
|
|
|
674
673
|
});
|
|
675
674
|
|
|
676
675
|
explorerClient.getInflightUserTransfers.resolves([]);
|
|
677
|
-
mailboxStub.
|
|
676
|
+
mailboxStub.isDelivered.resolves(true);
|
|
678
677
|
|
|
679
|
-
|
|
680
|
-
await tracker.syncTransfers(confirmedBlockTags);
|
|
678
|
+
await tracker.syncTransfers();
|
|
681
679
|
|
|
682
|
-
expect(mailboxStub.
|
|
683
|
-
const call = mailboxStub.
|
|
680
|
+
expect(mailboxStub.isDelivered.calledOnce).to.be.true;
|
|
681
|
+
const call = mailboxStub.isDelivered.firstCall;
|
|
684
682
|
expect(call.args[0]).to.equal('0xmsg1');
|
|
685
|
-
expect(call.args[1]).to.deep.equal({ blockTag: 12345 });
|
|
686
683
|
|
|
687
684
|
const transfer = await transferStore.get('0xmsg1');
|
|
688
685
|
expect(transfer?.status).to.equal('complete');
|
|
689
686
|
});
|
|
690
687
|
|
|
691
|
-
it('should
|
|
688
|
+
it('should check delivery status in syncRebalanceActions using adapter', async () => {
|
|
692
689
|
const intent: RebalanceIntent = {
|
|
693
690
|
id: 'intent-1',
|
|
694
691
|
status: 'in_progress',
|
|
@@ -716,21 +713,65 @@ describe('ActionTracker', () => {
|
|
|
716
713
|
await rebalanceActionStore.save(action);
|
|
717
714
|
|
|
718
715
|
explorerClient.getInflightRebalanceActions.resolves([]);
|
|
719
|
-
mailboxStub.
|
|
716
|
+
mailboxStub.isDelivered.resolves(true);
|
|
720
717
|
|
|
721
|
-
|
|
722
|
-
await tracker.syncRebalanceActions(confirmedBlockTags);
|
|
718
|
+
await tracker.syncRebalanceActions();
|
|
723
719
|
|
|
724
|
-
expect(mailboxStub.
|
|
725
|
-
const call = mailboxStub.
|
|
720
|
+
expect(mailboxStub.isDelivered.calledOnce).to.be.true;
|
|
721
|
+
const call = mailboxStub.isDelivered.firstCall;
|
|
726
722
|
expect(call.args[0]).to.equal('0xmsg1');
|
|
727
|
-
expect(call.args[1]).to.deep.equal({ blockTag: 99999 });
|
|
728
723
|
|
|
729
724
|
const updatedAction = await rebalanceActionStore.get('action-1');
|
|
730
725
|
expect(updatedAction?.status).to.equal('complete');
|
|
731
726
|
});
|
|
732
727
|
|
|
733
|
-
it('should
|
|
728
|
+
it('should keep transfer in_progress when not delivered', async () => {
|
|
729
|
+
await transferStore.save({
|
|
730
|
+
id: '0xmsg1',
|
|
731
|
+
status: 'in_progress',
|
|
732
|
+
messageId: '0xmsg1',
|
|
733
|
+
origin: 1,
|
|
734
|
+
destination: 2,
|
|
735
|
+
amount: 100n,
|
|
736
|
+
sender: '0xuser1',
|
|
737
|
+
recipient: '0xuser2',
|
|
738
|
+
createdAt: Date.now(),
|
|
739
|
+
updatedAt: Date.now(),
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
explorerClient.getInflightUserTransfers.resolves([]);
|
|
743
|
+
mailboxStub.isDelivered.resolves(false);
|
|
744
|
+
|
|
745
|
+
await tracker.syncTransfers();
|
|
746
|
+
|
|
747
|
+
expect(mailboxStub.isDelivered.calledOnce).to.be.true;
|
|
748
|
+
const transfer = await transferStore.get('0xmsg1');
|
|
749
|
+
expect(transfer?.status).to.equal('in_progress');
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
it('should check delivery for multiple destinations', async () => {
|
|
753
|
+
await transferStore.save({
|
|
754
|
+
id: '0xmsg1',
|
|
755
|
+
status: 'in_progress',
|
|
756
|
+
messageId: '0xmsg1',
|
|
757
|
+
origin: 1,
|
|
758
|
+
destination: 3,
|
|
759
|
+
amount: 100n,
|
|
760
|
+
sender: '0xuser1',
|
|
761
|
+
recipient: '0xuser2',
|
|
762
|
+
createdAt: Date.now(),
|
|
763
|
+
updatedAt: Date.now(),
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
explorerClient.getInflightUserTransfers.resolves([]);
|
|
767
|
+
mailboxStub.isDelivered.resolves(false);
|
|
768
|
+
|
|
769
|
+
await tracker.syncTransfers();
|
|
770
|
+
|
|
771
|
+
expect(mailboxStub.isDelivered.calledOnce).to.be.true;
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
it('should pass blockTag when checking delivery in syncTransfers', async () => {
|
|
734
775
|
await transferStore.save({
|
|
735
776
|
id: '0xmsg1',
|
|
736
777
|
status: 'in_progress',
|
|
@@ -745,25 +786,65 @@ describe('ActionTracker', () => {
|
|
|
745
786
|
});
|
|
746
787
|
|
|
747
788
|
explorerClient.getInflightUserTransfers.resolves([]);
|
|
748
|
-
mailboxStub.
|
|
789
|
+
mailboxStub.isDelivered.resolves(true);
|
|
749
790
|
|
|
750
|
-
const confirmedBlockTags
|
|
791
|
+
const confirmedBlockTags = {
|
|
751
792
|
chain2: EthJsonRpcBlockParameterTag.Finalized,
|
|
752
793
|
};
|
|
753
794
|
await tracker.syncTransfers(confirmedBlockTags);
|
|
754
795
|
|
|
755
|
-
expect(mailboxStub.
|
|
756
|
-
const call = mailboxStub.
|
|
757
|
-
expect(call.args[
|
|
796
|
+
expect(mailboxStub.isDelivered.calledOnce).to.be.true;
|
|
797
|
+
const call = mailboxStub.isDelivered.firstCall;
|
|
798
|
+
expect(call.args[0]).to.equal('0xmsg1');
|
|
799
|
+
expect(call.args[1]).to.equal(EthJsonRpcBlockParameterTag.Finalized);
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
it('should pass blockTag when checking delivery in syncRebalanceActions', async () => {
|
|
803
|
+
const intent: RebalanceIntent = {
|
|
804
|
+
id: 'intent-1',
|
|
805
|
+
status: 'in_progress',
|
|
806
|
+
origin: 1,
|
|
807
|
+
destination: 2,
|
|
808
|
+
amount: 100n,
|
|
809
|
+
fulfilledAmount: 0n,
|
|
810
|
+
createdAt: Date.now(),
|
|
811
|
+
updatedAt: Date.now(),
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
const action: RebalanceAction = {
|
|
815
|
+
id: 'action-1',
|
|
816
|
+
status: 'in_progress',
|
|
817
|
+
intentId: 'intent-1',
|
|
818
|
+
messageId: '0xmsg1',
|
|
819
|
+
origin: 1,
|
|
820
|
+
destination: 2,
|
|
821
|
+
amount: 100n,
|
|
822
|
+
createdAt: Date.now(),
|
|
823
|
+
updatedAt: Date.now(),
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
await rebalanceIntentStore.save(intent);
|
|
827
|
+
await rebalanceActionStore.save(action);
|
|
828
|
+
|
|
829
|
+
explorerClient.getInflightRebalanceActions.resolves([]);
|
|
830
|
+
mailboxStub.isDelivered.resolves(true);
|
|
831
|
+
|
|
832
|
+
const confirmedBlockTags = { chain2: 12345 };
|
|
833
|
+
await tracker.syncRebalanceActions(confirmedBlockTags);
|
|
834
|
+
|
|
835
|
+
expect(mailboxStub.isDelivered.calledOnce).to.be.true;
|
|
836
|
+
const call = mailboxStub.isDelivered.firstCall;
|
|
837
|
+
expect(call.args[0]).to.equal('0xmsg1');
|
|
838
|
+
expect(call.args[1]).to.equal(12345);
|
|
758
839
|
});
|
|
759
840
|
|
|
760
|
-
it('should
|
|
841
|
+
it('should pass undefined blockTag when confirmedBlockTags not provided', async () => {
|
|
761
842
|
await transferStore.save({
|
|
762
843
|
id: '0xmsg1',
|
|
763
844
|
status: 'in_progress',
|
|
764
845
|
messageId: '0xmsg1',
|
|
765
846
|
origin: 1,
|
|
766
|
-
destination:
|
|
847
|
+
destination: 2,
|
|
767
848
|
amount: 100n,
|
|
768
849
|
sender: '0xuser1',
|
|
769
850
|
recipient: '0xuser2',
|
|
@@ -772,12 +853,14 @@ describe('ActionTracker', () => {
|
|
|
772
853
|
});
|
|
773
854
|
|
|
774
855
|
explorerClient.getInflightUserTransfers.resolves([]);
|
|
775
|
-
mailboxStub.
|
|
856
|
+
mailboxStub.isDelivered.resolves(false);
|
|
776
857
|
|
|
777
|
-
|
|
778
|
-
await tracker.syncTransfers(confirmedBlockTags);
|
|
858
|
+
await tracker.syncTransfers(); // No confirmedBlockTags
|
|
779
859
|
|
|
780
|
-
expect(mailboxStub.
|
|
860
|
+
expect(mailboxStub.isDelivered.calledOnce).to.be.true;
|
|
861
|
+
const call = mailboxStub.isDelivered.firstCall;
|
|
862
|
+
expect(call.args[0]).to.equal('0xmsg1');
|
|
863
|
+
expect(call.args[1]).to.be.undefined;
|
|
781
864
|
});
|
|
782
865
|
});
|
|
783
866
|
});
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import type { Logger } from 'pino';
|
|
2
2
|
import { v4 as uuidv4 } from 'uuid';
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { MultiProtocolCore } from '@hyperlane-xyz/sdk';
|
|
5
5
|
import type { Address, Domain } from '@hyperlane-xyz/utils';
|
|
6
6
|
import { parseWarpRouteMessage } from '@hyperlane-xyz/utils';
|
|
7
7
|
|
|
8
|
-
import type {
|
|
9
|
-
ConfirmedBlockTag,
|
|
10
|
-
ConfirmedBlockTags,
|
|
11
|
-
} from '../interfaces/IMonitor.js';
|
|
8
|
+
import type { ConfirmedBlockTags } from '../interfaces/IMonitor.js';
|
|
12
9
|
import type {
|
|
13
10
|
ExplorerClient,
|
|
14
11
|
ExplorerMessage,
|
|
15
12
|
} from '../utils/ExplorerClient.js';
|
|
13
|
+
import { getConfirmedBlockTag } from '../utils/blockTag.js';
|
|
16
14
|
|
|
17
15
|
import type {
|
|
18
16
|
CreateRebalanceActionParams,
|
|
@@ -43,7 +41,7 @@ export class ActionTracker implements IActionTracker {
|
|
|
43
41
|
private readonly rebalanceIntentStore: IRebalanceIntentStore,
|
|
44
42
|
private readonly rebalanceActionStore: IRebalanceActionStore,
|
|
45
43
|
private readonly explorerClient: ExplorerClient,
|
|
46
|
-
private readonly core:
|
|
44
|
+
private readonly core: MultiProtocolCore,
|
|
47
45
|
private readonly config: ActionTrackerConfig,
|
|
48
46
|
private readonly logger: Logger,
|
|
49
47
|
) {}
|
|
@@ -171,11 +169,10 @@ export class ActionTracker implements IActionTracker {
|
|
|
171
169
|
|
|
172
170
|
const existingTransfers = await this.getInProgressTransfers();
|
|
173
171
|
for (const transfer of existingTransfers) {
|
|
174
|
-
const
|
|
172
|
+
const blockTag = await this.getConfirmedBlockTag(
|
|
175
173
|
transfer.destination,
|
|
174
|
+
confirmedBlockTags,
|
|
176
175
|
);
|
|
177
|
-
const blockTag = confirmedBlockTags?.[chainName];
|
|
178
|
-
|
|
179
176
|
const delivered = await this.isMessageDelivered(
|
|
180
177
|
transfer.messageId,
|
|
181
178
|
transfer.destination,
|
|
@@ -263,11 +260,10 @@ export class ActionTracker implements IActionTracker {
|
|
|
263
260
|
const inProgressActions =
|
|
264
261
|
await this.rebalanceActionStore.getByStatus('in_progress');
|
|
265
262
|
for (const action of inProgressActions) {
|
|
266
|
-
const
|
|
263
|
+
const blockTag = await this.getConfirmedBlockTag(
|
|
267
264
|
action.destination,
|
|
265
|
+
confirmedBlockTags,
|
|
268
266
|
);
|
|
269
|
-
const blockTag = confirmedBlockTags?.[chainName];
|
|
270
|
-
|
|
271
267
|
const delivered = await this.isMessageDelivered(
|
|
272
268
|
action.messageId,
|
|
273
269
|
action.destination,
|
|
@@ -515,45 +511,43 @@ export class ActionTracker implements IActionTracker {
|
|
|
515
511
|
|
|
516
512
|
// === Private Helpers ===
|
|
517
513
|
|
|
514
|
+
/**
|
|
515
|
+
* Get the confirmed block tag for delivery checks.
|
|
516
|
+
* Uses cached value from Monitor event if available, otherwise computes on-demand.
|
|
517
|
+
*/
|
|
518
518
|
private async getConfirmedBlockTag(
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
const reorgPeriod = metadata.blocks?.reorgPeriod ?? 32;
|
|
524
|
-
|
|
525
|
-
if (typeof reorgPeriod === 'string') {
|
|
526
|
-
return reorgPeriod as ConfirmedBlockTag;
|
|
527
|
-
}
|
|
519
|
+
destination: Domain,
|
|
520
|
+
confirmedBlockTags?: ConfirmedBlockTags,
|
|
521
|
+
): Promise<string | number | undefined> {
|
|
522
|
+
const chainName = this.core.multiProvider.getChainName(destination);
|
|
528
523
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
return
|
|
532
|
-
} catch (error) {
|
|
533
|
-
this.logger.warn(
|
|
534
|
-
{ chain: chainName, error: (error as Error).message },
|
|
535
|
-
'Failed to get confirmed block, using latest',
|
|
536
|
-
);
|
|
537
|
-
return undefined;
|
|
524
|
+
// If tags provided (from Monitor event), use cached value
|
|
525
|
+
if (confirmedBlockTags) {
|
|
526
|
+
return confirmedBlockTags[chainName];
|
|
538
527
|
}
|
|
528
|
+
|
|
529
|
+
// Otherwise compute on-demand (e.g., during initialize())
|
|
530
|
+
return getConfirmedBlockTag(
|
|
531
|
+
this.core.multiProvider,
|
|
532
|
+
chainName,
|
|
533
|
+
this.logger,
|
|
534
|
+
);
|
|
539
535
|
}
|
|
540
536
|
|
|
541
537
|
private async isMessageDelivered(
|
|
542
538
|
messageId: string,
|
|
543
539
|
destination: Domain,
|
|
544
|
-
|
|
540
|
+
blockTag?: string | number,
|
|
545
541
|
): Promise<boolean> {
|
|
546
542
|
try {
|
|
547
543
|
const chainName = this.core.multiProvider.getChainName(destination);
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
providedBlockTag ?? (await this.getConfirmedBlockTag(chainName));
|
|
552
|
-
const delivered = await mailbox.delivered(messageId, { blockTag });
|
|
544
|
+
const delivered = await this.core
|
|
545
|
+
.adapter(chainName)
|
|
546
|
+
.isDelivered(messageId, blockTag);
|
|
553
547
|
|
|
554
548
|
this.logger.debug(
|
|
555
|
-
{ messageId, destination: chainName,
|
|
556
|
-
'Checked message delivery
|
|
549
|
+
{ messageId, destination: chainName, delivered, blockTag },
|
|
550
|
+
'Checked message delivery',
|
|
557
551
|
);
|
|
558
552
|
|
|
559
553
|
return delivered;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Logger } from 'pino';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
EthJsonRpcBlockParameterTag,
|
|
5
|
+
MultiProtocolProvider,
|
|
6
|
+
} from '@hyperlane-xyz/sdk';
|
|
7
|
+
|
|
8
|
+
import type { ConfirmedBlockTag } from '../interfaces/IMonitor.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get the confirmed block tag for a chain, accounting for reorg period.
|
|
12
|
+
* Returns a block number that is safe from reorgs, or a named tag like 'finalized'.
|
|
13
|
+
*
|
|
14
|
+
* @param multiProvider - MultiProtocolProvider instance
|
|
15
|
+
* @param chainName - Name of the chain
|
|
16
|
+
* @param logger - Optional logger for warnings
|
|
17
|
+
* @returns Confirmed block tag (number, named tag, or undefined on error)
|
|
18
|
+
*/
|
|
19
|
+
export async function getConfirmedBlockTag(
|
|
20
|
+
multiProvider: MultiProtocolProvider,
|
|
21
|
+
chainName: string,
|
|
22
|
+
logger?: Logger,
|
|
23
|
+
): Promise<ConfirmedBlockTag> {
|
|
24
|
+
try {
|
|
25
|
+
const metadata = multiProvider.getChainMetadata(chainName);
|
|
26
|
+
const reorgPeriod = metadata.blocks?.reorgPeriod ?? 32;
|
|
27
|
+
|
|
28
|
+
if (typeof reorgPeriod === 'string') {
|
|
29
|
+
return reorgPeriod as EthJsonRpcBlockParameterTag;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const provider = multiProvider.getEthersV5Provider(chainName);
|
|
33
|
+
const latestBlock = await provider.getBlockNumber();
|
|
34
|
+
return Math.max(0, latestBlock - reorgPeriod);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
logger?.warn(
|
|
37
|
+
{ chain: chainName, error: (error as Error).message },
|
|
38
|
+
'Failed to get confirmed block, using latest',
|
|
39
|
+
);
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/utils/index.ts
CHANGED