@avalabs/bridge-unified 2.1.1 → 2.1.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.
Files changed (77) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +40 -24
  3. package/dist/index.cjs +8 -7
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +11 -36
  6. package/dist/index.d.ts +11 -36
  7. package/dist/index.js +3 -3
  8. package/dist/index.js.map +1 -1
  9. package/package.json +7 -3
  10. package/.turbo/turbo-build.log +0 -22
  11. package/.turbo/turbo-lint.log +0 -4
  12. package/.turbo/turbo-test.log +0 -26
  13. package/CHANGELOG.md +0 -37
  14. package/jest.config.js +0 -9
  15. package/src/bridges/cctp/__mocks__/asset.mock.ts +0 -15
  16. package/src/bridges/cctp/__mocks__/bridge-transfer.mock.ts +0 -48
  17. package/src/bridges/cctp/__mocks__/chain.mocks.ts +0 -33
  18. package/src/bridges/cctp/__mocks__/config.mock.ts +0 -45
  19. package/src/bridges/cctp/abis/erc20.ts +0 -117
  20. package/src/bridges/cctp/abis/message-transmitter.ts +0 -318
  21. package/src/bridges/cctp/abis/token-router.ts +0 -843
  22. package/src/bridges/cctp/factory.test.ts +0 -73
  23. package/src/bridges/cctp/factory.ts +0 -36
  24. package/src/bridges/cctp/handlers/estimate-gas.test.ts +0 -110
  25. package/src/bridges/cctp/handlers/estimate-gas.ts +0 -58
  26. package/src/bridges/cctp/handlers/get-assets.test.ts +0 -47
  27. package/src/bridges/cctp/handlers/get-assets.ts +0 -27
  28. package/src/bridges/cctp/handlers/get-fees.test.ts +0 -61
  29. package/src/bridges/cctp/handlers/get-fees.ts +0 -26
  30. package/src/bridges/cctp/handlers/track-transfer.test.ts +0 -779
  31. package/src/bridges/cctp/handlers/track-transfer.ts +0 -365
  32. package/src/bridges/cctp/handlers/transfer-asset.test.ts +0 -429
  33. package/src/bridges/cctp/handlers/transfer-asset.ts +0 -179
  34. package/src/bridges/cctp/index.ts +0 -1
  35. package/src/bridges/cctp/types/chain.ts +0 -9
  36. package/src/bridges/cctp/types/config.ts +0 -20
  37. package/src/bridges/cctp/utils/build-tx.ts +0 -30
  38. package/src/bridges/cctp/utils/config.test.ts +0 -49
  39. package/src/bridges/cctp/utils/config.ts +0 -36
  40. package/src/bridges/cctp/utils/transfer-data.test.ts +0 -83
  41. package/src/bridges/cctp/utils/transfer-data.ts +0 -48
  42. package/src/errors/bridge-error.ts +0 -11
  43. package/src/errors/bridge-initialization-error.ts +0 -9
  44. package/src/errors/bridge-unavailable-error.ts +0 -9
  45. package/src/errors/index.ts +0 -4
  46. package/src/errors/invalid-params-error.ts +0 -9
  47. package/src/index.ts +0 -3
  48. package/src/types/asset.ts +0 -26
  49. package/src/types/bridge.ts +0 -64
  50. package/src/types/chain.ts +0 -10
  51. package/src/types/config.ts +0 -10
  52. package/src/types/environment.ts +0 -4
  53. package/src/types/error.ts +0 -19
  54. package/src/types/index.ts +0 -9
  55. package/src/types/provider.ts +0 -12
  56. package/src/types/signer.ts +0 -18
  57. package/src/types/transfer.ts +0 -35
  58. package/src/unified-bridge-service.test.ts +0 -209
  59. package/src/unified-bridge-service.ts +0 -97
  60. package/src/utils/bridge-types.test.ts +0 -103
  61. package/src/utils/bridge-types.ts +0 -32
  62. package/src/utils/caip2.test.ts +0 -44
  63. package/src/utils/caip2.ts +0 -41
  64. package/src/utils/client.test.ts +0 -97
  65. package/src/utils/client.ts +0 -44
  66. package/src/utils/ensure-config.test.ts +0 -43
  67. package/src/utils/ensure-config.ts +0 -12
  68. package/src/utils/index.ts +0 -2
  69. package/src/utils/network-fee.test.ts +0 -24
  70. package/src/utils/network-fee.ts +0 -6
  71. package/src/utils/retry-promise.test.ts +0 -115
  72. package/src/utils/retry-promise.ts +0 -72
  73. package/src/utils/wait.test.ts +0 -33
  74. package/src/utils/wait.ts +0 -4
  75. package/tsconfig.jest.json +0 -7
  76. package/tsconfig.json +0 -9
  77. package/tsup.config.ts +0 -4
