@circle-fin/provider-cctp-v2 1.4.0 → 1.4.1
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/CHANGELOG.md +6 -0
- package/README.md +5 -5
- package/index.cjs +1471 -640
- package/index.d.ts +655 -32
- package/index.mjs +1471 -640
- package/package.json +1 -6
package/index.cjs
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
'use strict';
|
|
20
20
|
|
|
21
21
|
// Buffer polyfill setup - executes before any other code
|
|
22
|
-
// Ensures globalThis.Buffer is available for
|
|
22
|
+
// Ensures globalThis.Buffer is available for Solana libraries
|
|
23
23
|
const { Buffer } = require('buffer');
|
|
24
24
|
if (typeof globalThis !== 'undefined' && typeof globalThis.Buffer === 'undefined') {
|
|
25
25
|
globalThis.Buffer = Buffer;
|
|
@@ -116,6 +116,122 @@ var Blockchain;
|
|
|
116
116
|
Blockchain["ZKSync_Era"] = "ZKSync_Era";
|
|
117
117
|
Blockchain["ZKSync_Sepolia"] = "ZKSync_Sepolia";
|
|
118
118
|
})(Blockchain || (Blockchain = {}));
|
|
119
|
+
/**
|
|
120
|
+
* Enum representing the subset of {@link Blockchain} that supports swap operations.
|
|
121
|
+
*
|
|
122
|
+
* This enum provides compile-time type safety for swap chain selection,
|
|
123
|
+
* ensuring only supported chains are available in IDE autocomplete
|
|
124
|
+
* when building swap parameters.
|
|
125
|
+
*
|
|
126
|
+
* @remarks
|
|
127
|
+
* Unlike the full {@link Blockchain} enum, SwapChain only includes networks
|
|
128
|
+
* where the swap functionality is actively supported by the library.
|
|
129
|
+
* Using this enum prevents runtime errors from attempting unsupported
|
|
130
|
+
* cross-chain swaps.
|
|
131
|
+
*
|
|
132
|
+
* Currently supports:
|
|
133
|
+
* - Ethereum mainnet
|
|
134
|
+
* - Base mainnet
|
|
135
|
+
* - Polygon mainnet
|
|
136
|
+
* - Solana mainnet
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* import { SwapChain, swap, createSwapKitContext } from '@circle-fin/swap-kit'
|
|
141
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
142
|
+
*
|
|
143
|
+
* const context = createSwapKitContext()
|
|
144
|
+
* const adapter = createViemAdapterFromPrivateKey({
|
|
145
|
+
* privateKey: process.env.PRIVATE_KEY
|
|
146
|
+
* })
|
|
147
|
+
*
|
|
148
|
+
* // ✅ Autocomplete shows only swap-supported chains
|
|
149
|
+
* const result = await swap(context, {
|
|
150
|
+
* from: {
|
|
151
|
+
* adapter,
|
|
152
|
+
* chain: SwapChain.Ethereum // Autocomplete: Ethereum, Base, Polygon, Solana
|
|
153
|
+
* },
|
|
154
|
+
* tokenIn: 'USDC',
|
|
155
|
+
* tokenOut: 'USDT',
|
|
156
|
+
* amount: '100.0'
|
|
157
|
+
* })
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* // String literals also work (constrained to SwapChain values)
|
|
163
|
+
* const result = await swap(context, {
|
|
164
|
+
* from: {
|
|
165
|
+
* adapter,
|
|
166
|
+
* chain: 'Ethereum' // ✅ Only SwapChain strings allowed
|
|
167
|
+
* },
|
|
168
|
+
* tokenIn: 'USDC',
|
|
169
|
+
* tokenOut: 'NATIVE',
|
|
170
|
+
* amount: '50.0'
|
|
171
|
+
* })
|
|
172
|
+
*
|
|
173
|
+
* // ❌ TypeScript error - Sui not in SwapChain enum
|
|
174
|
+
* const invalidResult = await swap(context, {
|
|
175
|
+
* from: {
|
|
176
|
+
* adapter,
|
|
177
|
+
* chain: 'Sui' // Compile-time error!
|
|
178
|
+
* },
|
|
179
|
+
* tokenIn: 'USDC',
|
|
180
|
+
* tokenOut: 'USDT',
|
|
181
|
+
* amount: '100.0'
|
|
182
|
+
* })
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
/**
|
|
186
|
+
* Enum representing chains that support same-chain swaps through the Swap Kit.
|
|
187
|
+
*
|
|
188
|
+
* Unlike the full {@link Blockchain} enum, SwapChain includes only mainnet
|
|
189
|
+
* networks where adapter contracts are deployed (CCTPv2 support).
|
|
190
|
+
*
|
|
191
|
+
* Dynamic validation via {@link isSwapSupportedChain} ensures chains
|
|
192
|
+
* automatically work when adapter contracts and supported tokens are deployed.
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* import { SwapChain } from '@core/chains'
|
|
197
|
+
* import { swap } from '@circle-fin/swap-kit'
|
|
198
|
+
*
|
|
199
|
+
* const result = await swap(context, {
|
|
200
|
+
* from: {
|
|
201
|
+
* adapter,
|
|
202
|
+
* chain: SwapChain.Arbitrum // Now supported!
|
|
203
|
+
* },
|
|
204
|
+
* tokenIn: 'USDC',
|
|
205
|
+
* tokenOut: 'WETH',
|
|
206
|
+
* amount: '100.0'
|
|
207
|
+
* })
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* @see {@link isSwapSupportedChain} for runtime validation
|
|
211
|
+
* @see {@link getSwapSupportedChains} for all supported chains
|
|
212
|
+
*/
|
|
213
|
+
var SwapChain;
|
|
214
|
+
(function (SwapChain) {
|
|
215
|
+
// Original 4 chains
|
|
216
|
+
SwapChain["Ethereum"] = "Ethereum";
|
|
217
|
+
SwapChain["Base"] = "Base";
|
|
218
|
+
SwapChain["Polygon"] = "Polygon";
|
|
219
|
+
SwapChain["Solana"] = "Solana";
|
|
220
|
+
// Additional supported chains
|
|
221
|
+
SwapChain["Arbitrum"] = "Arbitrum";
|
|
222
|
+
SwapChain["Optimism"] = "Optimism";
|
|
223
|
+
SwapChain["Avalanche"] = "Avalanche";
|
|
224
|
+
SwapChain["Linea"] = "Linea";
|
|
225
|
+
SwapChain["Ink"] = "Ink";
|
|
226
|
+
SwapChain["World_Chain"] = "World_Chain";
|
|
227
|
+
SwapChain["Unichain"] = "Unichain";
|
|
228
|
+
SwapChain["Plume"] = "Plume";
|
|
229
|
+
SwapChain["Sei"] = "Sei";
|
|
230
|
+
SwapChain["Sonic"] = "Sonic";
|
|
231
|
+
SwapChain["XDC"] = "XDC";
|
|
232
|
+
SwapChain["HyperEVM"] = "HyperEVM";
|
|
233
|
+
SwapChain["Monad"] = "Monad";
|
|
234
|
+
})(SwapChain || (SwapChain = {}));
|
|
119
235
|
// -----------------------------------------------------------------------------
|
|
120
236
|
// Bridge Chain Enum (CCTPv2 Supported Chains)
|
|
121
237
|
// -----------------------------------------------------------------------------
|
|
@@ -267,6 +383,7 @@ const Algorand = defineChain({
|
|
|
267
383
|
rpcEndpoints: ['https://mainnet-api.algonode.cloud'],
|
|
268
384
|
eurcAddress: null,
|
|
269
385
|
usdcAddress: '31566704',
|
|
386
|
+
usdtAddress: null,
|
|
270
387
|
cctp: null,
|
|
271
388
|
});
|
|
272
389
|
|
|
@@ -290,6 +407,7 @@ const AlgorandTestnet = defineChain({
|
|
|
290
407
|
rpcEndpoints: ['https://testnet-api.algonode.cloud'],
|
|
291
408
|
eurcAddress: null,
|
|
292
409
|
usdcAddress: '10458941',
|
|
410
|
+
usdtAddress: null,
|
|
293
411
|
cctp: null,
|
|
294
412
|
});
|
|
295
413
|
|
|
@@ -313,6 +431,7 @@ const Aptos = defineChain({
|
|
|
313
431
|
rpcEndpoints: ['https://fullnode.mainnet.aptoslabs.com/v1'],
|
|
314
432
|
eurcAddress: null,
|
|
315
433
|
usdcAddress: '0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b',
|
|
434
|
+
usdtAddress: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
316
435
|
cctp: {
|
|
317
436
|
domain: 9,
|
|
318
437
|
contracts: {
|
|
@@ -350,6 +469,7 @@ const AptosTestnet = defineChain({
|
|
|
350
469
|
rpcEndpoints: ['https://fullnode.testnet.aptoslabs.com/v1'],
|
|
351
470
|
eurcAddress: null,
|
|
352
471
|
usdcAddress: '0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832',
|
|
472
|
+
usdtAddress: null,
|
|
353
473
|
cctp: {
|
|
354
474
|
domain: 9,
|
|
355
475
|
contracts: {
|
|
@@ -367,6 +487,121 @@ const AptosTestnet = defineChain({
|
|
|
367
487
|
},
|
|
368
488
|
});
|
|
369
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Complete swap token registry - single source of truth for all swap-supported tokens.
|
|
492
|
+
*
|
|
493
|
+
* @remarks
|
|
494
|
+
* All packages should import from this registry for swap operations.
|
|
495
|
+
* Adding a new swap token requires updating only this registry.
|
|
496
|
+
*
|
|
497
|
+
* The NATIVE token is handled separately as it resolves dynamically based on chain.
|
|
498
|
+
*
|
|
499
|
+
* @example
|
|
500
|
+
* ```typescript
|
|
501
|
+
* import { SWAP_TOKEN_REGISTRY } from '@core/chains'
|
|
502
|
+
*
|
|
503
|
+
* // Get token decimals
|
|
504
|
+
* const decimals = SWAP_TOKEN_REGISTRY.USDC.decimals // 6
|
|
505
|
+
*
|
|
506
|
+
* // Check if token is stablecoin
|
|
507
|
+
* const isStable = SWAP_TOKEN_REGISTRY.DAI.category === 'stablecoin' // true
|
|
508
|
+
* ```
|
|
509
|
+
*/
|
|
510
|
+
const SWAP_TOKEN_REGISTRY = {
|
|
511
|
+
// ============================================================================
|
|
512
|
+
// Stablecoins (6 decimals)
|
|
513
|
+
// ============================================================================
|
|
514
|
+
USDC: {
|
|
515
|
+
symbol: 'USDC',
|
|
516
|
+
decimals: 6,
|
|
517
|
+
category: 'stablecoin',
|
|
518
|
+
description: 'USD Coin',
|
|
519
|
+
},
|
|
520
|
+
EURC: {
|
|
521
|
+
symbol: 'EURC',
|
|
522
|
+
decimals: 6,
|
|
523
|
+
category: 'stablecoin',
|
|
524
|
+
description: 'Euro Coin',
|
|
525
|
+
},
|
|
526
|
+
USDT: {
|
|
527
|
+
symbol: 'USDT',
|
|
528
|
+
decimals: 6,
|
|
529
|
+
category: 'stablecoin',
|
|
530
|
+
description: 'Tether USD',
|
|
531
|
+
},
|
|
532
|
+
PYUSD: {
|
|
533
|
+
symbol: 'PYUSD',
|
|
534
|
+
decimals: 6,
|
|
535
|
+
category: 'stablecoin',
|
|
536
|
+
description: 'PayPal USD',
|
|
537
|
+
},
|
|
538
|
+
// ============================================================================
|
|
539
|
+
// Stablecoins (18 decimals)
|
|
540
|
+
// ============================================================================
|
|
541
|
+
DAI: {
|
|
542
|
+
symbol: 'DAI',
|
|
543
|
+
decimals: 18,
|
|
544
|
+
category: 'stablecoin',
|
|
545
|
+
description: 'MakerDAO stablecoin',
|
|
546
|
+
},
|
|
547
|
+
USDE: {
|
|
548
|
+
symbol: 'USDE',
|
|
549
|
+
decimals: 18,
|
|
550
|
+
category: 'stablecoin',
|
|
551
|
+
description: 'Ethena USD (synthetic dollar)',
|
|
552
|
+
},
|
|
553
|
+
// ============================================================================
|
|
554
|
+
// Wrapped Tokens
|
|
555
|
+
// ============================================================================
|
|
556
|
+
WBTC: {
|
|
557
|
+
symbol: 'WBTC',
|
|
558
|
+
decimals: 8,
|
|
559
|
+
category: 'wrapped',
|
|
560
|
+
description: 'Wrapped Bitcoin',
|
|
561
|
+
},
|
|
562
|
+
WETH: {
|
|
563
|
+
symbol: 'WETH',
|
|
564
|
+
decimals: 18,
|
|
565
|
+
category: 'wrapped',
|
|
566
|
+
description: 'Wrapped Ethereum',
|
|
567
|
+
},
|
|
568
|
+
WSOL: {
|
|
569
|
+
symbol: 'WSOL',
|
|
570
|
+
decimals: 9,
|
|
571
|
+
category: 'wrapped',
|
|
572
|
+
description: 'Wrapped Solana',
|
|
573
|
+
},
|
|
574
|
+
WAVAX: {
|
|
575
|
+
symbol: 'WAVAX',
|
|
576
|
+
decimals: 18,
|
|
577
|
+
category: 'wrapped',
|
|
578
|
+
description: 'Wrapped Avalanche',
|
|
579
|
+
},
|
|
580
|
+
WPOL: {
|
|
581
|
+
symbol: 'WPOL',
|
|
582
|
+
decimals: 18,
|
|
583
|
+
category: 'wrapped',
|
|
584
|
+
description: 'Wrapped Polygon',
|
|
585
|
+
},
|
|
586
|
+
};
|
|
587
|
+
/**
|
|
588
|
+
* Special NATIVE token constant for swap operations.
|
|
589
|
+
*
|
|
590
|
+
* @remarks
|
|
591
|
+
* NATIVE is handled separately from SWAP_TOKEN_REGISTRY because it resolves
|
|
592
|
+
* dynamically based on the chain (ETH on Ethereum, SOL on Solana, etc.).
|
|
593
|
+
* Its decimals are chain-specific.
|
|
594
|
+
*/
|
|
595
|
+
const NATIVE_TOKEN = 'NATIVE';
|
|
596
|
+
/**
|
|
597
|
+
* Array of all supported swap token symbols including NATIVE.
|
|
598
|
+
* Useful for iteration, validation, and filtering.
|
|
599
|
+
*/
|
|
600
|
+
[
|
|
601
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
602
|
+
NATIVE_TOKEN,
|
|
603
|
+
];
|
|
604
|
+
|
|
370
605
|
/**
|
|
371
606
|
* The bridge contract address for EVM testnet networks.
|
|
372
607
|
*
|
|
@@ -383,6 +618,13 @@ const BRIDGE_CONTRACT_EVM_TESTNET = '0xC5567a5E3370d4DBfB0540025078e283e36A363d'
|
|
|
383
618
|
* USDC transfers on live networks.
|
|
384
619
|
*/
|
|
385
620
|
const BRIDGE_CONTRACT_EVM_MAINNET = '0xB3FA262d0fB521cc93bE83d87b322b8A23DAf3F0';
|
|
621
|
+
/**
|
|
622
|
+
* The adapter contract address for EVM mainnet networks.
|
|
623
|
+
*
|
|
624
|
+
* This contract serves as an adapter for integrating with various protocols
|
|
625
|
+
* on EVM-compatible chains. Use this address for mainnet adapter integrations.
|
|
626
|
+
*/
|
|
627
|
+
const ADAPTER_CONTRACT_EVM_MAINNET = '0x7FB8c7260b63934d8da38aF902f87ae6e284a845';
|
|
386
628
|
|
|
387
629
|
/**
|
|
388
630
|
* Arc Testnet chain definition
|
|
@@ -412,6 +654,7 @@ const ArcTestnet = defineChain({
|
|
|
412
654
|
rpcEndpoints: ['https://rpc.testnet.arc.network/'],
|
|
413
655
|
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
414
656
|
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
657
|
+
usdtAddress: null,
|
|
415
658
|
cctp: {
|
|
416
659
|
domain: 26,
|
|
417
660
|
contracts: {
|
|
@@ -454,6 +697,7 @@ const Arbitrum = defineChain({
|
|
|
454
697
|
rpcEndpoints: ['https://arb1.arbitrum.io/rpc'],
|
|
455
698
|
eurcAddress: null,
|
|
456
699
|
usdcAddress: '0xaf88d065e77c8cc2239327c5edb3a432268e5831',
|
|
700
|
+
usdtAddress: null,
|
|
457
701
|
cctp: {
|
|
458
702
|
domain: 3,
|
|
459
703
|
contracts: {
|
|
@@ -478,6 +722,7 @@ const Arbitrum = defineChain({
|
|
|
478
722
|
},
|
|
479
723
|
kitContracts: {
|
|
480
724
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
725
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
481
726
|
},
|
|
482
727
|
});
|
|
483
728
|
|
|
@@ -502,6 +747,7 @@ const ArbitrumSepolia = defineChain({
|
|
|
502
747
|
rpcEndpoints: ['https://sepolia-rollup.arbitrum.io/rpc'],
|
|
503
748
|
eurcAddress: null,
|
|
504
749
|
usdcAddress: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
750
|
+
usdtAddress: null,
|
|
505
751
|
cctp: {
|
|
506
752
|
domain: 3,
|
|
507
753
|
contracts: {
|
|
@@ -550,6 +796,7 @@ const Avalanche = defineChain({
|
|
|
550
796
|
rpcEndpoints: ['https://api.avax.network/ext/bc/C/rpc'],
|
|
551
797
|
eurcAddress: '0xc891eb4cbdeff6e073e859e987815ed1505c2acd',
|
|
552
798
|
usdcAddress: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
799
|
+
usdtAddress: '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7',
|
|
553
800
|
cctp: {
|
|
554
801
|
domain: 1,
|
|
555
802
|
contracts: {
|
|
@@ -574,6 +821,7 @@ const Avalanche = defineChain({
|
|
|
574
821
|
},
|
|
575
822
|
kitContracts: {
|
|
576
823
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
824
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
577
825
|
},
|
|
578
826
|
});
|
|
579
827
|
|
|
@@ -597,6 +845,7 @@ const AvalancheFuji = defineChain({
|
|
|
597
845
|
explorerUrl: 'https://subnets-test.avax.network/c-chain/tx/{hash}',
|
|
598
846
|
eurcAddress: '0x5e44db7996c682e92a960b65ac713a54ad815c6b',
|
|
599
847
|
usdcAddress: '0x5425890298aed601595a70ab815c96711a31bc65',
|
|
848
|
+
usdtAddress: null,
|
|
600
849
|
cctp: {
|
|
601
850
|
domain: 1,
|
|
602
851
|
contracts: {
|
|
@@ -646,6 +895,7 @@ const Base = defineChain({
|
|
|
646
895
|
rpcEndpoints: ['https://mainnet.base.org', 'https://base.publicnode.com'],
|
|
647
896
|
eurcAddress: '0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42',
|
|
648
897
|
usdcAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
898
|
+
usdtAddress: null,
|
|
649
899
|
cctp: {
|
|
650
900
|
domain: 6,
|
|
651
901
|
contracts: {
|
|
@@ -670,6 +920,7 @@ const Base = defineChain({
|
|
|
670
920
|
},
|
|
671
921
|
kitContracts: {
|
|
672
922
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
923
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
673
924
|
},
|
|
674
925
|
});
|
|
675
926
|
|
|
@@ -694,6 +945,7 @@ const BaseSepolia = defineChain({
|
|
|
694
945
|
rpcEndpoints: ['https://sepolia.base.org'],
|
|
695
946
|
eurcAddress: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
696
947
|
usdcAddress: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
948
|
+
usdtAddress: null,
|
|
697
949
|
cctp: {
|
|
698
950
|
domain: 6,
|
|
699
951
|
contracts: {
|
|
@@ -742,6 +994,7 @@ const Celo = defineChain({
|
|
|
742
994
|
rpcEndpoints: ['https://forno.celo.org'],
|
|
743
995
|
eurcAddress: null,
|
|
744
996
|
usdcAddress: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
997
|
+
usdtAddress: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
745
998
|
cctp: null,
|
|
746
999
|
});
|
|
747
1000
|
|
|
@@ -766,6 +1019,7 @@ const CeloAlfajoresTestnet = defineChain({
|
|
|
766
1019
|
rpcEndpoints: ['https://alfajores-forno.celo-testnet.org'],
|
|
767
1020
|
eurcAddress: null,
|
|
768
1021
|
usdcAddress: '0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B',
|
|
1022
|
+
usdtAddress: null,
|
|
769
1023
|
cctp: null,
|
|
770
1024
|
});
|
|
771
1025
|
|
|
@@ -790,6 +1044,7 @@ const Codex = defineChain({
|
|
|
790
1044
|
rpcEndpoints: ['https://rpc.codex.xyz'],
|
|
791
1045
|
eurcAddress: null,
|
|
792
1046
|
usdcAddress: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
1047
|
+
usdtAddress: null,
|
|
793
1048
|
cctp: {
|
|
794
1049
|
domain: 12,
|
|
795
1050
|
contracts: {
|
|
@@ -832,6 +1087,7 @@ const CodexTestnet = defineChain({
|
|
|
832
1087
|
rpcEndpoints: ['https://rpc.codex-stg.xyz'],
|
|
833
1088
|
eurcAddress: null,
|
|
834
1089
|
usdcAddress: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
1090
|
+
usdtAddress: null,
|
|
835
1091
|
cctp: {
|
|
836
1092
|
domain: 12,
|
|
837
1093
|
contracts: {
|
|
@@ -874,6 +1130,7 @@ const Ethereum = defineChain({
|
|
|
874
1130
|
rpcEndpoints: ['https://eth.merkle.io', 'https://ethereum.publicnode.com'],
|
|
875
1131
|
eurcAddress: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
876
1132
|
usdcAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
1133
|
+
usdtAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7',
|
|
877
1134
|
cctp: {
|
|
878
1135
|
domain: 0,
|
|
879
1136
|
contracts: {
|
|
@@ -898,6 +1155,7 @@ const Ethereum = defineChain({
|
|
|
898
1155
|
},
|
|
899
1156
|
kitContracts: {
|
|
900
1157
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1158
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
901
1159
|
},
|
|
902
1160
|
});
|
|
903
1161
|
|
|
@@ -922,6 +1180,7 @@ const EthereumSepolia = defineChain({
|
|
|
922
1180
|
rpcEndpoints: ['https://sepolia.drpc.org'],
|
|
923
1181
|
eurcAddress: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4',
|
|
924
1182
|
usdcAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
1183
|
+
usdtAddress: null,
|
|
925
1184
|
cctp: {
|
|
926
1185
|
domain: 0,
|
|
927
1186
|
contracts: {
|
|
@@ -969,6 +1228,7 @@ const Hedera = defineChain({
|
|
|
969
1228
|
rpcEndpoints: ['https://mainnet.hashio.io/api'],
|
|
970
1229
|
eurcAddress: null,
|
|
971
1230
|
usdcAddress: '0.0.456858',
|
|
1231
|
+
usdtAddress: null,
|
|
972
1232
|
cctp: null,
|
|
973
1233
|
});
|
|
974
1234
|
|
|
@@ -992,6 +1252,7 @@ const HederaTestnet = defineChain({
|
|
|
992
1252
|
rpcEndpoints: ['https://testnet.hashio.io/api'],
|
|
993
1253
|
eurcAddress: null,
|
|
994
1254
|
usdcAddress: '0.0.429274',
|
|
1255
|
+
usdtAddress: null,
|
|
995
1256
|
cctp: null,
|
|
996
1257
|
});
|
|
997
1258
|
|
|
@@ -1018,6 +1279,7 @@ const HyperEVM = defineChain({
|
|
|
1018
1279
|
rpcEndpoints: ['https://rpc.hyperliquid.xyz/evm'],
|
|
1019
1280
|
eurcAddress: null,
|
|
1020
1281
|
usdcAddress: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
1282
|
+
usdtAddress: null,
|
|
1021
1283
|
cctp: {
|
|
1022
1284
|
domain: 19,
|
|
1023
1285
|
contracts: {
|
|
@@ -1036,6 +1298,7 @@ const HyperEVM = defineChain({
|
|
|
1036
1298
|
},
|
|
1037
1299
|
kitContracts: {
|
|
1038
1300
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1301
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1039
1302
|
},
|
|
1040
1303
|
});
|
|
1041
1304
|
|
|
@@ -1061,6 +1324,7 @@ const HyperEVMTestnet = defineChain({
|
|
|
1061
1324
|
rpcEndpoints: ['https://rpc.hyperliquid-testnet.xyz/evm'],
|
|
1062
1325
|
eurcAddress: null,
|
|
1063
1326
|
usdcAddress: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
1327
|
+
usdtAddress: null,
|
|
1064
1328
|
cctp: {
|
|
1065
1329
|
domain: 19,
|
|
1066
1330
|
contracts: {
|
|
@@ -1108,6 +1372,7 @@ const Ink = defineChain({
|
|
|
1108
1372
|
],
|
|
1109
1373
|
eurcAddress: null,
|
|
1110
1374
|
usdcAddress: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
1375
|
+
usdtAddress: null,
|
|
1111
1376
|
cctp: {
|
|
1112
1377
|
domain: 21,
|
|
1113
1378
|
contracts: {
|
|
@@ -1126,6 +1391,7 @@ const Ink = defineChain({
|
|
|
1126
1391
|
},
|
|
1127
1392
|
kitContracts: {
|
|
1128
1393
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1394
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1129
1395
|
},
|
|
1130
1396
|
});
|
|
1131
1397
|
|
|
@@ -1154,6 +1420,7 @@ const InkTestnet = defineChain({
|
|
|
1154
1420
|
],
|
|
1155
1421
|
eurcAddress: null,
|
|
1156
1422
|
usdcAddress: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
1423
|
+
usdtAddress: null,
|
|
1157
1424
|
cctp: {
|
|
1158
1425
|
domain: 21,
|
|
1159
1426
|
contracts: {
|
|
@@ -1196,6 +1463,7 @@ const Linea = defineChain({
|
|
|
1196
1463
|
rpcEndpoints: ['https://rpc.linea.build'],
|
|
1197
1464
|
eurcAddress: null,
|
|
1198
1465
|
usdcAddress: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
1466
|
+
usdtAddress: null,
|
|
1199
1467
|
cctp: {
|
|
1200
1468
|
domain: 11,
|
|
1201
1469
|
contracts: {
|
|
@@ -1214,6 +1482,7 @@ const Linea = defineChain({
|
|
|
1214
1482
|
},
|
|
1215
1483
|
kitContracts: {
|
|
1216
1484
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1485
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1217
1486
|
},
|
|
1218
1487
|
});
|
|
1219
1488
|
|
|
@@ -1238,6 +1507,7 @@ const LineaSepolia = defineChain({
|
|
|
1238
1507
|
rpcEndpoints: ['https://rpc.sepolia.linea.build'],
|
|
1239
1508
|
eurcAddress: null,
|
|
1240
1509
|
usdcAddress: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
1510
|
+
usdtAddress: null,
|
|
1241
1511
|
cctp: {
|
|
1242
1512
|
domain: 11,
|
|
1243
1513
|
contracts: {
|
|
@@ -1282,6 +1552,7 @@ const Monad = defineChain({
|
|
|
1282
1552
|
rpcEndpoints: ['https://rpc.monad.xyz'],
|
|
1283
1553
|
eurcAddress: null,
|
|
1284
1554
|
usdcAddress: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
1555
|
+
usdtAddress: null,
|
|
1285
1556
|
cctp: {
|
|
1286
1557
|
domain: 15,
|
|
1287
1558
|
contracts: {
|
|
@@ -1300,6 +1571,7 @@ const Monad = defineChain({
|
|
|
1300
1571
|
},
|
|
1301
1572
|
kitContracts: {
|
|
1302
1573
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1574
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1303
1575
|
},
|
|
1304
1576
|
});
|
|
1305
1577
|
|
|
@@ -1326,6 +1598,7 @@ const MonadTestnet = defineChain({
|
|
|
1326
1598
|
rpcEndpoints: ['https://testnet-rpc.monad.xyz'],
|
|
1327
1599
|
eurcAddress: null,
|
|
1328
1600
|
usdcAddress: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
1601
|
+
usdtAddress: null,
|
|
1329
1602
|
cctp: {
|
|
1330
1603
|
domain: 15,
|
|
1331
1604
|
contracts: {
|
|
@@ -1367,6 +1640,7 @@ const NEAR = defineChain({
|
|
|
1367
1640
|
rpcEndpoints: ['https://eth-rpc.mainnet.near.org'],
|
|
1368
1641
|
eurcAddress: null,
|
|
1369
1642
|
usdcAddress: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
1643
|
+
usdtAddress: 'usdt.tether-token.near',
|
|
1370
1644
|
cctp: null,
|
|
1371
1645
|
});
|
|
1372
1646
|
|
|
@@ -1390,6 +1664,7 @@ const NEARTestnet = defineChain({
|
|
|
1390
1664
|
rpcEndpoints: ['https://eth-rpc.testnet.near.org'],
|
|
1391
1665
|
eurcAddress: null,
|
|
1392
1666
|
usdcAddress: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
1667
|
+
usdtAddress: null,
|
|
1393
1668
|
cctp: null,
|
|
1394
1669
|
});
|
|
1395
1670
|
|
|
@@ -1413,6 +1688,7 @@ const Noble = defineChain({
|
|
|
1413
1688
|
rpcEndpoints: ['https://noble-rpc.polkachu.com'],
|
|
1414
1689
|
eurcAddress: null,
|
|
1415
1690
|
usdcAddress: 'uusdc',
|
|
1691
|
+
usdtAddress: null,
|
|
1416
1692
|
cctp: {
|
|
1417
1693
|
domain: 4,
|
|
1418
1694
|
contracts: {
|
|
@@ -1449,6 +1725,7 @@ const NobleTestnet = defineChain({
|
|
|
1449
1725
|
rpcEndpoints: ['https://noble-testnet-rpc.polkachu.com'],
|
|
1450
1726
|
eurcAddress: null,
|
|
1451
1727
|
usdcAddress: 'uusdc',
|
|
1728
|
+
usdtAddress: null,
|
|
1452
1729
|
cctp: {
|
|
1453
1730
|
domain: 4,
|
|
1454
1731
|
contracts: {
|
|
@@ -1486,6 +1763,7 @@ const Optimism = defineChain({
|
|
|
1486
1763
|
rpcEndpoints: ['https://mainnet.optimism.io'],
|
|
1487
1764
|
eurcAddress: null,
|
|
1488
1765
|
usdcAddress: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
1766
|
+
usdtAddress: null,
|
|
1489
1767
|
cctp: {
|
|
1490
1768
|
domain: 2,
|
|
1491
1769
|
contracts: {
|
|
@@ -1510,6 +1788,7 @@ const Optimism = defineChain({
|
|
|
1510
1788
|
},
|
|
1511
1789
|
kitContracts: {
|
|
1512
1790
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1791
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1513
1792
|
},
|
|
1514
1793
|
});
|
|
1515
1794
|
|
|
@@ -1534,6 +1813,7 @@ const OptimismSepolia = defineChain({
|
|
|
1534
1813
|
rpcEndpoints: ['https://sepolia.optimism.io'],
|
|
1535
1814
|
eurcAddress: null,
|
|
1536
1815
|
usdcAddress: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
1816
|
+
usdtAddress: null,
|
|
1537
1817
|
cctp: {
|
|
1538
1818
|
domain: 2,
|
|
1539
1819
|
contracts: {
|
|
@@ -1584,6 +1864,7 @@ const Plume = defineChain({
|
|
|
1584
1864
|
rpcEndpoints: ['https://rpc.plume.org'],
|
|
1585
1865
|
eurcAddress: null,
|
|
1586
1866
|
usdcAddress: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
1867
|
+
usdtAddress: null,
|
|
1587
1868
|
cctp: {
|
|
1588
1869
|
domain: 22,
|
|
1589
1870
|
contracts: {
|
|
@@ -1602,6 +1883,7 @@ const Plume = defineChain({
|
|
|
1602
1883
|
},
|
|
1603
1884
|
kitContracts: {
|
|
1604
1885
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1886
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1605
1887
|
},
|
|
1606
1888
|
});
|
|
1607
1889
|
|
|
@@ -1627,6 +1909,7 @@ const PlumeTestnet = defineChain({
|
|
|
1627
1909
|
rpcEndpoints: ['https://testnet-rpc.plume.org'],
|
|
1628
1910
|
eurcAddress: null,
|
|
1629
1911
|
usdcAddress: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
1912
|
+
usdtAddress: null,
|
|
1630
1913
|
cctp: {
|
|
1631
1914
|
domain: 22,
|
|
1632
1915
|
contracts: {
|
|
@@ -1668,6 +1951,7 @@ const PolkadotAssetHub = defineChain({
|
|
|
1668
1951
|
rpcEndpoints: ['https://asset-hub-polkadot-rpc.n.dwellir.com'],
|
|
1669
1952
|
eurcAddress: null,
|
|
1670
1953
|
usdcAddress: '1337',
|
|
1954
|
+
usdtAddress: '1984',
|
|
1671
1955
|
cctp: null,
|
|
1672
1956
|
});
|
|
1673
1957
|
|
|
@@ -1691,6 +1975,7 @@ const PolkadotWestmint = defineChain({
|
|
|
1691
1975
|
rpcEndpoints: ['https://westmint-rpc.polkadot.io'],
|
|
1692
1976
|
eurcAddress: null,
|
|
1693
1977
|
usdcAddress: 'Asset ID 31337',
|
|
1978
|
+
usdtAddress: null,
|
|
1694
1979
|
cctp: null,
|
|
1695
1980
|
});
|
|
1696
1981
|
|
|
@@ -1712,9 +1997,10 @@ const Polygon = defineChain({
|
|
|
1712
1997
|
chainId: 137,
|
|
1713
1998
|
isTestnet: false,
|
|
1714
1999
|
explorerUrl: 'https://polygonscan.com/tx/{hash}',
|
|
1715
|
-
rpcEndpoints: ['https://polygon
|
|
2000
|
+
rpcEndpoints: ['https://polygon.publicnode.com', 'https://polygon.drpc.org'],
|
|
1716
2001
|
eurcAddress: null,
|
|
1717
2002
|
usdcAddress: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
2003
|
+
usdtAddress: null,
|
|
1718
2004
|
cctp: {
|
|
1719
2005
|
domain: 7,
|
|
1720
2006
|
contracts: {
|
|
@@ -1739,6 +2025,7 @@ const Polygon = defineChain({
|
|
|
1739
2025
|
},
|
|
1740
2026
|
kitContracts: {
|
|
1741
2027
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2028
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1742
2029
|
},
|
|
1743
2030
|
});
|
|
1744
2031
|
|
|
@@ -1763,6 +2050,7 @@ const PolygonAmoy = defineChain({
|
|
|
1763
2050
|
rpcEndpoints: ['https://rpc-amoy.polygon.technology'],
|
|
1764
2051
|
eurcAddress: null,
|
|
1765
2052
|
usdcAddress: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
2053
|
+
usdtAddress: null,
|
|
1766
2054
|
cctp: {
|
|
1767
2055
|
domain: 7,
|
|
1768
2056
|
contracts: {
|
|
@@ -1813,6 +2101,7 @@ const Sei = defineChain({
|
|
|
1813
2101
|
rpcEndpoints: ['https://evm-rpc.sei-apis.com'],
|
|
1814
2102
|
eurcAddress: null,
|
|
1815
2103
|
usdcAddress: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
2104
|
+
usdtAddress: null,
|
|
1816
2105
|
cctp: {
|
|
1817
2106
|
domain: 16,
|
|
1818
2107
|
contracts: {
|
|
@@ -1831,6 +2120,7 @@ const Sei = defineChain({
|
|
|
1831
2120
|
},
|
|
1832
2121
|
kitContracts: {
|
|
1833
2122
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2123
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1834
2124
|
},
|
|
1835
2125
|
});
|
|
1836
2126
|
|
|
@@ -1856,6 +2146,7 @@ const SeiTestnet = defineChain({
|
|
|
1856
2146
|
rpcEndpoints: ['https://evm-rpc-testnet.sei-apis.com'],
|
|
1857
2147
|
eurcAddress: null,
|
|
1858
2148
|
usdcAddress: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
2149
|
+
usdtAddress: null,
|
|
1859
2150
|
cctp: {
|
|
1860
2151
|
domain: 16,
|
|
1861
2152
|
contracts: {
|
|
@@ -1898,6 +2189,7 @@ const Sonic = defineChain({
|
|
|
1898
2189
|
rpcEndpoints: ['https://rpc.soniclabs.com'],
|
|
1899
2190
|
eurcAddress: null,
|
|
1900
2191
|
usdcAddress: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
2192
|
+
usdtAddress: null,
|
|
1901
2193
|
cctp: {
|
|
1902
2194
|
domain: 13,
|
|
1903
2195
|
contracts: {
|
|
@@ -1916,6 +2208,7 @@ const Sonic = defineChain({
|
|
|
1916
2208
|
},
|
|
1917
2209
|
kitContracts: {
|
|
1918
2210
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2211
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1919
2212
|
},
|
|
1920
2213
|
});
|
|
1921
2214
|
|
|
@@ -1940,6 +2233,7 @@ const SonicTestnet = defineChain({
|
|
|
1940
2233
|
rpcEndpoints: ['https://rpc.testnet.soniclabs.com'],
|
|
1941
2234
|
eurcAddress: null,
|
|
1942
2235
|
usdcAddress: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
2236
|
+
usdtAddress: null,
|
|
1943
2237
|
cctp: {
|
|
1944
2238
|
domain: 13,
|
|
1945
2239
|
contracts: {
|
|
@@ -1981,6 +2275,7 @@ const Solana = defineChain({
|
|
|
1981
2275
|
rpcEndpoints: ['https://api.mainnet-beta.solana.com'],
|
|
1982
2276
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
1983
2277
|
usdcAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
2278
|
+
usdtAddress: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
1984
2279
|
cctp: {
|
|
1985
2280
|
domain: 5,
|
|
1986
2281
|
contracts: {
|
|
@@ -2027,6 +2322,7 @@ const SolanaDevnet = defineChain({
|
|
|
2027
2322
|
explorerUrl: 'https://solscan.io/tx/{hash}?cluster=devnet',
|
|
2028
2323
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
2029
2324
|
usdcAddress: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
2325
|
+
usdtAddress: null,
|
|
2030
2326
|
cctp: {
|
|
2031
2327
|
domain: 5,
|
|
2032
2328
|
contracts: {
|
|
@@ -2075,6 +2371,7 @@ const Stellar = defineChain({
|
|
|
2075
2371
|
rpcEndpoints: ['https://horizon.stellar.org'],
|
|
2076
2372
|
eurcAddress: 'EURC-GDHU6WRG4IEQXM5NZ4BMPKOXHW76MZM4Y2IEMFDVXBSDP6SJY4ITNPP2',
|
|
2077
2373
|
usdcAddress: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
2374
|
+
usdtAddress: null,
|
|
2078
2375
|
cctp: null,
|
|
2079
2376
|
});
|
|
2080
2377
|
|
|
@@ -2098,6 +2395,7 @@ const StellarTestnet = defineChain({
|
|
|
2098
2395
|
rpcEndpoints: ['https://horizon-testnet.stellar.org'],
|
|
2099
2396
|
eurcAddress: 'EURC-GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO',
|
|
2100
2397
|
usdcAddress: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
2398
|
+
usdtAddress: null,
|
|
2101
2399
|
cctp: null,
|
|
2102
2400
|
});
|
|
2103
2401
|
|
|
@@ -2121,6 +2419,7 @@ const Sui = defineChain({
|
|
|
2121
2419
|
rpcEndpoints: ['https://fullnode.mainnet.sui.io'],
|
|
2122
2420
|
eurcAddress: null,
|
|
2123
2421
|
usdcAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
2422
|
+
usdtAddress: null,
|
|
2124
2423
|
cctp: {
|
|
2125
2424
|
domain: 8,
|
|
2126
2425
|
contracts: {
|
|
@@ -2158,6 +2457,7 @@ const SuiTestnet = defineChain({
|
|
|
2158
2457
|
rpcEndpoints: ['https://fullnode.testnet.sui.io'],
|
|
2159
2458
|
eurcAddress: null,
|
|
2160
2459
|
usdcAddress: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
2460
|
+
usdtAddress: null,
|
|
2161
2461
|
cctp: {
|
|
2162
2462
|
domain: 8,
|
|
2163
2463
|
contracts: {
|
|
@@ -2196,6 +2496,7 @@ const Unichain = defineChain({
|
|
|
2196
2496
|
rpcEndpoints: ['https://mainnet.unichain.org'],
|
|
2197
2497
|
eurcAddress: null,
|
|
2198
2498
|
usdcAddress: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
2499
|
+
usdtAddress: null,
|
|
2199
2500
|
cctp: {
|
|
2200
2501
|
domain: 10,
|
|
2201
2502
|
contracts: {
|
|
@@ -2220,6 +2521,7 @@ const Unichain = defineChain({
|
|
|
2220
2521
|
},
|
|
2221
2522
|
kitContracts: {
|
|
2222
2523
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2524
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2223
2525
|
},
|
|
2224
2526
|
});
|
|
2225
2527
|
|
|
@@ -2244,6 +2546,7 @@ const UnichainSepolia = defineChain({
|
|
|
2244
2546
|
rpcEndpoints: ['https://sepolia.unichain.org'],
|
|
2245
2547
|
eurcAddress: null,
|
|
2246
2548
|
usdcAddress: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
2549
|
+
usdtAddress: null,
|
|
2247
2550
|
cctp: {
|
|
2248
2551
|
domain: 10,
|
|
2249
2552
|
contracts: {
|
|
@@ -2292,6 +2595,7 @@ const WorldChain = defineChain({
|
|
|
2292
2595
|
rpcEndpoints: ['https://worldchain-mainnet.g.alchemy.com/public'],
|
|
2293
2596
|
eurcAddress: null,
|
|
2294
2597
|
usdcAddress: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
2598
|
+
usdtAddress: null,
|
|
2295
2599
|
cctp: {
|
|
2296
2600
|
domain: 14,
|
|
2297
2601
|
contracts: {
|
|
@@ -2310,6 +2614,7 @@ const WorldChain = defineChain({
|
|
|
2310
2614
|
},
|
|
2311
2615
|
kitContracts: {
|
|
2312
2616
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2617
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2313
2618
|
},
|
|
2314
2619
|
});
|
|
2315
2620
|
|
|
@@ -2337,6 +2642,7 @@ const WorldChainSepolia = defineChain({
|
|
|
2337
2642
|
],
|
|
2338
2643
|
eurcAddress: null,
|
|
2339
2644
|
usdcAddress: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
2645
|
+
usdtAddress: null,
|
|
2340
2646
|
cctp: {
|
|
2341
2647
|
domain: 14,
|
|
2342
2648
|
contracts: {
|
|
@@ -2381,6 +2687,7 @@ const XDC = defineChain({
|
|
|
2381
2687
|
rpcEndpoints: ['https://erpc.xdcrpc.com', 'https://erpc.xinfin.network'],
|
|
2382
2688
|
eurcAddress: null,
|
|
2383
2689
|
usdcAddress: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
2690
|
+
usdtAddress: null,
|
|
2384
2691
|
cctp: {
|
|
2385
2692
|
domain: 18,
|
|
2386
2693
|
contracts: {
|
|
@@ -2399,6 +2706,7 @@ const XDC = defineChain({
|
|
|
2399
2706
|
},
|
|
2400
2707
|
kitContracts: {
|
|
2401
2708
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2709
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2402
2710
|
},
|
|
2403
2711
|
});
|
|
2404
2712
|
|
|
@@ -2423,6 +2731,7 @@ const XDCApothem = defineChain({
|
|
|
2423
2731
|
rpcEndpoints: ['https://erpc.apothem.network'],
|
|
2424
2732
|
eurcAddress: null,
|
|
2425
2733
|
usdcAddress: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
2734
|
+
usdtAddress: null,
|
|
2426
2735
|
cctp: {
|
|
2427
2736
|
domain: 18,
|
|
2428
2737
|
contracts: {
|
|
@@ -2465,6 +2774,7 @@ const ZKSyncEra = defineChain({
|
|
|
2465
2774
|
rpcEndpoints: ['https://mainnet.era.zksync.io'],
|
|
2466
2775
|
eurcAddress: null,
|
|
2467
2776
|
usdcAddress: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
2777
|
+
usdtAddress: null,
|
|
2468
2778
|
cctp: null,
|
|
2469
2779
|
});
|
|
2470
2780
|
|
|
@@ -2489,6 +2799,7 @@ const ZKSyncEraSepolia = defineChain({
|
|
|
2489
2799
|
rpcEndpoints: ['https://sepolia.era.zksync.dev'],
|
|
2490
2800
|
eurcAddress: null,
|
|
2491
2801
|
usdcAddress: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
2802
|
+
usdtAddress: null,
|
|
2492
2803
|
cctp: null,
|
|
2493
2804
|
});
|
|
2494
2805
|
|
|
@@ -2656,10 +2967,12 @@ const baseChainDefinitionSchema = zod.z.object({
|
|
|
2656
2967
|
rpcEndpoints: zod.z.array(zod.z.string()),
|
|
2657
2968
|
eurcAddress: zod.z.string().nullable(),
|
|
2658
2969
|
usdcAddress: zod.z.string().nullable(),
|
|
2970
|
+
usdtAddress: zod.z.string().nullable(),
|
|
2659
2971
|
cctp: zod.z.any().nullable(), // We'll accept any CCTP config structure
|
|
2660
2972
|
kitContracts: zod.z
|
|
2661
2973
|
.object({
|
|
2662
2974
|
bridge: zod.z.string().optional(),
|
|
2975
|
+
adapter: zod.z.string().optional(),
|
|
2663
2976
|
})
|
|
2664
2977
|
.optional(),
|
|
2665
2978
|
});
|
|
@@ -2774,6 +3087,29 @@ zod.z.union([
|
|
|
2774
3087
|
zod.z.nativeEnum(Blockchain),
|
|
2775
3088
|
chainDefinitionSchema$2,
|
|
2776
3089
|
]);
|
|
3090
|
+
/**
|
|
3091
|
+
* Zod schema for validating swap-specific chain identifiers.
|
|
3092
|
+
*
|
|
3093
|
+
* Validates chains based on:
|
|
3094
|
+
* - CCTPv2 support (adapter contract deployed)
|
|
3095
|
+
* - Mainnet only (no testnets)
|
|
3096
|
+
* - At least one supported token available
|
|
3097
|
+
*
|
|
3098
|
+
*/
|
|
3099
|
+
zod.z.union([
|
|
3100
|
+
// String blockchain identifier (accepts SwapChain enum values)
|
|
3101
|
+
zod.z.string().refine((val) => val in SwapChain, (val) => ({
|
|
3102
|
+
message: `"${val}" is not a supported swap chain. ` +
|
|
3103
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
3104
|
+
})),
|
|
3105
|
+
// SwapChain enum
|
|
3106
|
+
zod.z.nativeEnum(SwapChain),
|
|
3107
|
+
// ChainDefinition object (checks if chain.chain is in SwapChain)
|
|
3108
|
+
chainDefinitionSchema$2.refine((chain) => chain.chain in SwapChain, (chain) => ({
|
|
3109
|
+
message: `"${chain.chain}" is not a supported swap chain. ` +
|
|
3110
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
3111
|
+
})),
|
|
3112
|
+
]);
|
|
2777
3113
|
/**
|
|
2778
3114
|
* Zod schema for validating bridge chain identifiers.
|
|
2779
3115
|
*
|
|
@@ -2813,6 +3149,38 @@ zod.z.union([
|
|
|
2813
3149
|
})),
|
|
2814
3150
|
]);
|
|
2815
3151
|
|
|
3152
|
+
/**
|
|
3153
|
+
* @packageDocumentation
|
|
3154
|
+
* @module SwapTokenSchemas
|
|
3155
|
+
*
|
|
3156
|
+
* Zod validation schemas for supported swap tokens.
|
|
3157
|
+
*/
|
|
3158
|
+
// Internal enum used after input normalization.
|
|
3159
|
+
const swapTokenEnumSchema = zod.z.enum([
|
|
3160
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
3161
|
+
NATIVE_TOKEN,
|
|
3162
|
+
]);
|
|
3163
|
+
/**
|
|
3164
|
+
* Zod schema for validating supported swap token symbols.
|
|
3165
|
+
*
|
|
3166
|
+
* Accepts any token symbol from the SWAP_TOKEN_REGISTRY plus NATIVE.
|
|
3167
|
+
* Input matching is case-insensitive and normalized to uppercase.
|
|
3168
|
+
*
|
|
3169
|
+
* @example
|
|
3170
|
+
* ```typescript
|
|
3171
|
+
* import { supportedSwapTokenSchema } from '@core/chains'
|
|
3172
|
+
*
|
|
3173
|
+
* const result = supportedSwapTokenSchema.safeParse('USDC')
|
|
3174
|
+
* if (result.success) {
|
|
3175
|
+
* console.log('Valid swap token:', result.data)
|
|
3176
|
+
* }
|
|
3177
|
+
* ```
|
|
3178
|
+
*/
|
|
3179
|
+
zod.z
|
|
3180
|
+
.string()
|
|
3181
|
+
.transform((value) => value.toUpperCase())
|
|
3182
|
+
.pipe(swapTokenEnumSchema);
|
|
3183
|
+
|
|
2816
3184
|
/**
|
|
2817
3185
|
* Retrieve a chain definition by its blockchain enum value.
|
|
2818
3186
|
*
|
|
@@ -2867,6 +3235,11 @@ const getChainByEnum = (blockchain) => {
|
|
|
2867
3235
|
* ```
|
|
2868
3236
|
*/
|
|
2869
3237
|
function resolveChainIdentifier(chainIdentifier) {
|
|
3238
|
+
// Handle null explicitly (typeof null === 'object' in JavaScript)
|
|
3239
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
3240
|
+
if (chainIdentifier === null) {
|
|
3241
|
+
throw new Error(`Invalid chain identifier type: null. Expected ChainDefinition object, Blockchain enum, or string literal.`);
|
|
3242
|
+
}
|
|
2870
3243
|
// If it's already a ChainDefinition object, return it unchanged
|
|
2871
3244
|
if (typeof chainIdentifier === 'object') {
|
|
2872
3245
|
return chainIdentifier;
|
|
@@ -3158,11 +3531,11 @@ const formatComponent = (nameWithVersion) => {
|
|
|
3158
3531
|
const createRequestContext = () => {
|
|
3159
3532
|
const context = {};
|
|
3160
3533
|
if (typeof globalThis !== 'undefined') {
|
|
3161
|
-
if (globalThis.
|
|
3162
|
-
context.externalPrefix = globalThis.
|
|
3534
|
+
if (globalThis.__APP_KITS_EXTERNAL_PREFIX__ !== undefined) {
|
|
3535
|
+
context.externalPrefix = globalThis.__APP_KITS_EXTERNAL_PREFIX__;
|
|
3163
3536
|
}
|
|
3164
|
-
if (globalThis.
|
|
3165
|
-
context.kit = globalThis.
|
|
3537
|
+
if (globalThis.__APP_KITS_CURRENT_KIT__ !== undefined) {
|
|
3538
|
+
context.kit = globalThis.__APP_KITS_CURRENT_KIT__;
|
|
3166
3539
|
}
|
|
3167
3540
|
}
|
|
3168
3541
|
return context;
|
|
@@ -3268,6 +3641,10 @@ const ERROR_TYPES = {
|
|
|
3268
3641
|
RPC: 'RPC',
|
|
3269
3642
|
/** Internet connectivity, DNS resolution, connection issues */
|
|
3270
3643
|
NETWORK: 'NETWORK',
|
|
3644
|
+
/** API throttling, request frequency limits errors */
|
|
3645
|
+
RATE_LIMIT: 'RATE_LIMIT',
|
|
3646
|
+
/** Service errors */
|
|
3647
|
+
SERVICE: 'SERVICE',
|
|
3271
3648
|
/** Catch-all for unrecognized errors (code 0) */
|
|
3272
3649
|
UNKNOWN: 'UNKNOWN',
|
|
3273
3650
|
};
|
|
@@ -3291,6 +3668,8 @@ const ERROR_CODE_RANGES = [
|
|
|
3291
3668
|
{ min: 3000, max: 3999, type: 'NETWORK' },
|
|
3292
3669
|
{ min: 4000, max: 4999, type: 'RPC' },
|
|
3293
3670
|
{ min: 5000, max: 5999, type: 'ONCHAIN' },
|
|
3671
|
+
{ min: 7000, max: 7999, type: 'RATE_LIMIT' },
|
|
3672
|
+
{ min: 8000, max: 8999, type: 'SERVICE' },
|
|
3294
3673
|
{ min: 9000, max: 9999, type: 'BALANCE' },
|
|
3295
3674
|
];
|
|
3296
3675
|
/** Special code for UNKNOWN errors */
|
|
@@ -3338,6 +3717,8 @@ const errorDetailsSchema = zod.z.object({
|
|
|
3338
3717
|
* - 3000-3999: NETWORK errors - Connectivity issues
|
|
3339
3718
|
* - 4000-4999: RPC errors - Provider issues, gas estimation
|
|
3340
3719
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures
|
|
3720
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling
|
|
3721
|
+
* - 8000-8999: SERVICE errors - Internal service errors
|
|
3341
3722
|
* - 9000-9999: BALANCE errors - Insufficient funds
|
|
3342
3723
|
*/
|
|
3343
3724
|
code: zod.z
|
|
@@ -3446,11 +3827,11 @@ const AMOUNT_FORMAT_ERROR_MESSAGE = 'Amount must be a numeric string with dot (.
|
|
|
3446
3827
|
const MAX_FEE_FORMAT_ERROR_MESSAGE = 'maxFee must be a numeric string with dot (.) as decimal separator (e.g., "1", "0.5", ".5", "1.5"), with no thousand separators or comma decimals';
|
|
3447
3828
|
|
|
3448
3829
|
/**
|
|
3449
|
-
* Structured error class for
|
|
3830
|
+
* Structured error class for App Kit operations.
|
|
3450
3831
|
*
|
|
3451
3832
|
* This class extends the native Error class while implementing the ErrorDetails
|
|
3452
3833
|
* interface, providing a consistent error format for programmatic handling
|
|
3453
|
-
* across the
|
|
3834
|
+
* across the App Kits ecosystem. All properties are immutable to ensure
|
|
3454
3835
|
* error objects cannot be modified after creation.
|
|
3455
3836
|
*
|
|
3456
3837
|
* @example
|
|
@@ -3460,6 +3841,7 @@ const MAX_FEE_FORMAT_ERROR_MESSAGE = 'maxFee must be a numeric string with dot (
|
|
|
3460
3841
|
* const error = new KitError({
|
|
3461
3842
|
* code: 1001,
|
|
3462
3843
|
* name: 'INPUT_NETWORK_MISMATCH',
|
|
3844
|
+
* type: 'INPUT',
|
|
3463
3845
|
* recoverability: 'FATAL',
|
|
3464
3846
|
* message: 'Cannot bridge between mainnet and testnet'
|
|
3465
3847
|
* })
|
|
@@ -3477,7 +3859,8 @@ const MAX_FEE_FORMAT_ERROR_MESSAGE = 'maxFee must be a numeric string with dot (
|
|
|
3477
3859
|
* // Error with cause information
|
|
3478
3860
|
* const error = new KitError({
|
|
3479
3861
|
* code: 1002,
|
|
3480
|
-
* name: '
|
|
3862
|
+
* name: 'INPUT_INVALID_AMOUNT',
|
|
3863
|
+
* type: 'INPUT',
|
|
3481
3864
|
* recoverability: 'FATAL',
|
|
3482
3865
|
* message: 'Amount must be greater than zero',
|
|
3483
3866
|
* cause: {
|
|
@@ -3561,6 +3944,8 @@ class KitError extends Error {
|
|
|
3561
3944
|
* - 3000-3999: NETWORK errors - Internet connectivity, DNS, connection issues
|
|
3562
3945
|
* - 4000-4999: RPC errors - Blockchain provider issues, gas estimation, nonce errors
|
|
3563
3946
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures, gas exhaustion, reverts
|
|
3947
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling, request frequency limits
|
|
3948
|
+
* - 8000-8999: SERVICE errors - Internal service errors, server failures
|
|
3564
3949
|
* - 9000-9999: BALANCE errors - Insufficient funds, token balance, allowance
|
|
3565
3950
|
*/
|
|
3566
3951
|
/**
|
|
@@ -3621,10 +4006,22 @@ const InputError = {
|
|
|
3621
4006
|
name: 'INPUT_INVALID_CHAIN',
|
|
3622
4007
|
type: 'INPUT',
|
|
3623
4008
|
},
|
|
3624
|
-
/**
|
|
3625
|
-
|
|
4009
|
+
/** Unsupported token for chain */
|
|
4010
|
+
UNSUPPORTED_TOKEN: {
|
|
3626
4011
|
code: 1006,
|
|
3627
|
-
name: '
|
|
4012
|
+
name: 'INPUT_UNSUPPORTED_TOKEN',
|
|
4013
|
+
type: 'INPUT',
|
|
4014
|
+
},
|
|
4015
|
+
/** Insufficient swap amount for the token pair */
|
|
4016
|
+
INSUFFICIENT_SWAP_AMOUNT: {
|
|
4017
|
+
code: 1007,
|
|
4018
|
+
name: 'INPUT_INSUFFICIENT_SWAP_AMOUNT',
|
|
4019
|
+
type: 'INPUT',
|
|
4020
|
+
},
|
|
4021
|
+
/** Action not supported by this adapter / ecosystem */
|
|
4022
|
+
UNSUPPORTED_ACTION: {
|
|
4023
|
+
code: 1008,
|
|
4024
|
+
name: 'INPUT_UNSUPPORTED_ACTION',
|
|
3628
4025
|
type: 'INPUT',
|
|
3629
4026
|
},
|
|
3630
4027
|
/** General validation failure for complex validation rules */
|
|
@@ -3633,6 +4030,12 @@ const InputError = {
|
|
|
3633
4030
|
name: 'INPUT_VALIDATION_FAILED',
|
|
3634
4031
|
type: 'INPUT',
|
|
3635
4032
|
},
|
|
4033
|
+
/** User cancelled wallet interaction (signature, transaction, connection) */
|
|
4034
|
+
USER_CANCELLED: {
|
|
4035
|
+
code: 1099,
|
|
4036
|
+
name: 'INPUT_USER_CANCELLED',
|
|
4037
|
+
type: 'INPUT',
|
|
4038
|
+
},
|
|
3636
4039
|
};
|
|
3637
4040
|
/**
|
|
3638
4041
|
* Standardized error definitions for BALANCE type errors.
|
|
@@ -3720,8 +4123,7 @@ const NetworkError = {
|
|
|
3720
4123
|
code: 3004,
|
|
3721
4124
|
name: 'NETWORK_RELAYER_PENDING',
|
|
3722
4125
|
type: 'NETWORK',
|
|
3723
|
-
}
|
|
3724
|
-
};
|
|
4126
|
+
}};
|
|
3725
4127
|
|
|
3726
4128
|
/**
|
|
3727
4129
|
* Creates error for network type mismatch between source and destination.
|
|
@@ -3808,7 +4210,7 @@ function createInvalidChainError(chain, reason) {
|
|
|
3808
4210
|
const errorDetails = {
|
|
3809
4211
|
...InputError.INVALID_CHAIN,
|
|
3810
4212
|
recoverability: 'FATAL',
|
|
3811
|
-
message: `Invalid chain '${chain}': ${reason}
|
|
4213
|
+
message: `Invalid chain '${chain}': ${reason}.`,
|
|
3812
4214
|
cause: {
|
|
3813
4215
|
trace: { chain, reason },
|
|
3814
4216
|
},
|
|
@@ -4157,6 +4559,9 @@ function getErrorMessage(error) {
|
|
|
4157
4559
|
if (typeof error === 'string') {
|
|
4158
4560
|
return error;
|
|
4159
4561
|
}
|
|
4562
|
+
if (typeof error === 'object' && error !== null && 'message' in error) {
|
|
4563
|
+
return String(error.message);
|
|
4564
|
+
}
|
|
4160
4565
|
return 'An unknown error occurred';
|
|
4161
4566
|
}
|
|
4162
4567
|
/**
|
|
@@ -4213,6 +4618,9 @@ function extractErrorInfo(error) {
|
|
|
4213
4618
|
if (typeof err.code === 'number') {
|
|
4214
4619
|
info.code = err.code;
|
|
4215
4620
|
}
|
|
4621
|
+
if (isKitError(error)) {
|
|
4622
|
+
info.type = error.type;
|
|
4623
|
+
}
|
|
4216
4624
|
return info;
|
|
4217
4625
|
}
|
|
4218
4626
|
|
|
@@ -4335,7 +4743,17 @@ const makeApiRequest = async (url, method, isValidType, config, body) => {
|
|
|
4335
4743
|
const response = await fetch(url, requestInit);
|
|
4336
4744
|
clearTimeout(timeoutId);
|
|
4337
4745
|
if (!response.ok) {
|
|
4338
|
-
|
|
4746
|
+
let responseBody;
|
|
4747
|
+
try {
|
|
4748
|
+
responseBody = (await response.json());
|
|
4749
|
+
}
|
|
4750
|
+
catch {
|
|
4751
|
+
// Parse response body for diagnostics; continue even if malformed
|
|
4752
|
+
// so callers always receive HTTP status context
|
|
4753
|
+
}
|
|
4754
|
+
const httpError = new Error(`HTTP ${String(response.status)} - ${response.statusText}`);
|
|
4755
|
+
httpError.responseBody = responseBody;
|
|
4756
|
+
throw httpError;
|
|
4339
4757
|
}
|
|
4340
4758
|
const parsedJson = (await response.json());
|
|
4341
4759
|
if (!isValidType(parsedJson)) {
|
|
@@ -4907,7 +5325,7 @@ const convertAddress = (address, targetFormat) => {
|
|
|
4907
5325
|
*
|
|
4908
5326
|
* This function normalizes token values from their blockchain representation (where
|
|
4909
5327
|
* everything is stored as integers in the smallest denomination) to human-readable
|
|
4910
|
-
* decimal format. Uses the battle-tested implementation from
|
|
5328
|
+
* decimal format. Uses the battle-tested implementation from \@ethersproject/units.
|
|
4911
5329
|
*
|
|
4912
5330
|
* @param value - The value in smallest units (e.g., "1000000" for 1 USDC with 6 decimals)
|
|
4913
5331
|
* @param decimals - The number of decimal places for the unit conversion
|
|
@@ -4936,116 +5354,837 @@ const formatUnits = (value, decimals) => {
|
|
|
4936
5354
|
};
|
|
4937
5355
|
|
|
4938
5356
|
/**
|
|
4939
|
-
*
|
|
4940
|
-
*
|
|
4941
|
-
* This function takes a chain definition containing an explorer URL template
|
|
4942
|
-
* and replaces the `{hash}` placeholder with the provided transaction hash
|
|
4943
|
-
* to create a complete, valid explorer URL.
|
|
4944
|
-
*
|
|
4945
|
-
* @param chainDef - The chain definition containing the explorer URL template.
|
|
4946
|
-
* @param txHash - The transaction hash to insert into the URL template.
|
|
4947
|
-
* @returns A complete explorer URL with the transaction hash inserted.
|
|
4948
|
-
* @throws Error if the chain definition is null/undefined.
|
|
4949
|
-
* @throws Error if the transaction hash is null/undefined/empty.
|
|
4950
|
-
* @throws Error if the explorer URL template is missing or empty.
|
|
4951
|
-
* @throws Error if the explorer URL template doesn't contain the {hash} placeholder.
|
|
4952
|
-
* @throws Error if the resulting URL is invalid.
|
|
4953
|
-
*
|
|
4954
|
-
* @example
|
|
4955
|
-
* ```typescript
|
|
4956
|
-
* import { buildExplorerUrl } from '@core/utils'
|
|
4957
|
-
* import { Ethereum } from '@core/chains'
|
|
4958
|
-
*
|
|
4959
|
-
* // Build URL for Ethereum transaction
|
|
4960
|
-
* const url = buildExplorerUrl(Ethereum, '0x1234567890abcdef...')
|
|
4961
|
-
* console.log(url) // 'https://etherscan.io/tx/0x1234567890abcdef...'
|
|
4962
|
-
* ```
|
|
5357
|
+
* Create a structured error for token resolution failures.
|
|
4963
5358
|
*
|
|
4964
|
-
* @
|
|
4965
|
-
*
|
|
4966
|
-
*
|
|
4967
|
-
* import { Solana } from '@core/chains'
|
|
5359
|
+
* @remarks
|
|
5360
|
+
* Returns a `KitError` with `INPUT_UNSUPPORTED_TOKEN` code (1006).
|
|
5361
|
+
* The error trace contains the selector and chain context for debugging.
|
|
4968
5362
|
*
|
|
4969
|
-
*
|
|
4970
|
-
*
|
|
4971
|
-
*
|
|
4972
|
-
*
|
|
5363
|
+
* @param message - Human-readable error description.
|
|
5364
|
+
* @param selector - The token selector that failed to resolve.
|
|
5365
|
+
* @param chainId - The chain being resolved for (optional).
|
|
5366
|
+
* @param cause - The underlying error, if any (optional).
|
|
5367
|
+
* @returns A KitError with INPUT type and FATAL recoverability.
|
|
4973
5368
|
*
|
|
4974
5369
|
* @example
|
|
4975
5370
|
* ```typescript
|
|
4976
|
-
*
|
|
4977
|
-
*
|
|
4978
|
-
*
|
|
4979
|
-
*
|
|
4980
|
-
*
|
|
4981
|
-
* console.log(url) // 'https://explorer.aptoslabs.com/txn/0xabc123...?network=mainnet'
|
|
5371
|
+
* throw createTokenResolutionError(
|
|
5372
|
+
* 'Unknown token symbol: FAKE',
|
|
5373
|
+
* 'FAKE',
|
|
5374
|
+
* 'Ethereum'
|
|
5375
|
+
* )
|
|
4982
5376
|
* ```
|
|
4983
5377
|
*/
|
|
4984
|
-
function
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
5378
|
+
function createTokenResolutionError(message, selector, chainId, cause) {
|
|
5379
|
+
const trace = {
|
|
5380
|
+
selector,
|
|
5381
|
+
...(chainId === undefined ? {} : { chainId }),
|
|
5382
|
+
...({} ),
|
|
5383
|
+
};
|
|
5384
|
+
return new KitError({
|
|
5385
|
+
...InputError.UNSUPPORTED_TOKEN,
|
|
5386
|
+
recoverability: 'FATAL',
|
|
5387
|
+
message,
|
|
5388
|
+
cause: { trace },
|
|
5389
|
+
});
|
|
4994
5390
|
}
|
|
4995
5391
|
|
|
4996
5392
|
/**
|
|
4997
|
-
*
|
|
4998
|
-
*
|
|
4999
|
-
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
5000
|
-
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
5001
|
-
*/
|
|
5002
|
-
const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
5003
|
-
/**
|
|
5004
|
-
* CCTP forwarding version number.
|
|
5005
|
-
*
|
|
5006
|
-
* Version 0 is used for basic forwarding requests.
|
|
5007
|
-
*/
|
|
5008
|
-
const CCTP_FORWARD_VERSION = 0;
|
|
5009
|
-
/**
|
|
5010
|
-
* Length of Circle-reserved payload for basic forwarding (0 bytes).
|
|
5011
|
-
*
|
|
5012
|
-
* Set to 0 when no additional Circle-reserved data is needed.
|
|
5013
|
-
*/
|
|
5014
|
-
const CCTP_FORWARD_PAYLOAD_LENGTH = 0;
|
|
5015
|
-
/**
|
|
5016
|
-
* Build the hookData bytes for CCTP forwarding.
|
|
5017
|
-
*
|
|
5018
|
-
* Constructs a 32-byte hookData payload that signals to Circle's Orbit relayer
|
|
5019
|
-
* that the user wants automated attestation fetching and destination mint execution.
|
|
5393
|
+
* USDC token definition with addresses and metadata.
|
|
5020
5394
|
*
|
|
5021
|
-
*
|
|
5022
|
-
*
|
|
5023
|
-
*
|
|
5024
|
-
* - Bytes 28-31: uint32 length (big-endian) - 0 for basic forwarding
|
|
5395
|
+
* @remarks
|
|
5396
|
+
* This is the built-in USDC definition used by the TokenRegistry.
|
|
5397
|
+
* Includes all known USDC addresses across supported chains.
|
|
5025
5398
|
*
|
|
5026
|
-
*
|
|
5399
|
+
* Keys use the `Blockchain` enum for type safety. Both enum values
|
|
5400
|
+
* and string literals are supported:
|
|
5401
|
+
* - `Blockchain.Ethereum` or `'Ethereum'`
|
|
5027
5402
|
*
|
|
5028
5403
|
* @example
|
|
5029
5404
|
* ```typescript
|
|
5030
|
-
* import {
|
|
5031
|
-
*
|
|
5032
|
-
* const hookData = buildForwardingHookData()
|
|
5033
|
-
* // Returns: '0x636374702d666f72776172640000000000000000000000000000000000000000'
|
|
5405
|
+
* import { USDC } from '@core/tokens'
|
|
5406
|
+
* import { Blockchain } from '@core/chains'
|
|
5034
5407
|
*
|
|
5035
|
-
* //
|
|
5036
|
-
*
|
|
5037
|
-
*
|
|
5038
|
-
*
|
|
5039
|
-
* maxFee: BigInt('50000'),
|
|
5040
|
-
* minFinalityThreshold: 1000,
|
|
5041
|
-
* fromChain: ethereum,
|
|
5042
|
-
* toChain: base,
|
|
5043
|
-
* hookData
|
|
5044
|
-
* })
|
|
5408
|
+
* console.log(USDC.symbol) // 'USDC'
|
|
5409
|
+
* console.log(USDC.decimals) // 6
|
|
5410
|
+
* console.log(USDC.locators[Blockchain.Ethereum])
|
|
5411
|
+
* // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
5045
5412
|
* ```
|
|
5046
5413
|
*/
|
|
5047
|
-
|
|
5048
|
-
|
|
5414
|
+
const USDC = {
|
|
5415
|
+
symbol: 'USDC',
|
|
5416
|
+
decimals: 6,
|
|
5417
|
+
locators: {
|
|
5418
|
+
// =========================================================================
|
|
5419
|
+
// Mainnets (alphabetically sorted)
|
|
5420
|
+
// =========================================================================
|
|
5421
|
+
[Blockchain.Arbitrum]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
5422
|
+
[Blockchain.Avalanche]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
5423
|
+
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
5424
|
+
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
5425
|
+
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
5426
|
+
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
5427
|
+
[Blockchain.Hedera]: '0.0.456858',
|
|
5428
|
+
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
5429
|
+
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
5430
|
+
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
5431
|
+
[Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
5432
|
+
[Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
5433
|
+
[Blockchain.Noble]: 'uusdc',
|
|
5434
|
+
[Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
5435
|
+
[Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
5436
|
+
[Blockchain.Polkadot_Asset_Hub]: '1337',
|
|
5437
|
+
[Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
5438
|
+
[Blockchain.Sei]: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
5439
|
+
[Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
5440
|
+
[Blockchain.Sonic]: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
5441
|
+
[Blockchain.Stellar]: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
5442
|
+
[Blockchain.Sui]: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
5443
|
+
[Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
5444
|
+
[Blockchain.World_Chain]: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
5445
|
+
[Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
5446
|
+
[Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
5447
|
+
// =========================================================================
|
|
5448
|
+
// Testnets (alphabetically sorted)
|
|
5449
|
+
// =========================================================================
|
|
5450
|
+
[Blockchain.Arbitrum_Sepolia]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
5451
|
+
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
5452
|
+
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
5453
|
+
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
5454
|
+
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
5455
|
+
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
5456
|
+
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
5457
|
+
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
5458
|
+
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
5459
|
+
[Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
5460
|
+
[Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
5461
|
+
[Blockchain.Noble_Testnet]: 'uusdc',
|
|
5462
|
+
[Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
5463
|
+
[Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
5464
|
+
[Blockchain.Polkadot_Westmint]: '31337',
|
|
5465
|
+
[Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
5466
|
+
[Blockchain.Sei_Testnet]: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
5467
|
+
[Blockchain.Solana_Devnet]: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
5468
|
+
[Blockchain.Sonic_Testnet]: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
5469
|
+
[Blockchain.Stellar_Testnet]: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
5470
|
+
[Blockchain.Sui_Testnet]: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
5471
|
+
[Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
5472
|
+
[Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
5473
|
+
[Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
5474
|
+
[Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
5475
|
+
},
|
|
5476
|
+
};
|
|
5477
|
+
|
|
5478
|
+
/**
|
|
5479
|
+
* USDT (Tether) token definition with addresses and metadata.
|
|
5480
|
+
*
|
|
5481
|
+
* @remarks
|
|
5482
|
+
* Built-in USDT definition for the TokenRegistry. Includes chain locators
|
|
5483
|
+
* for swap-supported chains.
|
|
5484
|
+
*/
|
|
5485
|
+
const USDT = {
|
|
5486
|
+
symbol: 'USDT',
|
|
5487
|
+
decimals: 6,
|
|
5488
|
+
locators: {
|
|
5489
|
+
[Blockchain.Aptos]: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
5490
|
+
[Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
|
|
5491
|
+
[Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
|
|
5492
|
+
[Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
5493
|
+
[Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
|
5494
|
+
[Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
|
|
5495
|
+
[Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
|
|
5496
|
+
[Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
|
|
5497
|
+
[Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
|
|
5498
|
+
[Blockchain.NEAR]: 'usdt.tether-token.near',
|
|
5499
|
+
[Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
|
|
5500
|
+
[Blockchain.Polkadot_Asset_Hub]: '1984',
|
|
5501
|
+
[Blockchain.Polygon]: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
|
5502
|
+
[Blockchain.Sei]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
5503
|
+
[Blockchain.Solana]: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
5504
|
+
[Blockchain.Unichain]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
5505
|
+
},
|
|
5506
|
+
};
|
|
5507
|
+
|
|
5508
|
+
/**
|
|
5509
|
+
* EURC (Euro Coin) token definition with addresses and metadata.
|
|
5510
|
+
*
|
|
5511
|
+
* @remarks
|
|
5512
|
+
* Built-in EURC definition for the TokenRegistry. Includes chain locators
|
|
5513
|
+
* for swap-supported chains.
|
|
5514
|
+
*/
|
|
5515
|
+
const EURC = {
|
|
5516
|
+
symbol: 'EURC',
|
|
5517
|
+
decimals: 6,
|
|
5518
|
+
locators: {
|
|
5519
|
+
[Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
5520
|
+
[Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
5521
|
+
[Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
5522
|
+
[Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
5523
|
+
[Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
5524
|
+
},
|
|
5525
|
+
};
|
|
5526
|
+
|
|
5527
|
+
/**
|
|
5528
|
+
* DAI (Maker DAO) stablecoin token definition with addresses and metadata.
|
|
5529
|
+
*
|
|
5530
|
+
* @remarks
|
|
5531
|
+
* Built-in DAI definition for the TokenRegistry. Includes chain locators
|
|
5532
|
+
* for swap-supported chains.
|
|
5533
|
+
*/
|
|
5534
|
+
const DAI = {
|
|
5535
|
+
symbol: 'DAI',
|
|
5536
|
+
decimals: 18,
|
|
5537
|
+
chainDecimals: {
|
|
5538
|
+
[Blockchain.Solana]: 8,
|
|
5539
|
+
},
|
|
5540
|
+
locators: {
|
|
5541
|
+
[Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
5542
|
+
[Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
|
|
5543
|
+
[Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
|
|
5544
|
+
[Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
5545
|
+
[Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
|
|
5546
|
+
[Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
5547
|
+
[Blockchain.Polygon]: '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063',
|
|
5548
|
+
[Blockchain.Solana]: 'EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o',
|
|
5549
|
+
},
|
|
5550
|
+
};
|
|
5551
|
+
|
|
5552
|
+
/**
|
|
5553
|
+
* USDe (Ethena) synthetic dollar token definition with addresses and metadata.
|
|
5554
|
+
*
|
|
5555
|
+
* @remarks
|
|
5556
|
+
* Built-in USDE definition for the TokenRegistry. Includes chain locators
|
|
5557
|
+
* for swap-supported chains.
|
|
5558
|
+
*/
|
|
5559
|
+
const USDE = {
|
|
5560
|
+
symbol: 'USDe',
|
|
5561
|
+
decimals: 18,
|
|
5562
|
+
chainDecimals: {
|
|
5563
|
+
[Blockchain.Solana]: 9,
|
|
5564
|
+
},
|
|
5565
|
+
locators: {
|
|
5566
|
+
[Blockchain.Arbitrum]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5567
|
+
[Blockchain.Base]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5568
|
+
[Blockchain.Ethereum]: '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3',
|
|
5569
|
+
[Blockchain.Linea]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5570
|
+
[Blockchain.Optimism]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5571
|
+
[Blockchain.Solana]: 'DEkqHyPN7GMRJ5cArtQFAWefqbZb33Hyf6s5iCwjEonT',
|
|
5572
|
+
},
|
|
5573
|
+
};
|
|
5574
|
+
|
|
5575
|
+
/**
|
|
5576
|
+
* PYUSD (PayPal USD) stablecoin token definition with addresses and metadata.
|
|
5577
|
+
*
|
|
5578
|
+
* @remarks
|
|
5579
|
+
* Built-in PYUSD definition for the TokenRegistry. Includes chain locators
|
|
5580
|
+
* for swap-supported chains.
|
|
5581
|
+
*/
|
|
5582
|
+
const PYUSD = {
|
|
5583
|
+
symbol: 'PYUSD',
|
|
5584
|
+
decimals: 6,
|
|
5585
|
+
locators: {
|
|
5586
|
+
[Blockchain.Arbitrum]: '0x46850aD61C2B7d64d08c9C754F45254596696984',
|
|
5587
|
+
[Blockchain.Ethereum]: '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8',
|
|
5588
|
+
[Blockchain.Solana]: '2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo',
|
|
5589
|
+
},
|
|
5590
|
+
};
|
|
5591
|
+
|
|
5592
|
+
/**
|
|
5593
|
+
* WETH (Wrapped Ether) token definition with addresses and metadata.
|
|
5594
|
+
*
|
|
5595
|
+
* @remarks
|
|
5596
|
+
* Built-in WETH definition for the TokenRegistry. Includes chain locators
|
|
5597
|
+
* for swap-supported chains where WETH is available.
|
|
5598
|
+
*/
|
|
5599
|
+
const WETH = {
|
|
5600
|
+
symbol: 'WETH',
|
|
5601
|
+
decimals: 18,
|
|
5602
|
+
chainDecimals: {
|
|
5603
|
+
[Blockchain.Solana]: 9,
|
|
5604
|
+
},
|
|
5605
|
+
locators: {
|
|
5606
|
+
[Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
|
|
5607
|
+
[Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
|
|
5608
|
+
[Blockchain.Base]: '0x4200000000000000000000000000000000000006',
|
|
5609
|
+
[Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
5610
|
+
[Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
|
|
5611
|
+
[Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
|
|
5612
|
+
[Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs',
|
|
5613
|
+
},
|
|
5614
|
+
};
|
|
5615
|
+
|
|
5616
|
+
/**
|
|
5617
|
+
* WBTC (Wrapped Bitcoin) token definition with addresses and metadata.
|
|
5618
|
+
*
|
|
5619
|
+
* @remarks
|
|
5620
|
+
* Built-in WBTC definition for the TokenRegistry. Includes chain locators
|
|
5621
|
+
* for swap-supported chains where WBTC is available.
|
|
5622
|
+
*/
|
|
5623
|
+
const WBTC = {
|
|
5624
|
+
symbol: 'WBTC',
|
|
5625
|
+
decimals: 8,
|
|
5626
|
+
locators: {
|
|
5627
|
+
[Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
|
|
5628
|
+
[Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
|
|
5629
|
+
[Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218',
|
|
5630
|
+
},
|
|
5631
|
+
};
|
|
5632
|
+
|
|
5633
|
+
/**
|
|
5634
|
+
* WSOL (Wrapped SOL) token definition with addresses and metadata.
|
|
5635
|
+
*
|
|
5636
|
+
* @remarks
|
|
5637
|
+
* Built-in WSOL definition for the TokenRegistry. Includes chain locators
|
|
5638
|
+
* for swap-supported chains where WSOL is available.
|
|
5639
|
+
*/
|
|
5640
|
+
const WSOL = {
|
|
5641
|
+
symbol: 'WSOL',
|
|
5642
|
+
decimals: 9,
|
|
5643
|
+
locators: {
|
|
5644
|
+
[Blockchain.Solana]: 'So11111111111111111111111111111111111111112',
|
|
5645
|
+
},
|
|
5646
|
+
};
|
|
5647
|
+
|
|
5648
|
+
/**
|
|
5649
|
+
* WAVAX (Wrapped AVAX) token definition with addresses and metadata.
|
|
5650
|
+
*
|
|
5651
|
+
* @remarks
|
|
5652
|
+
* Built-in WAVAX definition for the TokenRegistry. Includes chain locators
|
|
5653
|
+
* for swap-supported chains where WAVAX is available.
|
|
5654
|
+
*/
|
|
5655
|
+
const WAVAX = {
|
|
5656
|
+
symbol: 'WAVAX',
|
|
5657
|
+
decimals: 18,
|
|
5658
|
+
locators: {
|
|
5659
|
+
[Blockchain.Avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7',
|
|
5660
|
+
},
|
|
5661
|
+
};
|
|
5662
|
+
|
|
5663
|
+
/**
|
|
5664
|
+
* WPOL (Wrapped POL) token definition with addresses and metadata.
|
|
5665
|
+
*
|
|
5666
|
+
* @remarks
|
|
5667
|
+
* Built-in WPOL definition for the TokenRegistry. Includes chain locators
|
|
5668
|
+
* for swap-supported chains where WPOL is available.
|
|
5669
|
+
*/
|
|
5670
|
+
const WPOL = {
|
|
5671
|
+
symbol: 'WPOL',
|
|
5672
|
+
decimals: 18,
|
|
5673
|
+
locators: {
|
|
5674
|
+
[Blockchain.Polygon]: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
|
|
5675
|
+
},
|
|
5676
|
+
};
|
|
5677
|
+
|
|
5678
|
+
/**
|
|
5679
|
+
* ETH (native Ether alias) token definition with metadata.
|
|
5680
|
+
*
|
|
5681
|
+
* @remarks
|
|
5682
|
+
* Built-in ETH definition for the TokenRegistry. Used as a symbol alias
|
|
5683
|
+
* for native ETH (e.g. in swap flows). Chain locators are TBD and will
|
|
5684
|
+
* be added when addresses are available. Use raw selector with
|
|
5685
|
+
* locator + decimals where native gas token is represented as a contract.
|
|
5686
|
+
*/
|
|
5687
|
+
const ETH = {
|
|
5688
|
+
symbol: 'ETH',
|
|
5689
|
+
decimals: 18,
|
|
5690
|
+
locators: {},
|
|
5691
|
+
};
|
|
5692
|
+
|
|
5693
|
+
/**
|
|
5694
|
+
* POL (Polygon native token) token definition with addresses and metadata.
|
|
5695
|
+
*
|
|
5696
|
+
* @remarks
|
|
5697
|
+
* Built-in POL definition for the TokenRegistry. Includes chain locators
|
|
5698
|
+
* where POL is available as a bridged/wrapped asset.
|
|
5699
|
+
*/
|
|
5700
|
+
const POL = {
|
|
5701
|
+
symbol: 'POL',
|
|
5702
|
+
decimals: 18,
|
|
5703
|
+
locators: {
|
|
5704
|
+
[Blockchain.Ethereum]: '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6',
|
|
5705
|
+
},
|
|
5706
|
+
};
|
|
5707
|
+
|
|
5708
|
+
/**
|
|
5709
|
+
* PLUME (Plume network token) token definition with addresses and metadata.
|
|
5710
|
+
*
|
|
5711
|
+
* @remarks
|
|
5712
|
+
* Built-in PLUME definition for the TokenRegistry. Includes chain locators
|
|
5713
|
+
* where PLUME is available.
|
|
5714
|
+
*/
|
|
5715
|
+
const PLUME = {
|
|
5716
|
+
symbol: 'PLUME',
|
|
5717
|
+
decimals: 18,
|
|
5718
|
+
locators: {
|
|
5719
|
+
[Blockchain.Ethereum]: '0x4C1746A800D224393fE2470C70A35717eD4eA5F1',
|
|
5720
|
+
},
|
|
5721
|
+
};
|
|
5722
|
+
|
|
5723
|
+
/**
|
|
5724
|
+
* MON token definition with Solana mint metadata.
|
|
5725
|
+
*
|
|
5726
|
+
* @remarks
|
|
5727
|
+
* Built-in MON definition for the TokenRegistry. Includes chain locators
|
|
5728
|
+
* for swap-supported chains.
|
|
5729
|
+
*/
|
|
5730
|
+
const MON = {
|
|
5731
|
+
symbol: 'MON',
|
|
5732
|
+
decimals: 18,
|
|
5733
|
+
chainDecimals: {
|
|
5734
|
+
[Blockchain.Solana]: 8,
|
|
5735
|
+
},
|
|
5736
|
+
locators: {
|
|
5737
|
+
[Blockchain.Solana]: 'CrAr4RRJMBVwRsZtT62pEhfA9H5utymC2mVx8e7FreP2',
|
|
5738
|
+
},
|
|
5739
|
+
};
|
|
5740
|
+
|
|
5741
|
+
// Re-export for consumers
|
|
5742
|
+
/**
|
|
5743
|
+
* All default token definitions.
|
|
5744
|
+
*
|
|
5745
|
+
* @remarks
|
|
5746
|
+
* These tokens are automatically included in the TokenRegistry when created
|
|
5747
|
+
* without explicit defaults. Extensions can override these definitions.
|
|
5748
|
+
* Includes USDC, USDT, EURC, DAI, USDE, PYUSD, WETH, WBTC, WSOL, WAVAX,
|
|
5749
|
+
* WPOL, ETH, POL, PLUME, and MON.
|
|
5750
|
+
*
|
|
5751
|
+
* @example
|
|
5752
|
+
* ```typescript
|
|
5753
|
+
* import { createTokenRegistry } from '@core/tokens'
|
|
5754
|
+
*
|
|
5755
|
+
* // Registry uses these by default
|
|
5756
|
+
* const registry = createTokenRegistry()
|
|
5757
|
+
*
|
|
5758
|
+
* // Add custom tokens (built-ins are still included)
|
|
5759
|
+
* const customRegistry = createTokenRegistry({
|
|
5760
|
+
* tokens: [myCustomToken],
|
|
5761
|
+
* })
|
|
5762
|
+
* ```
|
|
5763
|
+
*/
|
|
5764
|
+
const DEFAULT_TOKENS = [
|
|
5765
|
+
USDC,
|
|
5766
|
+
USDT,
|
|
5767
|
+
EURC,
|
|
5768
|
+
DAI,
|
|
5769
|
+
USDE,
|
|
5770
|
+
PYUSD,
|
|
5771
|
+
WETH,
|
|
5772
|
+
WBTC,
|
|
5773
|
+
WSOL,
|
|
5774
|
+
WAVAX,
|
|
5775
|
+
WPOL,
|
|
5776
|
+
ETH,
|
|
5777
|
+
POL,
|
|
5778
|
+
PLUME,
|
|
5779
|
+
MON,
|
|
5780
|
+
];
|
|
5781
|
+
/**
|
|
5782
|
+
* Uppercased token symbols approved for swap fee collection.
|
|
5783
|
+
*
|
|
5784
|
+
* @remarks
|
|
5785
|
+
* Derived from {@link DEFAULT_TOKENS} so all consumers share a single
|
|
5786
|
+
* allowlist source and stay in sync when defaults change.
|
|
5787
|
+
*/
|
|
5788
|
+
new Set(DEFAULT_TOKENS.map((t) => t.symbol.toUpperCase()));
|
|
5789
|
+
|
|
5790
|
+
/**
|
|
5791
|
+
* Resolve the effective decimals for a token on a specific chain.
|
|
5792
|
+
*
|
|
5793
|
+
* Returns the chain-specific override from `chainDecimals` when available,
|
|
5794
|
+
* otherwise falls back to the token's default `decimals`.
|
|
5795
|
+
*
|
|
5796
|
+
* @param token - The token definition to resolve decimals for.
|
|
5797
|
+
* @param chain - Optional chain identifier. When omitted, the default decimals are returned.
|
|
5798
|
+
* @returns The number of decimal places for the token on the given chain.
|
|
5799
|
+
*
|
|
5800
|
+
* @example
|
|
5801
|
+
* ```typescript
|
|
5802
|
+
* import { resolveTokenDecimals } from '\@core/tokens'
|
|
5803
|
+
*
|
|
5804
|
+
* // DAI: 18 decimals on EVM, 8 on Solana
|
|
5805
|
+
* resolveTokenDecimals(DAI) // 18 (default)
|
|
5806
|
+
* resolveTokenDecimals(DAI, 'Solana') // 8 (chain override)
|
|
5807
|
+
* resolveTokenDecimals(DAI, 'Ethereum') // 18 (no override, falls back)
|
|
5808
|
+
* ```
|
|
5809
|
+
*/
|
|
5810
|
+
function resolveTokenDecimals(token, chain) {
|
|
5811
|
+
if (chain === undefined) {
|
|
5812
|
+
return token.decimals;
|
|
5813
|
+
}
|
|
5814
|
+
return token.chainDecimals?.[chain] ?? token.decimals;
|
|
5815
|
+
}
|
|
5816
|
+
|
|
5817
|
+
/**
|
|
5818
|
+
* Check if a selector is a raw token selector (object form).
|
|
5819
|
+
*
|
|
5820
|
+
* @param selector - The token selector to check.
|
|
5821
|
+
* @returns True if the selector is a raw token selector.
|
|
5822
|
+
*/
|
|
5823
|
+
function isRawSelector(selector) {
|
|
5824
|
+
return typeof selector === 'object' && 'locator' in selector;
|
|
5825
|
+
}
|
|
5826
|
+
/**
|
|
5827
|
+
* Normalize a symbol to uppercase for case-insensitive lookup.
|
|
5828
|
+
*
|
|
5829
|
+
* @param symbol - The symbol to normalize.
|
|
5830
|
+
* @returns The normalized (uppercase) symbol.
|
|
5831
|
+
*/
|
|
5832
|
+
function normalizeSymbol(symbol) {
|
|
5833
|
+
return symbol.toUpperCase();
|
|
5834
|
+
}
|
|
5835
|
+
/**
|
|
5836
|
+
* Normalize a locator for stable chain-aware lookup.
|
|
5837
|
+
*
|
|
5838
|
+
* @remarks
|
|
5839
|
+
* EVM-style addresses (`0x...`) are normalized to lowercase for
|
|
5840
|
+
* case-insensitive matching. Non-EVM locators keep original casing.
|
|
5841
|
+
*/
|
|
5842
|
+
function normalizeLocator(locator) {
|
|
5843
|
+
if (locator.startsWith('0x') || locator.startsWith('0X')) {
|
|
5844
|
+
return locator.toLowerCase();
|
|
5845
|
+
}
|
|
5846
|
+
return locator;
|
|
5847
|
+
}
|
|
5848
|
+
/**
|
|
5849
|
+
* Build a stable map key for a chain + locator pair.
|
|
5850
|
+
*/
|
|
5851
|
+
function buildAddressKey(chainId, locator) {
|
|
5852
|
+
return `${chainId}::${normalizeLocator(locator)}`;
|
|
5853
|
+
}
|
|
5854
|
+
/**
|
|
5855
|
+
* Create a token registry with built-in tokens and optional extensions.
|
|
5856
|
+
*
|
|
5857
|
+
* @remarks
|
|
5858
|
+
* The registry always includes built-in tokens (DEFAULT_TOKENS) like USDC.
|
|
5859
|
+
* Custom tokens are merged on top - use this to add new tokens or override
|
|
5860
|
+
* built-in definitions.
|
|
5861
|
+
*
|
|
5862
|
+
* @param options - Configuration options for the registry.
|
|
5863
|
+
* @returns A token registry instance.
|
|
5864
|
+
*
|
|
5865
|
+
* @example
|
|
5866
|
+
* ```typescript
|
|
5867
|
+
* import { createTokenRegistry } from '@core/tokens'
|
|
5868
|
+
*
|
|
5869
|
+
* // Create registry with built-in tokens (USDC, etc.)
|
|
5870
|
+
* const registry = createTokenRegistry()
|
|
5871
|
+
*
|
|
5872
|
+
* // Resolve USDC on Ethereum
|
|
5873
|
+
* const usdc = registry.resolve('USDC', 'Ethereum')
|
|
5874
|
+
* console.log(usdc.locator) // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
5875
|
+
* console.log(usdc.decimals) // 6
|
|
5876
|
+
* ```
|
|
5877
|
+
*
|
|
5878
|
+
* @example
|
|
5879
|
+
* ```typescript
|
|
5880
|
+
* // Add custom tokens (built-ins are still included)
|
|
5881
|
+
* const myToken: TokenDefinition = {
|
|
5882
|
+
* symbol: 'MY',
|
|
5883
|
+
* decimals: 18,
|
|
5884
|
+
* locators: { Ethereum: '0x...' },
|
|
5885
|
+
* }
|
|
5886
|
+
*
|
|
5887
|
+
* const registry = createTokenRegistry({ tokens: [myToken] })
|
|
5888
|
+
* registry.resolve('USDC', 'Ethereum') // Still works!
|
|
5889
|
+
* registry.resolve('MY', 'Ethereum') // Also works
|
|
5890
|
+
* ```
|
|
5891
|
+
*
|
|
5892
|
+
* @example
|
|
5893
|
+
* ```typescript
|
|
5894
|
+
* // Override a built-in token
|
|
5895
|
+
* const customUsdc: TokenDefinition = {
|
|
5896
|
+
* symbol: 'USDC',
|
|
5897
|
+
* decimals: 6,
|
|
5898
|
+
* locators: { MyChain: '0xCustomAddress' },
|
|
5899
|
+
* }
|
|
5900
|
+
*
|
|
5901
|
+
* const registry = createTokenRegistry({ tokens: [customUsdc] })
|
|
5902
|
+
* // Now USDC resolves to customUsdc definition
|
|
5903
|
+
* ```
|
|
5904
|
+
*
|
|
5905
|
+
* @example
|
|
5906
|
+
* ```typescript
|
|
5907
|
+
* // Resolve arbitrary tokens by raw locator
|
|
5908
|
+
* const registry = createTokenRegistry()
|
|
5909
|
+
* const token = registry.resolve(
|
|
5910
|
+
* { locator: '0x1234...', decimals: 18 },
|
|
5911
|
+
* 'Ethereum'
|
|
5912
|
+
* )
|
|
5913
|
+
* ```
|
|
5914
|
+
*/
|
|
5915
|
+
function createTokenRegistry(options = {}) {
|
|
5916
|
+
const { tokens = [], requireDecimals = false } = options;
|
|
5917
|
+
// Build the token map: always start with DEFAULT_TOKENS, then add custom tokens
|
|
5918
|
+
const tokenMap = new Map();
|
|
5919
|
+
// Add built-in tokens first
|
|
5920
|
+
for (const def of DEFAULT_TOKENS) {
|
|
5921
|
+
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
5922
|
+
}
|
|
5923
|
+
// Custom tokens override built-ins
|
|
5924
|
+
for (const def of tokens) {
|
|
5925
|
+
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
5926
|
+
}
|
|
5927
|
+
// Build an address index from the resolved token map so overrides win.
|
|
5928
|
+
const addressMap = new Map();
|
|
5929
|
+
for (const token of tokenMap.values()) {
|
|
5930
|
+
for (const [chainId, locator] of Object.entries(token.locators)) {
|
|
5931
|
+
if (typeof locator !== 'string' || locator.trim() === '') {
|
|
5932
|
+
continue;
|
|
5933
|
+
}
|
|
5934
|
+
addressMap.set(buildAddressKey(chainId, locator), token);
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
/**
|
|
5938
|
+
* Resolve a symbol selector to token information.
|
|
5939
|
+
*/
|
|
5940
|
+
function resolveSymbol(symbol, chainId) {
|
|
5941
|
+
const normalizedSymbol = normalizeSymbol(symbol);
|
|
5942
|
+
const definition = tokenMap.get(normalizedSymbol);
|
|
5943
|
+
if (definition === undefined) {
|
|
5944
|
+
throw createTokenResolutionError(`Unknown token symbol: ${symbol}. Register it via createTokenRegistry({ tokens: [...] }) or use a raw selector.`, symbol, chainId);
|
|
5945
|
+
}
|
|
5946
|
+
const locator = definition.locators[chainId];
|
|
5947
|
+
if (locator === undefined || locator.trim() === '') {
|
|
5948
|
+
throw createTokenResolutionError(`Token ${symbol} has no locator for chain ${chainId}`, symbol, chainId);
|
|
5949
|
+
}
|
|
5950
|
+
const decimals = resolveTokenDecimals(definition, chainId);
|
|
5951
|
+
return {
|
|
5952
|
+
symbol: definition.symbol,
|
|
5953
|
+
decimals,
|
|
5954
|
+
locator: normalizeLocator(locator),
|
|
5955
|
+
};
|
|
5956
|
+
}
|
|
5957
|
+
/**
|
|
5958
|
+
* Resolve a raw selector to token information.
|
|
5959
|
+
*/
|
|
5960
|
+
function resolveRaw(selector, chainId) {
|
|
5961
|
+
const { locator, decimals } = selector;
|
|
5962
|
+
// Validate locator
|
|
5963
|
+
if (!locator || typeof locator !== 'string') {
|
|
5964
|
+
throw createTokenResolutionError('Raw selector must have a valid locator string', selector, chainId);
|
|
5965
|
+
}
|
|
5966
|
+
// Decimals are always required for raw selectors
|
|
5967
|
+
if (decimals === undefined) {
|
|
5968
|
+
const message = requireDecimals
|
|
5969
|
+
? 'Decimals required for raw token selector (requireDecimals: true)'
|
|
5970
|
+
: 'Decimals required for raw token selector. Provide { locator, decimals }.';
|
|
5971
|
+
throw createTokenResolutionError(message, selector, chainId);
|
|
5972
|
+
}
|
|
5973
|
+
// Validate decimals
|
|
5974
|
+
if (typeof decimals !== 'number' ||
|
|
5975
|
+
decimals < 0 ||
|
|
5976
|
+
!Number.isInteger(decimals)) {
|
|
5977
|
+
throw createTokenResolutionError(`Invalid decimals: ${String(decimals)}. Must be a non-negative integer.`, selector, chainId);
|
|
5978
|
+
}
|
|
5979
|
+
return {
|
|
5980
|
+
decimals,
|
|
5981
|
+
locator: normalizeLocator(locator),
|
|
5982
|
+
};
|
|
5983
|
+
}
|
|
5984
|
+
return {
|
|
5985
|
+
resolve(selector, chainId) {
|
|
5986
|
+
// Runtime validation of inputs - these checks are for JS consumers
|
|
5987
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
5988
|
+
if (selector === null || selector === undefined) {
|
|
5989
|
+
throw createTokenResolutionError('Token selector cannot be null or undefined', selector, chainId);
|
|
5990
|
+
}
|
|
5991
|
+
if (chainId === '' || typeof chainId !== 'string') {
|
|
5992
|
+
throw createTokenResolutionError('Chain ID is required for token resolution', selector, chainId);
|
|
5993
|
+
}
|
|
5994
|
+
// Dispatch based on selector type
|
|
5995
|
+
if (isRawSelector(selector)) {
|
|
5996
|
+
return resolveRaw(selector, chainId);
|
|
5997
|
+
}
|
|
5998
|
+
if (typeof selector === 'string') {
|
|
5999
|
+
return resolveSymbol(selector, chainId);
|
|
6000
|
+
}
|
|
6001
|
+
throw createTokenResolutionError(`Invalid selector type: ${typeof selector}. Expected string or object with locator.`, selector, chainId);
|
|
6002
|
+
},
|
|
6003
|
+
resolveByAddress(address, chainId) {
|
|
6004
|
+
if (!address || typeof address !== 'string') {
|
|
6005
|
+
throw createTokenResolutionError('Token address is required for address resolution', { locator: address }, chainId);
|
|
6006
|
+
}
|
|
6007
|
+
if (chainId === '' || typeof chainId !== 'string') {
|
|
6008
|
+
throw createTokenResolutionError('Chain ID is required for token resolution', { locator: address }, chainId);
|
|
6009
|
+
}
|
|
6010
|
+
const definition = addressMap.get(buildAddressKey(chainId, address));
|
|
6011
|
+
if (definition === undefined) {
|
|
6012
|
+
throw createTokenResolutionError(`Unknown token address: ${address} for chain ${chainId}`, { locator: address }, chainId);
|
|
6013
|
+
}
|
|
6014
|
+
const locator = definition.locators[chainId];
|
|
6015
|
+
if (locator === undefined || locator.trim() === '') {
|
|
6016
|
+
throw createTokenResolutionError(`Token ${definition.symbol} has no locator for chain ${chainId}`, definition.symbol, chainId);
|
|
6017
|
+
}
|
|
6018
|
+
const decimals = resolveTokenDecimals(definition, chainId);
|
|
6019
|
+
return {
|
|
6020
|
+
symbol: definition.symbol,
|
|
6021
|
+
decimals,
|
|
6022
|
+
locator: normalizeLocator(locator),
|
|
6023
|
+
};
|
|
6024
|
+
},
|
|
6025
|
+
get(symbol) {
|
|
6026
|
+
if (!symbol || typeof symbol !== 'string') {
|
|
6027
|
+
return undefined;
|
|
6028
|
+
}
|
|
6029
|
+
return tokenMap.get(normalizeSymbol(symbol));
|
|
6030
|
+
},
|
|
6031
|
+
has(symbol) {
|
|
6032
|
+
if (!symbol || typeof symbol !== 'string') {
|
|
6033
|
+
return false;
|
|
6034
|
+
}
|
|
6035
|
+
return tokenMap.has(normalizeSymbol(symbol));
|
|
6036
|
+
},
|
|
6037
|
+
symbols() {
|
|
6038
|
+
return Array.from(tokenMap.values()).map((def) => def.symbol);
|
|
6039
|
+
},
|
|
6040
|
+
entries() {
|
|
6041
|
+
return Array.from(tokenMap.values());
|
|
6042
|
+
},
|
|
6043
|
+
};
|
|
6044
|
+
}
|
|
6045
|
+
|
|
6046
|
+
/**
|
|
6047
|
+
* Define a schema for token registry interfaces.
|
|
6048
|
+
*
|
|
6049
|
+
* @remarks
|
|
6050
|
+
* Validate that a registry exposes the `resolve()` API used by adapters.
|
|
6051
|
+
*
|
|
6052
|
+
* @example
|
|
6053
|
+
* ```typescript
|
|
6054
|
+
* import { tokenRegistrySchema } from '@core/tokens'
|
|
6055
|
+
*
|
|
6056
|
+
* const registry = {
|
|
6057
|
+
* resolve: () => ({ locator: '0x0', decimals: 6 }),
|
|
6058
|
+
* }
|
|
6059
|
+
*
|
|
6060
|
+
* tokenRegistrySchema.parse(registry)
|
|
6061
|
+
* ```
|
|
6062
|
+
*/
|
|
6063
|
+
zod.z.custom((value) => {
|
|
6064
|
+
if (value === null || typeof value !== 'object') {
|
|
6065
|
+
return false;
|
|
6066
|
+
}
|
|
6067
|
+
const record = value;
|
|
6068
|
+
return (typeof record['resolve'] === 'function' &&
|
|
6069
|
+
typeof record['get'] === 'function' &&
|
|
6070
|
+
typeof record['has'] === 'function' &&
|
|
6071
|
+
typeof record['symbols'] === 'function' &&
|
|
6072
|
+
typeof record['entries'] === 'function');
|
|
6073
|
+
}, {
|
|
6074
|
+
message: 'Invalid token registry',
|
|
6075
|
+
});
|
|
6076
|
+
|
|
6077
|
+
/**
|
|
6078
|
+
* Build a complete explorer URL from a chain definition and transaction hash.
|
|
6079
|
+
*
|
|
6080
|
+
* This function takes a chain definition containing an explorer URL template
|
|
6081
|
+
* and replaces the `{hash}` placeholder with the provided transaction hash
|
|
6082
|
+
* to create a complete, valid explorer URL.
|
|
6083
|
+
*
|
|
6084
|
+
* @param chainDef - The chain definition containing the explorer URL template.
|
|
6085
|
+
* @param txHash - The transaction hash to insert into the URL template.
|
|
6086
|
+
* @returns A complete explorer URL with the transaction hash inserted.
|
|
6087
|
+
* @throws Error if the chain definition is null/undefined.
|
|
6088
|
+
* @throws Error if the transaction hash is null/undefined/empty.
|
|
6089
|
+
* @throws Error if the explorer URL template is missing or empty.
|
|
6090
|
+
* @throws Error if the explorer URL template doesn't contain the {hash} placeholder.
|
|
6091
|
+
* @throws Error if the resulting URL is invalid.
|
|
6092
|
+
*
|
|
6093
|
+
* @example
|
|
6094
|
+
* ```typescript
|
|
6095
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6096
|
+
* import { Ethereum } from '@core/chains'
|
|
6097
|
+
*
|
|
6098
|
+
* // Build URL for Ethereum transaction
|
|
6099
|
+
* const url = buildExplorerUrl(Ethereum, '0x1234567890abcdef...')
|
|
6100
|
+
* console.log(url) // 'https://etherscan.io/tx/0x1234567890abcdef...'
|
|
6101
|
+
* ```
|
|
6102
|
+
*
|
|
6103
|
+
* @example
|
|
6104
|
+
* ```typescript
|
|
6105
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6106
|
+
* import { Solana } from '@core/chains'
|
|
6107
|
+
*
|
|
6108
|
+
* // Build URL for Solana transaction
|
|
6109
|
+
* const url = buildExplorerUrl(Solana, 'abc123def456...')
|
|
6110
|
+
* console.log(url) // 'https://solscan.io/tx/abc123def456...'
|
|
6111
|
+
* ```
|
|
6112
|
+
*
|
|
6113
|
+
* @example
|
|
6114
|
+
* ```typescript
|
|
6115
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6116
|
+
* import { Aptos } from '@core/chains'
|
|
6117
|
+
*
|
|
6118
|
+
* // Build URL for Aptos transaction with query parameters
|
|
6119
|
+
* const url = buildExplorerUrl(Aptos, '0xabc123...')
|
|
6120
|
+
* console.log(url) // 'https://explorer.aptoslabs.com/txn/0xabc123...?network=mainnet'
|
|
6121
|
+
* ```
|
|
6122
|
+
*/
|
|
6123
|
+
function buildExplorerUrl(chainDef, txHash) {
|
|
6124
|
+
// Validate input parameters using our standard validation pattern
|
|
6125
|
+
validateOrThrow({ chainDef, txHash }, buildExplorerUrlParamsSchema, 'Invalid buildExplorerUrl parameters');
|
|
6126
|
+
// Parse and transform input parameters (e.g., trim whitespace from txHash)
|
|
6127
|
+
const { chainDef: validChainDef, txHash: validTxHash } = buildExplorerUrlParamsSchema.parse({ chainDef, txHash });
|
|
6128
|
+
// Replace all occurrences of the placeholder with the transaction hash
|
|
6129
|
+
const explorerUrl = validChainDef.explorerUrl.replace(/{hash}/g, validTxHash);
|
|
6130
|
+
// Validate the resulting URL
|
|
6131
|
+
validate(explorerUrl, explorerUrlSchema, 'explorer URL');
|
|
6132
|
+
return explorerUrl;
|
|
6133
|
+
}
|
|
6134
|
+
|
|
6135
|
+
/**
|
|
6136
|
+
* CCTP forwarding magic bytes prefix.
|
|
6137
|
+
*
|
|
6138
|
+
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
6139
|
+
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
6140
|
+
*/
|
|
6141
|
+
const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
6142
|
+
/**
|
|
6143
|
+
* CCTP forwarding version number.
|
|
6144
|
+
*
|
|
6145
|
+
* Version 0 is used for basic forwarding requests.
|
|
6146
|
+
*/
|
|
6147
|
+
const CCTP_FORWARD_VERSION = 0;
|
|
6148
|
+
/**
|
|
6149
|
+
* Length of Circle-reserved payload for basic forwarding (0 bytes).
|
|
6150
|
+
*
|
|
6151
|
+
* Set to 0 when no additional Circle-reserved data is needed.
|
|
6152
|
+
*/
|
|
6153
|
+
const CCTP_FORWARD_PAYLOAD_LENGTH = 0;
|
|
6154
|
+
/**
|
|
6155
|
+
* Build the hookData bytes for CCTP forwarding.
|
|
6156
|
+
*
|
|
6157
|
+
* Constructs a 32-byte hookData payload that signals to Circle's Orbit relayer
|
|
6158
|
+
* that the user wants automated attestation fetching and destination mint execution.
|
|
6159
|
+
*
|
|
6160
|
+
* The hookData format is:
|
|
6161
|
+
* - Bytes 0-23: ASCII "cctp-forward" right-padded to 24 bytes with zeros
|
|
6162
|
+
* - Bytes 24-27: uint32 version (big-endian) - currently 0
|
|
6163
|
+
* - Bytes 28-31: uint32 length (big-endian) - 0 for basic forwarding
|
|
6164
|
+
*
|
|
6165
|
+
* @returns A 0x-prefixed hex string representing the 32-byte hookData
|
|
6166
|
+
*
|
|
6167
|
+
* @example
|
|
6168
|
+
* ```typescript
|
|
6169
|
+
* import { buildForwardingHookData } from '@core/utils'
|
|
6170
|
+
*
|
|
6171
|
+
* const hookData = buildForwardingHookData()
|
|
6172
|
+
* // Returns: '0x636374702d666f72776172640000000000000000000000000000000000000000'
|
|
6173
|
+
*
|
|
6174
|
+
* // Use with depositForBurnWithHook action
|
|
6175
|
+
* await adapter.action('cctp.v2.depositForBurnWithHook', {
|
|
6176
|
+
* amount: BigInt('1000000'),
|
|
6177
|
+
* mintRecipient: '0x...',
|
|
6178
|
+
* maxFee: BigInt('50000'),
|
|
6179
|
+
* minFinalityThreshold: 1000,
|
|
6180
|
+
* fromChain: ethereum,
|
|
6181
|
+
* toChain: base,
|
|
6182
|
+
* hookData
|
|
6183
|
+
* })
|
|
6184
|
+
* ```
|
|
6185
|
+
*/
|
|
6186
|
+
// Cached result for memoization (computed once on first call)
|
|
6187
|
+
let cachedHookDataHex = null;
|
|
5049
6188
|
function buildForwardingHookData() {
|
|
5050
6189
|
// Return cached result if already computed
|
|
5051
6190
|
if (cachedHookDataHex !== null) {
|
|
@@ -5549,6 +6688,21 @@ async function fetchUsdcFastBurnFee(sourceDomain, destinationDomain, isTestnet)
|
|
|
5549
6688
|
return minimumFee;
|
|
5550
6689
|
}
|
|
5551
6690
|
|
|
6691
|
+
/**
|
|
6692
|
+
* Well-known SPL Token program ID.
|
|
6693
|
+
* Duplicated here as a raw string to avoid a static import of \@core/adapter-solana
|
|
6694
|
+
* (which would transitively pull \@solana/web3.js into the top-level bundle and
|
|
6695
|
+
* break lazy-loading for EVM-only consumers).
|
|
6696
|
+
*
|
|
6697
|
+
* This MUST match TOKEN_PROGRAM_ID in @core/adapter-solana/src/utils/splTokenUtils.
|
|
6698
|
+
*/
|
|
6699
|
+
const TOKEN_PROGRAM_ID_BASE58 = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; // NOSONAR — public Solana program address
|
|
6700
|
+
/**
|
|
6701
|
+
* Well-known SPL Associated Token Account program ID (same rationale as above).
|
|
6702
|
+
*
|
|
6703
|
+
* This MUST match ASSOCIATED_TOKEN_PROGRAM_ID in @core/adapter-solana/src/utils/splTokenUtils.
|
|
6704
|
+
*/
|
|
6705
|
+
const ASSOCIATED_TOKEN_PROGRAM_ID_BASE58 = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'; // NOSONAR — public Solana program address
|
|
5552
6706
|
/**
|
|
5553
6707
|
* Get the token account address where USDC will be minted for the recipient.
|
|
5554
6708
|
*
|
|
@@ -5592,20 +6746,30 @@ mintAddress) => {
|
|
|
5592
6746
|
return rawAddress;
|
|
5593
6747
|
}
|
|
5594
6748
|
else {
|
|
5595
|
-
// Solana: derive the associated token account
|
|
5596
|
-
//
|
|
6749
|
+
// Solana: derive the associated token account.
|
|
6750
|
+
// Both @solana/web3.js and the program-ID constants are resolved lazily
|
|
6751
|
+
// so that EVM-only consumers never load Solana code.
|
|
6752
|
+
const { PublicKey } = await import('@solana/web3.js').catch(() => {
|
|
6753
|
+
throw new KitError({
|
|
6754
|
+
...InputError.VALIDATION_FAILED,
|
|
6755
|
+
recoverability: 'FATAL',
|
|
6756
|
+
message: 'Failed to load @solana/web3.js. Please ensure it is installed: npm install @solana/web3.js',
|
|
6757
|
+
});
|
|
6758
|
+
});
|
|
5597
6759
|
try {
|
|
5598
|
-
const [{ PublicKey }, { getAssociatedTokenAddressSync }] = await Promise.all([
|
|
5599
|
-
import('@solana/web3.js'),
|
|
5600
|
-
import('@solana/spl-token'),
|
|
5601
|
-
]);
|
|
5602
6760
|
const owner = new PublicKey(rawAddress);
|
|
5603
6761
|
const mintPub = new PublicKey(mintAddress);
|
|
5604
|
-
const
|
|
6762
|
+
const tokenProgramId = new PublicKey(TOKEN_PROGRAM_ID_BASE58);
|
|
6763
|
+
const ataProgramId = new PublicKey(ASSOCIATED_TOKEN_PROGRAM_ID_BASE58);
|
|
6764
|
+
const [ata] = PublicKey.findProgramAddressSync([owner.toBuffer(), tokenProgramId.toBuffer(), mintPub.toBuffer()], ataProgramId);
|
|
5605
6765
|
return ata.toBase58();
|
|
5606
6766
|
}
|
|
5607
|
-
catch {
|
|
5608
|
-
throw new
|
|
6767
|
+
catch (error) {
|
|
6768
|
+
throw new KitError({
|
|
6769
|
+
...InputError.INVALID_ADDRESS,
|
|
6770
|
+
recoverability: 'FATAL',
|
|
6771
|
+
message: `Failed to derive Solana Associated Token Account for recipient "${rawAddress}": ${error instanceof Error ? error.message : String(error)}`,
|
|
6772
|
+
});
|
|
5609
6773
|
}
|
|
5610
6774
|
}
|
|
5611
6775
|
};
|
|
@@ -7921,590 +9085,239 @@ function createLogger(options, stream) {
|
|
|
7921
9085
|
const finalOptions = redactConfig
|
|
7922
9086
|
? { ...pinoOptions, redact: redactConfig }
|
|
7923
9087
|
: pinoOptions;
|
|
7924
|
-
const pinoInstance = pino__default(finalOptions);
|
|
7925
|
-
return wrapPino(pinoInstance);
|
|
7926
|
-
}
|
|
7927
|
-
|
|
7928
|
-
/**
|
|
7929
|
-
* Factory for creating Runtime instances with defaults.
|
|
7930
|
-
*
|
|
7931
|
-
* @packageDocumentation
|
|
7932
|
-
*/
|
|
7933
|
-
// ============================================================================
|
|
7934
|
-
// Validation Schema
|
|
7935
|
-
// ============================================================================
|
|
7936
|
-
/**
|
|
7937
|
-
* Schema for validating {@link RuntimeOptions}.
|
|
7938
|
-
*
|
|
7939
|
-
* @remarks
|
|
7940
|
-
* Used internally by {@link createRuntime} to validate options from JS consumers.
|
|
7941
|
-
* Exported for advanced use cases where manual validation is needed.
|
|
7942
|
-
*/
|
|
7943
|
-
zod.z
|
|
7944
|
-
.object({
|
|
7945
|
-
logger: loggerSchema.optional(),
|
|
7946
|
-
metrics: metricsSchema.optional(),
|
|
7947
|
-
})
|
|
7948
|
-
.passthrough();
|
|
7949
|
-
// ============================================================================
|
|
7950
|
-
// Factory
|
|
7951
|
-
// ============================================================================
|
|
7952
|
-
/**
|
|
7953
|
-
* Create a complete Runtime with sensible defaults.
|
|
7954
|
-
*
|
|
7955
|
-
* @param options - Optional configuration to override logger and metrics.
|
|
7956
|
-
* @returns A frozen, immutable Runtime with all services guaranteed present.
|
|
7957
|
-
* @throws KitError (INPUT_VALIDATION_FAILED) if options contain invalid services.
|
|
7958
|
-
*
|
|
7959
|
-
* @remarks
|
|
7960
|
-
* Creates a fully-configured runtime by merging provided options with defaults.
|
|
7961
|
-
* The returned runtime is frozen to enforce immutability.
|
|
7962
|
-
*
|
|
7963
|
-
* | Service | Default | Configurable |
|
|
7964
|
-
* |---------|---------|--------------|
|
|
7965
|
-
* | `logger` | pino logger (info level) | Yes |
|
|
7966
|
-
* | `metrics` | No-op metrics | Yes |
|
|
7967
|
-
* | `events` | Internal event bus | No |
|
|
7968
|
-
* | `clock` | `Date.now()` | No |
|
|
7969
|
-
*
|
|
7970
|
-
* **Why only logger and metrics?**
|
|
7971
|
-
*
|
|
7972
|
-
* - **Logger/Metrics**: Integration points with your infrastructure
|
|
7973
|
-
* - **Events**: Internal pub/sub mechanism - subscribe via `runtime.events.on()`
|
|
7974
|
-
* - **Clock**: Testing concern - use mock factories for tests
|
|
7975
|
-
*
|
|
7976
|
-
* @example
|
|
7977
|
-
* ```typescript
|
|
7978
|
-
* import { createRuntime, createLogger } from '@core/runtime'
|
|
7979
|
-
*
|
|
7980
|
-
* // Use all defaults
|
|
7981
|
-
* const runtime = createRuntime()
|
|
7982
|
-
*
|
|
7983
|
-
* // Custom logger
|
|
7984
|
-
* const runtime = createRuntime({
|
|
7985
|
-
* logger: createLogger({ level: 'debug' }),
|
|
7986
|
-
* })
|
|
7987
|
-
*
|
|
7988
|
-
* // Custom metrics (e.g., Prometheus)
|
|
7989
|
-
* const runtime = createRuntime({
|
|
7990
|
-
* metrics: myPrometheusMetrics,
|
|
7991
|
-
* })
|
|
7992
|
-
*
|
|
7993
|
-
* // Subscribe to events (don't replace the bus)
|
|
7994
|
-
* runtime.events.on('operation.*', (event) => {
|
|
7995
|
-
* console.log('Event:', event.name)
|
|
7996
|
-
* })
|
|
7997
|
-
* ```
|
|
7998
|
-
*/
|
|
7999
|
-
function createRuntime(options) {
|
|
8000
|
-
// Resolve logger first (events may need it)
|
|
8001
|
-
const logger = createLogger();
|
|
8002
|
-
// Internal services - not configurable
|
|
8003
|
-
const events = createEventBus({ logger });
|
|
8004
|
-
const clock = defaultClock;
|
|
8005
|
-
// Resolve metrics
|
|
8006
|
-
const metrics = noopMetrics;
|
|
8007
|
-
return Object.freeze({ logger, events, metrics, clock });
|
|
8008
|
-
}
|
|
8009
|
-
|
|
8010
|
-
/**
|
|
8011
|
-
* Invocation context resolution - resolves the **WHO/HOW** of an operation.
|
|
8012
|
-
*
|
|
8013
|
-
* @packageDocumentation
|
|
8014
|
-
*/
|
|
8015
|
-
// ============================================================================
|
|
8016
|
-
// Validation Schemas
|
|
8017
|
-
// ============================================================================
|
|
8018
|
-
/**
|
|
8019
|
-
* Schema for validating Caller.
|
|
8020
|
-
*/
|
|
8021
|
-
const callerSchema = zod.z.object({
|
|
8022
|
-
type: zod.z.string(),
|
|
8023
|
-
name: zod.z.string(),
|
|
8024
|
-
version: zod.z.string().optional(),
|
|
8025
|
-
});
|
|
8026
|
-
/**
|
|
8027
|
-
* Schema for validating InvocationMeta input.
|
|
8028
|
-
*/
|
|
8029
|
-
const invocationMetaSchema = zod.z
|
|
8030
|
-
.object({
|
|
8031
|
-
traceId: zod.z.string().optional(),
|
|
8032
|
-
runtime: zod.z.object({}).passthrough().optional(),
|
|
8033
|
-
tokens: zod.z.object({}).passthrough().optional(),
|
|
8034
|
-
callers: zod.z.array(callerSchema).optional(),
|
|
8035
|
-
})
|
|
8036
|
-
.strict();
|
|
8037
|
-
// ============================================================================
|
|
8038
|
-
// Invocation Context Resolution
|
|
8039
|
-
// ============================================================================
|
|
8040
|
-
/**
|
|
8041
|
-
* Resolve invocation metadata to invocation context.
|
|
8042
|
-
*
|
|
8043
|
-
* @param meta - User-provided invocation metadata (**WHO/HOW**), optional.
|
|
8044
|
-
* @param defaults - Default runtime and tokens to use if not overridden.
|
|
8045
|
-
* @returns Frozen, immutable invocation context with guaranteed values.
|
|
8046
|
-
* @throws KitError when meta contains invalid properties.
|
|
8047
|
-
*
|
|
8048
|
-
* @remarks
|
|
8049
|
-
* Resolves the **WHO** called and **HOW** to observe:
|
|
8050
|
-
* - TraceId: Uses provided value or generates new one
|
|
8051
|
-
* - Runtime: Uses meta.runtime if provided, otherwise defaults.runtime
|
|
8052
|
-
* - Tokens: Uses meta.tokens if provided, otherwise defaults.tokens
|
|
8053
|
-
* - Callers: Uses provided array or empty array
|
|
8054
|
-
*
|
|
8055
|
-
* The returned context is frozen to enforce immutability.
|
|
8056
|
-
*
|
|
8057
|
-
* @example
|
|
8058
|
-
* ```typescript
|
|
8059
|
-
* import { resolveInvocationContext, createRuntime } from '@core/runtime'
|
|
8060
|
-
* import { createTokenRegistry } from '@core/tokens'
|
|
8061
|
-
*
|
|
8062
|
-
* const defaults = {
|
|
8063
|
-
* runtime: createRuntime(),
|
|
8064
|
-
* tokens: createTokenRegistry(),
|
|
8065
|
-
* }
|
|
8066
|
-
*
|
|
8067
|
-
* // Minimal - just using defaults
|
|
8068
|
-
* const ctx = resolveInvocationContext(undefined, defaults)
|
|
8069
|
-
*
|
|
8070
|
-
* // With trace ID and caller info
|
|
8071
|
-
* const ctx = resolveInvocationContext(
|
|
8072
|
-
* {
|
|
8073
|
-
* traceId: 'abc-123',
|
|
8074
|
-
* callers: [{ type: 'kit', name: 'BridgeKit', version: '1.0.0' }],
|
|
8075
|
-
* },
|
|
8076
|
-
* defaults
|
|
8077
|
-
* )
|
|
8078
|
-
*
|
|
8079
|
-
* // With runtime override (complete replacement)
|
|
8080
|
-
* const ctx = resolveInvocationContext(
|
|
8081
|
-
* { runtime: createRuntime({ logger: myLogger }) },
|
|
8082
|
-
* defaults
|
|
8083
|
-
* )
|
|
8084
|
-
* ```
|
|
8085
|
-
*/
|
|
8086
|
-
function resolveInvocationContext(meta, defaults) {
|
|
8087
|
-
// Validate meta input if provided
|
|
8088
|
-
if (meta !== undefined) {
|
|
8089
|
-
const result = invocationMetaSchema.safeParse(meta);
|
|
8090
|
-
if (!result.success) {
|
|
8091
|
-
throw createValidationFailedError('invocationMeta', meta, result.error.errors.map((e) => e.message).join(', '));
|
|
8092
|
-
}
|
|
8093
|
-
}
|
|
8094
|
-
// Generate trace ID if not provided
|
|
8095
|
-
const traceId = meta?.traceId ?? createTraceId();
|
|
8096
|
-
// Use meta overrides or fall back to defaults
|
|
8097
|
-
const runtime = meta?.runtime ?? defaults.runtime;
|
|
8098
|
-
const tokens = meta?.tokens ?? defaults.tokens;
|
|
8099
|
-
const callers = meta?.callers ?? [];
|
|
8100
|
-
return Object.freeze({ traceId, runtime, tokens, callers });
|
|
9088
|
+
const pinoInstance = pino__default(finalOptions);
|
|
9089
|
+
return wrapPino(pinoInstance);
|
|
8101
9090
|
}
|
|
8102
9091
|
|
|
8103
9092
|
/**
|
|
8104
|
-
*
|
|
9093
|
+
* Factory for creating Runtime instances with defaults.
|
|
8105
9094
|
*
|
|
8106
|
-
* @
|
|
8107
|
-
|
|
8108
|
-
|
|
9095
|
+
* @packageDocumentation
|
|
9096
|
+
*/
|
|
9097
|
+
// ============================================================================
|
|
9098
|
+
// Validation Schema
|
|
9099
|
+
// ============================================================================
|
|
9100
|
+
/**
|
|
9101
|
+
* Schema for validating {@link RuntimeOptions}.
|
|
8109
9102
|
*
|
|
8110
9103
|
* @remarks
|
|
8111
|
-
*
|
|
8112
|
-
*
|
|
8113
|
-
* (traceId, runtime, tokens).
|
|
8114
|
-
*
|
|
8115
|
-
* The returned context is frozen to enforce immutability.
|
|
8116
|
-
*
|
|
8117
|
-
* @example
|
|
8118
|
-
* ```typescript
|
|
8119
|
-
* import { extendInvocationContext } from '@core/runtime'
|
|
8120
|
-
*
|
|
8121
|
-
* const caller = { type: 'provider', name: 'CCTPV2', version: '1.0.0' }
|
|
8122
|
-
* const extended = extendInvocationContext(existingContext, caller)
|
|
8123
|
-
* // extended.callers === [...existingContext.callers, caller]
|
|
8124
|
-
* ```
|
|
9104
|
+
* Used internally by {@link createRuntime} to validate options from JS consumers.
|
|
9105
|
+
* Exported for advanced use cases where manual validation is needed.
|
|
8125
9106
|
*/
|
|
8126
|
-
function extendInvocationContext(context, caller) {
|
|
8127
|
-
return Object.freeze({
|
|
8128
|
-
traceId: context.traceId,
|
|
8129
|
-
runtime: context.runtime,
|
|
8130
|
-
tokens: context.tokens,
|
|
8131
|
-
callers: [...context.callers, caller],
|
|
8132
|
-
});
|
|
8133
|
-
}
|
|
8134
|
-
|
|
8135
|
-
// Clock - expose defaultClock for backward compatibility
|
|
8136
|
-
/** Clock validation schema (backward compatibility). */
|
|
8137
|
-
zod.z.custom((val) => val !== null &&
|
|
8138
|
-
typeof val === 'object' &&
|
|
8139
|
-
'now' in val &&
|
|
8140
|
-
typeof val['now'] === 'function');
|
|
8141
|
-
/** EventBus validation schema (backward compatibility). */
|
|
8142
|
-
zod.z.custom((val) => val !== null &&
|
|
8143
|
-
typeof val === 'object' &&
|
|
8144
|
-
'emit' in val &&
|
|
8145
|
-
typeof val['emit'] === 'function');
|
|
8146
|
-
/** Runtime validation schema (backward compatibility). */
|
|
8147
9107
|
zod.z
|
|
8148
9108
|
.object({
|
|
8149
|
-
logger:
|
|
8150
|
-
|
|
8151
|
-
metrics: zod.z.any().optional(),
|
|
8152
|
-
clock: zod.z.any().optional(),
|
|
9109
|
+
logger: loggerSchema.optional(),
|
|
9110
|
+
metrics: metricsSchema.optional(),
|
|
8153
9111
|
})
|
|
8154
9112
|
.passthrough();
|
|
8155
|
-
|
|
9113
|
+
// ============================================================================
|
|
9114
|
+
// Factory
|
|
9115
|
+
// ============================================================================
|
|
8156
9116
|
/**
|
|
8157
|
-
* Create a
|
|
9117
|
+
* Create a complete Runtime with sensible defaults.
|
|
8158
9118
|
*
|
|
8159
|
-
* @
|
|
8160
|
-
*
|
|
8161
|
-
*
|
|
9119
|
+
* @param options - Optional configuration to override logger and metrics.
|
|
9120
|
+
* @returns A frozen, immutable Runtime with all services guaranteed present.
|
|
9121
|
+
* @throws KitError (INPUT_VALIDATION_FAILED) if options contain invalid services.
|
|
8162
9122
|
*
|
|
8163
|
-
* @
|
|
8164
|
-
*
|
|
8165
|
-
*
|
|
8166
|
-
* @param cause - The underlying error, if any (optional).
|
|
8167
|
-
* @returns A KitError with INPUT type and FATAL recoverability.
|
|
9123
|
+
* @remarks
|
|
9124
|
+
* Creates a fully-configured runtime by merging provided options with defaults.
|
|
9125
|
+
* The returned runtime is frozen to enforce immutability.
|
|
8168
9126
|
*
|
|
8169
|
-
*
|
|
8170
|
-
*
|
|
8171
|
-
*
|
|
8172
|
-
*
|
|
8173
|
-
*
|
|
8174
|
-
*
|
|
8175
|
-
* )
|
|
8176
|
-
* ```
|
|
8177
|
-
*/
|
|
8178
|
-
function createTokenResolutionError(message, selector, chainId, cause) {
|
|
8179
|
-
const trace = {
|
|
8180
|
-
selector,
|
|
8181
|
-
...(chainId === undefined ? {} : { chainId }),
|
|
8182
|
-
...({} ),
|
|
8183
|
-
};
|
|
8184
|
-
return new KitError({
|
|
8185
|
-
...InputError.INVALID_TOKEN,
|
|
8186
|
-
recoverability: 'FATAL',
|
|
8187
|
-
message,
|
|
8188
|
-
cause: { trace },
|
|
8189
|
-
});
|
|
8190
|
-
}
|
|
8191
|
-
|
|
8192
|
-
/**
|
|
8193
|
-
* USDC token definition with addresses and metadata.
|
|
9127
|
+
* | Service | Default | Configurable |
|
|
9128
|
+
* |---------|---------|--------------|
|
|
9129
|
+
* | `logger` | pino logger (info level) | Yes |
|
|
9130
|
+
* | `metrics` | No-op metrics | Yes |
|
|
9131
|
+
* | `events` | Internal event bus | No |
|
|
9132
|
+
* | `clock` | `Date.now()` | No |
|
|
8194
9133
|
*
|
|
8195
|
-
*
|
|
8196
|
-
* This is the built-in USDC definition used by the TokenRegistry.
|
|
8197
|
-
* Includes all known USDC addresses across supported chains.
|
|
9134
|
+
* **Why only logger and metrics?**
|
|
8198
9135
|
*
|
|
8199
|
-
*
|
|
8200
|
-
*
|
|
8201
|
-
* -
|
|
9136
|
+
* - **Logger/Metrics**: Integration points with your infrastructure
|
|
9137
|
+
* - **Events**: Internal pub/sub mechanism - subscribe via `runtime.events.on()`
|
|
9138
|
+
* - **Clock**: Testing concern - use mock factories for tests
|
|
8202
9139
|
*
|
|
8203
9140
|
* @example
|
|
8204
9141
|
* ```typescript
|
|
8205
|
-
* import {
|
|
8206
|
-
* import { Blockchain } from '@core/chains'
|
|
8207
|
-
*
|
|
8208
|
-
* console.log(USDC.symbol) // 'USDC'
|
|
8209
|
-
* console.log(USDC.decimals) // 6
|
|
8210
|
-
* console.log(USDC.locators[Blockchain.Ethereum])
|
|
8211
|
-
* // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
8212
|
-
* ```
|
|
8213
|
-
*/
|
|
8214
|
-
const USDC = {
|
|
8215
|
-
symbol: 'USDC',
|
|
8216
|
-
decimals: 6,
|
|
8217
|
-
locators: {
|
|
8218
|
-
// =========================================================================
|
|
8219
|
-
// Mainnets (alphabetically sorted)
|
|
8220
|
-
// =========================================================================
|
|
8221
|
-
[Blockchain.Arbitrum]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
8222
|
-
[Blockchain.Avalanche]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
8223
|
-
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
8224
|
-
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
8225
|
-
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
8226
|
-
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
8227
|
-
[Blockchain.Hedera]: '0.0.456858',
|
|
8228
|
-
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
8229
|
-
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
8230
|
-
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
8231
|
-
[Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
8232
|
-
[Blockchain.Noble]: 'uusdc',
|
|
8233
|
-
[Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
8234
|
-
[Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
8235
|
-
[Blockchain.Polkadot_Asset_Hub]: '1337',
|
|
8236
|
-
[Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
8237
|
-
[Blockchain.Sei]: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
8238
|
-
[Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
8239
|
-
[Blockchain.Sonic]: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
8240
|
-
[Blockchain.Stellar]: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
8241
|
-
[Blockchain.Sui]: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
8242
|
-
[Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
8243
|
-
[Blockchain.World_Chain]: '0x79A02482A880bCe3F13E09da970dC34dB4cD24D1',
|
|
8244
|
-
[Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
8245
|
-
[Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
8246
|
-
// =========================================================================
|
|
8247
|
-
// Testnets (alphabetically sorted)
|
|
8248
|
-
// =========================================================================
|
|
8249
|
-
[Blockchain.Arbitrum_Sepolia]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
8250
|
-
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
8251
|
-
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
8252
|
-
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
8253
|
-
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
8254
|
-
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
8255
|
-
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
8256
|
-
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
8257
|
-
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
8258
|
-
[Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
8259
|
-
[Blockchain.Noble_Testnet]: 'uusdc',
|
|
8260
|
-
[Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
8261
|
-
[Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
8262
|
-
[Blockchain.Polkadot_Westmint]: '31337',
|
|
8263
|
-
[Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
8264
|
-
[Blockchain.Sei_Testnet]: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
8265
|
-
[Blockchain.Solana_Devnet]: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
8266
|
-
[Blockchain.Sonic_Testnet]: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
8267
|
-
[Blockchain.Stellar_Testnet]: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
8268
|
-
[Blockchain.Sui_Testnet]: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
8269
|
-
[Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
8270
|
-
[Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
8271
|
-
[Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
8272
|
-
[Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
8273
|
-
},
|
|
8274
|
-
};
|
|
8275
|
-
|
|
8276
|
-
// Re-export for consumers
|
|
8277
|
-
/**
|
|
8278
|
-
* All default token definitions.
|
|
9142
|
+
* import { createRuntime, createLogger } from '@core/runtime'
|
|
8279
9143
|
*
|
|
8280
|
-
*
|
|
8281
|
-
*
|
|
8282
|
-
* without explicit defaults. Extensions can override these definitions.
|
|
9144
|
+
* // Use all defaults
|
|
9145
|
+
* const runtime = createRuntime()
|
|
8283
9146
|
*
|
|
8284
|
-
*
|
|
8285
|
-
*
|
|
8286
|
-
*
|
|
9147
|
+
* // Custom logger
|
|
9148
|
+
* const runtime = createRuntime({
|
|
9149
|
+
* logger: createLogger({ level: 'debug' }),
|
|
9150
|
+
* })
|
|
8287
9151
|
*
|
|
8288
|
-
* //
|
|
8289
|
-
* const
|
|
9152
|
+
* // Custom metrics (e.g., Prometheus)
|
|
9153
|
+
* const runtime = createRuntime({
|
|
9154
|
+
* metrics: myPrometheusMetrics,
|
|
9155
|
+
* })
|
|
8290
9156
|
*
|
|
8291
|
-
* //
|
|
8292
|
-
*
|
|
8293
|
-
*
|
|
9157
|
+
* // Subscribe to events (don't replace the bus)
|
|
9158
|
+
* runtime.events.on('operation.*', (event) => {
|
|
9159
|
+
* console.log('Event:', event.name)
|
|
8294
9160
|
* })
|
|
8295
9161
|
* ```
|
|
8296
9162
|
*/
|
|
8297
|
-
|
|
9163
|
+
function createRuntime(options) {
|
|
9164
|
+
// Resolve logger first (events may need it)
|
|
9165
|
+
const logger = createLogger();
|
|
9166
|
+
// Internal services - not configurable
|
|
9167
|
+
const events = createEventBus({ logger });
|
|
9168
|
+
const clock = defaultClock;
|
|
9169
|
+
// Resolve metrics
|
|
9170
|
+
const metrics = noopMetrics;
|
|
9171
|
+
return Object.freeze({ logger, events, metrics, clock });
|
|
9172
|
+
}
|
|
8298
9173
|
|
|
8299
9174
|
/**
|
|
8300
|
-
*
|
|
9175
|
+
* Invocation context resolution - resolves the **WHO/HOW** of an operation.
|
|
8301
9176
|
*
|
|
8302
|
-
* @
|
|
8303
|
-
* @returns True if the selector is a raw token selector.
|
|
9177
|
+
* @packageDocumentation
|
|
8304
9178
|
*/
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
9179
|
+
// ============================================================================
|
|
9180
|
+
// Validation Schemas
|
|
9181
|
+
// ============================================================================
|
|
9182
|
+
/**
|
|
9183
|
+
* Schema for validating Caller.
|
|
9184
|
+
*/
|
|
9185
|
+
const callerSchema = zod.z.object({
|
|
9186
|
+
type: zod.z.string(),
|
|
9187
|
+
name: zod.z.string(),
|
|
9188
|
+
version: zod.z.string().optional(),
|
|
9189
|
+
});
|
|
9190
|
+
/**
|
|
9191
|
+
* Schema for validating InvocationMeta input.
|
|
9192
|
+
*/
|
|
9193
|
+
const invocationMetaSchema = zod.z
|
|
9194
|
+
.object({
|
|
9195
|
+
traceId: zod.z.string().optional(),
|
|
9196
|
+
runtime: zod.z.object({}).passthrough().optional(),
|
|
9197
|
+
tokens: zod.z.object({}).passthrough().optional(),
|
|
9198
|
+
callers: zod.z.array(callerSchema).optional(),
|
|
9199
|
+
})
|
|
9200
|
+
.strict();
|
|
9201
|
+
// ============================================================================
|
|
9202
|
+
// Invocation Context Resolution
|
|
9203
|
+
// ============================================================================
|
|
8308
9204
|
/**
|
|
8309
|
-
*
|
|
9205
|
+
* Resolve invocation metadata to invocation context.
|
|
8310
9206
|
*
|
|
8311
|
-
* @param
|
|
8312
|
-
* @
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
return symbol.toUpperCase();
|
|
8316
|
-
}
|
|
8317
|
-
/**
|
|
8318
|
-
* Create a token registry with built-in tokens and optional extensions.
|
|
9207
|
+
* @param meta - User-provided invocation metadata (**WHO/HOW**), optional.
|
|
9208
|
+
* @param defaults - Default runtime and tokens to use if not overridden.
|
|
9209
|
+
* @returns Frozen, immutable invocation context with guaranteed values.
|
|
9210
|
+
* @throws KitError when meta contains invalid properties.
|
|
8319
9211
|
*
|
|
8320
9212
|
* @remarks
|
|
8321
|
-
*
|
|
8322
|
-
*
|
|
8323
|
-
*
|
|
9213
|
+
* Resolves the **WHO** called and **HOW** to observe:
|
|
9214
|
+
* - TraceId: Uses provided value or generates new one
|
|
9215
|
+
* - Runtime: Uses meta.runtime if provided, otherwise defaults.runtime
|
|
9216
|
+
* - Tokens: Uses meta.tokens if provided, otherwise defaults.tokens
|
|
9217
|
+
* - Callers: Uses provided array or empty array
|
|
8324
9218
|
*
|
|
8325
|
-
*
|
|
8326
|
-
* @returns A token registry instance.
|
|
9219
|
+
* The returned context is frozen to enforce immutability.
|
|
8327
9220
|
*
|
|
8328
9221
|
* @example
|
|
8329
9222
|
* ```typescript
|
|
9223
|
+
* import { resolveInvocationContext, createRuntime } from '@core/runtime'
|
|
8330
9224
|
* import { createTokenRegistry } from '@core/tokens'
|
|
8331
9225
|
*
|
|
8332
|
-
*
|
|
8333
|
-
*
|
|
8334
|
-
*
|
|
8335
|
-
* // Resolve USDC on Ethereum
|
|
8336
|
-
* const usdc = registry.resolve('USDC', 'Ethereum')
|
|
8337
|
-
* console.log(usdc.locator) // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
8338
|
-
* console.log(usdc.decimals) // 6
|
|
8339
|
-
* ```
|
|
8340
|
-
*
|
|
8341
|
-
* @example
|
|
8342
|
-
* ```typescript
|
|
8343
|
-
* // Add custom tokens (built-ins are still included)
|
|
8344
|
-
* const myToken: TokenDefinition = {
|
|
8345
|
-
* symbol: 'MY',
|
|
8346
|
-
* decimals: 18,
|
|
8347
|
-
* locators: { Ethereum: '0x...' },
|
|
9226
|
+
* const defaults = {
|
|
9227
|
+
* runtime: createRuntime(),
|
|
9228
|
+
* tokens: createTokenRegistry(),
|
|
8348
9229
|
* }
|
|
8349
9230
|
*
|
|
8350
|
-
*
|
|
8351
|
-
*
|
|
8352
|
-
* registry.resolve('MY', 'Ethereum') // Also works
|
|
8353
|
-
* ```
|
|
8354
|
-
*
|
|
8355
|
-
* @example
|
|
8356
|
-
* ```typescript
|
|
8357
|
-
* // Override a built-in token
|
|
8358
|
-
* const customUsdc: TokenDefinition = {
|
|
8359
|
-
* symbol: 'USDC',
|
|
8360
|
-
* decimals: 6,
|
|
8361
|
-
* locators: { MyChain: '0xCustomAddress' },
|
|
8362
|
-
* }
|
|
9231
|
+
* // Minimal - just using defaults
|
|
9232
|
+
* const ctx = resolveInvocationContext(undefined, defaults)
|
|
8363
9233
|
*
|
|
8364
|
-
*
|
|
8365
|
-
*
|
|
8366
|
-
*
|
|
9234
|
+
* // With trace ID and caller info
|
|
9235
|
+
* const ctx = resolveInvocationContext(
|
|
9236
|
+
* {
|
|
9237
|
+
* traceId: 'abc-123',
|
|
9238
|
+
* callers: [{ type: 'kit', name: 'BridgeKit', version: '1.0.0' }],
|
|
9239
|
+
* },
|
|
9240
|
+
* defaults
|
|
9241
|
+
* )
|
|
8367
9242
|
*
|
|
8368
|
-
*
|
|
8369
|
-
*
|
|
8370
|
-
*
|
|
8371
|
-
*
|
|
8372
|
-
* const token = registry.resolve(
|
|
8373
|
-
* { locator: '0x1234...', decimals: 18 },
|
|
8374
|
-
* 'Ethereum'
|
|
9243
|
+
* // With runtime override (complete replacement)
|
|
9244
|
+
* const ctx = resolveInvocationContext(
|
|
9245
|
+
* { runtime: createRuntime({ logger: myLogger }) },
|
|
9246
|
+
* defaults
|
|
8375
9247
|
* )
|
|
8376
9248
|
* ```
|
|
8377
9249
|
*/
|
|
8378
|
-
function
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
8385
|
-
}
|
|
8386
|
-
// Custom tokens override built-ins
|
|
8387
|
-
for (const def of tokens) {
|
|
8388
|
-
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
8389
|
-
}
|
|
8390
|
-
/**
|
|
8391
|
-
* Resolve a symbol selector to token information.
|
|
8392
|
-
*/
|
|
8393
|
-
function resolveSymbol(symbol, chainId) {
|
|
8394
|
-
const normalizedSymbol = normalizeSymbol(symbol);
|
|
8395
|
-
const definition = tokenMap.get(normalizedSymbol);
|
|
8396
|
-
if (definition === undefined) {
|
|
8397
|
-
throw createTokenResolutionError(`Unknown token symbol: ${symbol}. Register it via createTokenRegistry({ tokens: [...] }) or use a raw selector.`, symbol, chainId);
|
|
8398
|
-
}
|
|
8399
|
-
const locator = definition.locators[chainId];
|
|
8400
|
-
if (locator === undefined || locator.trim() === '') {
|
|
8401
|
-
throw createTokenResolutionError(`Token ${symbol} has no locator for chain ${chainId}`, symbol, chainId);
|
|
8402
|
-
}
|
|
8403
|
-
return {
|
|
8404
|
-
symbol: definition.symbol,
|
|
8405
|
-
decimals: definition.decimals,
|
|
8406
|
-
locator,
|
|
8407
|
-
};
|
|
8408
|
-
}
|
|
8409
|
-
/**
|
|
8410
|
-
* Resolve a raw selector to token information.
|
|
8411
|
-
*/
|
|
8412
|
-
function resolveRaw(selector, chainId) {
|
|
8413
|
-
const { locator, decimals } = selector;
|
|
8414
|
-
// Validate locator
|
|
8415
|
-
if (!locator || typeof locator !== 'string') {
|
|
8416
|
-
throw createTokenResolutionError('Raw selector must have a valid locator string', selector, chainId);
|
|
8417
|
-
}
|
|
8418
|
-
// Decimals are always required for raw selectors
|
|
8419
|
-
if (decimals === undefined) {
|
|
8420
|
-
const message = requireDecimals
|
|
8421
|
-
? 'Decimals required for raw token selector (requireDecimals: true)'
|
|
8422
|
-
: 'Decimals required for raw token selector. Provide { locator, decimals }.';
|
|
8423
|
-
throw createTokenResolutionError(message, selector, chainId);
|
|
8424
|
-
}
|
|
8425
|
-
// Validate decimals
|
|
8426
|
-
if (typeof decimals !== 'number' ||
|
|
8427
|
-
decimals < 0 ||
|
|
8428
|
-
!Number.isInteger(decimals)) {
|
|
8429
|
-
throw createTokenResolutionError(`Invalid decimals: ${String(decimals)}. Must be a non-negative integer.`, selector, chainId);
|
|
9250
|
+
function resolveInvocationContext(meta, defaults) {
|
|
9251
|
+
// Validate meta input if provided
|
|
9252
|
+
if (meta !== undefined) {
|
|
9253
|
+
const result = invocationMetaSchema.safeParse(meta);
|
|
9254
|
+
if (!result.success) {
|
|
9255
|
+
throw createValidationFailedError('invocationMeta', meta, result.error.errors.map((e) => e.message).join(', '));
|
|
8430
9256
|
}
|
|
8431
|
-
return {
|
|
8432
|
-
decimals,
|
|
8433
|
-
locator,
|
|
8434
|
-
};
|
|
8435
9257
|
}
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
if (chainId === '' || typeof chainId !== 'string') {
|
|
8444
|
-
throw createTokenResolutionError('Chain ID is required for token resolution', selector, chainId);
|
|
8445
|
-
}
|
|
8446
|
-
// Dispatch based on selector type
|
|
8447
|
-
if (isRawSelector(selector)) {
|
|
8448
|
-
return resolveRaw(selector, chainId);
|
|
8449
|
-
}
|
|
8450
|
-
if (typeof selector === 'string') {
|
|
8451
|
-
return resolveSymbol(selector, chainId);
|
|
8452
|
-
}
|
|
8453
|
-
throw createTokenResolutionError(`Invalid selector type: ${typeof selector}. Expected string or object with locator.`, selector, chainId);
|
|
8454
|
-
},
|
|
8455
|
-
get(symbol) {
|
|
8456
|
-
if (!symbol || typeof symbol !== 'string') {
|
|
8457
|
-
return undefined;
|
|
8458
|
-
}
|
|
8459
|
-
return tokenMap.get(normalizeSymbol(symbol));
|
|
8460
|
-
},
|
|
8461
|
-
has(symbol) {
|
|
8462
|
-
if (!symbol || typeof symbol !== 'string') {
|
|
8463
|
-
return false;
|
|
8464
|
-
}
|
|
8465
|
-
return tokenMap.has(normalizeSymbol(symbol));
|
|
8466
|
-
},
|
|
8467
|
-
symbols() {
|
|
8468
|
-
return Array.from(tokenMap.values()).map((def) => def.symbol);
|
|
8469
|
-
},
|
|
8470
|
-
entries() {
|
|
8471
|
-
return Array.from(tokenMap.values());
|
|
8472
|
-
},
|
|
8473
|
-
};
|
|
9258
|
+
// Generate trace ID if not provided
|
|
9259
|
+
const traceId = meta?.traceId ?? createTraceId();
|
|
9260
|
+
// Use meta overrides or fall back to defaults
|
|
9261
|
+
const runtime = meta?.runtime ?? defaults.runtime;
|
|
9262
|
+
const tokens = meta?.tokens ?? defaults.tokens;
|
|
9263
|
+
const callers = meta?.callers ?? [];
|
|
9264
|
+
return Object.freeze({ traceId, runtime, tokens, callers });
|
|
8474
9265
|
}
|
|
8475
9266
|
|
|
8476
9267
|
/**
|
|
8477
|
-
*
|
|
9268
|
+
* Extend an invocation context by appending a caller to its call chain.
|
|
9269
|
+
*
|
|
9270
|
+
* @param context - The existing invocation context to extend.
|
|
9271
|
+
* @param caller - The caller to append to the call chain.
|
|
9272
|
+
* @returns A new frozen invocation context with the caller appended.
|
|
8478
9273
|
*
|
|
8479
9274
|
* @remarks
|
|
8480
|
-
*
|
|
9275
|
+
* This function creates a new immutable context with the caller appended
|
|
9276
|
+
* to the `callers` array while preserving all other context properties
|
|
9277
|
+
* (traceId, runtime, tokens).
|
|
9278
|
+
*
|
|
9279
|
+
* The returned context is frozen to enforce immutability.
|
|
8481
9280
|
*
|
|
8482
9281
|
* @example
|
|
8483
9282
|
* ```typescript
|
|
8484
|
-
* import {
|
|
8485
|
-
*
|
|
8486
|
-
* const registry = {
|
|
8487
|
-
* resolve: () => ({ locator: '0x0', decimals: 6 }),
|
|
8488
|
-
* }
|
|
9283
|
+
* import { extendInvocationContext } from '@core/runtime'
|
|
8489
9284
|
*
|
|
8490
|
-
*
|
|
9285
|
+
* const caller = { type: 'provider', name: 'CCTPV2', version: '1.0.0' }
|
|
9286
|
+
* const extended = extendInvocationContext(existingContext, caller)
|
|
9287
|
+
* // extended.callers === [...existingContext.callers, caller]
|
|
8491
9288
|
* ```
|
|
8492
9289
|
*/
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
9290
|
+
function extendInvocationContext(context, caller) {
|
|
9291
|
+
return Object.freeze({
|
|
9292
|
+
traceId: context.traceId,
|
|
9293
|
+
runtime: context.runtime,
|
|
9294
|
+
tokens: context.tokens,
|
|
9295
|
+
callers: [...context.callers, caller],
|
|
9296
|
+
});
|
|
9297
|
+
}
|
|
9298
|
+
|
|
9299
|
+
// Clock - expose defaultClock for backward compatibility
|
|
9300
|
+
/** Clock validation schema (backward compatibility). */
|
|
9301
|
+
zod.z.custom((val) => val !== null &&
|
|
9302
|
+
typeof val === 'object' &&
|
|
9303
|
+
'now' in val &&
|
|
9304
|
+
typeof val['now'] === 'function');
|
|
9305
|
+
/** EventBus validation schema (backward compatibility). */
|
|
9306
|
+
zod.z.custom((val) => val !== null &&
|
|
9307
|
+
typeof val === 'object' &&
|
|
9308
|
+
'emit' in val &&
|
|
9309
|
+
typeof val['emit'] === 'function');
|
|
9310
|
+
/** Runtime validation schema (backward compatibility). */
|
|
9311
|
+
zod.z
|
|
9312
|
+
.object({
|
|
9313
|
+
logger: zod.z.any().optional(),
|
|
9314
|
+
events: zod.z.any().optional(),
|
|
9315
|
+
metrics: zod.z.any().optional(),
|
|
9316
|
+
clock: zod.z.any().optional(),
|
|
9317
|
+
})
|
|
9318
|
+
.passthrough();
|
|
8506
9319
|
|
|
8507
|
-
var version = "1.4.
|
|
9320
|
+
var version = "1.4.1";
|
|
8508
9321
|
var pkg = {
|
|
8509
9322
|
version: version};
|
|
8510
9323
|
|
|
@@ -8987,6 +9800,24 @@ const validateNativeBalanceForTransaction = async (params) => {
|
|
|
8987
9800
|
}
|
|
8988
9801
|
};
|
|
8989
9802
|
|
|
9803
|
+
/**
|
|
9804
|
+
* Permit signature standards for gasless token approvals.
|
|
9805
|
+
*
|
|
9806
|
+
* Defines the permit types that can be used to approve token spending
|
|
9807
|
+
* without requiring a separate approval transaction.
|
|
9808
|
+
*
|
|
9809
|
+
* @remarks
|
|
9810
|
+
* - NONE: No permit, tokens must be pre-approved via separate transaction
|
|
9811
|
+
* - EIP2612: Standard ERC-20 permit (USDC, DAI v2, and most modern tokens)
|
|
9812
|
+
*/
|
|
9813
|
+
var PermitType;
|
|
9814
|
+
(function (PermitType) {
|
|
9815
|
+
/** No permit required - tokens must be pre-approved */
|
|
9816
|
+
PermitType[PermitType["NONE"] = 0] = "NONE";
|
|
9817
|
+
/** EIP-2612 standard permit */
|
|
9818
|
+
PermitType[PermitType["EIP2612"] = 1] = "EIP2612";
|
|
9819
|
+
})(PermitType || (PermitType = {}));
|
|
9820
|
+
|
|
8990
9821
|
/**
|
|
8991
9822
|
* CCTP bridge step names that can occur in the bridging flow.
|
|
8992
9823
|
*
|