@avalabs/bridge-unified 2.1.1 → 3.0.0

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 +115 -31
  3. package/dist/index.cjs +36 -10
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +252 -84
  6. package/dist/index.d.ts +252 -84
  7. package/dist/index.js +9 -4
  8. package/dist/index.js.map +1 -1
  9. package/package.json +14 -4
  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,429 +0,0 @@
1
- import { encodeFunctionData, isAddress } from 'viem';
2
- import {
3
- Environment,
4
- type BridgeService,
5
- type TransferParams,
6
- BridgeType,
7
- ErrorReason,
8
- type Signer,
9
- BridgeSignatureReason,
10
- } from '../../../types';
11
- import { getClientForChain } from '../../../utils/client';
12
- import { BRIDGE_ASSET } from '../__mocks__/asset.mock';
13
- import { SOURCE_CHAIN, TARGET_CHAIN } from '../__mocks__/chain.mocks';
14
- import { CCTP_CONFIG, SOURCE_ROUTER_ADDRESS } from '../__mocks__/config.mock';
15
- import { transferAsset } from './transfer-asset';
16
- import { getBridgeTransferMock } from '../__mocks__/bridge-transfer.mock';
17
- import { ERC20_ABI } from '../abis/erc20';
18
- import { TOKEN_ROUTER_ABI } from '../abis/token-router';
19
- import { InvalidParamsError } from '../../../errors';
20
-
21
- jest.mock('viem');
22
- jest.mock('../../../utils/client');
23
-
24
- describe('CCTP transferAsset', () => {
25
- const environment = Environment.TEST;
26
- const targetBlockNumber = 10n;
27
-
28
- const sourceProviderMock = {
29
- request: jest.fn(),
30
- };
31
- const targetProviderMock = {
32
- request: jest.fn(),
33
- };
34
- const feesMock = {
35
- [BRIDGE_ASSET.address!]: 2_000_000,
36
- };
37
- const bridgeMock = {
38
- type: BridgeType.CCTP,
39
- config: CCTP_CONFIG,
40
- ensureHasConfig: jest.fn(),
41
- getFees: jest.fn(),
42
- } as unknown as BridgeService;
43
- const sourceClientMock = {
44
- readContract: jest.fn(),
45
- writeContract: jest.fn(),
46
- simulateContract: jest.fn(),
47
- sendRawTransaction: jest.fn(),
48
- waitForTransactionReceipt: jest.fn(),
49
- };
50
- const targetClientMock = {
51
- getBlockNumber: jest.fn(),
52
- };
53
- const onStepChangeSpy = jest.fn();
54
-
55
- const getTransferParams = (props?: Partial<TransferParams>) =>
56
- ({
57
- asset: BRIDGE_ASSET,
58
- amount: 1_000_000,
59
- fromAddress: '0x787',
60
- sourceChain: SOURCE_CHAIN,
61
- targetChain: TARGET_CHAIN,
62
- sourceProvider: sourceProviderMock,
63
- targetProvider: targetProviderMock,
64
- onStepChange: onStepChangeSpy,
65
- ...(props ?? {}),
66
- }) as TransferParams;
67
-
68
- beforeEach(() => {
69
- jest.resetAllMocks();
70
- targetClientMock.getBlockNumber.mockResolvedValue(targetBlockNumber);
71
- (bridgeMock.getFees as jest.Mock).mockResolvedValue(feesMock);
72
- (getClientForChain as jest.Mock).mockReturnValueOnce(sourceClientMock).mockReturnValueOnce(targetClientMock);
73
- jest.mocked(isAddress).mockReturnValue(true);
74
- });
75
-
76
- it('calls ensureHasConfig', async () => {
77
- const params = getTransferParams();
78
- const error = new Error('error');
79
- (bridgeMock.ensureHasConfig as jest.Mock).mockRejectedValueOnce(error);
80
-
81
- await expect(transferAsset(bridgeMock, params, environment)).rejects.toThrow(error);
82
- });
83
-
84
- it('throws when addresses are incorrect', async () => {
85
- jest.mocked(isAddress).mockReturnValue(false);
86
- const params = getTransferParams();
87
- await expect(transferAsset(bridgeMock, params, environment)).rejects.toThrow(
88
- new InvalidParamsError(ErrorReason.INCORRECT_ADDRESS_PROVIDED),
89
- );
90
- });
91
-
92
- describe('needs additional approval', () => {
93
- it('works with a provided signer', async () => {
94
- const start = 1000;
95
- const dateSpy = jest.spyOn(Date, 'now');
96
- dateSpy.mockReturnValue(start);
97
-
98
- const approvalSignedHex = '0x1';
99
- const approvalTxHash = '0x2';
100
- const approvalTxData = 'approval-tx-data';
101
- const bridgeSignedHex = '0x3';
102
- const bridgeTxHash = '0x4';
103
- const bridgeTxData = 'bridge-tx-data';
104
-
105
- const approvalSignMock: Signer = jest.fn((_, dispatch) => dispatch(approvalSignedHex));
106
- const bridgeSignMock: Signer = jest.fn((_, dispatch) => dispatch(bridgeSignedHex));
107
- const customSigner = jest.fn().mockImplementationOnce(approvalSignMock).mockImplementationOnce(bridgeSignMock);
108
-
109
- sourceClientMock.readContract.mockResolvedValue(0n);
110
- sourceClientMock.sendRawTransaction.mockResolvedValueOnce(approvalTxHash).mockResolvedValueOnce(bridgeTxHash);
111
- (encodeFunctionData as jest.Mock).mockReturnValueOnce(approvalTxData).mockReturnValueOnce(bridgeTxData);
112
-
113
- const params = getTransferParams({ sourceProvider: sourceProviderMock, sign: customSigner });
114
- const bridgeTransfer = await transferAsset(bridgeMock, params, environment);
115
-
116
- expect(bridgeTransfer).toStrictEqual(
117
- getBridgeTransferMock({
118
- amount: params.amount,
119
- amountDecimals: params.asset.decimals,
120
- fromAddress: params.fromAddress,
121
- sourceTxHash: bridgeTxHash,
122
- startBlockNumber: targetBlockNumber,
123
- sourceStartedAt: start,
124
- }),
125
- );
126
-
127
- expect(getClientForChain).toHaveBeenCalledTimes(2);
128
- expect(getClientForChain).toHaveBeenNthCalledWith(1, {
129
- chain: params.sourceChain,
130
- provider: sourceProviderMock,
131
- });
132
- expect(getClientForChain).toHaveBeenNthCalledWith(2, {
133
- chain: params.targetChain,
134
- provider: targetProviderMock,
135
- });
136
-
137
- expect(sourceClientMock.readContract).toHaveBeenCalledWith({
138
- address: BRIDGE_ASSET.address,
139
- abi: ERC20_ABI,
140
- functionName: 'allowance',
141
- args: [params.fromAddress, SOURCE_ROUTER_ADDRESS],
142
- });
143
-
144
- expect(encodeFunctionData).toHaveBeenCalledTimes(2);
145
- expect(encodeFunctionData).toHaveBeenNthCalledWith(1, {
146
- abi: ERC20_ABI,
147
- functionName: 'approve',
148
- args: [SOURCE_ROUTER_ADDRESS, params.amount],
149
- });
150
- expect(encodeFunctionData).toHaveBeenNthCalledWith(2, {
151
- abi: TOKEN_ROUTER_ABI,
152
- functionName: 'transferTokens',
153
- args: [params.amount, 1, params.fromAddress, BRIDGE_ASSET.address],
154
- });
155
-
156
- expect(customSigner).toHaveBeenCalledTimes(2);
157
- expect(customSigner).toHaveBeenNthCalledWith(
158
- 1,
159
- {
160
- from: params.fromAddress,
161
- to: BRIDGE_ASSET.address,
162
- data: approvalTxData,
163
- },
164
- expect.any(Function),
165
- );
166
- expect(customSigner).toHaveBeenNthCalledWith(
167
- 2,
168
- {
169
- from: params.fromAddress,
170
- to: SOURCE_ROUTER_ADDRESS,
171
- data: bridgeTxData,
172
- },
173
- expect.any(Function),
174
- );
175
-
176
- expect(sourceClientMock.sendRawTransaction).toHaveBeenCalledTimes(2);
177
- expect(sourceClientMock.sendRawTransaction).toHaveBeenNthCalledWith(1, {
178
- serializedTransaction: approvalSignedHex,
179
- });
180
- expect(sourceClientMock.sendRawTransaction).toHaveBeenNthCalledWith(2, {
181
- serializedTransaction: bridgeSignedHex,
182
- });
183
-
184
- expect(sourceClientMock.waitForTransactionReceipt).toHaveBeenCalledWith({
185
- hash: approvalTxHash,
186
- pollingInterval: 1_000,
187
- });
188
-
189
- expect(onStepChangeSpy).toHaveBeenCalledTimes(2);
190
- expect(onStepChangeSpy).toHaveBeenNthCalledWith(1, {
191
- currentSignature: 1,
192
- requiredSignatures: 2,
193
- currentSignatureReason: BridgeSignatureReason.AllowanceApproval,
194
- });
195
- expect(onStepChangeSpy).toHaveBeenNthCalledWith(2, {
196
- currentSignature: 2,
197
- requiredSignatures: 2,
198
- currentSignatureReason: BridgeSignatureReason.TokensTransfer,
199
- });
200
- });
201
-
202
- it('works without provided signer', async () => {
203
- const start = 1000;
204
- const dateSpy = jest.spyOn(Date, 'now');
205
- dateSpy.mockReturnValue(start);
206
-
207
- const approvalTxHash = '0x1';
208
- const approvalTxRequest = 'approval-tx-request';
209
- const bridgeTxHash = '0x2';
210
- const bridgeTxRequest = 'bridge-tx-request';
211
-
212
- sourceClientMock.readContract.mockResolvedValue(0n);
213
- sourceClientMock.simulateContract
214
- .mockResolvedValueOnce({ request: approvalTxRequest })
215
- .mockResolvedValueOnce({ request: bridgeTxRequest });
216
- sourceClientMock.writeContract.mockResolvedValueOnce(approvalTxHash).mockResolvedValueOnce(bridgeTxHash);
217
-
218
- const params = getTransferParams({ sourceProvider: sourceProviderMock });
219
- const bridgeTransfer = await transferAsset(bridgeMock, params, environment);
220
-
221
- expect(bridgeTransfer).toStrictEqual(
222
- getBridgeTransferMock({
223
- amount: params.amount,
224
- amountDecimals: params.asset.decimals,
225
- fromAddress: params.fromAddress,
226
- sourceTxHash: bridgeTxHash,
227
- startBlockNumber: targetBlockNumber,
228
- sourceStartedAt: start,
229
- }),
230
- );
231
-
232
- expect(getClientForChain).toHaveBeenCalledTimes(2);
233
- expect(getClientForChain).toHaveBeenNthCalledWith(1, {
234
- chain: params.sourceChain,
235
- provider: sourceProviderMock,
236
- });
237
- expect(getClientForChain).toHaveBeenNthCalledWith(2, {
238
- chain: params.targetChain,
239
- provider: targetProviderMock,
240
- });
241
-
242
- expect(sourceClientMock.readContract).toHaveBeenCalledWith({
243
- address: BRIDGE_ASSET.address,
244
- abi: ERC20_ABI,
245
- functionName: 'allowance',
246
- args: [params.fromAddress, SOURCE_ROUTER_ADDRESS],
247
- });
248
-
249
- expect(sourceClientMock.simulateContract).toHaveBeenCalledTimes(2);
250
- expect(sourceClientMock.simulateContract).toHaveBeenNthCalledWith(1, {
251
- account: params.fromAddress,
252
- address: BRIDGE_ASSET.address,
253
- abi: ERC20_ABI,
254
- functionName: 'approve',
255
- args: [SOURCE_ROUTER_ADDRESS, params.amount],
256
- });
257
- expect(sourceClientMock.simulateContract).toHaveBeenNthCalledWith(2, {
258
- account: params.fromAddress,
259
- address: SOURCE_ROUTER_ADDRESS,
260
- abi: TOKEN_ROUTER_ABI,
261
- functionName: 'transferTokens',
262
- args: [params.amount, 1, params.fromAddress, BRIDGE_ASSET.address],
263
- });
264
-
265
- expect(sourceClientMock.writeContract).toHaveBeenCalledTimes(2);
266
- expect(sourceClientMock.writeContract).toHaveBeenNthCalledWith(1, approvalTxRequest);
267
- expect(sourceClientMock.writeContract).toHaveBeenNthCalledWith(2, bridgeTxRequest);
268
-
269
- expect(sourceClientMock.waitForTransactionReceipt).toHaveBeenCalledWith({
270
- hash: approvalTxHash,
271
- pollingInterval: 1_000,
272
- });
273
-
274
- expect(onStepChangeSpy).toHaveBeenCalledTimes(2);
275
- expect(onStepChangeSpy).toHaveBeenNthCalledWith(1, {
276
- currentSignature: 1,
277
- requiredSignatures: 2,
278
- currentSignatureReason: BridgeSignatureReason.AllowanceApproval,
279
- });
280
- expect(onStepChangeSpy).toHaveBeenNthCalledWith(2, {
281
- currentSignature: 2,
282
- requiredSignatures: 2,
283
- currentSignatureReason: BridgeSignatureReason.TokensTransfer,
284
- });
285
- });
286
- });
287
-
288
- describe('does not need additional approval', () => {
289
- it('works with a provided signer', async () => {
290
- const start = 1000;
291
- const dateSpy = jest.spyOn(Date, 'now');
292
- dateSpy.mockReturnValue(start);
293
-
294
- const bridgeSignedHex = '0x3';
295
- const bridgeTxHash = '0x4';
296
- const bridgeTxData = 'bridge-tx-data';
297
-
298
- const bridgeSignMock: Signer = jest.fn((_, dispatch) => dispatch(bridgeSignedHex));
299
- const customSigner = jest.fn().mockImplementationOnce(bridgeSignMock);
300
- const params = getTransferParams({ sourceProvider: sourceProviderMock, sign: customSigner });
301
-
302
- sourceClientMock.readContract.mockResolvedValue(params.amount);
303
- sourceClientMock.sendRawTransaction.mockResolvedValueOnce(bridgeTxHash);
304
- (encodeFunctionData as jest.Mock).mockReturnValueOnce(bridgeTxData);
305
-
306
- const bridgeTransfer = await transferAsset(bridgeMock, params, environment);
307
-
308
- expect(bridgeTransfer).toStrictEqual(
309
- getBridgeTransferMock({
310
- amount: params.amount,
311
- amountDecimals: params.asset.decimals,
312
- fromAddress: params.fromAddress,
313
- sourceTxHash: bridgeTxHash,
314
- startBlockNumber: targetBlockNumber,
315
- sourceStartedAt: start,
316
- }),
317
- );
318
-
319
- expect(getClientForChain).toHaveBeenCalledTimes(2);
320
- expect(getClientForChain).toHaveBeenNthCalledWith(1, {
321
- chain: params.sourceChain,
322
- provider: sourceProviderMock,
323
- });
324
- expect(getClientForChain).toHaveBeenNthCalledWith(2, {
325
- chain: params.targetChain,
326
- provider: targetProviderMock,
327
- });
328
-
329
- expect(sourceClientMock.readContract).toHaveBeenCalledWith({
330
- address: BRIDGE_ASSET.address,
331
- abi: ERC20_ABI,
332
- functionName: 'allowance',
333
- args: [params.fromAddress, SOURCE_ROUTER_ADDRESS],
334
- });
335
-
336
- expect(encodeFunctionData).toHaveBeenCalledTimes(1);
337
- expect(encodeFunctionData).toHaveBeenCalledWith({
338
- abi: TOKEN_ROUTER_ABI,
339
- functionName: 'transferTokens',
340
- args: [params.amount, 1, params.fromAddress, BRIDGE_ASSET.address],
341
- });
342
-
343
- expect(customSigner).toHaveBeenCalledTimes(1);
344
- expect(customSigner).toHaveBeenCalledWith(
345
- {
346
- from: params.fromAddress,
347
- to: SOURCE_ROUTER_ADDRESS,
348
- data: bridgeTxData,
349
- },
350
- expect.any(Function),
351
- );
352
-
353
- expect(sourceClientMock.sendRawTransaction).toHaveBeenCalledTimes(1);
354
- expect(sourceClientMock.sendRawTransaction).toHaveBeenCalledWith({
355
- serializedTransaction: bridgeSignedHex,
356
- });
357
-
358
- expect(onStepChangeSpy).toHaveBeenCalledTimes(1);
359
- expect(onStepChangeSpy).toHaveBeenNthCalledWith(1, {
360
- currentSignature: 1,
361
- requiredSignatures: 1,
362
- currentSignatureReason: BridgeSignatureReason.TokensTransfer,
363
- });
364
- });
365
-
366
- it('works without provided signer', async () => {
367
- const start = 1000;
368
- const dateSpy = jest.spyOn(Date, 'now');
369
- dateSpy.mockReturnValue(start);
370
-
371
- const bridgeTxHash = '0x2';
372
- const bridgeTxRequest = 'bridge-tx-request';
373
- const params = getTransferParams({ sourceProvider: sourceProviderMock });
374
-
375
- sourceClientMock.readContract.mockResolvedValue(params.amount);
376
- sourceClientMock.simulateContract.mockResolvedValueOnce({ request: bridgeTxRequest });
377
- sourceClientMock.writeContract.mockResolvedValueOnce(bridgeTxHash);
378
-
379
- const bridgeTransfer = await transferAsset(bridgeMock, params, environment);
380
-
381
- expect(bridgeTransfer).toStrictEqual(
382
- getBridgeTransferMock({
383
- amount: params.amount,
384
- amountDecimals: params.asset.decimals,
385
- fromAddress: params.fromAddress,
386
- sourceTxHash: bridgeTxHash,
387
- startBlockNumber: targetBlockNumber,
388
- sourceStartedAt: start,
389
- }),
390
- );
391
-
392
- expect(getClientForChain).toHaveBeenCalledTimes(2);
393
- expect(getClientForChain).toHaveBeenNthCalledWith(1, {
394
- chain: params.sourceChain,
395
- provider: sourceProviderMock,
396
- });
397
- expect(getClientForChain).toHaveBeenNthCalledWith(2, {
398
- chain: params.targetChain,
399
- provider: targetProviderMock,
400
- });
401
-
402
- expect(sourceClientMock.readContract).toHaveBeenCalledWith({
403
- address: BRIDGE_ASSET.address,
404
- abi: ERC20_ABI,
405
- functionName: 'allowance',
406
- args: [params.fromAddress, SOURCE_ROUTER_ADDRESS],
407
- });
408
-
409
- expect(sourceClientMock.simulateContract).toHaveBeenCalledTimes(1);
410
- expect(sourceClientMock.simulateContract).toHaveBeenCalledWith({
411
- account: params.fromAddress,
412
- address: SOURCE_ROUTER_ADDRESS,
413
- abi: TOKEN_ROUTER_ABI,
414
- functionName: 'transferTokens',
415
- args: [params.amount, 1, params.fromAddress, BRIDGE_ASSET.address],
416
- });
417
-
418
- expect(sourceClientMock.writeContract).toHaveBeenCalledTimes(1);
419
- expect(sourceClientMock.writeContract).toHaveBeenCalledWith(bridgeTxRequest);
420
-
421
- expect(onStepChangeSpy).toHaveBeenCalledTimes(1);
422
- expect(onStepChangeSpy).toHaveBeenNthCalledWith(1, {
423
- currentSignature: 1,
424
- requiredSignatures: 1,
425
- currentSignatureReason: BridgeSignatureReason.TokensTransfer,
426
- });
427
- });
428
- });
429
- });
@@ -1,179 +0,0 @@
1
- import { isAddress, type PublicClient } from 'viem';
2
- import {
3
- ErrorReason,
4
- type BridgeService,
5
- type Environment,
6
- type TransferParams,
7
- type Hex,
8
- type BridgeTransfer,
9
- BridgeSignatureReason,
10
- } from '../../../types';
11
- import { getClientForChain } from '../../../utils/client';
12
- import { ERC20_ABI } from '../abis/erc20';
13
- import { getTransferData } from '../utils/transfer-data';
14
- import { TOKEN_ROUTER_ABI } from '../abis/token-router';
15
- import { InvalidParamsError } from '../../../errors';
16
- import { buildApprovalTxData, buildTransferTxData } from '../utils/build-tx';
17
-
18
- const approveAndTransfer = async (bridge: BridgeService, params: TransferParams) => {
19
- const {
20
- sourceChain,
21
- targetChain,
22
- asset,
23
- amount,
24
- fromAddress,
25
- toAddress: maybeToAddress,
26
- sourceProvider,
27
- onStepChange,
28
- sign,
29
- } = params;
30
- const toAddress = maybeToAddress ?? fromAddress;
31
-
32
- if (!isAddress(fromAddress) || !isAddress(toAddress)) {
33
- throw new InvalidParamsError(ErrorReason.INCORRECT_ADDRESS_PROVIDED);
34
- }
35
-
36
- const { sourceChainData, targetChainData, burnToken } = getTransferData(
37
- { sourceChain, targetChain, asset, amount },
38
- bridge.config!,
39
- );
40
- const client = getClientForChain({ chain: sourceChain, provider: sourceProvider });
41
-
42
- const allowance = await client.readContract({
43
- address: burnToken.address,
44
- abi: ERC20_ABI,
45
- functionName: 'allowance',
46
- args: [fromAddress, sourceChainData.tokenRouterAddress],
47
- });
48
-
49
- const isAllowanceApprovalRequired = allowance < amount;
50
- const requiredSignatures = isAllowanceApprovalRequired ? 2 : 1; // if approval is required, we'll need 2 signatures
51
-
52
- if (isAllowanceApprovalRequired) {
53
- onStepChange?.({
54
- currentSignature: 1,
55
- currentSignatureReason: BridgeSignatureReason.AllowanceApproval,
56
- requiredSignatures,
57
- });
58
-
59
- if (sign) {
60
- const data = buildApprovalTxData({
61
- amount,
62
- sourceChainData,
63
- });
64
- const txHash = await sign(
65
- {
66
- from: fromAddress,
67
- to: burnToken.address,
68
- data,
69
- },
70
- (signedTxHash: Hex) => client.sendRawTransaction({ serializedTransaction: signedTxHash }),
71
- );
72
-
73
- await client.waitForTransactionReceipt({ hash: txHash, pollingInterval: 1_000 });
74
- } else {
75
- const { request } = await client.simulateContract({
76
- account: fromAddress,
77
- address: burnToken.address,
78
- abi: ERC20_ABI,
79
- functionName: 'approve',
80
- args: [sourceChainData.tokenRouterAddress, amount],
81
- });
82
-
83
- const txHash = await client.writeContract(request);
84
- await client.waitForTransactionReceipt({ hash: txHash, pollingInterval: 1_000 });
85
- }
86
- }
87
-
88
- onStepChange?.({
89
- currentSignature: isAllowanceApprovalRequired ? 2 : 1,
90
- currentSignatureReason: BridgeSignatureReason.TokensTransfer,
91
- requiredSignatures,
92
- });
93
-
94
- if (sign) {
95
- const data = buildTransferTxData({
96
- amount,
97
- burnToken,
98
- targetChainData,
99
- toAddress,
100
- });
101
-
102
- return sign(
103
- {
104
- from: fromAddress,
105
- to: sourceChainData.tokenRouterAddress,
106
- data,
107
- },
108
- (signedTxHash: Hex) => client.sendRawTransaction({ serializedTransaction: signedTxHash }),
109
- );
110
- } else {
111
- const { request } = await client.simulateContract({
112
- account: fromAddress,
113
- address: sourceChainData.tokenRouterAddress,
114
- abi: TOKEN_ROUTER_ABI,
115
- functionName: 'transferTokens',
116
- args: [amount, targetChainData.domain, toAddress, burnToken.address],
117
- });
118
-
119
- return client.writeContract(request);
120
- }
121
- };
122
-
123
- const getStartBlockNumber = async (targetClient: PublicClient) => {
124
- try {
125
- const startBlockNumber = await targetClient.getBlockNumber();
126
- return startBlockNumber;
127
- } catch {
128
- return undefined;
129
- }
130
- };
131
-
132
- export async function transferAsset(
133
- bridge: BridgeService,
134
- params: TransferParams,
135
- environment: Environment,
136
- ): Promise<BridgeTransfer> {
137
- await bridge.ensureHasConfig();
138
-
139
- const { minimumConfirmations: requiredSourceConfirmationCount } =
140
- bridge.config!.find((chainData) => chainData.chainId === params.sourceChain.chainId) ?? {};
141
- const { minimumConfirmations: requiredTargetConfirmationCount } =
142
- bridge.config!.find((chainData) => chainData.chainId === params.targetChain.chainId) ?? {};
143
-
144
- if (!requiredSourceConfirmationCount || !requiredTargetConfirmationCount) {
145
- throw new InvalidParamsError(ErrorReason.CONFIRMATION_COUNT_UNKNOWN);
146
- }
147
-
148
- const fees = await bridge.getFees({ ...params, provider: params.sourceProvider });
149
-
150
- const bridgeFee = (params.asset.address && fees[params.asset.address]) ?? 0n;
151
- const txHash = await approveAndTransfer(bridge, params);
152
- const sourceStartedAt = Date.now();
153
- const targetClient = getClientForChain({ chain: params.targetChain, provider: params.targetProvider });
154
- const targetBlockNumber = await getStartBlockNumber(targetClient);
155
-
156
- return {
157
- type: bridge.type,
158
- environment,
159
- fromAddress: params.fromAddress,
160
- toAddress: params.toAddress ?? params.fromAddress,
161
- amount: params.amount,
162
- amountDecimals: params.asset.decimals,
163
- symbol: params.asset.symbol,
164
-
165
- bridgeFee,
166
-
167
- sourceChain: params.sourceChain,
168
- sourceStartedAt,
169
- sourceTxHash: txHash,
170
- sourceConfirmationCount: 0,
171
- requiredSourceConfirmationCount,
172
-
173
- targetChain: params.targetChain,
174
- targetConfirmationCount: 0,
175
- requiredTargetConfirmationCount,
176
-
177
- startBlockNumber: targetBlockNumber,
178
- };
179
- }
@@ -1 +0,0 @@
1
- export * from './factory';
@@ -1,9 +0,0 @@
1
- export enum AvalancheChainIds {
2
- FUJI = 'eip155:43113',
3
- MAINNET = 'eip155:43114',
4
- }
5
-
6
- export enum ChainDomain {
7
- Ethereum = 0,
8
- Avalanche = 1,
9
- }
@@ -1,20 +0,0 @@
1
- import type { Address } from 'viem';
2
- import type { ChainDomain } from './chain';
3
-
4
- export type Token = {
5
- address: Address;
6
- name: string;
7
- symbol: string;
8
- decimals: number;
9
- };
10
-
11
- export type ChainData = {
12
- chainId: string;
13
- domain: ChainDomain;
14
- tokenRouterAddress: Address;
15
- messageTransmitterAddress: Address;
16
- tokens: Token[];
17
- minimumConfirmations: number;
18
- };
19
-
20
- export type Config = ChainData[];
@@ -1,30 +0,0 @@
1
- import { encodeFunctionData } from 'viem';
2
- import type { ChainData, Token } from '../types/config';
3
- import { TOKEN_ROUTER_ABI } from '../abis/token-router';
4
- import { ERC20_ABI } from '../abis/erc20';
5
-
6
- export function buildTransferTxData({
7
- amount,
8
- burnToken,
9
- targetChainData,
10
- toAddress,
11
- }: {
12
- targetChainData: ChainData;
13
- toAddress: `0x${string}`;
14
- burnToken: Token;
15
- amount: bigint;
16
- }) {
17
- return encodeFunctionData({
18
- abi: TOKEN_ROUTER_ABI,
19
- functionName: 'transferTokens',
20
- args: [amount, targetChainData.domain, toAddress, burnToken.address],
21
- });
22
- }
23
-
24
- export function buildApprovalTxData({ amount, sourceChainData }: { amount: bigint; sourceChainData: ChainData }) {
25
- return encodeFunctionData({
26
- abi: ERC20_ABI,
27
- functionName: 'approve',
28
- args: [sourceChainData.tokenRouterAddress, amount],
29
- });
30
- }