@@ -1,779 +0,0 @@
1
- import { decodeEventLog } from 'viem';
2
- import { BridgeType, type BridgeService, ErrorCode, ErrorReason } from '../../../types';
3
- import { getClientForChain } from '../../../utils/client';
4
- import { getNetworkFeeEVM } from '../../../utils/network-fee';
5
- import { retryPromise } from '../../../utils/retry-promise';
6
- import { getBridgeTrackinParams } from '../__mocks__/bridge-transfer.mock';
7
- import {
8
- CCTP_CONFIG,
9
- SOURCE_ROUTER_ADDRESS_RANDOMIZED_CASING,
10
- TARGET_TRANSMITTER_ADDRESS,
11
- } from '../__mocks__/config.mock';
12
- import { getTrackingDelayByChainId } from '../utils/config';
13
- import * as tracking from './track-transfer';
14
- import {
15
- MAX_BLOCKS,
16
- TRACKING_LIMIT_MS,
17
- INITIAL_DELAY,
18
- trackSourceTx,
19
- trackTargetTx,
20
- trackTransfer,
21
- } from './track-transfer';
22
- import { SOURCE_CHAIN, TARGET_CHAIN } from '../__mocks__/chain.mocks';
23
- import { TOKEN_ROUTER_ABI } from '../abis/token-router';
24
- import { InvalidParamsError } from '../../../errors';
25
-
26
- jest.mock('../../../utils/retry-promise');
27
- jest.mock('../../../utils/client');
28
- jest.mock('../../../utils/network-fee');
29
- jest.mock('../utils/config');
30
- jest.mock('viem');
31
-
32
- describe('CCTP trackTransfer', () => {
33
- const now = 10;
34
- const networkFee = 1000n;
35
- const delay = 5000;
36
-
37
- // used for updateListener callback param testing
38
- // https://github.com/jestjs/jest/issues/434
39
- const updateListenerWithoutReference = jest.fn();
40
- const updateListener = jest.fn();
41
- const doneMock = jest.fn();
42
-
43
- const txMock = { hash: 'hash' };
44
- const bridgeMock = {
45
- type: BridgeType.CCTP,
46
- config: CCTP_CONFIG,
47
- ensureHasConfig: jest.fn(),
48
- } as unknown as BridgeService;
49
- const sourceClientMock = {
50
- getTransactionReceipt: jest.fn(),
51
- getTransaction: jest.fn(),
52
- getTransactionConfirmations: jest.fn(),
53
- };
54
- const targetClientMock = {
55
- getTransactionReceipt: jest.fn(),
56
- getTransaction: jest.fn(),
57
- getTransactionConfirmations: jest.fn(),
58
- getBlockNumber: jest.fn(),
59
- getLogs: jest.fn(),
60
- };
61
-
62
- beforeEach(() => {
63
- jest.resetAllMocks();
64
- jest.useFakeTimers().setSystemTime(new Date(now));
65
-
66
- (retryPromise as jest.Mock).mockImplementation(
67
- ({ promise }: { promise: (done: () => unknown) => Promise<unknown> }) => ({
68
- result: promise(doneMock),
69
- }),
70
- );
71
-
72
- updateListener.mockImplementation((args) => updateListenerWithoutReference({ ...args }));
73
- doneMock.mockImplementation((arg) => arg);
74
- sourceClientMock.getTransaction.mockResolvedValue(txMock);
75
- targetClientMock.getTransaction.mockResolvedValue(txMock);
76
- (getNetworkFeeEVM as jest.Mock).mockReturnValue(networkFee);
77
- (getTrackingDelayByChainId as jest.Mock).mockReturnValue(delay);
78
- });
79
-
80
- afterEach(() => {
81
- jest.useRealTimers();
82
- });
83
-
84
- describe('combined tracking', () => {
85
- afterEach(() => {
86
- jest.restoreAllMocks();
87
- });
88
-
89
- it('calls ensureHasConfig', async () => {
90
- const params = getBridgeTrackinParams({ updateListener });
91
- const error = new Error('error');
92
- (bridgeMock.ensureHasConfig as jest.Mock).mockRejectedValueOnce(error);
93
-
94
- const { result } = trackTransfer(bridgeMock, params);
95
-
96
- await expect(result).rejects.toThrow(error);
97
- });
98
-
99
- it('tracks the transactions correctly', async () => {
100
- const initialParams = getBridgeTrackinParams({ updateListener });
101
- const transferAfterSource = { ...initialParams.bridgeTransfer, metadata: { nonce: 1 } };
102
- const transferAfterTarget = { ...transferAfterSource, completedAt: 999 };
103
-
104
- const sourceCancel = jest.fn();
105
- const targetCancel = jest.fn();
106
-
107
- const sourceTrackerSpy = jest.spyOn(tracking, 'trackSourceTx').mockResolvedValueOnce({
108
- result: new Promise((res) => res(transferAfterSource)),
109
- cancel: sourceCancel,
110
- });
111
-
112
- const targetTrackerSpy = jest.spyOn(tracking, 'trackTargetTx').mockResolvedValueOnce({
113
- result: new Promise((res) => res(transferAfterTarget)),
114
- cancel: targetCancel,
115
- });
116
-
117
- const { result, cancel } = trackTransfer(bridgeMock, initialParams);
118
- expect(await result).toStrictEqual(transferAfterTarget);
119
- expect(sourceTrackerSpy).toHaveBeenCalledWith(bridgeMock.config, initialParams);
120
- expect(targetTrackerSpy).toHaveBeenCalledWith(bridgeMock.config, {
121
- ...initialParams,
122
- bridgeTransfer: transferAfterSource,
123
- });
124
-
125
- cancel();
126
- expect(sourceCancel).not.toHaveBeenCalled();
127
- expect(targetCancel).toHaveBeenCalled();
128
- });
129
- });
130
-
131
- describe('source tx tracking', () => {
132
- beforeEach(() => {
133
- (getClientForChain as jest.Mock)
134
- .mockReturnValueOnce(sourceClientMock)
135
- .mockReturnValueOnce(targetClientMock)
136
- .mockReturnValueOnce(targetClientMock);
137
- });
138
-
139
- it('resolves if bridging has already completed', async () => {
140
- const params = getBridgeTrackinParams({
141
- bridgeTransfer: {
142
- completedAt: 1,
143
- },
144
- updateListener,
145
- });
146
-
147
- const { result } = await trackSourceTx(bridgeMock.config!, params);
148
- expect(await result).toStrictEqual(params.bridgeTransfer);
149
- expect(doneMock).toHaveBeenCalledWith(params.bridgeTransfer);
150
- expect(updateListenerWithoutReference).not.toHaveBeenCalled();
151
-
152
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(SOURCE_CHAIN.chainId);
153
- expect(retryPromise).toHaveBeenCalledWith({
154
- promise: expect.any(Function),
155
- delay,
156
- startAfter: INITIAL_DELAY,
157
- });
158
- });
159
-
160
- it('resolves if message nonce is already known', async () => {
161
- const params = getBridgeTrackinParams({
162
- bridgeTransfer: {
163
- metadata: { nonce: 1 },
164
- },
165
- updateListener,
166
- });
167
-
168
- const { result } = await trackSourceTx(bridgeMock.config!, params);
169
- expect(await result).toStrictEqual(params.bridgeTransfer);
170
- expect(doneMock).toHaveBeenCalledWith(params.bridgeTransfer);
171
- expect(updateListenerWithoutReference).not.toHaveBeenCalled();
172
-
173
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(SOURCE_CHAIN.chainId);
174
- expect(retryPromise).toHaveBeenCalledWith({
175
- promise: expect.any(Function),
176
- delay,
177
- startAfter: INITIAL_DELAY,
178
- });
179
- });
180
-
181
- it('resolves if transaction has timed out', async () => {
182
- const params = getBridgeTrackinParams({
183
- updateListener,
184
- });
185
- const time = params.bridgeTransfer.sourceStartedAt + TRACKING_LIMIT_MS;
186
-
187
- jest.useFakeTimers().setSystemTime(time);
188
-
189
- const { result } = await trackSourceTx(bridgeMock.config!, params);
190
- const expectedResult = { ...params.bridgeTransfer, completedAt: time, errorCode: ErrorCode.TIMEOUT };
191
-
192
- expect(await result).toStrictEqual(expectedResult);
193
- expect(doneMock).toHaveBeenCalledWith(expectedResult);
194
- expect(updateListenerWithoutReference).toHaveBeenCalledTimes(1);
195
- expect(updateListenerWithoutReference).toHaveBeenCalledWith(expectedResult);
196
-
197
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(SOURCE_CHAIN.chainId);
198
- expect(retryPromise).toHaveBeenCalledWith({
199
- promise: expect.any(Function),
200
- delay,
201
- startAfter: INITIAL_DELAY,
202
- });
203
- });
204
-
205
- it('resolves if transaction was reverted', async () => {
206
- const receiptMock = {
207
- status: 'reverted',
208
- };
209
- const params = getBridgeTrackinParams({
210
- updateListener,
211
- });
212
-
213
- sourceClientMock.getTransactionReceipt.mockResolvedValueOnce(receiptMock);
214
-
215
- const { result } = await trackSourceTx(bridgeMock.config!, params);
216
- const expectedResult = {
217
- ...params.bridgeTransfer,
218
- sourceNetworkFee: networkFee,
219
- completedAt: now,
220
- errorCode: ErrorCode.TRANSACTION_REVERTED,
221
- };
222
-
223
- expect(await result).toStrictEqual(expectedResult);
224
- expect(doneMock).toHaveBeenCalledWith(expectedResult);
225
- expect(updateListenerWithoutReference).toHaveBeenCalledTimes(2);
226
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(1, {
227
- ...params.bridgeTransfer,
228
- sourceNetworkFee: networkFee,
229
- });
230
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(2, expectedResult);
231
-
232
- expect(sourceClientMock.getTransactionReceipt).toHaveBeenCalledWith({
233
- hash: params.bridgeTransfer.sourceTxHash,
234
- });
235
- expect(sourceClientMock.getTransaction).toHaveBeenCalledWith({
236
- hash: params.bridgeTransfer.sourceTxHash,
237
- });
238
- expect(getNetworkFeeEVM).toHaveBeenCalledWith(txMock, receiptMock);
239
-
240
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(SOURCE_CHAIN.chainId);
241
- expect(retryPromise).toHaveBeenCalledWith({
242
- promise: expect.any(Function),
243
- delay,
244
- startAfter: INITIAL_DELAY,
245
- });
246
- });
247
-
248
- it('does not resolve if more confirmations are needed', async () => {
249
- const confirmations = 3;
250
- const targetBlockNumber = 50n;
251
- const receiptMock = {
252
- status: 'succeeded',
253
- };
254
-
255
- const params = getBridgeTrackinParams({
256
- updateListener,
257
- bridgeTransfer: {
258
- requiredSourceConfirmationCount: 5,
259
- },
260
- });
261
-
262
- sourceClientMock.getTransactionReceipt.mockResolvedValueOnce(receiptMock);
263
- sourceClientMock.getTransactionConfirmations.mockResolvedValueOnce(confirmations);
264
- targetClientMock.getBlockNumber.mockResolvedValueOnce(targetBlockNumber);
265
-
266
- const { result } = await trackSourceTx(bridgeMock.config!, params);
267
- const expectedResult = {
268
- ...params.bridgeTransfer,
269
- sourceNetworkFee: networkFee,
270
- sourceConfirmationCount: confirmations,
271
- startBlockNumber: targetBlockNumber,
272
- };
273
-
274
- expect(await result).toBeUndefined();
275
- expect(doneMock).not.toHaveBeenCalled();
276
- expect(updateListenerWithoutReference).toHaveBeenCalledTimes(2);
277
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(1, {
278
- ...params.bridgeTransfer,
279
- sourceNetworkFee: networkFee,
280
- });
281
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(2, expectedResult);
282
-
283
- expect(sourceClientMock.getTransactionReceipt).toHaveBeenCalledWith({
284
- hash: params.bridgeTransfer.sourceTxHash,
285
- });
286
- expect(sourceClientMock.getTransaction).toHaveBeenCalledWith({
287
- hash: params.bridgeTransfer.sourceTxHash,
288
- });
289
- expect(getNetworkFeeEVM).toHaveBeenCalledWith(txMock, receiptMock);
290
- expect(sourceClientMock.getTransactionConfirmations).toHaveBeenCalledWith({
291
- hash: params.bridgeTransfer.sourceTxHash,
292
- });
293
-
294
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(SOURCE_CHAIN.chainId);
295
- expect(retryPromise).toHaveBeenCalledWith({
296
- promise: expect.any(Function),
297
- delay,
298
- startAfter: INITIAL_DELAY,
299
- });
300
- });
301
-
302
- it('resolves if transaction has enough confirmations', async () => {
303
- const nonce = 999;
304
- const confirmations = 5;
305
- const targetBlockNumber = 50n;
306
- const receiptMock = {
307
- status: 'succeeded',
308
- logs: [{ address: SOURCE_ROUTER_ADDRESS_RANDOMIZED_CASING }],
309
- };
310
-
311
- const params = getBridgeTrackinParams({
312
- updateListener,
313
- bridgeTransfer: {
314
- requiredSourceConfirmationCount: confirmations,
315
- },
316
- });
317
-
318
- (decodeEventLog as jest.Mock)
319
- .mockReturnValueOnce({ eventName: 'TransferTokens' })
320
- .mockReturnValueOnce({ args: { nonce } });
321
- sourceClientMock.getTransactionReceipt.mockResolvedValueOnce(receiptMock);
322
- sourceClientMock.getTransactionConfirmations.mockResolvedValueOnce(confirmations);
323
- targetClientMock.getBlockNumber.mockResolvedValueOnce(targetBlockNumber);
324
-
325
- const { result } = await trackSourceTx(bridgeMock.config!, params);
326
-
327
- const expectedResult = {
328
- ...params.bridgeTransfer,
329
- sourceNetworkFee: networkFee,
330
- sourceConfirmationCount: confirmations,
331
- targetStartedAt: now,
332
- startBlockNumber: targetBlockNumber,
333
- metadata: {
334
- nonce,
335
- },
336
- };
337
-
338
- expect(await result).toStrictEqual(expectedResult);
339
- expect(doneMock).toHaveBeenCalledWith(expectedResult);
340
- expect(updateListenerWithoutReference).toHaveBeenCalledTimes(4);
341
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(1, {
342
- ...params.bridgeTransfer,
343
- sourceNetworkFee: networkFee,
344
- });
345
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(2, {
346
- ...params.bridgeTransfer,
347
- sourceNetworkFee: networkFee,
348
- sourceConfirmationCount: confirmations,
349
- });
350
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(3, {
351
- ...params.bridgeTransfer,
352
- sourceNetworkFee: networkFee,
353
- sourceConfirmationCount: confirmations,
354
- startBlockNumber: targetBlockNumber,
355
- });
356
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(4, expectedResult);
357
-
358
- expect(sourceClientMock.getTransactionReceipt).toHaveBeenCalledWith({
359
- hash: params.bridgeTransfer.sourceTxHash,
360
- });
361
- expect(sourceClientMock.getTransaction).toHaveBeenCalledWith({
362
- hash: params.bridgeTransfer.sourceTxHash,
363
- });
364
- expect(getNetworkFeeEVM).toHaveBeenCalledWith(txMock, receiptMock);
365
- expect(sourceClientMock.getTransactionConfirmations).toHaveBeenCalledWith({
366
- hash: params.bridgeTransfer.sourceTxHash,
367
- });
368
- expect(decodeEventLog).toHaveBeenCalledTimes(2);
369
- expect(decodeEventLog).toHaveBeenNthCalledWith(1, {
370
- abi: TOKEN_ROUTER_ABI,
371
- address: SOURCE_ROUTER_ADDRESS_RANDOMIZED_CASING,
372
- });
373
- expect(decodeEventLog).toHaveBeenNthCalledWith(2, {
374
- abi: TOKEN_ROUTER_ABI,
375
- eventName: 'TransferTokens',
376
- address: SOURCE_ROUTER_ADDRESS_RANDOMIZED_CASING,
377
- });
378
-
379
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(SOURCE_CHAIN.chainId);
380
- expect(retryPromise).toHaveBeenCalledWith({
381
- promise: expect.any(Function),
382
- delay,
383
- startAfter: INITIAL_DELAY,
384
- });
385
- });
386
- });
387
-
388
- describe('target tx tracking', () => {
389
- const nonce = 999;
390
- const startBlockNumber = 12n;
391
- const txHash = '0x124124';
392
- const msgReceivedEvent = {
393
- name: 'MessageReceived',
394
- type: 'event',
395
- inputs: [
396
- { indexed: true, internalType: 'address', name: 'caller', type: 'address' },
397
- { indexed: false, internalType: 'uint32', name: 'sourceDomain', type: 'uint32' },
398
- { indexed: true, internalType: 'uint64', name: 'nonce', type: 'uint64' },
399
- { indexed: false, internalType: 'bytes32', name: 'sender', type: 'bytes32' },
400
- { indexed: false, internalType: 'bytes', name: 'messageBody', type: 'bytes' },
401
- ],
402
- };
403
-
404
- beforeEach(() => {
405
- (getClientForChain as jest.Mock).mockReturnValueOnce(targetClientMock);
406
- });
407
-
408
- it('throws if message nonce is missing', async () => {
409
- const params = getBridgeTrackinParams({
410
- updateListener,
411
- });
412
-
413
- await expect(trackTargetTx(bridgeMock.config!, params)).rejects.toThrow(
414
- new InvalidParamsError(ErrorReason.INVALID_PARAMS, 'nonce is missing'),
415
- );
416
- });
417
-
418
- it('throws if start block number is missing', async () => {
419
- const params = getBridgeTrackinParams({
420
- updateListener,
421
- bridgeTransfer: {
422
- metadata: {
423
- nonce,
424
- },
425
- },
426
- });
427
-
428
- await expect(trackTargetTx(bridgeMock.config!, params)).rejects.toThrow(
429
- new InvalidParamsError(ErrorReason.INVALID_PARAMS, `startBlockNumber is missing`),
430
- );
431
- });
432
-
433
- it('resolves if bridging has already completed', async () => {
434
- const params = getBridgeTrackinParams({
435
- bridgeTransfer: {
436
- completedAt: 1,
437
- startBlockNumber,
438
- metadata: {
439
- nonce,
440
- },
441
- },
442
- updateListener,
443
- });
444
-
445
- const { result } = await trackTargetTx(bridgeMock.config!, params);
446
- expect(await result).toStrictEqual(params.bridgeTransfer);
447
- expect(doneMock).toHaveBeenCalledWith(params.bridgeTransfer);
448
- expect(updateListenerWithoutReference).not.toHaveBeenCalled();
449
-
450
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(TARGET_CHAIN.chainId);
451
- expect(retryPromise).toHaveBeenCalledWith({
452
- promise: expect.any(Function),
453
- delay,
454
- startAfter: INITIAL_DELAY,
455
- });
456
- });
457
-
458
- it('resolves if transaction has timed out', async () => {
459
- const params = getBridgeTrackinParams({
460
- bridgeTransfer: {
461
- startBlockNumber,
462
- metadata: {
463
- nonce,
464
- },
465
- },
466
- updateListener,
467
- });
468
-
469
- const time = params.bridgeTransfer.sourceStartedAt + TRACKING_LIMIT_MS;
470
-
471
- jest.useFakeTimers().setSystemTime(time);
472
-
473
- const expectedResult = {
474
- ...params.bridgeTransfer,
475
- completedAt: time,
476
- errorCode: ErrorCode.TIMEOUT,
477
- };
478
-
479
- const { result } = await trackTargetTx(bridgeMock.config!, params);
480
- expect(await result).toStrictEqual(expectedResult);
481
- expect(doneMock).toHaveBeenCalledWith(expectedResult);
482
- expect(updateListenerWithoutReference).toHaveBeenCalledTimes(1);
483
- expect(updateListenerWithoutReference).toHaveBeenCalledWith(expectedResult);
484
-
485
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(TARGET_CHAIN.chainId);
486
- expect(retryPromise).toHaveBeenCalledWith({
487
- promise: expect.any(Function),
488
- delay,
489
- startAfter: INITIAL_DELAY,
490
- });
491
- });
492
-
493
- it('resolves if startBlockNumber became invalid', async () => {
494
- (retryPromise as jest.Mock).mockImplementationOnce(
495
- ({ promise }: { promise: (done: () => unknown) => Promise<unknown> }) => ({
496
- result: promise(doneMock).then(() => promise(doneMock)),
497
- }),
498
- );
499
-
500
- const targetBlockNumber = 0n;
501
-
502
- const params = getBridgeTrackinParams({
503
- bridgeTransfer: {
504
- requiredTargetConfirmationCount: 5,
505
- startBlockNumber,
506
- metadata: {
507
- nonce,
508
- },
509
- },
510
- updateListener,
511
- });
512
-
513
- const expectedResult = {
514
- ...params.bridgeTransfer,
515
- completedAt: now,
516
- startBlockNumber: targetBlockNumber,
517
- errorCode: ErrorCode.INVALID_PARAMS,
518
- };
519
-
520
- targetClientMock.getBlockNumber.mockResolvedValueOnce(targetBlockNumber);
521
- targetClientMock.getLogs.mockResolvedValueOnce([]);
522
-
523
- const { result } = await trackTargetTx(bridgeMock.config!, params);
524
- expect(await result).toStrictEqual(expectedResult);
525
- expect(doneMock).toHaveBeenCalledWith(expectedResult);
526
-
527
- expect(updateListenerWithoutReference).toHaveBeenCalledTimes(2);
528
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(1, {
529
- ...params.bridgeTransfer,
530
- startBlockNumber: targetBlockNumber,
531
- });
532
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(2, expectedResult);
533
-
534
- expect(targetClientMock.getTransactionReceipt).not.toHaveBeenCalled();
535
- expect(retryPromise).toHaveBeenCalledWith({
536
- promise: expect.any(Function),
537
- delay,
538
- startAfter: INITIAL_DELAY,
539
- });
540
- });
541
-
542
- it('resolves if transaction was reverted', async () => {
543
- const targetBlockNumber = 50n;
544
- const receiptMock = {
545
- status: 'reverted',
546
- };
547
- const params = getBridgeTrackinParams({
548
- bridgeTransfer: {
549
- startBlockNumber,
550
- metadata: {
551
- nonce,
552
- },
553
- },
554
- updateListener,
555
- });
556
-
557
- targetClientMock.getLogs.mockResolvedValueOnce([{ transactionHash: txHash }]);
558
- targetClientMock.getTransactionReceipt.mockResolvedValueOnce(receiptMock);
559
- targetClientMock.getBlockNumber.mockResolvedValueOnce(targetBlockNumber);
560
-
561
- const expectedResult = {
562
- ...params.bridgeTransfer,
563
- targetTxHash: txHash,
564
- targetNetworkFee: networkFee,
565
- completedAt: now,
566
- errorCode: ErrorCode.TRANSACTION_REVERTED,
567
- };
568
-
569
- const { result } = await trackTargetTx(bridgeMock.config!, params);
570
- expect(await result).toStrictEqual(expectedResult);
571
- expect(doneMock).toHaveBeenCalledWith(expectedResult);
572
- expect(updateListenerWithoutReference).toHaveBeenCalledTimes(3);
573
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(1, {
574
- ...params.bridgeTransfer,
575
- targetTxHash: txHash,
576
- });
577
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(2, {
578
- ...params.bridgeTransfer,
579
- targetTxHash: txHash,
580
- targetNetworkFee: networkFee,
581
- });
582
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(3, expectedResult);
583
-
584
- expect(targetClientMock.getLogs).toHaveBeenCalledWith({
585
- address: TARGET_TRANSMITTER_ADDRESS,
586
- event: msgReceivedEvent,
587
- args: { nonce },
588
- fromBlock: 'earliest',
589
- toBlock: 'latest',
590
- });
591
- expect(targetClientMock.getTransactionReceipt).toHaveBeenCalledWith({ hash: txHash });
592
- expect(targetClientMock.getTransaction).toHaveBeenCalledWith({ hash: txHash });
593
- expect(getNetworkFeeEVM).toHaveBeenCalledWith(txMock, receiptMock);
594
-
595
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(TARGET_CHAIN.chainId);
596
- expect(retryPromise).toHaveBeenCalledWith({
597
- promise: expect.any(Function),
598
- delay,
599
- startAfter: INITIAL_DELAY,
600
- });
601
- });
602
-
603
- it('does not resolve if transaction hash is unknown', async () => {
604
- const targetBlockNumber = 50;
605
-
606
- const params = getBridgeTrackinParams({
607
- bridgeTransfer: {
608
- requiredTargetConfirmationCount: 5,
609
- startBlockNumber,
610
- metadata: {
611
- nonce,
612
- },
613
- },
614
- updateListener,
615
- });
616
-
617
- targetClientMock.getBlockNumber.mockResolvedValueOnce(targetBlockNumber);
618
- targetClientMock.getLogs.mockResolvedValueOnce([]);
619
-
620
- const { result } = await trackTargetTx(bridgeMock.config!, params);
621
- expect(await result).toBeUndefined();
622
- expect(doneMock).not.toHaveBeenCalled();
623
-
624
- expect(updateListenerWithoutReference).toHaveBeenCalledTimes(1);
625
- expect(updateListenerWithoutReference).toHaveBeenCalledWith({
626
- ...params.bridgeTransfer,
627
- startBlockNumber: targetBlockNumber,
628
- });
629
-
630
- expect(targetClientMock.getLogs).toHaveBeenCalledWith({
631
- address: TARGET_TRANSMITTER_ADDRESS,
632
- event: msgReceivedEvent,
633
- args: { nonce },
634
- fromBlock: 'earliest',
635
- toBlock: 'latest',
636
- });
637
-
638
- expect(targetClientMock.getTransactionReceipt).not.toHaveBeenCalled();
639
- expect(retryPromise).toHaveBeenCalledWith({
640
- promise: expect.any(Function),
641
- delay,
642
- startAfter: INITIAL_DELAY,
643
- });
644
- });
645
-
646
- it('does not resolve if more confirmations are needed', async () => {
647
- const targetBlockNumber = 50;
648
- const receiptMock = {
649
- status: 'succeeded',
650
- };
651
- const confirmations = 3;
652
- const params = getBridgeTrackinParams({
653
- bridgeTransfer: {
654
- requiredTargetConfirmationCount: 5,
655
- startBlockNumber,
656
- metadata: {
657
- nonce,
658
- },
659
- },
660
- updateListener,
661
- });
662
-
663
- targetClientMock.getLogs.mockResolvedValueOnce([{ transactionHash: txHash }]);
664
- targetClientMock.getTransactionReceipt.mockResolvedValueOnce(receiptMock);
665
- targetClientMock.getTransactionConfirmations.mockResolvedValueOnce(confirmations);
666
- targetClientMock.getBlockNumber.mockResolvedValueOnce(targetBlockNumber);
667
-
668
- const { result } = await trackTargetTx(bridgeMock.config!, params);
669
- expect(await result).toBeUndefined();
670
- expect(doneMock).not.toHaveBeenCalled();
671
- expect(updateListenerWithoutReference).toHaveBeenCalledTimes(3);
672
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(1, {
673
- ...params.bridgeTransfer,
674
- targetTxHash: txHash,
675
- });
676
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(2, {
677
- ...params.bridgeTransfer,
678
- targetTxHash: txHash,
679
- targetNetworkFee: networkFee,
680
- });
681
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(3, {
682
- ...params.bridgeTransfer,
683
- targetTxHash: txHash,
684
- targetNetworkFee: networkFee,
685
- targetConfirmationCount: confirmations,
686
- });
687
-
688
- expect(targetClientMock.getLogs).toHaveBeenCalledWith({
689
- address: TARGET_TRANSMITTER_ADDRESS,
690
- event: msgReceivedEvent,
691
- args: { nonce },
692
- fromBlock: 'earliest',
693
- toBlock: 'latest',
694
- });
695
- expect(targetClientMock.getTransactionReceipt).toHaveBeenCalledWith({ hash: txHash });
696
- expect(targetClientMock.getTransaction).toHaveBeenCalledWith({ hash: txHash });
697
- expect(getNetworkFeeEVM).toHaveBeenCalledWith(txMock, receiptMock);
698
- expect(targetClientMock.getTransactionConfirmations).toHaveBeenCalledWith({ hash: txHash });
699
-
700
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(TARGET_CHAIN.chainId);
701
- expect(retryPromise).toHaveBeenCalledWith({
702
- promise: expect.any(Function),
703
- delay,
704
- startAfter: INITIAL_DELAY,
705
- });
706
- });
707
-
708
- it('resolves if transaction has enough confirmations', async () => {
709
- const targetBlockNumber = MAX_BLOCKS * 6n;
710
- const receiptMock = {
711
- status: 'succeeded',
712
- };
713
- const confirmations = 3;
714
- const params = getBridgeTrackinParams({
715
- bridgeTransfer: {
716
- requiredTargetConfirmationCount: confirmations,
717
- startBlockNumber: MAX_BLOCKS * 2n,
718
- metadata: {
719
- nonce,
720
- },
721
- },
722
- updateListener,
723
- });
724
-
725
- const expectedResult = {
726
- ...params.bridgeTransfer,
727
- targetTxHash: txHash,
728
- targetNetworkFee: networkFee,
729
- targetConfirmationCount: confirmations,
730
- completedAt: now,
731
- };
732
-
733
- targetClientMock.getLogs.mockResolvedValueOnce([{ transactionHash: txHash }]);
734
- targetClientMock.getTransactionReceipt.mockResolvedValueOnce(receiptMock);
735
- targetClientMock.getTransactionConfirmations.mockResolvedValueOnce(confirmations);
736
- targetClientMock.getBlockNumber.mockResolvedValueOnce(targetBlockNumber);
737
-
738
- const { result } = await trackTargetTx(bridgeMock.config!, params);
739
- expect(await result).toStrictEqual(expectedResult);
740
- expect(doneMock).toHaveBeenCalledWith(expectedResult);
741
- expect(updateListenerWithoutReference).toHaveBeenCalledTimes(4);
742
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(1, {
743
- ...params.bridgeTransfer,
744
- targetTxHash: txHash,
745
- });
746
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(2, {
747
- ...params.bridgeTransfer,
748
- targetTxHash: txHash,
749
- targetNetworkFee: networkFee,
750
- });
751
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(3, {
752
- ...params.bridgeTransfer,
753
- targetTxHash: txHash,
754
- targetNetworkFee: networkFee,
755
- targetConfirmationCount: confirmations,
756
- });
757
- expect(updateListenerWithoutReference).toHaveBeenNthCalledWith(4, expectedResult);
758
-
759
- expect(targetClientMock.getLogs).toHaveBeenCalledWith({
760
- address: TARGET_TRANSMITTER_ADDRESS,
761
- event: msgReceivedEvent,
762
- args: { nonce },
763
- fromBlock: params.bridgeTransfer.startBlockNumber! - MAX_BLOCKS,
764
- toBlock: params.bridgeTransfer.startBlockNumber! + MAX_BLOCKS,
765
- });
766
- expect(targetClientMock.getTransactionReceipt).toHaveBeenCalledWith({ hash: txHash });
767
- expect(targetClientMock.getTransaction).toHaveBeenCalledWith({ hash: txHash });
768
- expect(getNetworkFeeEVM).toHaveBeenCalledWith(txMock, receiptMock);
769
- expect(targetClientMock.getTransactionConfirmations).toHaveBeenCalledWith({ hash: txHash });
770
-
771
- expect(getTrackingDelayByChainId).toHaveBeenCalledWith(TARGET_CHAIN.chainId);
772
- expect(retryPromise).toHaveBeenCalledWith({
773
- promise: expect.any(Function),
774
- delay,
775
- startAfter: INITIAL_DELAY,
776
- });
777
- });
778
- });
779
- });