@agglayer/sdk 0.1.0-beta.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,1842 @@
1
+ // src/native/chains/registry.ts
2
+ var ChainRegistry = class _ChainRegistry {
3
+ constructor() {
4
+ this.chains = /* @__PURE__ */ new Map();
5
+ this.viemChains = /* @__PURE__ */ new Map();
6
+ this.initializeDefaultChains();
7
+ }
8
+ static getInstance() {
9
+ if (!_ChainRegistry.instance) {
10
+ _ChainRegistry.instance = new _ChainRegistry();
11
+ }
12
+ return _ChainRegistry.instance;
13
+ }
14
+ initializeDefaultChains() {
15
+ this.registerChain({
16
+ chainId: 11155111,
17
+ networkId: 0,
18
+ name: "Ethereum Sepolia",
19
+ rpcUrl: "https://rpc.sepolia.org",
20
+ nativeCurrency: { name: "Sepolia Ether", symbol: "ETH", decimals: 18 },
21
+ blockExplorer: {
22
+ name: "Sepolia Etherscan",
23
+ url: "https://sepolia.etherscan.io"
24
+ },
25
+ bridgeAddress: "0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582",
26
+ proofApiUrl: "https://api-gateway.polygon.technology/api/v3/proof/testnet/",
27
+ isTestnet: true
28
+ });
29
+ this.registerChain({
30
+ chainId: 2442,
31
+ networkId: 1,
32
+ name: "Polygon Cardona",
33
+ rpcUrl: "https://rpc.cardona.zkevm-rpc.com",
34
+ nativeCurrency: { name: "Ethereum", symbol: "ETH", decimals: 18 },
35
+ blockExplorer: {
36
+ name: "Cardona PolygonScan",
37
+ url: "https://cardona-zkevm.polygonscan.com"
38
+ },
39
+ bridgeAddress: "0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582",
40
+ proofApiUrl: "https://api-gateway.polygon.technology/api/v3/proof/testnet/",
41
+ isTestnet: true
42
+ });
43
+ }
44
+ /**
45
+ * Register a new chain
46
+ */
47
+ registerChain(config) {
48
+ this.chains.set(config.chainId, config);
49
+ const viemChain = {
50
+ id: config.chainId,
51
+ name: config.name,
52
+ nativeCurrency: config.nativeCurrency,
53
+ rpcUrls: {
54
+ default: { http: [config.rpcUrl] }
55
+ }
56
+ };
57
+ this.viemChains.set(config.chainId, viemChain);
58
+ }
59
+ /**
60
+ * Get chain configuration by ID
61
+ */
62
+ getChain(chainId) {
63
+ const chain = this.chains.get(chainId);
64
+ if (!chain) {
65
+ throw new Error(
66
+ `Chain ${chainId} not found. Available chains: ${Array.from(this.chains.keys()).join(", ")}`
67
+ );
68
+ }
69
+ return chain;
70
+ }
71
+ /**
72
+ * Get chain configuration by network ID
73
+ */
74
+ getChainByNetworkId(networkId) {
75
+ const chain = Array.from(this.chains.values()).find(
76
+ (chain2) => chain2.networkId === networkId
77
+ );
78
+ if (!chain) {
79
+ throw new Error(
80
+ `Chain with network ID ${networkId} not found. Available network IDs: ${Array.from(
81
+ this.chains.values()
82
+ ).map((chain2) => chain2.networkId).filter(Boolean).join(", ")}`
83
+ );
84
+ }
85
+ return chain;
86
+ }
87
+ /**
88
+ * Get viem chain object by ID
89
+ */
90
+ getViemChain(chainId) {
91
+ const chain = this.viemChains.get(chainId);
92
+ if (!chain) {
93
+ throw new Error(
94
+ `Chain ${chainId} not found. Available chains: ${Array.from(this.viemChains.keys()).join(", ")}`
95
+ );
96
+ }
97
+ return chain;
98
+ }
99
+ /**
100
+ * Get all registered chain IDs
101
+ */
102
+ getSupportedChainIds() {
103
+ return Array.from(this.chains.keys());
104
+ }
105
+ /**
106
+ * Get all registered chains
107
+ */
108
+ getAllChains() {
109
+ return Array.from(this.chains.values());
110
+ }
111
+ /**
112
+ * Check if chain is supported
113
+ */
114
+ isChainSupported(chainId) {
115
+ return this.chains.has(chainId);
116
+ }
117
+ /**
118
+ * Check if chain is supported by network ID
119
+ */
120
+ isChainSupportedByNetworkId(networkId) {
121
+ return Array.from(this.chains.values()).some(
122
+ (chain) => chain.networkId === networkId
123
+ );
124
+ }
125
+ /**
126
+ * Get chains by type
127
+ */
128
+ getChainsByType(type) {
129
+ return Array.from(this.chains.values()).filter((chain) => {
130
+ if (type === "mainnet") {
131
+ return !chain.isTestnet && !chain.isLocal;
132
+ }
133
+ if (type === "testnet") {
134
+ return chain.isTestnet;
135
+ }
136
+ if (type === "local") {
137
+ return chain.isLocal;
138
+ }
139
+ return false;
140
+ });
141
+ }
142
+ /**
143
+ * Add custom RPC URL for existing chain
144
+ */
145
+ addCustomRpcUrl(chainId, rpcUrl) {
146
+ const chain = this.getChain(chainId);
147
+ const customChain = {
148
+ ...chain,
149
+ rpcUrl
150
+ };
151
+ this.registerChain(customChain);
152
+ }
153
+ };
154
+ var chainRegistry = ChainRegistry.getInstance();
155
+
156
+ // src/native/utils/validation.ts
157
+ var ValidationUtils = class {
158
+ /**
159
+ * Convert value to BigInt safely
160
+ */
161
+ static toBigInt(value) {
162
+ return BigInt(value.toString());
163
+ }
164
+ /**
165
+ * Validate Ethereum address format
166
+ */
167
+ static validateAddress(address, name = "Address") {
168
+ if (!address || !address.startsWith("0x") || address.length !== 42) {
169
+ throw new Error(`${name} must be a valid 0x-prefixed address`);
170
+ }
171
+ }
172
+ /**
173
+ * Validate amount (must be positive)
174
+ */
175
+ static validateAmount(amount, name = "Amount") {
176
+ const amountStr = amount.toString();
177
+ if (!amountStr || amountStr === "0" || this.toBigInt(amount) <= 0n) {
178
+ throw new Error(`${name} must be a positive value`);
179
+ }
180
+ }
181
+ /**
182
+ * Check if address is valid without throwing
183
+ */
184
+ static isValidAddress(address) {
185
+ return Boolean(address) && address.startsWith("0x") && address.length === 42;
186
+ }
187
+ /**
188
+ * Check if amount is valid without throwing
189
+ */
190
+ static isValidAmount(amount) {
191
+ try {
192
+ const amountStr = amount.toString();
193
+ return Boolean(amountStr) && amountStr !== "0" && this.toBigInt(amount) > 0n;
194
+ } catch {
195
+ return false;
196
+ }
197
+ }
198
+ /**
199
+ * Validate chain ID
200
+ */
201
+ static validateChainId(chainId) {
202
+ if (!Number.isInteger(chainId) || chainId <= 0) {
203
+ throw new Error("Chain ID must be a positive integer");
204
+ }
205
+ }
206
+ /**
207
+ * Validate RPC URL
208
+ */
209
+ static validateRpcUrl(rpcUrl) {
210
+ if (!rpcUrl || !rpcUrl.startsWith("http")) {
211
+ throw new Error("RPC URL must be a valid HTTP/HTTPS URL");
212
+ }
213
+ }
214
+ };
215
+
216
+ // src/native/base/contract.ts
217
+ import {
218
+ createPublicClient,
219
+ http
220
+ } from "viem";
221
+ var BaseContract = class {
222
+ constructor(config) {
223
+ const chain = chainRegistry.getViemChain(config.chainId);
224
+ this.client = createPublicClient({
225
+ chain,
226
+ transport: http(config.rpcUrl)
227
+ });
228
+ }
229
+ /**
230
+ * Get nonce for an address
231
+ */
232
+ async getNonce(address) {
233
+ if (!address) return void 0;
234
+ const nonceValue = await this.client.getTransactionCount({
235
+ address
236
+ });
237
+ return `0x${nonceValue.toString(16)}`;
238
+ }
239
+ /**
240
+ * Estimate gas for transaction
241
+ */
242
+ async estimateGas(data, to, from) {
243
+ const gasEstimate = await this.client.estimateGas({
244
+ account: from,
245
+ to,
246
+ data
247
+ });
248
+ return gasEstimate.toString();
249
+ }
250
+ };
251
+
252
+ // src/native/tokens/build.ts
253
+ import { encodeFunctionData } from "viem";
254
+
255
+ // src/native/tokens/abi/erc20.ts
256
+ var erc20Abi = [
257
+ // Standard ERC20 functions
258
+ {
259
+ name: "approve",
260
+ type: "function",
261
+ stateMutability: "nonpayable",
262
+ inputs: [
263
+ { name: "spender", type: "address" },
264
+ { name: "amount", type: "uint256" }
265
+ ],
266
+ outputs: [{ name: "", type: "bool" }]
267
+ },
268
+ {
269
+ name: "transfer",
270
+ type: "function",
271
+ stateMutability: "nonpayable",
272
+ inputs: [
273
+ { name: "to", type: "address" },
274
+ { name: "amount", type: "uint256" }
275
+ ],
276
+ outputs: [{ name: "", type: "bool" }]
277
+ },
278
+ {
279
+ name: "transferFrom",
280
+ type: "function",
281
+ stateMutability: "nonpayable",
282
+ inputs: [
283
+ { name: "from", type: "address" },
284
+ { name: "to", type: "address" },
285
+ { name: "amount", type: "uint256" }
286
+ ],
287
+ outputs: [{ name: "", type: "bool" }]
288
+ },
289
+ {
290
+ name: "allowance",
291
+ type: "function",
292
+ stateMutability: "view",
293
+ inputs: [
294
+ { name: "owner", type: "address" },
295
+ { name: "spender", type: "address" }
296
+ ],
297
+ outputs: [{ name: "", type: "uint256" }]
298
+ },
299
+ {
300
+ name: "balanceOf",
301
+ type: "function",
302
+ stateMutability: "view",
303
+ inputs: [{ name: "account", type: "address" }],
304
+ outputs: [{ name: "", type: "uint256" }]
305
+ },
306
+ // Additional ERC20 functions
307
+ {
308
+ name: "name",
309
+ type: "function",
310
+ stateMutability: "view",
311
+ inputs: [],
312
+ outputs: [{ name: "", type: "string" }]
313
+ },
314
+ {
315
+ name: "symbol",
316
+ type: "function",
317
+ stateMutability: "view",
318
+ inputs: [],
319
+ outputs: [{ name: "", type: "string" }]
320
+ },
321
+ {
322
+ name: "decimals",
323
+ type: "function",
324
+ stateMutability: "view",
325
+ inputs: [],
326
+ outputs: [{ name: "", type: "uint8" }]
327
+ },
328
+ {
329
+ name: "totalSupply",
330
+ type: "function",
331
+ stateMutability: "view",
332
+ inputs: [],
333
+ outputs: [{ name: "", type: "uint256" }]
334
+ },
335
+ // Events
336
+ {
337
+ name: "Transfer",
338
+ type: "event",
339
+ inputs: [
340
+ { name: "from", type: "address", indexed: true },
341
+ { name: "to", type: "address", indexed: true },
342
+ { name: "value", type: "uint256", indexed: false }
343
+ ]
344
+ },
345
+ {
346
+ name: "Approval",
347
+ type: "event",
348
+ inputs: [
349
+ { name: "owner", type: "address", indexed: true },
350
+ { name: "spender", type: "address", indexed: true },
351
+ { name: "value", type: "uint256", indexed: false }
352
+ ]
353
+ }
354
+ ];
355
+
356
+ // src/native/tokens/build.ts
357
+ async function buildApprove(ctx, spender, amount, from) {
358
+ const data = encodeFunctionData({
359
+ abi: erc20Abi,
360
+ functionName: "approve",
361
+ args: [spender, amount]
362
+ });
363
+ const [nonce, gas] = await Promise.all([
364
+ ctx.getNonce(from),
365
+ ctx.estimateGas(data, from)
366
+ ]);
367
+ return {
368
+ from,
369
+ to: ctx.tokenAddress,
370
+ data,
371
+ gas,
372
+ nonce
373
+ };
374
+ }
375
+ async function buildTransfer(ctx, to, amount, from) {
376
+ const data = encodeFunctionData({
377
+ abi: erc20Abi,
378
+ functionName: "transfer",
379
+ args: [to, amount]
380
+ });
381
+ const [nonce, gas] = await Promise.all([
382
+ ctx.getNonce(from),
383
+ ctx.estimateGas(data, from)
384
+ ]);
385
+ return {
386
+ from,
387
+ to: ctx.tokenAddress,
388
+ data,
389
+ gas,
390
+ nonce
391
+ };
392
+ }
393
+ async function buildTransferFrom(ctx, fromAddress, to, amount, spender) {
394
+ const data = encodeFunctionData({
395
+ abi: erc20Abi,
396
+ functionName: "transferFrom",
397
+ args: [fromAddress, to, amount]
398
+ });
399
+ const [nonce, gas] = await Promise.all([
400
+ ctx.getNonce(spender),
401
+ ctx.estimateGas(data, spender)
402
+ ]);
403
+ return {
404
+ from: spender,
405
+ to: ctx.tokenAddress,
406
+ data,
407
+ gas,
408
+ nonce
409
+ };
410
+ }
411
+
412
+ // src/native/bridge/build.ts
413
+ import { encodeFunctionData as encodeFunctionData2 } from "viem";
414
+
415
+ // src/native/bridge/abi/bridge.ts
416
+ var bridgeAbi = [
417
+ {
418
+ inputs: [
419
+ { internalType: "uint32", name: "destinationNetwork", type: "uint32" },
420
+ { internalType: "address", name: "destinationAddress", type: "address" },
421
+ { internalType: "uint256", name: "amount", type: "uint256" },
422
+ { internalType: "address", name: "token", type: "address" },
423
+ { internalType: "bool", name: "forceUpdateGlobalExitRoot", type: "bool" },
424
+ { internalType: "bytes", name: "permitData", type: "bytes" }
425
+ ],
426
+ name: "bridgeAsset",
427
+ outputs: [],
428
+ stateMutability: "payable",
429
+ type: "function"
430
+ },
431
+ {
432
+ inputs: [
433
+ {
434
+ internalType: "bytes32[32]",
435
+ name: "smtProofLocalExitRoot",
436
+ type: "bytes32[32]"
437
+ },
438
+ {
439
+ internalType: "bytes32[32]",
440
+ name: "smtProofRollupExitRoot",
441
+ type: "bytes32[32]"
442
+ },
443
+ { internalType: "uint256", name: "globalIndex", type: "uint256" },
444
+ { internalType: "bytes32", name: "mainnetExitRoot", type: "bytes32" },
445
+ { internalType: "bytes32", name: "rollupExitRoot", type: "bytes32" },
446
+ { internalType: "uint32", name: "originNetwork", type: "uint32" },
447
+ { internalType: "address", name: "originTokenAddress", type: "address" },
448
+ { internalType: "uint32", name: "destinationNetwork", type: "uint32" },
449
+ { internalType: "address", name: "destinationAddress", type: "address" },
450
+ { internalType: "uint256", name: "amount", type: "uint256" },
451
+ { internalType: "bytes", name: "metadata", type: "bytes" }
452
+ ],
453
+ name: "claimAsset",
454
+ outputs: [],
455
+ stateMutability: "nonpayable",
456
+ type: "function"
457
+ },
458
+ {
459
+ inputs: [
460
+ { internalType: "uint32", name: "leafIndex", type: "uint32" },
461
+ { internalType: "uint32", name: "sourceBridgeNetwork", type: "uint32" }
462
+ ],
463
+ name: "isClaimed",
464
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
465
+ stateMutability: "view",
466
+ type: "function"
467
+ },
468
+ {
469
+ inputs: [
470
+ { internalType: "uint32", name: "originNetwork", type: "uint32" },
471
+ { internalType: "address", name: "originTokenAddress", type: "address" }
472
+ ],
473
+ name: "getTokenWrappedAddress",
474
+ outputs: [{ internalType: "address", name: "", type: "address" }],
475
+ stateMutability: "view",
476
+ type: "function"
477
+ },
478
+ {
479
+ inputs: [
480
+ { internalType: "uint32", name: "destinationNetwork", type: "uint32" },
481
+ { internalType: "address", name: "destinationAddress", type: "address" },
482
+ { internalType: "bool", name: "forceUpdateGlobalExitRoot", type: "bool" },
483
+ { internalType: "bytes", name: "permitData", type: "bytes" }
484
+ ],
485
+ name: "bridgeMessage",
486
+ outputs: [],
487
+ stateMutability: "payable",
488
+ type: "function"
489
+ },
490
+ {
491
+ inputs: [
492
+ {
493
+ internalType: "bytes32[32]",
494
+ name: "smtProofLocalExitRoot",
495
+ type: "bytes32[32]"
496
+ },
497
+ {
498
+ internalType: "bytes32[32]",
499
+ name: "smtProofRollupExitRoot",
500
+ type: "bytes32[32]"
501
+ },
502
+ { internalType: "uint256", name: "globalIndex", type: "uint256" },
503
+ { internalType: "bytes32", name: "mainnetExitRoot", type: "bytes32" },
504
+ { internalType: "bytes32", name: "rollupExitRoot", type: "bytes32" },
505
+ { internalType: "uint32", name: "originNetwork", type: "uint32" },
506
+ { internalType: "address", name: "originTokenAddress", type: "address" },
507
+ { internalType: "uint32", name: "destinationNetwork", type: "uint32" },
508
+ { internalType: "address", name: "destinationAddress", type: "address" },
509
+ { internalType: "uint256", name: "amount", type: "uint256" },
510
+ { internalType: "bytes", name: "metadata", type: "bytes" }
511
+ ],
512
+ name: "claimMessage",
513
+ outputs: [],
514
+ stateMutability: "nonpayable",
515
+ type: "function"
516
+ },
517
+ {
518
+ inputs: [
519
+ { internalType: "uint32", name: "originNetwork", type: "uint32" },
520
+ { internalType: "address", name: "originTokenAddress", type: "address" }
521
+ ],
522
+ name: "precalculatedWrapperAddress",
523
+ outputs: [{ internalType: "address", name: "", type: "address" }],
524
+ stateMutability: "view",
525
+ type: "function"
526
+ },
527
+ {
528
+ inputs: [
529
+ { internalType: "address", name: "wrappedToken", type: "address" }
530
+ ],
531
+ name: "wrappedTokenToTokenInfo",
532
+ outputs: [
533
+ { internalType: "uint32", name: "originNetwork", type: "uint32" },
534
+ { internalType: "address", name: "originTokenAddress", type: "address" }
535
+ ],
536
+ stateMutability: "view",
537
+ type: "function"
538
+ },
539
+ {
540
+ inputs: [],
541
+ name: "networkID",
542
+ outputs: [{ internalType: "uint32", name: "", type: "uint32" }],
543
+ stateMutability: "view",
544
+ type: "function"
545
+ },
546
+ {
547
+ anonymous: false,
548
+ inputs: [
549
+ {
550
+ indexed: false,
551
+ internalType: "uint8",
552
+ name: "leafType",
553
+ type: "uint8"
554
+ },
555
+ {
556
+ indexed: false,
557
+ internalType: "uint32",
558
+ name: "originNetwork",
559
+ type: "uint32"
560
+ },
561
+ {
562
+ indexed: false,
563
+ internalType: "address",
564
+ name: "originAddress",
565
+ type: "address"
566
+ },
567
+ {
568
+ indexed: false,
569
+ internalType: "uint32",
570
+ name: "destinationNetwork",
571
+ type: "uint32"
572
+ },
573
+ {
574
+ indexed: false,
575
+ internalType: "address",
576
+ name: "destinationAddress",
577
+ type: "address"
578
+ },
579
+ {
580
+ indexed: false,
581
+ internalType: "uint256",
582
+ name: "amount",
583
+ type: "uint256"
584
+ },
585
+ {
586
+ indexed: false,
587
+ internalType: "bytes",
588
+ name: "metadata",
589
+ type: "bytes"
590
+ },
591
+ {
592
+ indexed: false,
593
+ internalType: "uint32",
594
+ name: "depositCount",
595
+ type: "uint32"
596
+ }
597
+ ],
598
+ name: "BridgeEvent",
599
+ type: "event"
600
+ }
601
+ ];
602
+
603
+ // src/native/bridge/build.ts
604
+ async function buildBridgeAsset(ctx, destinationNetwork, destinationAddress, amount, token, forceUpdateGlobalExitRoot, permitData = "0x", from) {
605
+ const data = encodeFunctionData2({
606
+ abi: bridgeAbi,
607
+ functionName: "bridgeAsset",
608
+ args: [
609
+ destinationNetwork,
610
+ destinationAddress,
611
+ amount,
612
+ token,
613
+ forceUpdateGlobalExitRoot,
614
+ permitData
615
+ ]
616
+ });
617
+ const [nonce, gas] = await Promise.all([
618
+ ctx.getNonce(from),
619
+ ctx.estimateGas(data, ctx.bridgeAddress, from)
620
+ ]);
621
+ return {
622
+ from,
623
+ to: ctx.bridgeAddress,
624
+ data,
625
+ gas,
626
+ nonce
627
+ };
628
+ }
629
+ async function buildClaimAsset(ctx, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadata, from) {
630
+ const data = encodeFunctionData2({
631
+ abi: bridgeAbi,
632
+ functionName: "claimAsset",
633
+ args: [
634
+ // @ts-ignore - Viem expects exact tuple types but we're passing arrays
635
+ smtProofLocalExitRoot,
636
+ // @ts-ignore - Viem expects exact tuple types but we're passing arrays
637
+ smtProofRollupExitRoot,
638
+ globalIndex,
639
+ mainnetExitRoot,
640
+ rollupExitRoot,
641
+ originNetwork,
642
+ originTokenAddress,
643
+ destinationNetwork,
644
+ destinationAddress,
645
+ amount,
646
+ metadata
647
+ ]
648
+ });
649
+ const [nonce, gas] = await Promise.all([
650
+ ctx.getNonce(from),
651
+ ctx.estimateGas(data, ctx.bridgeAddress, from)
652
+ ]);
653
+ return {
654
+ from,
655
+ to: ctx.bridgeAddress,
656
+ data,
657
+ gas,
658
+ nonce
659
+ };
660
+ }
661
+
662
+ // src/native/bridge/message.ts
663
+ import { encodeFunctionData as encodeFunctionData3 } from "viem";
664
+ async function buildBridgeMessage(ctx, destinationNetwork, destinationAddress, forceUpdateGlobalExitRoot, permitData = "0x", from) {
665
+ const data = encodeFunctionData3({
666
+ abi: bridgeAbi,
667
+ functionName: "bridgeMessage",
668
+ args: [
669
+ destinationNetwork,
670
+ destinationAddress,
671
+ forceUpdateGlobalExitRoot,
672
+ permitData
673
+ ]
674
+ });
675
+ const [nonce, gas] = await Promise.all([
676
+ ctx.getNonce(from),
677
+ ctx.estimateGas(data, ctx.bridgeAddress, from)
678
+ ]);
679
+ return {
680
+ from,
681
+ to: ctx.bridgeAddress,
682
+ data,
683
+ gas,
684
+ nonce
685
+ };
686
+ }
687
+ async function buildClaimMessage(ctx, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadata, from) {
688
+ const data = encodeFunctionData3({
689
+ abi: bridgeAbi,
690
+ functionName: "claimMessage",
691
+ args: [
692
+ // @ts-ignore - Viem expects exact tuple types but we're passing arrays
693
+ smtProofLocalExitRoot,
694
+ // @ts-ignore - Viem expects exact tuple types but we're passing arrays
695
+ smtProofRollupExitRoot,
696
+ globalIndex,
697
+ mainnetExitRoot,
698
+ rollupExitRoot,
699
+ originNetwork,
700
+ originTokenAddress,
701
+ destinationNetwork,
702
+ destinationAddress,
703
+ amount,
704
+ metadata
705
+ ]
706
+ });
707
+ const [nonce, gas] = await Promise.all([
708
+ ctx.getNonce(from),
709
+ ctx.estimateGas(data, ctx.bridgeAddress, from)
710
+ ]);
711
+ return {
712
+ from,
713
+ to: ctx.bridgeAddress,
714
+ data,
715
+ gas,
716
+ nonce
717
+ };
718
+ }
719
+
720
+ // src/native/bridge/util.ts
721
+ import {
722
+ decodeEventLog,
723
+ createPublicClient as createPublicClient2,
724
+ http as http2
725
+ } from "viem";
726
+ var BridgeUtil = class _BridgeUtil {
727
+ constructor(client, proofApiUrl) {
728
+ this.BRIDGE_TOPIC = "0x501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b";
729
+ this.client = client;
730
+ this.proofApiUrl = proofApiUrl;
731
+ }
732
+ /**
733
+ * Create BridgeUtil instance from network ID using chain registry
734
+ *
735
+ * @param sourceNetworkId - Network ID of the source network
736
+ * @returns BridgeUtil instance configured for the source network
737
+ */
738
+ static async fromNetworkId(sourceNetworkId) {
739
+ const chain = _BridgeUtil.findChain(sourceNetworkId);
740
+ if (!chain.proofApiUrl) {
741
+ throw new Error(
742
+ `No proof API URL configured for network ${sourceNetworkId}`
743
+ );
744
+ }
745
+ const sourceClient = createPublicClient2({
746
+ transport: http2(chain.rpcUrl)
747
+ });
748
+ return new _BridgeUtil(sourceClient, chain.proofApiUrl);
749
+ }
750
+ /**
751
+ * Find chain configuration by network ID
752
+ *
753
+ * @param sourceNetworkId - Network ID to search for
754
+ * @returns Chain configuration
755
+ * @throws Error if chain not found
756
+ */
757
+ static findChain(sourceNetworkId) {
758
+ try {
759
+ return chainRegistry.getChainByNetworkId(sourceNetworkId);
760
+ } catch {
761
+ const allChains = chainRegistry.getAllChains();
762
+ const availableNetworkIds = allChains.map((chain) => chain.networkId).filter(Boolean).join(", ");
763
+ throw new Error(
764
+ `Source network ${sourceNetworkId} not found in chain registry. Available network IDs: ${availableNetworkIds}`
765
+ );
766
+ }
767
+ }
768
+ /**
769
+ * Extract bridge event data from transaction receipt
770
+ */
771
+ async extractBridgeEvent(transactionHash, _networkId, bridgeIndex = 0) {
772
+ try {
773
+ const receipt = await this.client.getTransactionReceipt({
774
+ hash: transactionHash
775
+ });
776
+ const bridgeLogs = receipt.logs.filter(
777
+ (log2) => log2.topics[0] && log2.topics[0].toLowerCase() === this.BRIDGE_TOPIC.toLowerCase()
778
+ );
779
+ if (!bridgeLogs.length) {
780
+ throw new Error("No bridge event found in transaction receipt");
781
+ }
782
+ if (bridgeIndex >= bridgeLogs.length) {
783
+ throw new Error(
784
+ `Bridge index ${bridgeIndex} not found. Available indices: 0-${bridgeLogs.length - 1}`
785
+ );
786
+ }
787
+ const log = bridgeLogs[bridgeIndex];
788
+ if (!log) {
789
+ throw new Error("Bridge log not found");
790
+ }
791
+ const decoded = decodeEventLog({
792
+ abi: bridgeAbi,
793
+ data: log.data,
794
+ topics: log.topics
795
+ });
796
+ if (decoded.eventName !== "BridgeEvent") {
797
+ throw new Error("Invalid bridge event");
798
+ }
799
+ const args = decoded.args;
800
+ const {
801
+ originNetwork,
802
+ originAddress,
803
+ destinationNetwork,
804
+ destinationAddress,
805
+ amount,
806
+ metadata,
807
+ depositCount
808
+ } = args;
809
+ return {
810
+ originNetwork: Number(originNetwork),
811
+ originTokenAddress: originAddress,
812
+ destinationNetwork: Number(destinationNetwork),
813
+ destinationAddress,
814
+ amount,
815
+ metadata: metadata || "0x",
816
+ depositCount: Number(depositCount)
817
+ };
818
+ } catch (error) {
819
+ if (error instanceof Error) {
820
+ throw new Error(`Failed to extract bridge event: ${error.message}`);
821
+ }
822
+ throw new Error("Failed to extract bridge event: Unknown error");
823
+ }
824
+ }
825
+ /**
826
+ * Fetch merkle proof from Polygon's proof API
827
+ */
828
+ async fetchMerkleProof(networkId, depositCount) {
829
+ try {
830
+ const baseUrl = this.proofApiUrl.endsWith("/") ? this.proofApiUrl : `${this.proofApiUrl}/`;
831
+ const url = `${baseUrl}merkle-proof?networkId=${networkId}&depositCount=${depositCount}`;
832
+ const response = await fetch(url);
833
+ if (!response.ok) {
834
+ throw new Error(
835
+ `Failed to fetch merkle proof: ${response.statusText} (${response.status})`
836
+ );
837
+ }
838
+ const data = await response.json();
839
+ if (!data.proof) {
840
+ throw new Error("Invalid response format: missing proof data");
841
+ }
842
+ return data.proof;
843
+ } catch (error) {
844
+ if (error instanceof Error) {
845
+ throw new Error(`Failed to fetch merkle proof: ${error.message}`);
846
+ }
847
+ throw new Error("Failed to fetch merkle proof: Unknown error");
848
+ }
849
+ }
850
+ /**
851
+ * Compute global index from local index and network ID
852
+ */
853
+ computeGlobalIndex(indexLocal, sourceNetworkId) {
854
+ const MAINNET_FLAG = BigInt(2 ** 64);
855
+ if (BigInt(sourceNetworkId) === BigInt(0)) {
856
+ return BigInt(indexLocal) + MAINNET_FLAG;
857
+ } else {
858
+ return BigInt(indexLocal) + BigInt(sourceNetworkId - 1) * BigInt(2 ** 32);
859
+ }
860
+ }
861
+ /**
862
+ * Build claim payload from transaction hash (user-friendly method)
863
+ */
864
+ async buildPayloadForClaim(transactionHash, sourceNetworkId, bridgeIndex = 0) {
865
+ const bridgeEvent = await this.extractBridgeEvent(
866
+ transactionHash,
867
+ sourceNetworkId,
868
+ bridgeIndex
869
+ );
870
+ const proof = await this.fetchMerkleProof(
871
+ sourceNetworkId,
872
+ bridgeEvent.depositCount
873
+ );
874
+ const globalIndex = this.computeGlobalIndex(
875
+ bridgeEvent.depositCount,
876
+ sourceNetworkId
877
+ );
878
+ return {
879
+ smtProof: proof.merkle_proof,
880
+ smtProofRollup: proof.rollup_merkle_proof,
881
+ globalIndex: globalIndex.toString(),
882
+ mainnetExitRoot: proof.main_exit_root,
883
+ rollupExitRoot: proof.rollup_exit_root,
884
+ originNetwork: bridgeEvent.originNetwork,
885
+ originTokenAddress: bridgeEvent.originTokenAddress,
886
+ destinationNetwork: bridgeEvent.destinationNetwork,
887
+ destinationAddress: bridgeEvent.destinationAddress,
888
+ amount: bridgeEvent.amount,
889
+ metadata: bridgeEvent.metadata
890
+ };
891
+ }
892
+ /**
893
+ * Build claim asset parameters from transaction hash
894
+ */
895
+ async buildClaimAssetParams(transactionHash, sourceNetworkId, bridgeIndex = 0) {
896
+ const payload = await this.buildPayloadForClaim(
897
+ transactionHash,
898
+ sourceNetworkId,
899
+ bridgeIndex
900
+ );
901
+ return {
902
+ smtProofLocalExitRoot: payload.smtProof,
903
+ smtProofRollupExitRoot: payload.smtProofRollup,
904
+ globalIndex: BigInt(payload.globalIndex),
905
+ mainnetExitRoot: payload.mainnetExitRoot,
906
+ rollupExitRoot: payload.rollupExitRoot,
907
+ originNetwork: payload.originNetwork,
908
+ originTokenAddress: payload.originTokenAddress,
909
+ destinationNetwork: payload.destinationNetwork,
910
+ destinationAddress: payload.destinationAddress,
911
+ amount: payload.amount,
912
+ metadata: payload.metadata
913
+ };
914
+ }
915
+ /**
916
+ * Build claim message parameters from transaction hash
917
+ */
918
+ async buildClaimMessageParams(transactionHash, sourceNetworkId, bridgeIndex = 0) {
919
+ const payload = await this.buildPayloadForClaim(
920
+ transactionHash,
921
+ sourceNetworkId,
922
+ bridgeIndex
923
+ );
924
+ return {
925
+ smtProofLocalExitRoot: payload.smtProof,
926
+ smtProofRollupExitRoot: payload.smtProofRollup,
927
+ globalIndex: BigInt(payload.globalIndex),
928
+ mainnetExitRoot: payload.mainnetExitRoot,
929
+ rollupExitRoot: payload.rollupExitRoot,
930
+ originNetwork: payload.originNetwork,
931
+ originTokenAddress: payload.originTokenAddress,
932
+ destinationNetwork: payload.destinationNetwork,
933
+ destinationAddress: payload.destinationAddress,
934
+ amount: payload.amount,
935
+ metadata: payload.metadata
936
+ };
937
+ }
938
+ /**
939
+ * Get bridge event info from transaction hash
940
+ */
941
+ async getBridgeEventInfo(transactionHash, sourceNetworkId, bridgeIndex = 0) {
942
+ return this.extractBridgeEvent(
943
+ transactionHash,
944
+ sourceNetworkId,
945
+ bridgeIndex
946
+ );
947
+ }
948
+ };
949
+
950
+ // src/native/bridge/bridge.ts
951
+ var Bridge = class extends BaseContract {
952
+ constructor(config) {
953
+ super({ rpcUrl: config.rpcUrl, chainId: config.chainId });
954
+ this.bridgeAddress = config.bridgeAddress;
955
+ }
956
+ /**
957
+ * Build bridge asset transaction
958
+ */
959
+ async buildBridgeAsset(params, from) {
960
+ ValidationUtils.validateAddress(
961
+ params.destinationAddress,
962
+ "Destination address"
963
+ );
964
+ ValidationUtils.validateAddress(params.token, "Token address");
965
+ return buildBridgeAsset(
966
+ {
967
+ bridgeAddress: this.bridgeAddress,
968
+ estimateGas: (data, to, from2) => this.estimateGas(data, to, from2),
969
+ getNonce: (address) => this.getNonce(address)
970
+ },
971
+ params.destinationNetwork,
972
+ params.destinationAddress,
973
+ BigInt(params.amount),
974
+ params.token,
975
+ params.forceUpdateGlobalExitRoot,
976
+ params.permitData,
977
+ from
978
+ );
979
+ }
980
+ /**
981
+ * Build claim asset transaction
982
+ */
983
+ async buildClaimAsset(params, from) {
984
+ ValidationUtils.validateAddress(
985
+ params.originTokenAddress,
986
+ "Origin token address"
987
+ );
988
+ ValidationUtils.validateAddress(
989
+ params.destinationAddress,
990
+ "Destination address"
991
+ );
992
+ return buildClaimAsset(
993
+ {
994
+ bridgeAddress: this.bridgeAddress,
995
+ estimateGas: (data, to, from2) => this.estimateGas(data, to, from2),
996
+ getNonce: (address) => this.getNonce(address)
997
+ },
998
+ params.smtProofLocalExitRoot,
999
+ params.smtProofRollupExitRoot,
1000
+ params.globalIndex,
1001
+ params.mainnetExitRoot,
1002
+ params.rollupExitRoot,
1003
+ params.originNetwork,
1004
+ params.originTokenAddress,
1005
+ params.destinationNetwork,
1006
+ params.destinationAddress,
1007
+ params.amount,
1008
+ params.metadata,
1009
+ from
1010
+ );
1011
+ }
1012
+ /**
1013
+ * Check if bridge deposit is claimed
1014
+ */
1015
+ async isClaimed(params) {
1016
+ const result = await this.client.readContract({
1017
+ address: this.bridgeAddress,
1018
+ abi: bridgeAbi,
1019
+ functionName: "isClaimed",
1020
+ args: [params.leafIndex, params.sourceBridgeNetwork]
1021
+ });
1022
+ return result;
1023
+ }
1024
+ /**
1025
+ * Get wrapped token address
1026
+ */
1027
+ async getWrappedTokenAddress(params) {
1028
+ ValidationUtils.validateAddress(
1029
+ params.originTokenAddress,
1030
+ "Origin token address"
1031
+ );
1032
+ const result = await this.client.readContract({
1033
+ address: this.bridgeAddress,
1034
+ abi: bridgeAbi,
1035
+ functionName: "getTokenWrappedAddress",
1036
+ args: [params.originNetwork, params.originTokenAddress]
1037
+ });
1038
+ return result;
1039
+ }
1040
+ /**
1041
+ * Get network ID
1042
+ */
1043
+ async getNetworkId() {
1044
+ const result = await this.client.readContract({
1045
+ address: this.bridgeAddress,
1046
+ abi: bridgeAbi,
1047
+ functionName: "networkID",
1048
+ args: []
1049
+ });
1050
+ return Number(result);
1051
+ }
1052
+ /**
1053
+ * Get bridge contract address
1054
+ */
1055
+ getBridgeAddress() {
1056
+ return this.bridgeAddress;
1057
+ }
1058
+ /**
1059
+ * Build bridge message transaction
1060
+ */
1061
+ async buildBridgeMessage(params, from) {
1062
+ ValidationUtils.validateAddress(
1063
+ params.destinationAddress,
1064
+ "Destination address"
1065
+ );
1066
+ return buildBridgeMessage(
1067
+ {
1068
+ bridgeAddress: this.bridgeAddress,
1069
+ estimateGas: (data, to, from2) => this.estimateGas(data, to, from2),
1070
+ getNonce: (address) => this.getNonce(address)
1071
+ },
1072
+ params.destinationNetwork,
1073
+ params.destinationAddress,
1074
+ params.forceUpdateGlobalExitRoot,
1075
+ params.permitData || "0x",
1076
+ from
1077
+ );
1078
+ }
1079
+ /**
1080
+ * Build claim message transaction
1081
+ */
1082
+ async buildClaimMessage(params, from) {
1083
+ ValidationUtils.validateAddress(
1084
+ params.originTokenAddress,
1085
+ "Origin token address"
1086
+ );
1087
+ ValidationUtils.validateAddress(
1088
+ params.destinationAddress,
1089
+ "Destination address"
1090
+ );
1091
+ return buildClaimMessage(
1092
+ {
1093
+ bridgeAddress: this.bridgeAddress,
1094
+ estimateGas: (data, to, from2) => this.estimateGas(data, to, from2),
1095
+ getNonce: (address) => this.getNonce(address)
1096
+ },
1097
+ params.smtProofLocalExitRoot,
1098
+ params.smtProofRollupExitRoot,
1099
+ params.globalIndex,
1100
+ params.mainnetExitRoot,
1101
+ params.rollupExitRoot,
1102
+ params.originNetwork,
1103
+ params.originTokenAddress,
1104
+ params.destinationNetwork,
1105
+ params.destinationAddress,
1106
+ params.amount,
1107
+ params.metadata,
1108
+ from
1109
+ );
1110
+ }
1111
+ /**
1112
+ * Get precalculated wrapper address
1113
+ */
1114
+ async getPrecalculatedWrapperAddress(params) {
1115
+ ValidationUtils.validateAddress(
1116
+ params.originTokenAddress,
1117
+ "Origin token address"
1118
+ );
1119
+ const result = await this.client.readContract({
1120
+ address: this.bridgeAddress,
1121
+ abi: bridgeAbi,
1122
+ functionName: "precalculatedWrapperAddress",
1123
+ args: [params.originNetwork, params.originTokenAddress]
1124
+ });
1125
+ return result;
1126
+ }
1127
+ /**
1128
+ * Get origin token info from wrapped token
1129
+ */
1130
+ async getOriginTokenInfo(params) {
1131
+ ValidationUtils.validateAddress(
1132
+ params.wrappedToken,
1133
+ "Wrapped token address"
1134
+ );
1135
+ const result = await this.client.readContract({
1136
+ address: this.bridgeAddress,
1137
+ abi: bridgeAbi,
1138
+ functionName: "wrappedTokenToTokenInfo",
1139
+ args: [params.wrappedToken]
1140
+ });
1141
+ return result;
1142
+ }
1143
+ /**
1144
+ * Build claim asset transaction from bridge transaction hash
1145
+ *
1146
+ * @param transactionHash - Hash of the bridge transaction on the source network
1147
+ * @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
1148
+ * @param bridgeIndex - Index of bridge event in transaction (default: 0)
1149
+ * @param from - From address for the claim transaction
1150
+ */
1151
+ async buildClaimAssetFromHash(transactionHash, sourceNetworkId, bridgeIndex = 0, from) {
1152
+ const bridgeUtil = await BridgeUtil.fromNetworkId(sourceNetworkId);
1153
+ const params = await bridgeUtil.buildClaimAssetParams(
1154
+ transactionHash,
1155
+ sourceNetworkId,
1156
+ bridgeIndex
1157
+ );
1158
+ return this.buildClaimAsset(params, from);
1159
+ }
1160
+ /**
1161
+ * Build claim message transaction from bridge transaction hash
1162
+ *
1163
+ * @param transactionHash - Hash of the bridge transaction on the source network
1164
+ * @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
1165
+ * @param bridgeIndex - Index of bridge event in transaction (default: 0)
1166
+ * @param from - From address for the claim transaction
1167
+ */
1168
+ async buildClaimMessageFromHash(transactionHash, sourceNetworkId, bridgeIndex = 0, from) {
1169
+ const bridgeUtil = await BridgeUtil.fromNetworkId(sourceNetworkId);
1170
+ const params = await bridgeUtil.buildClaimMessageParams(
1171
+ transactionHash,
1172
+ sourceNetworkId,
1173
+ bridgeIndex
1174
+ );
1175
+ return this.buildClaimMessage(params, from);
1176
+ }
1177
+ /**
1178
+ * Get bridge event info from transaction hash
1179
+ *
1180
+ * @param transactionHash - Hash of the bridge transaction on the source network
1181
+ * @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
1182
+ * @param bridgeIndex - Index of bridge event in transaction (default: 0)
1183
+ */
1184
+ async getBridgeEventInfo(transactionHash, sourceNetworkId, bridgeIndex = 0) {
1185
+ const bridgeUtil = await BridgeUtil.fromNetworkId(sourceNetworkId);
1186
+ return bridgeUtil.getBridgeEventInfo(
1187
+ transactionHash,
1188
+ sourceNetworkId,
1189
+ bridgeIndex
1190
+ );
1191
+ }
1192
+ };
1193
+
1194
+ // src/native/services/abi.ts
1195
+ var ABIS = {
1196
+ BRIDGE: bridgeAbi,
1197
+ ERC20: erc20Abi
1198
+ };
1199
+ function getAbi(contractType) {
1200
+ return ABIS[contractType];
1201
+ }
1202
+
1203
+ // src/native/tokens/erc20.ts
1204
+ var ERC20 = class extends BaseContract {
1205
+ constructor(config) {
1206
+ super({ rpcUrl: config.rpcUrl, chainId: config.chainId });
1207
+ this.tokenAddress = config.tokenAddress;
1208
+ this.config = config;
1209
+ }
1210
+ /**
1211
+ * Get ERC20 token balance in wei
1212
+ */
1213
+ async getBalance(address) {
1214
+ ValidationUtils.validateAddress(address, "Address");
1215
+ const balance = await this.client.readContract({
1216
+ address: this.tokenAddress,
1217
+ abi: getAbi("ERC20"),
1218
+ functionName: "balanceOf",
1219
+ args: [address]
1220
+ });
1221
+ return balance.toString();
1222
+ }
1223
+ /**
1224
+ * Get allowance in wei
1225
+ */
1226
+ async getAllowance(owner, spender) {
1227
+ ValidationUtils.validateAddress(owner, "Owner address");
1228
+ ValidationUtils.validateAddress(spender, "Spender address");
1229
+ try {
1230
+ const allowance = await this.client.readContract({
1231
+ address: this.tokenAddress,
1232
+ abi: getAbi("ERC20"),
1233
+ functionName: "allowance",
1234
+ args: [owner, spender]
1235
+ });
1236
+ return allowance.toString();
1237
+ } catch (error) {
1238
+ throw new Error(
1239
+ `Failed to get allowance: ${error instanceof Error ? error.message : "Unknown error"}`
1240
+ );
1241
+ }
1242
+ }
1243
+ /**
1244
+ * Build approve transaction
1245
+ */
1246
+ async buildApprove(spender, amount, from) {
1247
+ ValidationUtils.validateAddress(spender, "Spender address");
1248
+ ValidationUtils.validateAmount(amount, "Amount");
1249
+ return buildApprove(
1250
+ {
1251
+ tokenAddress: this.tokenAddress,
1252
+ estimateGas: (data, from2) => this.estimateGas(data, this.tokenAddress, from2),
1253
+ getNonce: (address) => this.getNonce(address)
1254
+ },
1255
+ spender,
1256
+ BigInt(amount),
1257
+ from
1258
+ );
1259
+ }
1260
+ /**
1261
+ * Build transfer transaction
1262
+ */
1263
+ async buildTransfer(to, amount, from) {
1264
+ ValidationUtils.validateAddress(to, "Recipient address");
1265
+ ValidationUtils.validateAmount(amount, "Amount");
1266
+ return buildTransfer(
1267
+ {
1268
+ tokenAddress: this.tokenAddress,
1269
+ estimateGas: (data, from2) => this.estimateGas(data, this.tokenAddress, from2),
1270
+ getNonce: (address) => this.getNonce(address)
1271
+ },
1272
+ to,
1273
+ BigInt(amount),
1274
+ from
1275
+ );
1276
+ }
1277
+ /**
1278
+ * Build transferFrom transaction
1279
+ */
1280
+ async buildTransferFrom(from, to, amount, spender) {
1281
+ ValidationUtils.validateAddress(from, "Owner address");
1282
+ ValidationUtils.validateAddress(to, "Recipient address");
1283
+ ValidationUtils.validateAmount(amount, "Amount");
1284
+ return buildTransferFrom(
1285
+ {
1286
+ tokenAddress: this.tokenAddress,
1287
+ estimateGas: (data, from2) => this.estimateGas(data, this.tokenAddress, from2),
1288
+ getNonce: (address) => this.getNonce(address)
1289
+ },
1290
+ from,
1291
+ to,
1292
+ BigInt(amount),
1293
+ spender
1294
+ );
1295
+ }
1296
+ /**
1297
+ * Bridge this token to another network
1298
+ */
1299
+ async bridgeTo(destinationNetwork, destinationAddress, amount, from, options = {}) {
1300
+ ValidationUtils.validateAddress(destinationAddress, "Destination address");
1301
+ ValidationUtils.validateAmount(amount, "Amount");
1302
+ const bridge = this.getBridge();
1303
+ return bridge.buildBridgeAsset(
1304
+ {
1305
+ destinationNetwork,
1306
+ destinationAddress,
1307
+ amount,
1308
+ token: this.tokenAddress,
1309
+ forceUpdateGlobalExitRoot: options.forceUpdateGlobalExitRoot ?? true,
1310
+ permitData: options.permitData || "0x"
1311
+ },
1312
+ from
1313
+ );
1314
+ }
1315
+ /**
1316
+ * Get wrapped version of this token on destination network
1317
+ */
1318
+ async getWrappedToken() {
1319
+ const bridge = this.getBridge();
1320
+ return bridge.getWrappedTokenAddress({
1321
+ originNetwork: this.config.chainId,
1322
+ originTokenAddress: this.tokenAddress
1323
+ });
1324
+ }
1325
+ /**
1326
+ * Claim asset from bridge transaction hash
1327
+ *
1328
+ * @param transactionHash - Hash of the bridge transaction on the source network
1329
+ * @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
1330
+ * @param bridgeIndex - Index of bridge event in transaction (default: 0)
1331
+ * @param from - From address for the claim transaction
1332
+ */
1333
+ async claimAsset(transactionHash, sourceNetworkId, bridgeIndex = 0, from) {
1334
+ const bridge = this.getBridge();
1335
+ return bridge.buildClaimAssetFromHash(
1336
+ transactionHash,
1337
+ sourceNetworkId,
1338
+ bridgeIndex,
1339
+ from
1340
+ );
1341
+ }
1342
+ /**
1343
+ * Claim message from bridge transaction hash
1344
+ *
1345
+ * @param transactionHash - Hash of the bridge transaction on the source network
1346
+ * @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
1347
+ * @param bridgeIndex - Index of bridge event in transaction (default: 0)
1348
+ * @param from - From address for the claim transaction
1349
+ */
1350
+ async claimMessage(transactionHash, sourceNetworkId, bridgeIndex = 0, from) {
1351
+ const bridge = this.getBridge();
1352
+ return bridge.buildClaimMessageFromHash(
1353
+ transactionHash,
1354
+ sourceNetworkId,
1355
+ bridgeIndex,
1356
+ from
1357
+ );
1358
+ }
1359
+ /**
1360
+ * Get bridge event info from transaction hash
1361
+ *
1362
+ * @param transactionHash - Hash of the bridge transaction on the source network
1363
+ * @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
1364
+ * @param bridgeIndex - Index of bridge event in transaction (default: 0)
1365
+ */
1366
+ async getBridgeEventInfo(transactionHash, sourceNetworkId, bridgeIndex = 0) {
1367
+ const bridge = this.getBridge();
1368
+ return bridge.getBridgeEventInfo(
1369
+ transactionHash,
1370
+ sourceNetworkId,
1371
+ bridgeIndex
1372
+ );
1373
+ }
1374
+ getBridge() {
1375
+ const chain = chainRegistry.getChain(this.config.chainId);
1376
+ if (!chain.bridgeAddress) {
1377
+ throw new Error(
1378
+ `No bridge address configured for network ${this.config.chainId}`
1379
+ );
1380
+ }
1381
+ return new Bridge({
1382
+ bridgeAddress: chain.bridgeAddress,
1383
+ rpcUrl: this.config.rpcUrl,
1384
+ chainId: this.config.chainId
1385
+ });
1386
+ }
1387
+ };
1388
+
1389
+ // src/native/index.ts
1390
+ import { createPublicClient as createPublicClient3, http as http3 } from "viem";
1391
+
1392
+ // src/constants.ts
1393
+ var NETWORKS = {
1394
+ SEPOLIA: 11155111,
1395
+ CARDONA: 2442
1396
+ };
1397
+ var DEFAULT_NETWORK = NETWORKS.SEPOLIA;
1398
+
1399
+ // src/native/index.ts
1400
+ var NativeClient = class {
1401
+ constructor(config) {
1402
+ this.config = config;
1403
+ this.defaultNetwork = this.config.defaultNetwork || DEFAULT_NETWORK;
1404
+ if (this.config.chains) {
1405
+ this.config.chains.forEach((chain) => {
1406
+ chainRegistry.registerChain(chain);
1407
+ });
1408
+ }
1409
+ if (this.config.customRpcUrls) {
1410
+ Object.entries(this.config.customRpcUrls).forEach(([chainId, rpcUrl]) => {
1411
+ chainRegistry.addCustomRpcUrl(Number(chainId), rpcUrl);
1412
+ });
1413
+ }
1414
+ }
1415
+ /**
1416
+ * Get network configuration from chain registry
1417
+ * @param networkId - The network ID (chain ID)
1418
+ * @returns Chain configuration
1419
+ */
1420
+ getNetwork(networkId) {
1421
+ return chainRegistry.getChain(networkId);
1422
+ }
1423
+ /**
1424
+ * Get all supported networks
1425
+ * @returns Array of network IDs
1426
+ */
1427
+ getSupportedNetworks() {
1428
+ return chainRegistry.getSupportedChainIds();
1429
+ }
1430
+ /**
1431
+ * Get default network ID
1432
+ * @returns Default network ID
1433
+ */
1434
+ getDefaultNetwork() {
1435
+ return this.defaultNetwork;
1436
+ }
1437
+ /**
1438
+ * Get chain registry for advanced usage
1439
+ */
1440
+ getChainRegistry() {
1441
+ return chainRegistry;
1442
+ }
1443
+ /**
1444
+ * Create an ERC20 instance for a specific token on a specific network
1445
+ * @param tokenAddress - The ERC20 token contract address
1446
+ * @param networkId - The network ID (optional, uses default if not provided)
1447
+ * @returns ERC20 instance
1448
+ */
1449
+ erc20(tokenAddress, networkId) {
1450
+ const network = this.getNetwork(networkId || this.defaultNetwork);
1451
+ return new ERC20({
1452
+ tokenAddress,
1453
+ rpcUrl: network.rpcUrl,
1454
+ chainId: network.chainId
1455
+ });
1456
+ }
1457
+ /**
1458
+ * Get native token balance in wei
1459
+ * @param address - The address to check balance for
1460
+ * @param networkId - The network ID (optional, uses default if not provided)
1461
+ * @returns Native token balance as string
1462
+ */
1463
+ async getNativeBalance(address, networkId) {
1464
+ ValidationUtils.validateAddress(address, "Address");
1465
+ const network = this.getNetwork(networkId || this.defaultNetwork);
1466
+ const client = createPublicClient3({
1467
+ chain: {
1468
+ id: network.chainId,
1469
+ name: network.name,
1470
+ nativeCurrency: network.nativeCurrency,
1471
+ rpcUrls: {
1472
+ default: { http: [network.rpcUrl] },
1473
+ public: { http: [network.rpcUrl] }
1474
+ }
1475
+ },
1476
+ transport: http3(network.rpcUrl)
1477
+ });
1478
+ const balance = await client.getBalance({ address });
1479
+ return balance.toString();
1480
+ }
1481
+ /**
1482
+ * Create a Bridge instance for a specific network
1483
+ * @param bridgeAddress - The bridge contract address
1484
+ * @param networkId - The network ID (optional, uses default if not provided)
1485
+ * @returns Bridge instance
1486
+ */
1487
+ bridge(bridgeAddress, networkId) {
1488
+ const network = this.getNetwork(networkId || this.defaultNetwork);
1489
+ return new Bridge({
1490
+ bridgeAddress,
1491
+ rpcUrl: network.rpcUrl,
1492
+ chainId: network.chainId
1493
+ });
1494
+ }
1495
+ };
1496
+
1497
+ // src/types/config.ts
1498
+ var SDK_MODES = {
1499
+ CORE: "CORE",
1500
+ NATIVE: "NATIVE"
1501
+ };
1502
+
1503
+ // src/core/utils/httpClient.ts
1504
+ var HttpClient = class {
1505
+ constructor(config) {
1506
+ this.config = {
1507
+ timeout: 3e4,
1508
+ retries: 3,
1509
+ retryDelay: 1e3,
1510
+ defaultHeaders: {
1511
+ "Content-Type": "application/json"
1512
+ },
1513
+ ...config
1514
+ };
1515
+ }
1516
+ async request(url, config) {
1517
+ const fullUrl = this.buildUrl(url);
1518
+ const requestConfig = this.buildRequestConfig(config);
1519
+ let lastError;
1520
+ for (let attempt = 0; attempt <= (this.config.retries ?? 3); attempt++) {
1521
+ try {
1522
+ const response = await this.makeRequest(fullUrl, requestConfig);
1523
+ return response;
1524
+ } catch (error) {
1525
+ lastError = error;
1526
+ if (attempt === (this.config.retries ?? 3) || !this.isRetryableError(error)) {
1527
+ break;
1528
+ }
1529
+ if (attempt < (this.config.retries ?? 3)) {
1530
+ await this.delay(
1531
+ (this.config.retryDelay ?? 1e3) * Math.pow(2, attempt)
1532
+ );
1533
+ }
1534
+ }
1535
+ }
1536
+ throw new Error(
1537
+ `Request failed after ${this.config.retries ?? 3} retries: ${lastError?.message ?? "Unknown error"}`
1538
+ );
1539
+ }
1540
+ async get(url, params) {
1541
+ const queryString = params ? this.buildQueryString(params) : "";
1542
+ const fullUrl = queryString ? `${url}?${queryString}` : url;
1543
+ return this.request(fullUrl, { method: "GET" });
1544
+ }
1545
+ async post(url, data, config) {
1546
+ return this.request(url, {
1547
+ method: "POST",
1548
+ body: data,
1549
+ ...config
1550
+ });
1551
+ }
1552
+ buildUrl(url) {
1553
+ if (url.startsWith("http://") || url.startsWith("https://")) {
1554
+ return url;
1555
+ }
1556
+ return `${this.config.baseUrl}${url.startsWith("/") ? url : `/${url}`}`;
1557
+ }
1558
+ buildRequestConfig(config) {
1559
+ const headers = new Headers(this.config.defaultHeaders);
1560
+ if (config.headers) {
1561
+ Object.entries(config.headers).forEach(([key, value]) => {
1562
+ headers.set(key, value);
1563
+ });
1564
+ }
1565
+ const requestConfig = {
1566
+ method: config.method,
1567
+ headers
1568
+ };
1569
+ if (config.body) {
1570
+ if (typeof config.body === "string") {
1571
+ requestConfig.body = config.body;
1572
+ } else {
1573
+ requestConfig.body = JSON.stringify(config.body);
1574
+ }
1575
+ }
1576
+ return requestConfig;
1577
+ }
1578
+ async makeRequest(url, config) {
1579
+ const controller = new AbortController();
1580
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
1581
+ try {
1582
+ const response = await fetch(url, {
1583
+ ...config,
1584
+ signal: controller.signal
1585
+ });
1586
+ clearTimeout(timeoutId);
1587
+ if (!response.ok) {
1588
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
1589
+ }
1590
+ let data;
1591
+ const contentType = response.headers.get("content-type");
1592
+ if (contentType?.includes("application/json")) {
1593
+ data = await response.json();
1594
+ } else {
1595
+ data = await response.text();
1596
+ }
1597
+ return {
1598
+ data,
1599
+ status: response.status,
1600
+ statusText: response.statusText,
1601
+ headers: response.headers,
1602
+ ok: response.ok
1603
+ };
1604
+ } catch (error) {
1605
+ clearTimeout(timeoutId);
1606
+ if (error instanceof Error && error.name === "AbortError") {
1607
+ throw new Error(`Request timeout after ${this.config.timeout}ms`);
1608
+ }
1609
+ throw error;
1610
+ }
1611
+ }
1612
+ buildQueryString(params) {
1613
+ const flattenedParams = this.flattenParams(params);
1614
+ return Object.entries(flattenedParams).filter(([, value]) => value !== void 0 && value !== null).map(
1615
+ ([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`
1616
+ ).join("&");
1617
+ }
1618
+ flattenParams(params, prefix = "") {
1619
+ const result = {};
1620
+ for (const [key, value] of Object.entries(params)) {
1621
+ const fullKey = prefix ? `${prefix}[${key}]` : key;
1622
+ if (value === void 0 || value === null) {
1623
+ continue;
1624
+ }
1625
+ if (Array.isArray(value)) {
1626
+ value.forEach((item, index) => {
1627
+ if (item !== void 0 && item !== null) {
1628
+ result[`${fullKey}[${index}]`] = String(item);
1629
+ }
1630
+ });
1631
+ } else if (typeof value === "object") {
1632
+ Object.assign(
1633
+ result,
1634
+ this.flattenParams(value, fullKey)
1635
+ );
1636
+ } else {
1637
+ result[fullKey] = String(value);
1638
+ }
1639
+ }
1640
+ return result;
1641
+ }
1642
+ isRetryableError(error) {
1643
+ if (error instanceof Error) {
1644
+ const message = error.message.toLowerCase();
1645
+ return message.includes("timeout") || message.includes("network") || message.includes("fetch");
1646
+ }
1647
+ return false;
1648
+ }
1649
+ delay(ms) {
1650
+ return new Promise((resolve) => setTimeout(resolve, ms));
1651
+ }
1652
+ };
1653
+
1654
+ // src/core/services/arcApi.ts
1655
+ var ArcApiService = class {
1656
+ constructor({ baseUrl, timeout }) {
1657
+ this.httpClient = new HttpClient({ baseUrl, timeout });
1658
+ }
1659
+ // responsible for both chains metadata and tokens
1660
+ async chains({
1661
+ withSupportedTokens = false,
1662
+ limit = 20,
1663
+ startAfter = 0,
1664
+ chainIds
1665
+ } = {}) {
1666
+ return this.httpClient.get("/metadata/chains", {
1667
+ withSupportedTokens,
1668
+ limit,
1669
+ startAfter,
1670
+ chainIds
1671
+ });
1672
+ }
1673
+ async routes(routesRequestParams) {
1674
+ return this.httpClient.post("/routes", routesRequestParams);
1675
+ }
1676
+ async buildTransaction(builtTransactionRequestBody) {
1677
+ return this.httpClient.post(
1678
+ "/build-transaction",
1679
+ builtTransactionRequestBody
1680
+ );
1681
+ }
1682
+ async transactions(transactionsRequestQueryParams) {
1683
+ return this.httpClient.get("/transactions", {
1684
+ transactionsRequestQueryParams
1685
+ });
1686
+ }
1687
+ };
1688
+
1689
+ // src/core/index.ts
1690
+ var CoreClient = class {
1691
+ constructor(config) {
1692
+ this.config = config;
1693
+ if (!this.config) {
1694
+ throw new Error("Config is required");
1695
+ }
1696
+ if (!this.config.apiBaseUrl) {
1697
+ throw new Error("API base URL is required");
1698
+ }
1699
+ const { apiBaseUrl, apiTimeout } = this.config;
1700
+ this.arcApiService = new ArcApiService({
1701
+ baseUrl: apiBaseUrl,
1702
+ timeout: apiTimeout ?? 3e4
1703
+ });
1704
+ }
1705
+ /**
1706
+ * Get all chains metadata from AggLayer API
1707
+ */
1708
+ async getAllChains() {
1709
+ const response = await this.arcApiService.chains();
1710
+ if (response.data.status === "success") {
1711
+ return response.data.data;
1712
+ }
1713
+ throw new Error(response.data.message);
1714
+ }
1715
+ /**
1716
+ * Get chain metadata by id from AggLayer API
1717
+ * @param ids - the ids of the chains to get metadata for
1718
+ */
1719
+ async getChainMetadataByChainIds(ids) {
1720
+ const response = await this.arcApiService.chains({ chainIds: ids });
1721
+ if (response.data.status === "success") {
1722
+ return response.data.data;
1723
+ }
1724
+ throw new Error(response.data.message);
1725
+ }
1726
+ /**
1727
+ * Get all tokens from AggLayer API
1728
+ */
1729
+ async getTokens() {
1730
+ const response = await this.arcApiService.chains({
1731
+ withSupportedTokens: true
1732
+ });
1733
+ if (response.data.status === "success") {
1734
+ return response.data.data;
1735
+ }
1736
+ throw new Error(response.data.message);
1737
+ }
1738
+ /**
1739
+ * Get chain data and tokens by AggLayer API
1740
+ * @param ids - the ids of the chains to get data and tokens for
1741
+ */
1742
+ async getChainDataAndTokensByChainIds(ids) {
1743
+ const response = await this.arcApiService.chains({
1744
+ chainIds: ids,
1745
+ withSupportedTokens: true
1746
+ });
1747
+ if (response.data.status === "success") {
1748
+ return response.data.data;
1749
+ }
1750
+ throw new Error(response.data.message);
1751
+ }
1752
+ /**
1753
+ * Get all routes from AggLayer API
1754
+ */
1755
+ async getRoutes(routesRequestParams) {
1756
+ const response = await this.arcApiService.routes(routesRequestParams);
1757
+ if (response.data.status === "success") {
1758
+ return response.data.data;
1759
+ }
1760
+ throw new Error(response.data.message);
1761
+ }
1762
+ /**
1763
+ * Build transaction from a step object
1764
+ */
1765
+ async buildTransaction(builtTransactionRequestBody) {
1766
+ const response = await this.arcApiService.buildTransaction(
1767
+ builtTransactionRequestBody
1768
+ );
1769
+ if (response.data.status === "success") {
1770
+ return response.data.data;
1771
+ }
1772
+ throw new Error(response.data.message);
1773
+ }
1774
+ /**
1775
+ * Get all transactions via web sockets
1776
+ */
1777
+ async getTransactions(transactionsRequestQueryParams) {
1778
+ const response = await this.arcApiService.transactions(
1779
+ transactionsRequestQueryParams
1780
+ );
1781
+ if (response.data.status === "success") {
1782
+ return response.data.data;
1783
+ }
1784
+ throw new Error(response.data.message);
1785
+ }
1786
+ };
1787
+
1788
+ // src/index.ts
1789
+ var AggLayerSDK = class {
1790
+ constructor(config) {
1791
+ this.config = config;
1792
+ if (!config.mode || config.mode && config.mode.length === 0) {
1793
+ this.config.mode = ["CORE"];
1794
+ }
1795
+ if (config.mode.includes(SDK_MODES.CORE)) {
1796
+ if (!this.config.core) {
1797
+ throw new Error("Core config is required");
1798
+ }
1799
+ this.core = new CoreClient(this.config.core);
1800
+ }
1801
+ if (this.config.mode?.includes(SDK_MODES.NATIVE)) {
1802
+ if (!this.config.native) {
1803
+ throw new Error("NATIVE config is required");
1804
+ }
1805
+ const nativeConfig = {
1806
+ defaultNetwork: this.config.native?.defaultNetwork || DEFAULT_NETWORK,
1807
+ ...this.config.native?.chains && {
1808
+ chains: this.config.native.chains
1809
+ },
1810
+ ...this.config.native?.customRpcUrls && {
1811
+ customRpcUrls: this.config.native.customRpcUrls
1812
+ }
1813
+ };
1814
+ this.native = new NativeClient(nativeConfig);
1815
+ }
1816
+ }
1817
+ /**
1818
+ * Get core submodule
1819
+ */
1820
+ getCore() {
1821
+ if (!this.core) {
1822
+ throw new Error('Core module not initialized. Add "core" to mode array.');
1823
+ }
1824
+ return this.core;
1825
+ }
1826
+ /**
1827
+ * Get native submodule
1828
+ */
1829
+ getNative() {
1830
+ if (!this.native) {
1831
+ throw new Error(
1832
+ 'NATIVE module not initialized. Add "native" to mode array.'
1833
+ );
1834
+ }
1835
+ return this.native;
1836
+ }
1837
+ };
1838
+ export {
1839
+ AggLayerSDK,
1840
+ SDK_MODES
1841
+ };
1842
+ //# sourceMappingURL=index.mjs.map