@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.mjs
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
// Buffer polyfill setup - executes before any other code
|
|
20
|
-
// Ensures globalThis.Buffer is available for
|
|
20
|
+
// Ensures globalThis.Buffer is available for Solana libraries
|
|
21
21
|
import { Buffer } from 'buffer';
|
|
22
22
|
if (typeof globalThis !== 'undefined' && typeof globalThis.Buffer === 'undefined') {
|
|
23
23
|
globalThis.Buffer = Buffer;
|
|
@@ -109,6 +109,122 @@ var Blockchain;
|
|
|
109
109
|
Blockchain["ZKSync_Era"] = "ZKSync_Era";
|
|
110
110
|
Blockchain["ZKSync_Sepolia"] = "ZKSync_Sepolia";
|
|
111
111
|
})(Blockchain || (Blockchain = {}));
|
|
112
|
+
/**
|
|
113
|
+
* Enum representing the subset of {@link Blockchain} that supports swap operations.
|
|
114
|
+
*
|
|
115
|
+
* This enum provides compile-time type safety for swap chain selection,
|
|
116
|
+
* ensuring only supported chains are available in IDE autocomplete
|
|
117
|
+
* when building swap parameters.
|
|
118
|
+
*
|
|
119
|
+
* @remarks
|
|
120
|
+
* Unlike the full {@link Blockchain} enum, SwapChain only includes networks
|
|
121
|
+
* where the swap functionality is actively supported by the library.
|
|
122
|
+
* Using this enum prevents runtime errors from attempting unsupported
|
|
123
|
+
* cross-chain swaps.
|
|
124
|
+
*
|
|
125
|
+
* Currently supports:
|
|
126
|
+
* - Ethereum mainnet
|
|
127
|
+
* - Base mainnet
|
|
128
|
+
* - Polygon mainnet
|
|
129
|
+
* - Solana mainnet
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* import { SwapChain, swap, createSwapKitContext } from '@circle-fin/swap-kit'
|
|
134
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
135
|
+
*
|
|
136
|
+
* const context = createSwapKitContext()
|
|
137
|
+
* const adapter = createViemAdapterFromPrivateKey({
|
|
138
|
+
* privateKey: process.env.PRIVATE_KEY
|
|
139
|
+
* })
|
|
140
|
+
*
|
|
141
|
+
* // ✅ Autocomplete shows only swap-supported chains
|
|
142
|
+
* const result = await swap(context, {
|
|
143
|
+
* from: {
|
|
144
|
+
* adapter,
|
|
145
|
+
* chain: SwapChain.Ethereum // Autocomplete: Ethereum, Base, Polygon, Solana
|
|
146
|
+
* },
|
|
147
|
+
* tokenIn: 'USDC',
|
|
148
|
+
* tokenOut: 'USDT',
|
|
149
|
+
* amount: '100.0'
|
|
150
|
+
* })
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* // String literals also work (constrained to SwapChain values)
|
|
156
|
+
* const result = await swap(context, {
|
|
157
|
+
* from: {
|
|
158
|
+
* adapter,
|
|
159
|
+
* chain: 'Ethereum' // ✅ Only SwapChain strings allowed
|
|
160
|
+
* },
|
|
161
|
+
* tokenIn: 'USDC',
|
|
162
|
+
* tokenOut: 'NATIVE',
|
|
163
|
+
* amount: '50.0'
|
|
164
|
+
* })
|
|
165
|
+
*
|
|
166
|
+
* // ❌ TypeScript error - Sui not in SwapChain enum
|
|
167
|
+
* const invalidResult = await swap(context, {
|
|
168
|
+
* from: {
|
|
169
|
+
* adapter,
|
|
170
|
+
* chain: 'Sui' // Compile-time error!
|
|
171
|
+
* },
|
|
172
|
+
* tokenIn: 'USDC',
|
|
173
|
+
* tokenOut: 'USDT',
|
|
174
|
+
* amount: '100.0'
|
|
175
|
+
* })
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
/**
|
|
179
|
+
* Enum representing chains that support same-chain swaps through the Swap Kit.
|
|
180
|
+
*
|
|
181
|
+
* Unlike the full {@link Blockchain} enum, SwapChain includes only mainnet
|
|
182
|
+
* networks where adapter contracts are deployed (CCTPv2 support).
|
|
183
|
+
*
|
|
184
|
+
* Dynamic validation via {@link isSwapSupportedChain} ensures chains
|
|
185
|
+
* automatically work when adapter contracts and supported tokens are deployed.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* import { SwapChain } from '@core/chains'
|
|
190
|
+
* import { swap } from '@circle-fin/swap-kit'
|
|
191
|
+
*
|
|
192
|
+
* const result = await swap(context, {
|
|
193
|
+
* from: {
|
|
194
|
+
* adapter,
|
|
195
|
+
* chain: SwapChain.Arbitrum // Now supported!
|
|
196
|
+
* },
|
|
197
|
+
* tokenIn: 'USDC',
|
|
198
|
+
* tokenOut: 'WETH',
|
|
199
|
+
* amount: '100.0'
|
|
200
|
+
* })
|
|
201
|
+
* ```
|
|
202
|
+
*
|
|
203
|
+
* @see {@link isSwapSupportedChain} for runtime validation
|
|
204
|
+
* @see {@link getSwapSupportedChains} for all supported chains
|
|
205
|
+
*/
|
|
206
|
+
var SwapChain;
|
|
207
|
+
(function (SwapChain) {
|
|
208
|
+
// Original 4 chains
|
|
209
|
+
SwapChain["Ethereum"] = "Ethereum";
|
|
210
|
+
SwapChain["Base"] = "Base";
|
|
211
|
+
SwapChain["Polygon"] = "Polygon";
|
|
212
|
+
SwapChain["Solana"] = "Solana";
|
|
213
|
+
// Additional supported chains
|
|
214
|
+
SwapChain["Arbitrum"] = "Arbitrum";
|
|
215
|
+
SwapChain["Optimism"] = "Optimism";
|
|
216
|
+
SwapChain["Avalanche"] = "Avalanche";
|
|
217
|
+
SwapChain["Linea"] = "Linea";
|
|
218
|
+
SwapChain["Ink"] = "Ink";
|
|
219
|
+
SwapChain["World_Chain"] = "World_Chain";
|
|
220
|
+
SwapChain["Unichain"] = "Unichain";
|
|
221
|
+
SwapChain["Plume"] = "Plume";
|
|
222
|
+
SwapChain["Sei"] = "Sei";
|
|
223
|
+
SwapChain["Sonic"] = "Sonic";
|
|
224
|
+
SwapChain["XDC"] = "XDC";
|
|
225
|
+
SwapChain["HyperEVM"] = "HyperEVM";
|
|
226
|
+
SwapChain["Monad"] = "Monad";
|
|
227
|
+
})(SwapChain || (SwapChain = {}));
|
|
112
228
|
// -----------------------------------------------------------------------------
|
|
113
229
|
// Bridge Chain Enum (CCTPv2 Supported Chains)
|
|
114
230
|
// -----------------------------------------------------------------------------
|
|
@@ -260,6 +376,7 @@ const Algorand = defineChain({
|
|
|
260
376
|
rpcEndpoints: ['https://mainnet-api.algonode.cloud'],
|
|
261
377
|
eurcAddress: null,
|
|
262
378
|
usdcAddress: '31566704',
|
|
379
|
+
usdtAddress: null,
|
|
263
380
|
cctp: null,
|
|
264
381
|
});
|
|
265
382
|
|
|
@@ -283,6 +400,7 @@ const AlgorandTestnet = defineChain({
|
|
|
283
400
|
rpcEndpoints: ['https://testnet-api.algonode.cloud'],
|
|
284
401
|
eurcAddress: null,
|
|
285
402
|
usdcAddress: '10458941',
|
|
403
|
+
usdtAddress: null,
|
|
286
404
|
cctp: null,
|
|
287
405
|
});
|
|
288
406
|
|
|
@@ -306,6 +424,7 @@ const Aptos = defineChain({
|
|
|
306
424
|
rpcEndpoints: ['https://fullnode.mainnet.aptoslabs.com/v1'],
|
|
307
425
|
eurcAddress: null,
|
|
308
426
|
usdcAddress: '0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b',
|
|
427
|
+
usdtAddress: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
309
428
|
cctp: {
|
|
310
429
|
domain: 9,
|
|
311
430
|
contracts: {
|
|
@@ -343,6 +462,7 @@ const AptosTestnet = defineChain({
|
|
|
343
462
|
rpcEndpoints: ['https://fullnode.testnet.aptoslabs.com/v1'],
|
|
344
463
|
eurcAddress: null,
|
|
345
464
|
usdcAddress: '0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832',
|
|
465
|
+
usdtAddress: null,
|
|
346
466
|
cctp: {
|
|
347
467
|
domain: 9,
|
|
348
468
|
contracts: {
|
|
@@ -360,6 +480,121 @@ const AptosTestnet = defineChain({
|
|
|
360
480
|
},
|
|
361
481
|
});
|
|
362
482
|
|
|
483
|
+
/**
|
|
484
|
+
* Complete swap token registry - single source of truth for all swap-supported tokens.
|
|
485
|
+
*
|
|
486
|
+
* @remarks
|
|
487
|
+
* All packages should import from this registry for swap operations.
|
|
488
|
+
* Adding a new swap token requires updating only this registry.
|
|
489
|
+
*
|
|
490
|
+
* The NATIVE token is handled separately as it resolves dynamically based on chain.
|
|
491
|
+
*
|
|
492
|
+
* @example
|
|
493
|
+
* ```typescript
|
|
494
|
+
* import { SWAP_TOKEN_REGISTRY } from '@core/chains'
|
|
495
|
+
*
|
|
496
|
+
* // Get token decimals
|
|
497
|
+
* const decimals = SWAP_TOKEN_REGISTRY.USDC.decimals // 6
|
|
498
|
+
*
|
|
499
|
+
* // Check if token is stablecoin
|
|
500
|
+
* const isStable = SWAP_TOKEN_REGISTRY.DAI.category === 'stablecoin' // true
|
|
501
|
+
* ```
|
|
502
|
+
*/
|
|
503
|
+
const SWAP_TOKEN_REGISTRY = {
|
|
504
|
+
// ============================================================================
|
|
505
|
+
// Stablecoins (6 decimals)
|
|
506
|
+
// ============================================================================
|
|
507
|
+
USDC: {
|
|
508
|
+
symbol: 'USDC',
|
|
509
|
+
decimals: 6,
|
|
510
|
+
category: 'stablecoin',
|
|
511
|
+
description: 'USD Coin',
|
|
512
|
+
},
|
|
513
|
+
EURC: {
|
|
514
|
+
symbol: 'EURC',
|
|
515
|
+
decimals: 6,
|
|
516
|
+
category: 'stablecoin',
|
|
517
|
+
description: 'Euro Coin',
|
|
518
|
+
},
|
|
519
|
+
USDT: {
|
|
520
|
+
symbol: 'USDT',
|
|
521
|
+
decimals: 6,
|
|
522
|
+
category: 'stablecoin',
|
|
523
|
+
description: 'Tether USD',
|
|
524
|
+
},
|
|
525
|
+
PYUSD: {
|
|
526
|
+
symbol: 'PYUSD',
|
|
527
|
+
decimals: 6,
|
|
528
|
+
category: 'stablecoin',
|
|
529
|
+
description: 'PayPal USD',
|
|
530
|
+
},
|
|
531
|
+
// ============================================================================
|
|
532
|
+
// Stablecoins (18 decimals)
|
|
533
|
+
// ============================================================================
|
|
534
|
+
DAI: {
|
|
535
|
+
symbol: 'DAI',
|
|
536
|
+
decimals: 18,
|
|
537
|
+
category: 'stablecoin',
|
|
538
|
+
description: 'MakerDAO stablecoin',
|
|
539
|
+
},
|
|
540
|
+
USDE: {
|
|
541
|
+
symbol: 'USDE',
|
|
542
|
+
decimals: 18,
|
|
543
|
+
category: 'stablecoin',
|
|
544
|
+
description: 'Ethena USD (synthetic dollar)',
|
|
545
|
+
},
|
|
546
|
+
// ============================================================================
|
|
547
|
+
// Wrapped Tokens
|
|
548
|
+
// ============================================================================
|
|
549
|
+
WBTC: {
|
|
550
|
+
symbol: 'WBTC',
|
|
551
|
+
decimals: 8,
|
|
552
|
+
category: 'wrapped',
|
|
553
|
+
description: 'Wrapped Bitcoin',
|
|
554
|
+
},
|
|
555
|
+
WETH: {
|
|
556
|
+
symbol: 'WETH',
|
|
557
|
+
decimals: 18,
|
|
558
|
+
category: 'wrapped',
|
|
559
|
+
description: 'Wrapped Ethereum',
|
|
560
|
+
},
|
|
561
|
+
WSOL: {
|
|
562
|
+
symbol: 'WSOL',
|
|
563
|
+
decimals: 9,
|
|
564
|
+
category: 'wrapped',
|
|
565
|
+
description: 'Wrapped Solana',
|
|
566
|
+
},
|
|
567
|
+
WAVAX: {
|
|
568
|
+
symbol: 'WAVAX',
|
|
569
|
+
decimals: 18,
|
|
570
|
+
category: 'wrapped',
|
|
571
|
+
description: 'Wrapped Avalanche',
|
|
572
|
+
},
|
|
573
|
+
WPOL: {
|
|
574
|
+
symbol: 'WPOL',
|
|
575
|
+
decimals: 18,
|
|
576
|
+
category: 'wrapped',
|
|
577
|
+
description: 'Wrapped Polygon',
|
|
578
|
+
},
|
|
579
|
+
};
|
|
580
|
+
/**
|
|
581
|
+
* Special NATIVE token constant for swap operations.
|
|
582
|
+
*
|
|
583
|
+
* @remarks
|
|
584
|
+
* NATIVE is handled separately from SWAP_TOKEN_REGISTRY because it resolves
|
|
585
|
+
* dynamically based on the chain (ETH on Ethereum, SOL on Solana, etc.).
|
|
586
|
+
* Its decimals are chain-specific.
|
|
587
|
+
*/
|
|
588
|
+
const NATIVE_TOKEN = 'NATIVE';
|
|
589
|
+
/**
|
|
590
|
+
* Array of all supported swap token symbols including NATIVE.
|
|
591
|
+
* Useful for iteration, validation, and filtering.
|
|
592
|
+
*/
|
|
593
|
+
[
|
|
594
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
595
|
+
NATIVE_TOKEN,
|
|
596
|
+
];
|
|
597
|
+
|
|
363
598
|
/**
|
|
364
599
|
* The bridge contract address for EVM testnet networks.
|
|
365
600
|
*
|
|
@@ -376,6 +611,13 @@ const BRIDGE_CONTRACT_EVM_TESTNET = '0xC5567a5E3370d4DBfB0540025078e283e36A363d'
|
|
|
376
611
|
* USDC transfers on live networks.
|
|
377
612
|
*/
|
|
378
613
|
const BRIDGE_CONTRACT_EVM_MAINNET = '0xB3FA262d0fB521cc93bE83d87b322b8A23DAf3F0';
|
|
614
|
+
/**
|
|
615
|
+
* The adapter contract address for EVM mainnet networks.
|
|
616
|
+
*
|
|
617
|
+
* This contract serves as an adapter for integrating with various protocols
|
|
618
|
+
* on EVM-compatible chains. Use this address for mainnet adapter integrations.
|
|
619
|
+
*/
|
|
620
|
+
const ADAPTER_CONTRACT_EVM_MAINNET = '0x7FB8c7260b63934d8da38aF902f87ae6e284a845';
|
|
379
621
|
|
|
380
622
|
/**
|
|
381
623
|
* Arc Testnet chain definition
|
|
@@ -405,6 +647,7 @@ const ArcTestnet = defineChain({
|
|
|
405
647
|
rpcEndpoints: ['https://rpc.testnet.arc.network/'],
|
|
406
648
|
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
407
649
|
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
650
|
+
usdtAddress: null,
|
|
408
651
|
cctp: {
|
|
409
652
|
domain: 26,
|
|
410
653
|
contracts: {
|
|
@@ -447,6 +690,7 @@ const Arbitrum = defineChain({
|
|
|
447
690
|
rpcEndpoints: ['https://arb1.arbitrum.io/rpc'],
|
|
448
691
|
eurcAddress: null,
|
|
449
692
|
usdcAddress: '0xaf88d065e77c8cc2239327c5edb3a432268e5831',
|
|
693
|
+
usdtAddress: null,
|
|
450
694
|
cctp: {
|
|
451
695
|
domain: 3,
|
|
452
696
|
contracts: {
|
|
@@ -471,6 +715,7 @@ const Arbitrum = defineChain({
|
|
|
471
715
|
},
|
|
472
716
|
kitContracts: {
|
|
473
717
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
718
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
474
719
|
},
|
|
475
720
|
});
|
|
476
721
|
|
|
@@ -495,6 +740,7 @@ const ArbitrumSepolia = defineChain({
|
|
|
495
740
|
rpcEndpoints: ['https://sepolia-rollup.arbitrum.io/rpc'],
|
|
496
741
|
eurcAddress: null,
|
|
497
742
|
usdcAddress: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
743
|
+
usdtAddress: null,
|
|
498
744
|
cctp: {
|
|
499
745
|
domain: 3,
|
|
500
746
|
contracts: {
|
|
@@ -543,6 +789,7 @@ const Avalanche = defineChain({
|
|
|
543
789
|
rpcEndpoints: ['https://api.avax.network/ext/bc/C/rpc'],
|
|
544
790
|
eurcAddress: '0xc891eb4cbdeff6e073e859e987815ed1505c2acd',
|
|
545
791
|
usdcAddress: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
792
|
+
usdtAddress: '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7',
|
|
546
793
|
cctp: {
|
|
547
794
|
domain: 1,
|
|
548
795
|
contracts: {
|
|
@@ -567,6 +814,7 @@ const Avalanche = defineChain({
|
|
|
567
814
|
},
|
|
568
815
|
kitContracts: {
|
|
569
816
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
817
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
570
818
|
},
|
|
571
819
|
});
|
|
572
820
|
|
|
@@ -590,6 +838,7 @@ const AvalancheFuji = defineChain({
|
|
|
590
838
|
explorerUrl: 'https://subnets-test.avax.network/c-chain/tx/{hash}',
|
|
591
839
|
eurcAddress: '0x5e44db7996c682e92a960b65ac713a54ad815c6b',
|
|
592
840
|
usdcAddress: '0x5425890298aed601595a70ab815c96711a31bc65',
|
|
841
|
+
usdtAddress: null,
|
|
593
842
|
cctp: {
|
|
594
843
|
domain: 1,
|
|
595
844
|
contracts: {
|
|
@@ -639,6 +888,7 @@ const Base = defineChain({
|
|
|
639
888
|
rpcEndpoints: ['https://mainnet.base.org', 'https://base.publicnode.com'],
|
|
640
889
|
eurcAddress: '0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42',
|
|
641
890
|
usdcAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
891
|
+
usdtAddress: null,
|
|
642
892
|
cctp: {
|
|
643
893
|
domain: 6,
|
|
644
894
|
contracts: {
|
|
@@ -663,6 +913,7 @@ const Base = defineChain({
|
|
|
663
913
|
},
|
|
664
914
|
kitContracts: {
|
|
665
915
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
916
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
666
917
|
},
|
|
667
918
|
});
|
|
668
919
|
|
|
@@ -687,6 +938,7 @@ const BaseSepolia = defineChain({
|
|
|
687
938
|
rpcEndpoints: ['https://sepolia.base.org'],
|
|
688
939
|
eurcAddress: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
689
940
|
usdcAddress: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
941
|
+
usdtAddress: null,
|
|
690
942
|
cctp: {
|
|
691
943
|
domain: 6,
|
|
692
944
|
contracts: {
|
|
@@ -735,6 +987,7 @@ const Celo = defineChain({
|
|
|
735
987
|
rpcEndpoints: ['https://forno.celo.org'],
|
|
736
988
|
eurcAddress: null,
|
|
737
989
|
usdcAddress: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
990
|
+
usdtAddress: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
738
991
|
cctp: null,
|
|
739
992
|
});
|
|
740
993
|
|
|
@@ -759,6 +1012,7 @@ const CeloAlfajoresTestnet = defineChain({
|
|
|
759
1012
|
rpcEndpoints: ['https://alfajores-forno.celo-testnet.org'],
|
|
760
1013
|
eurcAddress: null,
|
|
761
1014
|
usdcAddress: '0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B',
|
|
1015
|
+
usdtAddress: null,
|
|
762
1016
|
cctp: null,
|
|
763
1017
|
});
|
|
764
1018
|
|
|
@@ -783,6 +1037,7 @@ const Codex = defineChain({
|
|
|
783
1037
|
rpcEndpoints: ['https://rpc.codex.xyz'],
|
|
784
1038
|
eurcAddress: null,
|
|
785
1039
|
usdcAddress: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
1040
|
+
usdtAddress: null,
|
|
786
1041
|
cctp: {
|
|
787
1042
|
domain: 12,
|
|
788
1043
|
contracts: {
|
|
@@ -825,6 +1080,7 @@ const CodexTestnet = defineChain({
|
|
|
825
1080
|
rpcEndpoints: ['https://rpc.codex-stg.xyz'],
|
|
826
1081
|
eurcAddress: null,
|
|
827
1082
|
usdcAddress: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
1083
|
+
usdtAddress: null,
|
|
828
1084
|
cctp: {
|
|
829
1085
|
domain: 12,
|
|
830
1086
|
contracts: {
|
|
@@ -867,6 +1123,7 @@ const Ethereum = defineChain({
|
|
|
867
1123
|
rpcEndpoints: ['https://eth.merkle.io', 'https://ethereum.publicnode.com'],
|
|
868
1124
|
eurcAddress: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
869
1125
|
usdcAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
1126
|
+
usdtAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7',
|
|
870
1127
|
cctp: {
|
|
871
1128
|
domain: 0,
|
|
872
1129
|
contracts: {
|
|
@@ -891,6 +1148,7 @@ const Ethereum = defineChain({
|
|
|
891
1148
|
},
|
|
892
1149
|
kitContracts: {
|
|
893
1150
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1151
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
894
1152
|
},
|
|
895
1153
|
});
|
|
896
1154
|
|
|
@@ -915,6 +1173,7 @@ const EthereumSepolia = defineChain({
|
|
|
915
1173
|
rpcEndpoints: ['https://sepolia.drpc.org'],
|
|
916
1174
|
eurcAddress: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4',
|
|
917
1175
|
usdcAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
1176
|
+
usdtAddress: null,
|
|
918
1177
|
cctp: {
|
|
919
1178
|
domain: 0,
|
|
920
1179
|
contracts: {
|
|
@@ -962,6 +1221,7 @@ const Hedera = defineChain({
|
|
|
962
1221
|
rpcEndpoints: ['https://mainnet.hashio.io/api'],
|
|
963
1222
|
eurcAddress: null,
|
|
964
1223
|
usdcAddress: '0.0.456858',
|
|
1224
|
+
usdtAddress: null,
|
|
965
1225
|
cctp: null,
|
|
966
1226
|
});
|
|
967
1227
|
|
|
@@ -985,6 +1245,7 @@ const HederaTestnet = defineChain({
|
|
|
985
1245
|
rpcEndpoints: ['https://testnet.hashio.io/api'],
|
|
986
1246
|
eurcAddress: null,
|
|
987
1247
|
usdcAddress: '0.0.429274',
|
|
1248
|
+
usdtAddress: null,
|
|
988
1249
|
cctp: null,
|
|
989
1250
|
});
|
|
990
1251
|
|
|
@@ -1011,6 +1272,7 @@ const HyperEVM = defineChain({
|
|
|
1011
1272
|
rpcEndpoints: ['https://rpc.hyperliquid.xyz/evm'],
|
|
1012
1273
|
eurcAddress: null,
|
|
1013
1274
|
usdcAddress: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
1275
|
+
usdtAddress: null,
|
|
1014
1276
|
cctp: {
|
|
1015
1277
|
domain: 19,
|
|
1016
1278
|
contracts: {
|
|
@@ -1029,6 +1291,7 @@ const HyperEVM = defineChain({
|
|
|
1029
1291
|
},
|
|
1030
1292
|
kitContracts: {
|
|
1031
1293
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1294
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1032
1295
|
},
|
|
1033
1296
|
});
|
|
1034
1297
|
|
|
@@ -1054,6 +1317,7 @@ const HyperEVMTestnet = defineChain({
|
|
|
1054
1317
|
rpcEndpoints: ['https://rpc.hyperliquid-testnet.xyz/evm'],
|
|
1055
1318
|
eurcAddress: null,
|
|
1056
1319
|
usdcAddress: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
1320
|
+
usdtAddress: null,
|
|
1057
1321
|
cctp: {
|
|
1058
1322
|
domain: 19,
|
|
1059
1323
|
contracts: {
|
|
@@ -1101,6 +1365,7 @@ const Ink = defineChain({
|
|
|
1101
1365
|
],
|
|
1102
1366
|
eurcAddress: null,
|
|
1103
1367
|
usdcAddress: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
1368
|
+
usdtAddress: null,
|
|
1104
1369
|
cctp: {
|
|
1105
1370
|
domain: 21,
|
|
1106
1371
|
contracts: {
|
|
@@ -1119,6 +1384,7 @@ const Ink = defineChain({
|
|
|
1119
1384
|
},
|
|
1120
1385
|
kitContracts: {
|
|
1121
1386
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1387
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1122
1388
|
},
|
|
1123
1389
|
});
|
|
1124
1390
|
|
|
@@ -1147,6 +1413,7 @@ const InkTestnet = defineChain({
|
|
|
1147
1413
|
],
|
|
1148
1414
|
eurcAddress: null,
|
|
1149
1415
|
usdcAddress: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
1416
|
+
usdtAddress: null,
|
|
1150
1417
|
cctp: {
|
|
1151
1418
|
domain: 21,
|
|
1152
1419
|
contracts: {
|
|
@@ -1189,6 +1456,7 @@ const Linea = defineChain({
|
|
|
1189
1456
|
rpcEndpoints: ['https://rpc.linea.build'],
|
|
1190
1457
|
eurcAddress: null,
|
|
1191
1458
|
usdcAddress: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
1459
|
+
usdtAddress: null,
|
|
1192
1460
|
cctp: {
|
|
1193
1461
|
domain: 11,
|
|
1194
1462
|
contracts: {
|
|
@@ -1207,6 +1475,7 @@ const Linea = defineChain({
|
|
|
1207
1475
|
},
|
|
1208
1476
|
kitContracts: {
|
|
1209
1477
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1478
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1210
1479
|
},
|
|
1211
1480
|
});
|
|
1212
1481
|
|
|
@@ -1231,6 +1500,7 @@ const LineaSepolia = defineChain({
|
|
|
1231
1500
|
rpcEndpoints: ['https://rpc.sepolia.linea.build'],
|
|
1232
1501
|
eurcAddress: null,
|
|
1233
1502
|
usdcAddress: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
1503
|
+
usdtAddress: null,
|
|
1234
1504
|
cctp: {
|
|
1235
1505
|
domain: 11,
|
|
1236
1506
|
contracts: {
|
|
@@ -1275,6 +1545,7 @@ const Monad = defineChain({
|
|
|
1275
1545
|
rpcEndpoints: ['https://rpc.monad.xyz'],
|
|
1276
1546
|
eurcAddress: null,
|
|
1277
1547
|
usdcAddress: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
1548
|
+
usdtAddress: null,
|
|
1278
1549
|
cctp: {
|
|
1279
1550
|
domain: 15,
|
|
1280
1551
|
contracts: {
|
|
@@ -1293,6 +1564,7 @@ const Monad = defineChain({
|
|
|
1293
1564
|
},
|
|
1294
1565
|
kitContracts: {
|
|
1295
1566
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1567
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1296
1568
|
},
|
|
1297
1569
|
});
|
|
1298
1570
|
|
|
@@ -1319,6 +1591,7 @@ const MonadTestnet = defineChain({
|
|
|
1319
1591
|
rpcEndpoints: ['https://testnet-rpc.monad.xyz'],
|
|
1320
1592
|
eurcAddress: null,
|
|
1321
1593
|
usdcAddress: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
1594
|
+
usdtAddress: null,
|
|
1322
1595
|
cctp: {
|
|
1323
1596
|
domain: 15,
|
|
1324
1597
|
contracts: {
|
|
@@ -1360,6 +1633,7 @@ const NEAR = defineChain({
|
|
|
1360
1633
|
rpcEndpoints: ['https://eth-rpc.mainnet.near.org'],
|
|
1361
1634
|
eurcAddress: null,
|
|
1362
1635
|
usdcAddress: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
1636
|
+
usdtAddress: 'usdt.tether-token.near',
|
|
1363
1637
|
cctp: null,
|
|
1364
1638
|
});
|
|
1365
1639
|
|
|
@@ -1383,6 +1657,7 @@ const NEARTestnet = defineChain({
|
|
|
1383
1657
|
rpcEndpoints: ['https://eth-rpc.testnet.near.org'],
|
|
1384
1658
|
eurcAddress: null,
|
|
1385
1659
|
usdcAddress: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
1660
|
+
usdtAddress: null,
|
|
1386
1661
|
cctp: null,
|
|
1387
1662
|
});
|
|
1388
1663
|
|
|
@@ -1406,6 +1681,7 @@ const Noble = defineChain({
|
|
|
1406
1681
|
rpcEndpoints: ['https://noble-rpc.polkachu.com'],
|
|
1407
1682
|
eurcAddress: null,
|
|
1408
1683
|
usdcAddress: 'uusdc',
|
|
1684
|
+
usdtAddress: null,
|
|
1409
1685
|
cctp: {
|
|
1410
1686
|
domain: 4,
|
|
1411
1687
|
contracts: {
|
|
@@ -1442,6 +1718,7 @@ const NobleTestnet = defineChain({
|
|
|
1442
1718
|
rpcEndpoints: ['https://noble-testnet-rpc.polkachu.com'],
|
|
1443
1719
|
eurcAddress: null,
|
|
1444
1720
|
usdcAddress: 'uusdc',
|
|
1721
|
+
usdtAddress: null,
|
|
1445
1722
|
cctp: {
|
|
1446
1723
|
domain: 4,
|
|
1447
1724
|
contracts: {
|
|
@@ -1479,6 +1756,7 @@ const Optimism = defineChain({
|
|
|
1479
1756
|
rpcEndpoints: ['https://mainnet.optimism.io'],
|
|
1480
1757
|
eurcAddress: null,
|
|
1481
1758
|
usdcAddress: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
1759
|
+
usdtAddress: null,
|
|
1482
1760
|
cctp: {
|
|
1483
1761
|
domain: 2,
|
|
1484
1762
|
contracts: {
|
|
@@ -1503,6 +1781,7 @@ const Optimism = defineChain({
|
|
|
1503
1781
|
},
|
|
1504
1782
|
kitContracts: {
|
|
1505
1783
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1784
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1506
1785
|
},
|
|
1507
1786
|
});
|
|
1508
1787
|
|
|
@@ -1527,6 +1806,7 @@ const OptimismSepolia = defineChain({
|
|
|
1527
1806
|
rpcEndpoints: ['https://sepolia.optimism.io'],
|
|
1528
1807
|
eurcAddress: null,
|
|
1529
1808
|
usdcAddress: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
1809
|
+
usdtAddress: null,
|
|
1530
1810
|
cctp: {
|
|
1531
1811
|
domain: 2,
|
|
1532
1812
|
contracts: {
|
|
@@ -1577,6 +1857,7 @@ const Plume = defineChain({
|
|
|
1577
1857
|
rpcEndpoints: ['https://rpc.plume.org'],
|
|
1578
1858
|
eurcAddress: null,
|
|
1579
1859
|
usdcAddress: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
1860
|
+
usdtAddress: null,
|
|
1580
1861
|
cctp: {
|
|
1581
1862
|
domain: 22,
|
|
1582
1863
|
contracts: {
|
|
@@ -1595,6 +1876,7 @@ const Plume = defineChain({
|
|
|
1595
1876
|
},
|
|
1596
1877
|
kitContracts: {
|
|
1597
1878
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1879
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1598
1880
|
},
|
|
1599
1881
|
});
|
|
1600
1882
|
|
|
@@ -1620,6 +1902,7 @@ const PlumeTestnet = defineChain({
|
|
|
1620
1902
|
rpcEndpoints: ['https://testnet-rpc.plume.org'],
|
|
1621
1903
|
eurcAddress: null,
|
|
1622
1904
|
usdcAddress: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
1905
|
+
usdtAddress: null,
|
|
1623
1906
|
cctp: {
|
|
1624
1907
|
domain: 22,
|
|
1625
1908
|
contracts: {
|
|
@@ -1661,6 +1944,7 @@ const PolkadotAssetHub = defineChain({
|
|
|
1661
1944
|
rpcEndpoints: ['https://asset-hub-polkadot-rpc.n.dwellir.com'],
|
|
1662
1945
|
eurcAddress: null,
|
|
1663
1946
|
usdcAddress: '1337',
|
|
1947
|
+
usdtAddress: '1984',
|
|
1664
1948
|
cctp: null,
|
|
1665
1949
|
});
|
|
1666
1950
|
|
|
@@ -1684,6 +1968,7 @@ const PolkadotWestmint = defineChain({
|
|
|
1684
1968
|
rpcEndpoints: ['https://westmint-rpc.polkadot.io'],
|
|
1685
1969
|
eurcAddress: null,
|
|
1686
1970
|
usdcAddress: 'Asset ID 31337',
|
|
1971
|
+
usdtAddress: null,
|
|
1687
1972
|
cctp: null,
|
|
1688
1973
|
});
|
|
1689
1974
|
|
|
@@ -1705,9 +1990,10 @@ const Polygon = defineChain({
|
|
|
1705
1990
|
chainId: 137,
|
|
1706
1991
|
isTestnet: false,
|
|
1707
1992
|
explorerUrl: 'https://polygonscan.com/tx/{hash}',
|
|
1708
|
-
rpcEndpoints: ['https://polygon
|
|
1993
|
+
rpcEndpoints: ['https://polygon.publicnode.com', 'https://polygon.drpc.org'],
|
|
1709
1994
|
eurcAddress: null,
|
|
1710
1995
|
usdcAddress: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
1996
|
+
usdtAddress: null,
|
|
1711
1997
|
cctp: {
|
|
1712
1998
|
domain: 7,
|
|
1713
1999
|
contracts: {
|
|
@@ -1732,6 +2018,7 @@ const Polygon = defineChain({
|
|
|
1732
2018
|
},
|
|
1733
2019
|
kitContracts: {
|
|
1734
2020
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2021
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1735
2022
|
},
|
|
1736
2023
|
});
|
|
1737
2024
|
|
|
@@ -1756,6 +2043,7 @@ const PolygonAmoy = defineChain({
|
|
|
1756
2043
|
rpcEndpoints: ['https://rpc-amoy.polygon.technology'],
|
|
1757
2044
|
eurcAddress: null,
|
|
1758
2045
|
usdcAddress: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
2046
|
+
usdtAddress: null,
|
|
1759
2047
|
cctp: {
|
|
1760
2048
|
domain: 7,
|
|
1761
2049
|
contracts: {
|
|
@@ -1806,6 +2094,7 @@ const Sei = defineChain({
|
|
|
1806
2094
|
rpcEndpoints: ['https://evm-rpc.sei-apis.com'],
|
|
1807
2095
|
eurcAddress: null,
|
|
1808
2096
|
usdcAddress: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
2097
|
+
usdtAddress: null,
|
|
1809
2098
|
cctp: {
|
|
1810
2099
|
domain: 16,
|
|
1811
2100
|
contracts: {
|
|
@@ -1824,6 +2113,7 @@ const Sei = defineChain({
|
|
|
1824
2113
|
},
|
|
1825
2114
|
kitContracts: {
|
|
1826
2115
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2116
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1827
2117
|
},
|
|
1828
2118
|
});
|
|
1829
2119
|
|
|
@@ -1849,6 +2139,7 @@ const SeiTestnet = defineChain({
|
|
|
1849
2139
|
rpcEndpoints: ['https://evm-rpc-testnet.sei-apis.com'],
|
|
1850
2140
|
eurcAddress: null,
|
|
1851
2141
|
usdcAddress: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
2142
|
+
usdtAddress: null,
|
|
1852
2143
|
cctp: {
|
|
1853
2144
|
domain: 16,
|
|
1854
2145
|
contracts: {
|
|
@@ -1891,6 +2182,7 @@ const Sonic = defineChain({
|
|
|
1891
2182
|
rpcEndpoints: ['https://rpc.soniclabs.com'],
|
|
1892
2183
|
eurcAddress: null,
|
|
1893
2184
|
usdcAddress: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
2185
|
+
usdtAddress: null,
|
|
1894
2186
|
cctp: {
|
|
1895
2187
|
domain: 13,
|
|
1896
2188
|
contracts: {
|
|
@@ -1909,6 +2201,7 @@ const Sonic = defineChain({
|
|
|
1909
2201
|
},
|
|
1910
2202
|
kitContracts: {
|
|
1911
2203
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2204
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1912
2205
|
},
|
|
1913
2206
|
});
|
|
1914
2207
|
|
|
@@ -1933,6 +2226,7 @@ const SonicTestnet = defineChain({
|
|
|
1933
2226
|
rpcEndpoints: ['https://rpc.testnet.soniclabs.com'],
|
|
1934
2227
|
eurcAddress: null,
|
|
1935
2228
|
usdcAddress: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
2229
|
+
usdtAddress: null,
|
|
1936
2230
|
cctp: {
|
|
1937
2231
|
domain: 13,
|
|
1938
2232
|
contracts: {
|
|
@@ -1974,6 +2268,7 @@ const Solana = defineChain({
|
|
|
1974
2268
|
rpcEndpoints: ['https://api.mainnet-beta.solana.com'],
|
|
1975
2269
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
1976
2270
|
usdcAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
2271
|
+
usdtAddress: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
1977
2272
|
cctp: {
|
|
1978
2273
|
domain: 5,
|
|
1979
2274
|
contracts: {
|
|
@@ -2020,6 +2315,7 @@ const SolanaDevnet = defineChain({
|
|
|
2020
2315
|
explorerUrl: 'https://solscan.io/tx/{hash}?cluster=devnet',
|
|
2021
2316
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
2022
2317
|
usdcAddress: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
2318
|
+
usdtAddress: null,
|
|
2023
2319
|
cctp: {
|
|
2024
2320
|
domain: 5,
|
|
2025
2321
|
contracts: {
|
|
@@ -2068,6 +2364,7 @@ const Stellar = defineChain({
|
|
|
2068
2364
|
rpcEndpoints: ['https://horizon.stellar.org'],
|
|
2069
2365
|
eurcAddress: 'EURC-GDHU6WRG4IEQXM5NZ4BMPKOXHW76MZM4Y2IEMFDVXBSDP6SJY4ITNPP2',
|
|
2070
2366
|
usdcAddress: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
2367
|
+
usdtAddress: null,
|
|
2071
2368
|
cctp: null,
|
|
2072
2369
|
});
|
|
2073
2370
|
|
|
@@ -2091,6 +2388,7 @@ const StellarTestnet = defineChain({
|
|
|
2091
2388
|
rpcEndpoints: ['https://horizon-testnet.stellar.org'],
|
|
2092
2389
|
eurcAddress: 'EURC-GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO',
|
|
2093
2390
|
usdcAddress: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
2391
|
+
usdtAddress: null,
|
|
2094
2392
|
cctp: null,
|
|
2095
2393
|
});
|
|
2096
2394
|
|
|
@@ -2114,6 +2412,7 @@ const Sui = defineChain({
|
|
|
2114
2412
|
rpcEndpoints: ['https://fullnode.mainnet.sui.io'],
|
|
2115
2413
|
eurcAddress: null,
|
|
2116
2414
|
usdcAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
2415
|
+
usdtAddress: null,
|
|
2117
2416
|
cctp: {
|
|
2118
2417
|
domain: 8,
|
|
2119
2418
|
contracts: {
|
|
@@ -2151,6 +2450,7 @@ const SuiTestnet = defineChain({
|
|
|
2151
2450
|
rpcEndpoints: ['https://fullnode.testnet.sui.io'],
|
|
2152
2451
|
eurcAddress: null,
|
|
2153
2452
|
usdcAddress: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
2453
|
+
usdtAddress: null,
|
|
2154
2454
|
cctp: {
|
|
2155
2455
|
domain: 8,
|
|
2156
2456
|
contracts: {
|
|
@@ -2189,6 +2489,7 @@ const Unichain = defineChain({
|
|
|
2189
2489
|
rpcEndpoints: ['https://mainnet.unichain.org'],
|
|
2190
2490
|
eurcAddress: null,
|
|
2191
2491
|
usdcAddress: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
2492
|
+
usdtAddress: null,
|
|
2192
2493
|
cctp: {
|
|
2193
2494
|
domain: 10,
|
|
2194
2495
|
contracts: {
|
|
@@ -2213,6 +2514,7 @@ const Unichain = defineChain({
|
|
|
2213
2514
|
},
|
|
2214
2515
|
kitContracts: {
|
|
2215
2516
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2517
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2216
2518
|
},
|
|
2217
2519
|
});
|
|
2218
2520
|
|
|
@@ -2237,6 +2539,7 @@ const UnichainSepolia = defineChain({
|
|
|
2237
2539
|
rpcEndpoints: ['https://sepolia.unichain.org'],
|
|
2238
2540
|
eurcAddress: null,
|
|
2239
2541
|
usdcAddress: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
2542
|
+
usdtAddress: null,
|
|
2240
2543
|
cctp: {
|
|
2241
2544
|
domain: 10,
|
|
2242
2545
|
contracts: {
|
|
@@ -2285,6 +2588,7 @@ const WorldChain = defineChain({
|
|
|
2285
2588
|
rpcEndpoints: ['https://worldchain-mainnet.g.alchemy.com/public'],
|
|
2286
2589
|
eurcAddress: null,
|
|
2287
2590
|
usdcAddress: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
2591
|
+
usdtAddress: null,
|
|
2288
2592
|
cctp: {
|
|
2289
2593
|
domain: 14,
|
|
2290
2594
|
contracts: {
|
|
@@ -2303,6 +2607,7 @@ const WorldChain = defineChain({
|
|
|
2303
2607
|
},
|
|
2304
2608
|
kitContracts: {
|
|
2305
2609
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2610
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2306
2611
|
},
|
|
2307
2612
|
});
|
|
2308
2613
|
|
|
@@ -2330,6 +2635,7 @@ const WorldChainSepolia = defineChain({
|
|
|
2330
2635
|
],
|
|
2331
2636
|
eurcAddress: null,
|
|
2332
2637
|
usdcAddress: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
2638
|
+
usdtAddress: null,
|
|
2333
2639
|
cctp: {
|
|
2334
2640
|
domain: 14,
|
|
2335
2641
|
contracts: {
|
|
@@ -2374,6 +2680,7 @@ const XDC = defineChain({
|
|
|
2374
2680
|
rpcEndpoints: ['https://erpc.xdcrpc.com', 'https://erpc.xinfin.network'],
|
|
2375
2681
|
eurcAddress: null,
|
|
2376
2682
|
usdcAddress: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
2683
|
+
usdtAddress: null,
|
|
2377
2684
|
cctp: {
|
|
2378
2685
|
domain: 18,
|
|
2379
2686
|
contracts: {
|
|
@@ -2392,6 +2699,7 @@ const XDC = defineChain({
|
|
|
2392
2699
|
},
|
|
2393
2700
|
kitContracts: {
|
|
2394
2701
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2702
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2395
2703
|
},
|
|
2396
2704
|
});
|
|
2397
2705
|
|
|
@@ -2416,6 +2724,7 @@ const XDCApothem = defineChain({
|
|
|
2416
2724
|
rpcEndpoints: ['https://erpc.apothem.network'],
|
|
2417
2725
|
eurcAddress: null,
|
|
2418
2726
|
usdcAddress: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
2727
|
+
usdtAddress: null,
|
|
2419
2728
|
cctp: {
|
|
2420
2729
|
domain: 18,
|
|
2421
2730
|
contracts: {
|
|
@@ -2458,6 +2767,7 @@ const ZKSyncEra = defineChain({
|
|
|
2458
2767
|
rpcEndpoints: ['https://mainnet.era.zksync.io'],
|
|
2459
2768
|
eurcAddress: null,
|
|
2460
2769
|
usdcAddress: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
2770
|
+
usdtAddress: null,
|
|
2461
2771
|
cctp: null,
|
|
2462
2772
|
});
|
|
2463
2773
|
|
|
@@ -2482,6 +2792,7 @@ const ZKSyncEraSepolia = defineChain({
|
|
|
2482
2792
|
rpcEndpoints: ['https://sepolia.era.zksync.dev'],
|
|
2483
2793
|
eurcAddress: null,
|
|
2484
2794
|
usdcAddress: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
2795
|
+
usdtAddress: null,
|
|
2485
2796
|
cctp: null,
|
|
2486
2797
|
});
|
|
2487
2798
|
|
|
@@ -2649,10 +2960,12 @@ const baseChainDefinitionSchema = z.object({
|
|
|
2649
2960
|
rpcEndpoints: z.array(z.string()),
|
|
2650
2961
|
eurcAddress: z.string().nullable(),
|
|
2651
2962
|
usdcAddress: z.string().nullable(),
|
|
2963
|
+
usdtAddress: z.string().nullable(),
|
|
2652
2964
|
cctp: z.any().nullable(), // We'll accept any CCTP config structure
|
|
2653
2965
|
kitContracts: z
|
|
2654
2966
|
.object({
|
|
2655
2967
|
bridge: z.string().optional(),
|
|
2968
|
+
adapter: z.string().optional(),
|
|
2656
2969
|
})
|
|
2657
2970
|
.optional(),
|
|
2658
2971
|
});
|
|
@@ -2767,6 +3080,29 @@ z.union([
|
|
|
2767
3080
|
z.nativeEnum(Blockchain),
|
|
2768
3081
|
chainDefinitionSchema$2,
|
|
2769
3082
|
]);
|
|
3083
|
+
/**
|
|
3084
|
+
* Zod schema for validating swap-specific chain identifiers.
|
|
3085
|
+
*
|
|
3086
|
+
* Validates chains based on:
|
|
3087
|
+
* - CCTPv2 support (adapter contract deployed)
|
|
3088
|
+
* - Mainnet only (no testnets)
|
|
3089
|
+
* - At least one supported token available
|
|
3090
|
+
*
|
|
3091
|
+
*/
|
|
3092
|
+
z.union([
|
|
3093
|
+
// String blockchain identifier (accepts SwapChain enum values)
|
|
3094
|
+
z.string().refine((val) => val in SwapChain, (val) => ({
|
|
3095
|
+
message: `"${val}" is not a supported swap chain. ` +
|
|
3096
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
3097
|
+
})),
|
|
3098
|
+
// SwapChain enum
|
|
3099
|
+
z.nativeEnum(SwapChain),
|
|
3100
|
+
// ChainDefinition object (checks if chain.chain is in SwapChain)
|
|
3101
|
+
chainDefinitionSchema$2.refine((chain) => chain.chain in SwapChain, (chain) => ({
|
|
3102
|
+
message: `"${chain.chain}" is not a supported swap chain. ` +
|
|
3103
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
3104
|
+
})),
|
|
3105
|
+
]);
|
|
2770
3106
|
/**
|
|
2771
3107
|
* Zod schema for validating bridge chain identifiers.
|
|
2772
3108
|
*
|
|
@@ -2806,6 +3142,38 @@ z.union([
|
|
|
2806
3142
|
})),
|
|
2807
3143
|
]);
|
|
2808
3144
|
|
|
3145
|
+
/**
|
|
3146
|
+
* @packageDocumentation
|
|
3147
|
+
* @module SwapTokenSchemas
|
|
3148
|
+
*
|
|
3149
|
+
* Zod validation schemas for supported swap tokens.
|
|
3150
|
+
*/
|
|
3151
|
+
// Internal enum used after input normalization.
|
|
3152
|
+
const swapTokenEnumSchema = z.enum([
|
|
3153
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
3154
|
+
NATIVE_TOKEN,
|
|
3155
|
+
]);
|
|
3156
|
+
/**
|
|
3157
|
+
* Zod schema for validating supported swap token symbols.
|
|
3158
|
+
*
|
|
3159
|
+
* Accepts any token symbol from the SWAP_TOKEN_REGISTRY plus NATIVE.
|
|
3160
|
+
* Input matching is case-insensitive and normalized to uppercase.
|
|
3161
|
+
*
|
|
3162
|
+
* @example
|
|
3163
|
+
* ```typescript
|
|
3164
|
+
* import { supportedSwapTokenSchema } from '@core/chains'
|
|
3165
|
+
*
|
|
3166
|
+
* const result = supportedSwapTokenSchema.safeParse('USDC')
|
|
3167
|
+
* if (result.success) {
|
|
3168
|
+
* console.log('Valid swap token:', result.data)
|
|
3169
|
+
* }
|
|
3170
|
+
* ```
|
|
3171
|
+
*/
|
|
3172
|
+
z
|
|
3173
|
+
.string()
|
|
3174
|
+
.transform((value) => value.toUpperCase())
|
|
3175
|
+
.pipe(swapTokenEnumSchema);
|
|
3176
|
+
|
|
2809
3177
|
/**
|
|
2810
3178
|
* Retrieve a chain definition by its blockchain enum value.
|
|
2811
3179
|
*
|
|
@@ -2860,6 +3228,11 @@ const getChainByEnum = (blockchain) => {
|
|
|
2860
3228
|
* ```
|
|
2861
3229
|
*/
|
|
2862
3230
|
function resolveChainIdentifier(chainIdentifier) {
|
|
3231
|
+
// Handle null explicitly (typeof null === 'object' in JavaScript)
|
|
3232
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
3233
|
+
if (chainIdentifier === null) {
|
|
3234
|
+
throw new Error(`Invalid chain identifier type: null. Expected ChainDefinition object, Blockchain enum, or string literal.`);
|
|
3235
|
+
}
|
|
2863
3236
|
// If it's already a ChainDefinition object, return it unchanged
|
|
2864
3237
|
if (typeof chainIdentifier === 'object') {
|
|
2865
3238
|
return chainIdentifier;
|
|
@@ -3151,11 +3524,11 @@ const formatComponent = (nameWithVersion) => {
|
|
|
3151
3524
|
const createRequestContext = () => {
|
|
3152
3525
|
const context = {};
|
|
3153
3526
|
if (typeof globalThis !== 'undefined') {
|
|
3154
|
-
if (globalThis.
|
|
3155
|
-
context.externalPrefix = globalThis.
|
|
3527
|
+
if (globalThis.__APP_KITS_EXTERNAL_PREFIX__ !== undefined) {
|
|
3528
|
+
context.externalPrefix = globalThis.__APP_KITS_EXTERNAL_PREFIX__;
|
|
3156
3529
|
}
|
|
3157
|
-
if (globalThis.
|
|
3158
|
-
context.kit = globalThis.
|
|
3530
|
+
if (globalThis.__APP_KITS_CURRENT_KIT__ !== undefined) {
|
|
3531
|
+
context.kit = globalThis.__APP_KITS_CURRENT_KIT__;
|
|
3159
3532
|
}
|
|
3160
3533
|
}
|
|
3161
3534
|
return context;
|
|
@@ -3261,6 +3634,10 @@ const ERROR_TYPES = {
|
|
|
3261
3634
|
RPC: 'RPC',
|
|
3262
3635
|
/** Internet connectivity, DNS resolution, connection issues */
|
|
3263
3636
|
NETWORK: 'NETWORK',
|
|
3637
|
+
/** API throttling, request frequency limits errors */
|
|
3638
|
+
RATE_LIMIT: 'RATE_LIMIT',
|
|
3639
|
+
/** Service errors */
|
|
3640
|
+
SERVICE: 'SERVICE',
|
|
3264
3641
|
/** Catch-all for unrecognized errors (code 0) */
|
|
3265
3642
|
UNKNOWN: 'UNKNOWN',
|
|
3266
3643
|
};
|
|
@@ -3284,6 +3661,8 @@ const ERROR_CODE_RANGES = [
|
|
|
3284
3661
|
{ min: 3000, max: 3999, type: 'NETWORK' },
|
|
3285
3662
|
{ min: 4000, max: 4999, type: 'RPC' },
|
|
3286
3663
|
{ min: 5000, max: 5999, type: 'ONCHAIN' },
|
|
3664
|
+
{ min: 7000, max: 7999, type: 'RATE_LIMIT' },
|
|
3665
|
+
{ min: 8000, max: 8999, type: 'SERVICE' },
|
|
3287
3666
|
{ min: 9000, max: 9999, type: 'BALANCE' },
|
|
3288
3667
|
];
|
|
3289
3668
|
/** Special code for UNKNOWN errors */
|
|
@@ -3331,6 +3710,8 @@ const errorDetailsSchema = z.object({
|
|
|
3331
3710
|
* - 3000-3999: NETWORK errors - Connectivity issues
|
|
3332
3711
|
* - 4000-4999: RPC errors - Provider issues, gas estimation
|
|
3333
3712
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures
|
|
3713
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling
|
|
3714
|
+
* - 8000-8999: SERVICE errors - Internal service errors
|
|
3334
3715
|
* - 9000-9999: BALANCE errors - Insufficient funds
|
|
3335
3716
|
*/
|
|
3336
3717
|
code: z
|
|
@@ -3439,11 +3820,11 @@ const AMOUNT_FORMAT_ERROR_MESSAGE = 'Amount must be a numeric string with dot (.
|
|
|
3439
3820
|
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';
|
|
3440
3821
|
|
|
3441
3822
|
/**
|
|
3442
|
-
* Structured error class for
|
|
3823
|
+
* Structured error class for App Kit operations.
|
|
3443
3824
|
*
|
|
3444
3825
|
* This class extends the native Error class while implementing the ErrorDetails
|
|
3445
3826
|
* interface, providing a consistent error format for programmatic handling
|
|
3446
|
-
* across the
|
|
3827
|
+
* across the App Kits ecosystem. All properties are immutable to ensure
|
|
3447
3828
|
* error objects cannot be modified after creation.
|
|
3448
3829
|
*
|
|
3449
3830
|
* @example
|
|
@@ -3453,6 +3834,7 @@ const MAX_FEE_FORMAT_ERROR_MESSAGE = 'maxFee must be a numeric string with dot (
|
|
|
3453
3834
|
* const error = new KitError({
|
|
3454
3835
|
* code: 1001,
|
|
3455
3836
|
* name: 'INPUT_NETWORK_MISMATCH',
|
|
3837
|
+
* type: 'INPUT',
|
|
3456
3838
|
* recoverability: 'FATAL',
|
|
3457
3839
|
* message: 'Cannot bridge between mainnet and testnet'
|
|
3458
3840
|
* })
|
|
@@ -3470,7 +3852,8 @@ const MAX_FEE_FORMAT_ERROR_MESSAGE = 'maxFee must be a numeric string with dot (
|
|
|
3470
3852
|
* // Error with cause information
|
|
3471
3853
|
* const error = new KitError({
|
|
3472
3854
|
* code: 1002,
|
|
3473
|
-
* name: '
|
|
3855
|
+
* name: 'INPUT_INVALID_AMOUNT',
|
|
3856
|
+
* type: 'INPUT',
|
|
3474
3857
|
* recoverability: 'FATAL',
|
|
3475
3858
|
* message: 'Amount must be greater than zero',
|
|
3476
3859
|
* cause: {
|
|
@@ -3554,6 +3937,8 @@ class KitError extends Error {
|
|
|
3554
3937
|
* - 3000-3999: NETWORK errors - Internet connectivity, DNS, connection issues
|
|
3555
3938
|
* - 4000-4999: RPC errors - Blockchain provider issues, gas estimation, nonce errors
|
|
3556
3939
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures, gas exhaustion, reverts
|
|
3940
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling, request frequency limits
|
|
3941
|
+
* - 8000-8999: SERVICE errors - Internal service errors, server failures
|
|
3557
3942
|
* - 9000-9999: BALANCE errors - Insufficient funds, token balance, allowance
|
|
3558
3943
|
*/
|
|
3559
3944
|
/**
|
|
@@ -3614,10 +3999,22 @@ const InputError = {
|
|
|
3614
3999
|
name: 'INPUT_INVALID_CHAIN',
|
|
3615
4000
|
type: 'INPUT',
|
|
3616
4001
|
},
|
|
3617
|
-
/**
|
|
3618
|
-
|
|
4002
|
+
/** Unsupported token for chain */
|
|
4003
|
+
UNSUPPORTED_TOKEN: {
|
|
3619
4004
|
code: 1006,
|
|
3620
|
-
name: '
|
|
4005
|
+
name: 'INPUT_UNSUPPORTED_TOKEN',
|
|
4006
|
+
type: 'INPUT',
|
|
4007
|
+
},
|
|
4008
|
+
/** Insufficient swap amount for the token pair */
|
|
4009
|
+
INSUFFICIENT_SWAP_AMOUNT: {
|
|
4010
|
+
code: 1007,
|
|
4011
|
+
name: 'INPUT_INSUFFICIENT_SWAP_AMOUNT',
|
|
4012
|
+
type: 'INPUT',
|
|
4013
|
+
},
|
|
4014
|
+
/** Action not supported by this adapter / ecosystem */
|
|
4015
|
+
UNSUPPORTED_ACTION: {
|
|
4016
|
+
code: 1008,
|
|
4017
|
+
name: 'INPUT_UNSUPPORTED_ACTION',
|
|
3621
4018
|
type: 'INPUT',
|
|
3622
4019
|
},
|
|
3623
4020
|
/** General validation failure for complex validation rules */
|
|
@@ -3626,6 +4023,12 @@ const InputError = {
|
|
|
3626
4023
|
name: 'INPUT_VALIDATION_FAILED',
|
|
3627
4024
|
type: 'INPUT',
|
|
3628
4025
|
},
|
|
4026
|
+
/** User cancelled wallet interaction (signature, transaction, connection) */
|
|
4027
|
+
USER_CANCELLED: {
|
|
4028
|
+
code: 1099,
|
|
4029
|
+
name: 'INPUT_USER_CANCELLED',
|
|
4030
|
+
type: 'INPUT',
|
|
4031
|
+
},
|
|
3629
4032
|
};
|
|
3630
4033
|
/**
|
|
3631
4034
|
* Standardized error definitions for BALANCE type errors.
|
|
@@ -3713,8 +4116,7 @@ const NetworkError = {
|
|
|
3713
4116
|
code: 3004,
|
|
3714
4117
|
name: 'NETWORK_RELAYER_PENDING',
|
|
3715
4118
|
type: 'NETWORK',
|
|
3716
|
-
}
|
|
3717
|
-
};
|
|
4119
|
+
}};
|
|
3718
4120
|
|
|
3719
4121
|
/**
|
|
3720
4122
|
* Creates error for network type mismatch between source and destination.
|
|
@@ -3801,7 +4203,7 @@ function createInvalidChainError(chain, reason) {
|
|
|
3801
4203
|
const errorDetails = {
|
|
3802
4204
|
...InputError.INVALID_CHAIN,
|
|
3803
4205
|
recoverability: 'FATAL',
|
|
3804
|
-
message: `Invalid chain '${chain}': ${reason}
|
|
4206
|
+
message: `Invalid chain '${chain}': ${reason}.`,
|
|
3805
4207
|
cause: {
|
|
3806
4208
|
trace: { chain, reason },
|
|
3807
4209
|
},
|
|
@@ -4150,6 +4552,9 @@ function getErrorMessage(error) {
|
|
|
4150
4552
|
if (typeof error === 'string') {
|
|
4151
4553
|
return error;
|
|
4152
4554
|
}
|
|
4555
|
+
if (typeof error === 'object' && error !== null && 'message' in error) {
|
|
4556
|
+
return String(error.message);
|
|
4557
|
+
}
|
|
4153
4558
|
return 'An unknown error occurred';
|
|
4154
4559
|
}
|
|
4155
4560
|
/**
|
|
@@ -4206,6 +4611,9 @@ function extractErrorInfo(error) {
|
|
|
4206
4611
|
if (typeof err.code === 'number') {
|
|
4207
4612
|
info.code = err.code;
|
|
4208
4613
|
}
|
|
4614
|
+
if (isKitError(error)) {
|
|
4615
|
+
info.type = error.type;
|
|
4616
|
+
}
|
|
4209
4617
|
return info;
|
|
4210
4618
|
}
|
|
4211
4619
|
|
|
@@ -4328,7 +4736,17 @@ const makeApiRequest = async (url, method, isValidType, config, body) => {
|
|
|
4328
4736
|
const response = await fetch(url, requestInit);
|
|
4329
4737
|
clearTimeout(timeoutId);
|
|
4330
4738
|
if (!response.ok) {
|
|
4331
|
-
|
|
4739
|
+
let responseBody;
|
|
4740
|
+
try {
|
|
4741
|
+
responseBody = (await response.json());
|
|
4742
|
+
}
|
|
4743
|
+
catch {
|
|
4744
|
+
// Parse response body for diagnostics; continue even if malformed
|
|
4745
|
+
// so callers always receive HTTP status context
|
|
4746
|
+
}
|
|
4747
|
+
const httpError = new Error(`HTTP ${String(response.status)} - ${response.statusText}`);
|
|
4748
|
+
httpError.responseBody = responseBody;
|
|
4749
|
+
throw httpError;
|
|
4332
4750
|
}
|
|
4333
4751
|
const parsedJson = (await response.json());
|
|
4334
4752
|
if (!isValidType(parsedJson)) {
|
|
@@ -4900,7 +5318,7 @@ const convertAddress = (address, targetFormat) => {
|
|
|
4900
5318
|
*
|
|
4901
5319
|
* This function normalizes token values from their blockchain representation (where
|
|
4902
5320
|
* everything is stored as integers in the smallest denomination) to human-readable
|
|
4903
|
-
* decimal format. Uses the battle-tested implementation from
|
|
5321
|
+
* decimal format. Uses the battle-tested implementation from \@ethersproject/units.
|
|
4904
5322
|
*
|
|
4905
5323
|
* @param value - The value in smallest units (e.g., "1000000" for 1 USDC with 6 decimals)
|
|
4906
5324
|
* @param decimals - The number of decimal places for the unit conversion
|
|
@@ -4929,116 +5347,837 @@ const formatUnits = (value, decimals) => {
|
|
|
4929
5347
|
};
|
|
4930
5348
|
|
|
4931
5349
|
/**
|
|
4932
|
-
*
|
|
4933
|
-
*
|
|
4934
|
-
* This function takes a chain definition containing an explorer URL template
|
|
4935
|
-
* and replaces the `{hash}` placeholder with the provided transaction hash
|
|
4936
|
-
* to create a complete, valid explorer URL.
|
|
4937
|
-
*
|
|
4938
|
-
* @param chainDef - The chain definition containing the explorer URL template.
|
|
4939
|
-
* @param txHash - The transaction hash to insert into the URL template.
|
|
4940
|
-
* @returns A complete explorer URL with the transaction hash inserted.
|
|
4941
|
-
* @throws Error if the chain definition is null/undefined.
|
|
4942
|
-
* @throws Error if the transaction hash is null/undefined/empty.
|
|
4943
|
-
* @throws Error if the explorer URL template is missing or empty.
|
|
4944
|
-
* @throws Error if the explorer URL template doesn't contain the {hash} placeholder.
|
|
4945
|
-
* @throws Error if the resulting URL is invalid.
|
|
4946
|
-
*
|
|
4947
|
-
* @example
|
|
4948
|
-
* ```typescript
|
|
4949
|
-
* import { buildExplorerUrl } from '@core/utils'
|
|
4950
|
-
* import { Ethereum } from '@core/chains'
|
|
4951
|
-
*
|
|
4952
|
-
* // Build URL for Ethereum transaction
|
|
4953
|
-
* const url = buildExplorerUrl(Ethereum, '0x1234567890abcdef...')
|
|
4954
|
-
* console.log(url) // 'https://etherscan.io/tx/0x1234567890abcdef...'
|
|
4955
|
-
* ```
|
|
5350
|
+
* Create a structured error for token resolution failures.
|
|
4956
5351
|
*
|
|
4957
|
-
* @
|
|
4958
|
-
*
|
|
4959
|
-
*
|
|
4960
|
-
* import { Solana } from '@core/chains'
|
|
5352
|
+
* @remarks
|
|
5353
|
+
* Returns a `KitError` with `INPUT_UNSUPPORTED_TOKEN` code (1006).
|
|
5354
|
+
* The error trace contains the selector and chain context for debugging.
|
|
4961
5355
|
*
|
|
4962
|
-
*
|
|
4963
|
-
*
|
|
4964
|
-
*
|
|
4965
|
-
*
|
|
5356
|
+
* @param message - Human-readable error description.
|
|
5357
|
+
* @param selector - The token selector that failed to resolve.
|
|
5358
|
+
* @param chainId - The chain being resolved for (optional).
|
|
5359
|
+
* @param cause - The underlying error, if any (optional).
|
|
5360
|
+
* @returns A KitError with INPUT type and FATAL recoverability.
|
|
4966
5361
|
*
|
|
4967
5362
|
* @example
|
|
4968
5363
|
* ```typescript
|
|
4969
|
-
*
|
|
4970
|
-
*
|
|
4971
|
-
*
|
|
4972
|
-
*
|
|
4973
|
-
*
|
|
4974
|
-
* console.log(url) // 'https://explorer.aptoslabs.com/txn/0xabc123...?network=mainnet'
|
|
5364
|
+
* throw createTokenResolutionError(
|
|
5365
|
+
* 'Unknown token symbol: FAKE',
|
|
5366
|
+
* 'FAKE',
|
|
5367
|
+
* 'Ethereum'
|
|
5368
|
+
* )
|
|
4975
5369
|
* ```
|
|
4976
5370
|
*/
|
|
4977
|
-
function
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
5371
|
+
function createTokenResolutionError(message, selector, chainId, cause) {
|
|
5372
|
+
const trace = {
|
|
5373
|
+
selector,
|
|
5374
|
+
...(chainId === undefined ? {} : { chainId }),
|
|
5375
|
+
...({} ),
|
|
5376
|
+
};
|
|
5377
|
+
return new KitError({
|
|
5378
|
+
...InputError.UNSUPPORTED_TOKEN,
|
|
5379
|
+
recoverability: 'FATAL',
|
|
5380
|
+
message,
|
|
5381
|
+
cause: { trace },
|
|
5382
|
+
});
|
|
4987
5383
|
}
|
|
4988
5384
|
|
|
4989
5385
|
/**
|
|
4990
|
-
*
|
|
4991
|
-
*
|
|
4992
|
-
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
4993
|
-
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
4994
|
-
*/
|
|
4995
|
-
const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
4996
|
-
/**
|
|
4997
|
-
* CCTP forwarding version number.
|
|
4998
|
-
*
|
|
4999
|
-
* Version 0 is used for basic forwarding requests.
|
|
5000
|
-
*/
|
|
5001
|
-
const CCTP_FORWARD_VERSION = 0;
|
|
5002
|
-
/**
|
|
5003
|
-
* Length of Circle-reserved payload for basic forwarding (0 bytes).
|
|
5004
|
-
*
|
|
5005
|
-
* Set to 0 when no additional Circle-reserved data is needed.
|
|
5006
|
-
*/
|
|
5007
|
-
const CCTP_FORWARD_PAYLOAD_LENGTH = 0;
|
|
5008
|
-
/**
|
|
5009
|
-
* Build the hookData bytes for CCTP forwarding.
|
|
5010
|
-
*
|
|
5011
|
-
* Constructs a 32-byte hookData payload that signals to Circle's Orbit relayer
|
|
5012
|
-
* that the user wants automated attestation fetching and destination mint execution.
|
|
5386
|
+
* USDC token definition with addresses and metadata.
|
|
5013
5387
|
*
|
|
5014
|
-
*
|
|
5015
|
-
*
|
|
5016
|
-
*
|
|
5017
|
-
* - Bytes 28-31: uint32 length (big-endian) - 0 for basic forwarding
|
|
5388
|
+
* @remarks
|
|
5389
|
+
* This is the built-in USDC definition used by the TokenRegistry.
|
|
5390
|
+
* Includes all known USDC addresses across supported chains.
|
|
5018
5391
|
*
|
|
5019
|
-
*
|
|
5392
|
+
* Keys use the `Blockchain` enum for type safety. Both enum values
|
|
5393
|
+
* and string literals are supported:
|
|
5394
|
+
* - `Blockchain.Ethereum` or `'Ethereum'`
|
|
5020
5395
|
*
|
|
5021
5396
|
* @example
|
|
5022
5397
|
* ```typescript
|
|
5023
|
-
* import {
|
|
5024
|
-
*
|
|
5025
|
-
* const hookData = buildForwardingHookData()
|
|
5026
|
-
* // Returns: '0x636374702d666f72776172640000000000000000000000000000000000000000'
|
|
5398
|
+
* import { USDC } from '@core/tokens'
|
|
5399
|
+
* import { Blockchain } from '@core/chains'
|
|
5027
5400
|
*
|
|
5028
|
-
* //
|
|
5029
|
-
*
|
|
5030
|
-
*
|
|
5031
|
-
*
|
|
5032
|
-
* maxFee: BigInt('50000'),
|
|
5033
|
-
* minFinalityThreshold: 1000,
|
|
5034
|
-
* fromChain: ethereum,
|
|
5035
|
-
* toChain: base,
|
|
5036
|
-
* hookData
|
|
5037
|
-
* })
|
|
5401
|
+
* console.log(USDC.symbol) // 'USDC'
|
|
5402
|
+
* console.log(USDC.decimals) // 6
|
|
5403
|
+
* console.log(USDC.locators[Blockchain.Ethereum])
|
|
5404
|
+
* // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
5038
5405
|
* ```
|
|
5039
5406
|
*/
|
|
5040
|
-
|
|
5041
|
-
|
|
5407
|
+
const USDC = {
|
|
5408
|
+
symbol: 'USDC',
|
|
5409
|
+
decimals: 6,
|
|
5410
|
+
locators: {
|
|
5411
|
+
// =========================================================================
|
|
5412
|
+
// Mainnets (alphabetically sorted)
|
|
5413
|
+
// =========================================================================
|
|
5414
|
+
[Blockchain.Arbitrum]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
5415
|
+
[Blockchain.Avalanche]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
5416
|
+
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
5417
|
+
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
5418
|
+
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
5419
|
+
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
5420
|
+
[Blockchain.Hedera]: '0.0.456858',
|
|
5421
|
+
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
5422
|
+
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
5423
|
+
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
5424
|
+
[Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
5425
|
+
[Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
5426
|
+
[Blockchain.Noble]: 'uusdc',
|
|
5427
|
+
[Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
5428
|
+
[Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
5429
|
+
[Blockchain.Polkadot_Asset_Hub]: '1337',
|
|
5430
|
+
[Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
5431
|
+
[Blockchain.Sei]: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
5432
|
+
[Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
5433
|
+
[Blockchain.Sonic]: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
5434
|
+
[Blockchain.Stellar]: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
5435
|
+
[Blockchain.Sui]: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
5436
|
+
[Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
5437
|
+
[Blockchain.World_Chain]: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
5438
|
+
[Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
5439
|
+
[Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
5440
|
+
// =========================================================================
|
|
5441
|
+
// Testnets (alphabetically sorted)
|
|
5442
|
+
// =========================================================================
|
|
5443
|
+
[Blockchain.Arbitrum_Sepolia]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
5444
|
+
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
5445
|
+
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
5446
|
+
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
5447
|
+
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
5448
|
+
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
5449
|
+
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
5450
|
+
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
5451
|
+
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
5452
|
+
[Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
5453
|
+
[Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
5454
|
+
[Blockchain.Noble_Testnet]: 'uusdc',
|
|
5455
|
+
[Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
5456
|
+
[Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
5457
|
+
[Blockchain.Polkadot_Westmint]: '31337',
|
|
5458
|
+
[Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
5459
|
+
[Blockchain.Sei_Testnet]: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
5460
|
+
[Blockchain.Solana_Devnet]: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
5461
|
+
[Blockchain.Sonic_Testnet]: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
5462
|
+
[Blockchain.Stellar_Testnet]: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
5463
|
+
[Blockchain.Sui_Testnet]: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
5464
|
+
[Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
5465
|
+
[Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
5466
|
+
[Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
5467
|
+
[Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
5468
|
+
},
|
|
5469
|
+
};
|
|
5470
|
+
|
|
5471
|
+
/**
|
|
5472
|
+
* USDT (Tether) token definition with addresses and metadata.
|
|
5473
|
+
*
|
|
5474
|
+
* @remarks
|
|
5475
|
+
* Built-in USDT definition for the TokenRegistry. Includes chain locators
|
|
5476
|
+
* for swap-supported chains.
|
|
5477
|
+
*/
|
|
5478
|
+
const USDT = {
|
|
5479
|
+
symbol: 'USDT',
|
|
5480
|
+
decimals: 6,
|
|
5481
|
+
locators: {
|
|
5482
|
+
[Blockchain.Aptos]: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
5483
|
+
[Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
|
|
5484
|
+
[Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
|
|
5485
|
+
[Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
5486
|
+
[Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
|
5487
|
+
[Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
|
|
5488
|
+
[Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
|
|
5489
|
+
[Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
|
|
5490
|
+
[Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
|
|
5491
|
+
[Blockchain.NEAR]: 'usdt.tether-token.near',
|
|
5492
|
+
[Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
|
|
5493
|
+
[Blockchain.Polkadot_Asset_Hub]: '1984',
|
|
5494
|
+
[Blockchain.Polygon]: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
|
5495
|
+
[Blockchain.Sei]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
5496
|
+
[Blockchain.Solana]: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
5497
|
+
[Blockchain.Unichain]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
5498
|
+
},
|
|
5499
|
+
};
|
|
5500
|
+
|
|
5501
|
+
/**
|
|
5502
|
+
* EURC (Euro Coin) token definition with addresses and metadata.
|
|
5503
|
+
*
|
|
5504
|
+
* @remarks
|
|
5505
|
+
* Built-in EURC definition for the TokenRegistry. Includes chain locators
|
|
5506
|
+
* for swap-supported chains.
|
|
5507
|
+
*/
|
|
5508
|
+
const EURC = {
|
|
5509
|
+
symbol: 'EURC',
|
|
5510
|
+
decimals: 6,
|
|
5511
|
+
locators: {
|
|
5512
|
+
[Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
5513
|
+
[Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
5514
|
+
[Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
5515
|
+
[Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
5516
|
+
[Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
5517
|
+
},
|
|
5518
|
+
};
|
|
5519
|
+
|
|
5520
|
+
/**
|
|
5521
|
+
* DAI (Maker DAO) stablecoin token definition with addresses and metadata.
|
|
5522
|
+
*
|
|
5523
|
+
* @remarks
|
|
5524
|
+
* Built-in DAI definition for the TokenRegistry. Includes chain locators
|
|
5525
|
+
* for swap-supported chains.
|
|
5526
|
+
*/
|
|
5527
|
+
const DAI = {
|
|
5528
|
+
symbol: 'DAI',
|
|
5529
|
+
decimals: 18,
|
|
5530
|
+
chainDecimals: {
|
|
5531
|
+
[Blockchain.Solana]: 8,
|
|
5532
|
+
},
|
|
5533
|
+
locators: {
|
|
5534
|
+
[Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
5535
|
+
[Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
|
|
5536
|
+
[Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
|
|
5537
|
+
[Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
5538
|
+
[Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
|
|
5539
|
+
[Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
5540
|
+
[Blockchain.Polygon]: '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063',
|
|
5541
|
+
[Blockchain.Solana]: 'EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o',
|
|
5542
|
+
},
|
|
5543
|
+
};
|
|
5544
|
+
|
|
5545
|
+
/**
|
|
5546
|
+
* USDe (Ethena) synthetic dollar token definition with addresses and metadata.
|
|
5547
|
+
*
|
|
5548
|
+
* @remarks
|
|
5549
|
+
* Built-in USDE definition for the TokenRegistry. Includes chain locators
|
|
5550
|
+
* for swap-supported chains.
|
|
5551
|
+
*/
|
|
5552
|
+
const USDE = {
|
|
5553
|
+
symbol: 'USDe',
|
|
5554
|
+
decimals: 18,
|
|
5555
|
+
chainDecimals: {
|
|
5556
|
+
[Blockchain.Solana]: 9,
|
|
5557
|
+
},
|
|
5558
|
+
locators: {
|
|
5559
|
+
[Blockchain.Arbitrum]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5560
|
+
[Blockchain.Base]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5561
|
+
[Blockchain.Ethereum]: '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3',
|
|
5562
|
+
[Blockchain.Linea]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5563
|
+
[Blockchain.Optimism]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5564
|
+
[Blockchain.Solana]: 'DEkqHyPN7GMRJ5cArtQFAWefqbZb33Hyf6s5iCwjEonT',
|
|
5565
|
+
},
|
|
5566
|
+
};
|
|
5567
|
+
|
|
5568
|
+
/**
|
|
5569
|
+
* PYUSD (PayPal USD) stablecoin token definition with addresses and metadata.
|
|
5570
|
+
*
|
|
5571
|
+
* @remarks
|
|
5572
|
+
* Built-in PYUSD definition for the TokenRegistry. Includes chain locators
|
|
5573
|
+
* for swap-supported chains.
|
|
5574
|
+
*/
|
|
5575
|
+
const PYUSD = {
|
|
5576
|
+
symbol: 'PYUSD',
|
|
5577
|
+
decimals: 6,
|
|
5578
|
+
locators: {
|
|
5579
|
+
[Blockchain.Arbitrum]: '0x46850aD61C2B7d64d08c9C754F45254596696984',
|
|
5580
|
+
[Blockchain.Ethereum]: '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8',
|
|
5581
|
+
[Blockchain.Solana]: '2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo',
|
|
5582
|
+
},
|
|
5583
|
+
};
|
|
5584
|
+
|
|
5585
|
+
/**
|
|
5586
|
+
* WETH (Wrapped Ether) token definition with addresses and metadata.
|
|
5587
|
+
*
|
|
5588
|
+
* @remarks
|
|
5589
|
+
* Built-in WETH definition for the TokenRegistry. Includes chain locators
|
|
5590
|
+
* for swap-supported chains where WETH is available.
|
|
5591
|
+
*/
|
|
5592
|
+
const WETH = {
|
|
5593
|
+
symbol: 'WETH',
|
|
5594
|
+
decimals: 18,
|
|
5595
|
+
chainDecimals: {
|
|
5596
|
+
[Blockchain.Solana]: 9,
|
|
5597
|
+
},
|
|
5598
|
+
locators: {
|
|
5599
|
+
[Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
|
|
5600
|
+
[Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
|
|
5601
|
+
[Blockchain.Base]: '0x4200000000000000000000000000000000000006',
|
|
5602
|
+
[Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
5603
|
+
[Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
|
|
5604
|
+
[Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
|
|
5605
|
+
[Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs',
|
|
5606
|
+
},
|
|
5607
|
+
};
|
|
5608
|
+
|
|
5609
|
+
/**
|
|
5610
|
+
* WBTC (Wrapped Bitcoin) token definition with addresses and metadata.
|
|
5611
|
+
*
|
|
5612
|
+
* @remarks
|
|
5613
|
+
* Built-in WBTC definition for the TokenRegistry. Includes chain locators
|
|
5614
|
+
* for swap-supported chains where WBTC is available.
|
|
5615
|
+
*/
|
|
5616
|
+
const WBTC = {
|
|
5617
|
+
symbol: 'WBTC',
|
|
5618
|
+
decimals: 8,
|
|
5619
|
+
locators: {
|
|
5620
|
+
[Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
|
|
5621
|
+
[Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
|
|
5622
|
+
[Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218',
|
|
5623
|
+
},
|
|
5624
|
+
};
|
|
5625
|
+
|
|
5626
|
+
/**
|
|
5627
|
+
* WSOL (Wrapped SOL) token definition with addresses and metadata.
|
|
5628
|
+
*
|
|
5629
|
+
* @remarks
|
|
5630
|
+
* Built-in WSOL definition for the TokenRegistry. Includes chain locators
|
|
5631
|
+
* for swap-supported chains where WSOL is available.
|
|
5632
|
+
*/
|
|
5633
|
+
const WSOL = {
|
|
5634
|
+
symbol: 'WSOL',
|
|
5635
|
+
decimals: 9,
|
|
5636
|
+
locators: {
|
|
5637
|
+
[Blockchain.Solana]: 'So11111111111111111111111111111111111111112',
|
|
5638
|
+
},
|
|
5639
|
+
};
|
|
5640
|
+
|
|
5641
|
+
/**
|
|
5642
|
+
* WAVAX (Wrapped AVAX) token definition with addresses and metadata.
|
|
5643
|
+
*
|
|
5644
|
+
* @remarks
|
|
5645
|
+
* Built-in WAVAX definition for the TokenRegistry. Includes chain locators
|
|
5646
|
+
* for swap-supported chains where WAVAX is available.
|
|
5647
|
+
*/
|
|
5648
|
+
const WAVAX = {
|
|
5649
|
+
symbol: 'WAVAX',
|
|
5650
|
+
decimals: 18,
|
|
5651
|
+
locators: {
|
|
5652
|
+
[Blockchain.Avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7',
|
|
5653
|
+
},
|
|
5654
|
+
};
|
|
5655
|
+
|
|
5656
|
+
/**
|
|
5657
|
+
* WPOL (Wrapped POL) token definition with addresses and metadata.
|
|
5658
|
+
*
|
|
5659
|
+
* @remarks
|
|
5660
|
+
* Built-in WPOL definition for the TokenRegistry. Includes chain locators
|
|
5661
|
+
* for swap-supported chains where WPOL is available.
|
|
5662
|
+
*/
|
|
5663
|
+
const WPOL = {
|
|
5664
|
+
symbol: 'WPOL',
|
|
5665
|
+
decimals: 18,
|
|
5666
|
+
locators: {
|
|
5667
|
+
[Blockchain.Polygon]: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
|
|
5668
|
+
},
|
|
5669
|
+
};
|
|
5670
|
+
|
|
5671
|
+
/**
|
|
5672
|
+
* ETH (native Ether alias) token definition with metadata.
|
|
5673
|
+
*
|
|
5674
|
+
* @remarks
|
|
5675
|
+
* Built-in ETH definition for the TokenRegistry. Used as a symbol alias
|
|
5676
|
+
* for native ETH (e.g. in swap flows). Chain locators are TBD and will
|
|
5677
|
+
* be added when addresses are available. Use raw selector with
|
|
5678
|
+
* locator + decimals where native gas token is represented as a contract.
|
|
5679
|
+
*/
|
|
5680
|
+
const ETH = {
|
|
5681
|
+
symbol: 'ETH',
|
|
5682
|
+
decimals: 18,
|
|
5683
|
+
locators: {},
|
|
5684
|
+
};
|
|
5685
|
+
|
|
5686
|
+
/**
|
|
5687
|
+
* POL (Polygon native token) token definition with addresses and metadata.
|
|
5688
|
+
*
|
|
5689
|
+
* @remarks
|
|
5690
|
+
* Built-in POL definition for the TokenRegistry. Includes chain locators
|
|
5691
|
+
* where POL is available as a bridged/wrapped asset.
|
|
5692
|
+
*/
|
|
5693
|
+
const POL = {
|
|
5694
|
+
symbol: 'POL',
|
|
5695
|
+
decimals: 18,
|
|
5696
|
+
locators: {
|
|
5697
|
+
[Blockchain.Ethereum]: '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6',
|
|
5698
|
+
},
|
|
5699
|
+
};
|
|
5700
|
+
|
|
5701
|
+
/**
|
|
5702
|
+
* PLUME (Plume network token) token definition with addresses and metadata.
|
|
5703
|
+
*
|
|
5704
|
+
* @remarks
|
|
5705
|
+
* Built-in PLUME definition for the TokenRegistry. Includes chain locators
|
|
5706
|
+
* where PLUME is available.
|
|
5707
|
+
*/
|
|
5708
|
+
const PLUME = {
|
|
5709
|
+
symbol: 'PLUME',
|
|
5710
|
+
decimals: 18,
|
|
5711
|
+
locators: {
|
|
5712
|
+
[Blockchain.Ethereum]: '0x4C1746A800D224393fE2470C70A35717eD4eA5F1',
|
|
5713
|
+
},
|
|
5714
|
+
};
|
|
5715
|
+
|
|
5716
|
+
/**
|
|
5717
|
+
* MON token definition with Solana mint metadata.
|
|
5718
|
+
*
|
|
5719
|
+
* @remarks
|
|
5720
|
+
* Built-in MON definition for the TokenRegistry. Includes chain locators
|
|
5721
|
+
* for swap-supported chains.
|
|
5722
|
+
*/
|
|
5723
|
+
const MON = {
|
|
5724
|
+
symbol: 'MON',
|
|
5725
|
+
decimals: 18,
|
|
5726
|
+
chainDecimals: {
|
|
5727
|
+
[Blockchain.Solana]: 8,
|
|
5728
|
+
},
|
|
5729
|
+
locators: {
|
|
5730
|
+
[Blockchain.Solana]: 'CrAr4RRJMBVwRsZtT62pEhfA9H5utymC2mVx8e7FreP2',
|
|
5731
|
+
},
|
|
5732
|
+
};
|
|
5733
|
+
|
|
5734
|
+
// Re-export for consumers
|
|
5735
|
+
/**
|
|
5736
|
+
* All default token definitions.
|
|
5737
|
+
*
|
|
5738
|
+
* @remarks
|
|
5739
|
+
* These tokens are automatically included in the TokenRegistry when created
|
|
5740
|
+
* without explicit defaults. Extensions can override these definitions.
|
|
5741
|
+
* Includes USDC, USDT, EURC, DAI, USDE, PYUSD, WETH, WBTC, WSOL, WAVAX,
|
|
5742
|
+
* WPOL, ETH, POL, PLUME, and MON.
|
|
5743
|
+
*
|
|
5744
|
+
* @example
|
|
5745
|
+
* ```typescript
|
|
5746
|
+
* import { createTokenRegistry } from '@core/tokens'
|
|
5747
|
+
*
|
|
5748
|
+
* // Registry uses these by default
|
|
5749
|
+
* const registry = createTokenRegistry()
|
|
5750
|
+
*
|
|
5751
|
+
* // Add custom tokens (built-ins are still included)
|
|
5752
|
+
* const customRegistry = createTokenRegistry({
|
|
5753
|
+
* tokens: [myCustomToken],
|
|
5754
|
+
* })
|
|
5755
|
+
* ```
|
|
5756
|
+
*/
|
|
5757
|
+
const DEFAULT_TOKENS = [
|
|
5758
|
+
USDC,
|
|
5759
|
+
USDT,
|
|
5760
|
+
EURC,
|
|
5761
|
+
DAI,
|
|
5762
|
+
USDE,
|
|
5763
|
+
PYUSD,
|
|
5764
|
+
WETH,
|
|
5765
|
+
WBTC,
|
|
5766
|
+
WSOL,
|
|
5767
|
+
WAVAX,
|
|
5768
|
+
WPOL,
|
|
5769
|
+
ETH,
|
|
5770
|
+
POL,
|
|
5771
|
+
PLUME,
|
|
5772
|
+
MON,
|
|
5773
|
+
];
|
|
5774
|
+
/**
|
|
5775
|
+
* Uppercased token symbols approved for swap fee collection.
|
|
5776
|
+
*
|
|
5777
|
+
* @remarks
|
|
5778
|
+
* Derived from {@link DEFAULT_TOKENS} so all consumers share a single
|
|
5779
|
+
* allowlist source and stay in sync when defaults change.
|
|
5780
|
+
*/
|
|
5781
|
+
new Set(DEFAULT_TOKENS.map((t) => t.symbol.toUpperCase()));
|
|
5782
|
+
|
|
5783
|
+
/**
|
|
5784
|
+
* Resolve the effective decimals for a token on a specific chain.
|
|
5785
|
+
*
|
|
5786
|
+
* Returns the chain-specific override from `chainDecimals` when available,
|
|
5787
|
+
* otherwise falls back to the token's default `decimals`.
|
|
5788
|
+
*
|
|
5789
|
+
* @param token - The token definition to resolve decimals for.
|
|
5790
|
+
* @param chain - Optional chain identifier. When omitted, the default decimals are returned.
|
|
5791
|
+
* @returns The number of decimal places for the token on the given chain.
|
|
5792
|
+
*
|
|
5793
|
+
* @example
|
|
5794
|
+
* ```typescript
|
|
5795
|
+
* import { resolveTokenDecimals } from '\@core/tokens'
|
|
5796
|
+
*
|
|
5797
|
+
* // DAI: 18 decimals on EVM, 8 on Solana
|
|
5798
|
+
* resolveTokenDecimals(DAI) // 18 (default)
|
|
5799
|
+
* resolveTokenDecimals(DAI, 'Solana') // 8 (chain override)
|
|
5800
|
+
* resolveTokenDecimals(DAI, 'Ethereum') // 18 (no override, falls back)
|
|
5801
|
+
* ```
|
|
5802
|
+
*/
|
|
5803
|
+
function resolveTokenDecimals(token, chain) {
|
|
5804
|
+
if (chain === undefined) {
|
|
5805
|
+
return token.decimals;
|
|
5806
|
+
}
|
|
5807
|
+
return token.chainDecimals?.[chain] ?? token.decimals;
|
|
5808
|
+
}
|
|
5809
|
+
|
|
5810
|
+
/**
|
|
5811
|
+
* Check if a selector is a raw token selector (object form).
|
|
5812
|
+
*
|
|
5813
|
+
* @param selector - The token selector to check.
|
|
5814
|
+
* @returns True if the selector is a raw token selector.
|
|
5815
|
+
*/
|
|
5816
|
+
function isRawSelector(selector) {
|
|
5817
|
+
return typeof selector === 'object' && 'locator' in selector;
|
|
5818
|
+
}
|
|
5819
|
+
/**
|
|
5820
|
+
* Normalize a symbol to uppercase for case-insensitive lookup.
|
|
5821
|
+
*
|
|
5822
|
+
* @param symbol - The symbol to normalize.
|
|
5823
|
+
* @returns The normalized (uppercase) symbol.
|
|
5824
|
+
*/
|
|
5825
|
+
function normalizeSymbol(symbol) {
|
|
5826
|
+
return symbol.toUpperCase();
|
|
5827
|
+
}
|
|
5828
|
+
/**
|
|
5829
|
+
* Normalize a locator for stable chain-aware lookup.
|
|
5830
|
+
*
|
|
5831
|
+
* @remarks
|
|
5832
|
+
* EVM-style addresses (`0x...`) are normalized to lowercase for
|
|
5833
|
+
* case-insensitive matching. Non-EVM locators keep original casing.
|
|
5834
|
+
*/
|
|
5835
|
+
function normalizeLocator(locator) {
|
|
5836
|
+
if (locator.startsWith('0x') || locator.startsWith('0X')) {
|
|
5837
|
+
return locator.toLowerCase();
|
|
5838
|
+
}
|
|
5839
|
+
return locator;
|
|
5840
|
+
}
|
|
5841
|
+
/**
|
|
5842
|
+
* Build a stable map key for a chain + locator pair.
|
|
5843
|
+
*/
|
|
5844
|
+
function buildAddressKey(chainId, locator) {
|
|
5845
|
+
return `${chainId}::${normalizeLocator(locator)}`;
|
|
5846
|
+
}
|
|
5847
|
+
/**
|
|
5848
|
+
* Create a token registry with built-in tokens and optional extensions.
|
|
5849
|
+
*
|
|
5850
|
+
* @remarks
|
|
5851
|
+
* The registry always includes built-in tokens (DEFAULT_TOKENS) like USDC.
|
|
5852
|
+
* Custom tokens are merged on top - use this to add new tokens or override
|
|
5853
|
+
* built-in definitions.
|
|
5854
|
+
*
|
|
5855
|
+
* @param options - Configuration options for the registry.
|
|
5856
|
+
* @returns A token registry instance.
|
|
5857
|
+
*
|
|
5858
|
+
* @example
|
|
5859
|
+
* ```typescript
|
|
5860
|
+
* import { createTokenRegistry } from '@core/tokens'
|
|
5861
|
+
*
|
|
5862
|
+
* // Create registry with built-in tokens (USDC, etc.)
|
|
5863
|
+
* const registry = createTokenRegistry()
|
|
5864
|
+
*
|
|
5865
|
+
* // Resolve USDC on Ethereum
|
|
5866
|
+
* const usdc = registry.resolve('USDC', 'Ethereum')
|
|
5867
|
+
* console.log(usdc.locator) // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
5868
|
+
* console.log(usdc.decimals) // 6
|
|
5869
|
+
* ```
|
|
5870
|
+
*
|
|
5871
|
+
* @example
|
|
5872
|
+
* ```typescript
|
|
5873
|
+
* // Add custom tokens (built-ins are still included)
|
|
5874
|
+
* const myToken: TokenDefinition = {
|
|
5875
|
+
* symbol: 'MY',
|
|
5876
|
+
* decimals: 18,
|
|
5877
|
+
* locators: { Ethereum: '0x...' },
|
|
5878
|
+
* }
|
|
5879
|
+
*
|
|
5880
|
+
* const registry = createTokenRegistry({ tokens: [myToken] })
|
|
5881
|
+
* registry.resolve('USDC', 'Ethereum') // Still works!
|
|
5882
|
+
* registry.resolve('MY', 'Ethereum') // Also works
|
|
5883
|
+
* ```
|
|
5884
|
+
*
|
|
5885
|
+
* @example
|
|
5886
|
+
* ```typescript
|
|
5887
|
+
* // Override a built-in token
|
|
5888
|
+
* const customUsdc: TokenDefinition = {
|
|
5889
|
+
* symbol: 'USDC',
|
|
5890
|
+
* decimals: 6,
|
|
5891
|
+
* locators: { MyChain: '0xCustomAddress' },
|
|
5892
|
+
* }
|
|
5893
|
+
*
|
|
5894
|
+
* const registry = createTokenRegistry({ tokens: [customUsdc] })
|
|
5895
|
+
* // Now USDC resolves to customUsdc definition
|
|
5896
|
+
* ```
|
|
5897
|
+
*
|
|
5898
|
+
* @example
|
|
5899
|
+
* ```typescript
|
|
5900
|
+
* // Resolve arbitrary tokens by raw locator
|
|
5901
|
+
* const registry = createTokenRegistry()
|
|
5902
|
+
* const token = registry.resolve(
|
|
5903
|
+
* { locator: '0x1234...', decimals: 18 },
|
|
5904
|
+
* 'Ethereum'
|
|
5905
|
+
* )
|
|
5906
|
+
* ```
|
|
5907
|
+
*/
|
|
5908
|
+
function createTokenRegistry(options = {}) {
|
|
5909
|
+
const { tokens = [], requireDecimals = false } = options;
|
|
5910
|
+
// Build the token map: always start with DEFAULT_TOKENS, then add custom tokens
|
|
5911
|
+
const tokenMap = new Map();
|
|
5912
|
+
// Add built-in tokens first
|
|
5913
|
+
for (const def of DEFAULT_TOKENS) {
|
|
5914
|
+
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
5915
|
+
}
|
|
5916
|
+
// Custom tokens override built-ins
|
|
5917
|
+
for (const def of tokens) {
|
|
5918
|
+
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
5919
|
+
}
|
|
5920
|
+
// Build an address index from the resolved token map so overrides win.
|
|
5921
|
+
const addressMap = new Map();
|
|
5922
|
+
for (const token of tokenMap.values()) {
|
|
5923
|
+
for (const [chainId, locator] of Object.entries(token.locators)) {
|
|
5924
|
+
if (typeof locator !== 'string' || locator.trim() === '') {
|
|
5925
|
+
continue;
|
|
5926
|
+
}
|
|
5927
|
+
addressMap.set(buildAddressKey(chainId, locator), token);
|
|
5928
|
+
}
|
|
5929
|
+
}
|
|
5930
|
+
/**
|
|
5931
|
+
* Resolve a symbol selector to token information.
|
|
5932
|
+
*/
|
|
5933
|
+
function resolveSymbol(symbol, chainId) {
|
|
5934
|
+
const normalizedSymbol = normalizeSymbol(symbol);
|
|
5935
|
+
const definition = tokenMap.get(normalizedSymbol);
|
|
5936
|
+
if (definition === undefined) {
|
|
5937
|
+
throw createTokenResolutionError(`Unknown token symbol: ${symbol}. Register it via createTokenRegistry({ tokens: [...] }) or use a raw selector.`, symbol, chainId);
|
|
5938
|
+
}
|
|
5939
|
+
const locator = definition.locators[chainId];
|
|
5940
|
+
if (locator === undefined || locator.trim() === '') {
|
|
5941
|
+
throw createTokenResolutionError(`Token ${symbol} has no locator for chain ${chainId}`, symbol, chainId);
|
|
5942
|
+
}
|
|
5943
|
+
const decimals = resolveTokenDecimals(definition, chainId);
|
|
5944
|
+
return {
|
|
5945
|
+
symbol: definition.symbol,
|
|
5946
|
+
decimals,
|
|
5947
|
+
locator: normalizeLocator(locator),
|
|
5948
|
+
};
|
|
5949
|
+
}
|
|
5950
|
+
/**
|
|
5951
|
+
* Resolve a raw selector to token information.
|
|
5952
|
+
*/
|
|
5953
|
+
function resolveRaw(selector, chainId) {
|
|
5954
|
+
const { locator, decimals } = selector;
|
|
5955
|
+
// Validate locator
|
|
5956
|
+
if (!locator || typeof locator !== 'string') {
|
|
5957
|
+
throw createTokenResolutionError('Raw selector must have a valid locator string', selector, chainId);
|
|
5958
|
+
}
|
|
5959
|
+
// Decimals are always required for raw selectors
|
|
5960
|
+
if (decimals === undefined) {
|
|
5961
|
+
const message = requireDecimals
|
|
5962
|
+
? 'Decimals required for raw token selector (requireDecimals: true)'
|
|
5963
|
+
: 'Decimals required for raw token selector. Provide { locator, decimals }.';
|
|
5964
|
+
throw createTokenResolutionError(message, selector, chainId);
|
|
5965
|
+
}
|
|
5966
|
+
// Validate decimals
|
|
5967
|
+
if (typeof decimals !== 'number' ||
|
|
5968
|
+
decimals < 0 ||
|
|
5969
|
+
!Number.isInteger(decimals)) {
|
|
5970
|
+
throw createTokenResolutionError(`Invalid decimals: ${String(decimals)}. Must be a non-negative integer.`, selector, chainId);
|
|
5971
|
+
}
|
|
5972
|
+
return {
|
|
5973
|
+
decimals,
|
|
5974
|
+
locator: normalizeLocator(locator),
|
|
5975
|
+
};
|
|
5976
|
+
}
|
|
5977
|
+
return {
|
|
5978
|
+
resolve(selector, chainId) {
|
|
5979
|
+
// Runtime validation of inputs - these checks are for JS consumers
|
|
5980
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
5981
|
+
if (selector === null || selector === undefined) {
|
|
5982
|
+
throw createTokenResolutionError('Token selector cannot be null or undefined', selector, chainId);
|
|
5983
|
+
}
|
|
5984
|
+
if (chainId === '' || typeof chainId !== 'string') {
|
|
5985
|
+
throw createTokenResolutionError('Chain ID is required for token resolution', selector, chainId);
|
|
5986
|
+
}
|
|
5987
|
+
// Dispatch based on selector type
|
|
5988
|
+
if (isRawSelector(selector)) {
|
|
5989
|
+
return resolveRaw(selector, chainId);
|
|
5990
|
+
}
|
|
5991
|
+
if (typeof selector === 'string') {
|
|
5992
|
+
return resolveSymbol(selector, chainId);
|
|
5993
|
+
}
|
|
5994
|
+
throw createTokenResolutionError(`Invalid selector type: ${typeof selector}. Expected string or object with locator.`, selector, chainId);
|
|
5995
|
+
},
|
|
5996
|
+
resolveByAddress(address, chainId) {
|
|
5997
|
+
if (!address || typeof address !== 'string') {
|
|
5998
|
+
throw createTokenResolutionError('Token address is required for address resolution', { locator: address }, chainId);
|
|
5999
|
+
}
|
|
6000
|
+
if (chainId === '' || typeof chainId !== 'string') {
|
|
6001
|
+
throw createTokenResolutionError('Chain ID is required for token resolution', { locator: address }, chainId);
|
|
6002
|
+
}
|
|
6003
|
+
const definition = addressMap.get(buildAddressKey(chainId, address));
|
|
6004
|
+
if (definition === undefined) {
|
|
6005
|
+
throw createTokenResolutionError(`Unknown token address: ${address} for chain ${chainId}`, { locator: address }, chainId);
|
|
6006
|
+
}
|
|
6007
|
+
const locator = definition.locators[chainId];
|
|
6008
|
+
if (locator === undefined || locator.trim() === '') {
|
|
6009
|
+
throw createTokenResolutionError(`Token ${definition.symbol} has no locator for chain ${chainId}`, definition.symbol, chainId);
|
|
6010
|
+
}
|
|
6011
|
+
const decimals = resolveTokenDecimals(definition, chainId);
|
|
6012
|
+
return {
|
|
6013
|
+
symbol: definition.symbol,
|
|
6014
|
+
decimals,
|
|
6015
|
+
locator: normalizeLocator(locator),
|
|
6016
|
+
};
|
|
6017
|
+
},
|
|
6018
|
+
get(symbol) {
|
|
6019
|
+
if (!symbol || typeof symbol !== 'string') {
|
|
6020
|
+
return undefined;
|
|
6021
|
+
}
|
|
6022
|
+
return tokenMap.get(normalizeSymbol(symbol));
|
|
6023
|
+
},
|
|
6024
|
+
has(symbol) {
|
|
6025
|
+
if (!symbol || typeof symbol !== 'string') {
|
|
6026
|
+
return false;
|
|
6027
|
+
}
|
|
6028
|
+
return tokenMap.has(normalizeSymbol(symbol));
|
|
6029
|
+
},
|
|
6030
|
+
symbols() {
|
|
6031
|
+
return Array.from(tokenMap.values()).map((def) => def.symbol);
|
|
6032
|
+
},
|
|
6033
|
+
entries() {
|
|
6034
|
+
return Array.from(tokenMap.values());
|
|
6035
|
+
},
|
|
6036
|
+
};
|
|
6037
|
+
}
|
|
6038
|
+
|
|
6039
|
+
/**
|
|
6040
|
+
* Define a schema for token registry interfaces.
|
|
6041
|
+
*
|
|
6042
|
+
* @remarks
|
|
6043
|
+
* Validate that a registry exposes the `resolve()` API used by adapters.
|
|
6044
|
+
*
|
|
6045
|
+
* @example
|
|
6046
|
+
* ```typescript
|
|
6047
|
+
* import { tokenRegistrySchema } from '@core/tokens'
|
|
6048
|
+
*
|
|
6049
|
+
* const registry = {
|
|
6050
|
+
* resolve: () => ({ locator: '0x0', decimals: 6 }),
|
|
6051
|
+
* }
|
|
6052
|
+
*
|
|
6053
|
+
* tokenRegistrySchema.parse(registry)
|
|
6054
|
+
* ```
|
|
6055
|
+
*/
|
|
6056
|
+
z.custom((value) => {
|
|
6057
|
+
if (value === null || typeof value !== 'object') {
|
|
6058
|
+
return false;
|
|
6059
|
+
}
|
|
6060
|
+
const record = value;
|
|
6061
|
+
return (typeof record['resolve'] === 'function' &&
|
|
6062
|
+
typeof record['get'] === 'function' &&
|
|
6063
|
+
typeof record['has'] === 'function' &&
|
|
6064
|
+
typeof record['symbols'] === 'function' &&
|
|
6065
|
+
typeof record['entries'] === 'function');
|
|
6066
|
+
}, {
|
|
6067
|
+
message: 'Invalid token registry',
|
|
6068
|
+
});
|
|
6069
|
+
|
|
6070
|
+
/**
|
|
6071
|
+
* Build a complete explorer URL from a chain definition and transaction hash.
|
|
6072
|
+
*
|
|
6073
|
+
* This function takes a chain definition containing an explorer URL template
|
|
6074
|
+
* and replaces the `{hash}` placeholder with the provided transaction hash
|
|
6075
|
+
* to create a complete, valid explorer URL.
|
|
6076
|
+
*
|
|
6077
|
+
* @param chainDef - The chain definition containing the explorer URL template.
|
|
6078
|
+
* @param txHash - The transaction hash to insert into the URL template.
|
|
6079
|
+
* @returns A complete explorer URL with the transaction hash inserted.
|
|
6080
|
+
* @throws Error if the chain definition is null/undefined.
|
|
6081
|
+
* @throws Error if the transaction hash is null/undefined/empty.
|
|
6082
|
+
* @throws Error if the explorer URL template is missing or empty.
|
|
6083
|
+
* @throws Error if the explorer URL template doesn't contain the {hash} placeholder.
|
|
6084
|
+
* @throws Error if the resulting URL is invalid.
|
|
6085
|
+
*
|
|
6086
|
+
* @example
|
|
6087
|
+
* ```typescript
|
|
6088
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6089
|
+
* import { Ethereum } from '@core/chains'
|
|
6090
|
+
*
|
|
6091
|
+
* // Build URL for Ethereum transaction
|
|
6092
|
+
* const url = buildExplorerUrl(Ethereum, '0x1234567890abcdef...')
|
|
6093
|
+
* console.log(url) // 'https://etherscan.io/tx/0x1234567890abcdef...'
|
|
6094
|
+
* ```
|
|
6095
|
+
*
|
|
6096
|
+
* @example
|
|
6097
|
+
* ```typescript
|
|
6098
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6099
|
+
* import { Solana } from '@core/chains'
|
|
6100
|
+
*
|
|
6101
|
+
* // Build URL for Solana transaction
|
|
6102
|
+
* const url = buildExplorerUrl(Solana, 'abc123def456...')
|
|
6103
|
+
* console.log(url) // 'https://solscan.io/tx/abc123def456...'
|
|
6104
|
+
* ```
|
|
6105
|
+
*
|
|
6106
|
+
* @example
|
|
6107
|
+
* ```typescript
|
|
6108
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6109
|
+
* import { Aptos } from '@core/chains'
|
|
6110
|
+
*
|
|
6111
|
+
* // Build URL for Aptos transaction with query parameters
|
|
6112
|
+
* const url = buildExplorerUrl(Aptos, '0xabc123...')
|
|
6113
|
+
* console.log(url) // 'https://explorer.aptoslabs.com/txn/0xabc123...?network=mainnet'
|
|
6114
|
+
* ```
|
|
6115
|
+
*/
|
|
6116
|
+
function buildExplorerUrl(chainDef, txHash) {
|
|
6117
|
+
// Validate input parameters using our standard validation pattern
|
|
6118
|
+
validateOrThrow({ chainDef, txHash }, buildExplorerUrlParamsSchema, 'Invalid buildExplorerUrl parameters');
|
|
6119
|
+
// Parse and transform input parameters (e.g., trim whitespace from txHash)
|
|
6120
|
+
const { chainDef: validChainDef, txHash: validTxHash } = buildExplorerUrlParamsSchema.parse({ chainDef, txHash });
|
|
6121
|
+
// Replace all occurrences of the placeholder with the transaction hash
|
|
6122
|
+
const explorerUrl = validChainDef.explorerUrl.replace(/{hash}/g, validTxHash);
|
|
6123
|
+
// Validate the resulting URL
|
|
6124
|
+
validate(explorerUrl, explorerUrlSchema, 'explorer URL');
|
|
6125
|
+
return explorerUrl;
|
|
6126
|
+
}
|
|
6127
|
+
|
|
6128
|
+
/**
|
|
6129
|
+
* CCTP forwarding magic bytes prefix.
|
|
6130
|
+
*
|
|
6131
|
+
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
6132
|
+
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
6133
|
+
*/
|
|
6134
|
+
const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
6135
|
+
/**
|
|
6136
|
+
* CCTP forwarding version number.
|
|
6137
|
+
*
|
|
6138
|
+
* Version 0 is used for basic forwarding requests.
|
|
6139
|
+
*/
|
|
6140
|
+
const CCTP_FORWARD_VERSION = 0;
|
|
6141
|
+
/**
|
|
6142
|
+
* Length of Circle-reserved payload for basic forwarding (0 bytes).
|
|
6143
|
+
*
|
|
6144
|
+
* Set to 0 when no additional Circle-reserved data is needed.
|
|
6145
|
+
*/
|
|
6146
|
+
const CCTP_FORWARD_PAYLOAD_LENGTH = 0;
|
|
6147
|
+
/**
|
|
6148
|
+
* Build the hookData bytes for CCTP forwarding.
|
|
6149
|
+
*
|
|
6150
|
+
* Constructs a 32-byte hookData payload that signals to Circle's Orbit relayer
|
|
6151
|
+
* that the user wants automated attestation fetching and destination mint execution.
|
|
6152
|
+
*
|
|
6153
|
+
* The hookData format is:
|
|
6154
|
+
* - Bytes 0-23: ASCII "cctp-forward" right-padded to 24 bytes with zeros
|
|
6155
|
+
* - Bytes 24-27: uint32 version (big-endian) - currently 0
|
|
6156
|
+
* - Bytes 28-31: uint32 length (big-endian) - 0 for basic forwarding
|
|
6157
|
+
*
|
|
6158
|
+
* @returns A 0x-prefixed hex string representing the 32-byte hookData
|
|
6159
|
+
*
|
|
6160
|
+
* @example
|
|
6161
|
+
* ```typescript
|
|
6162
|
+
* import { buildForwardingHookData } from '@core/utils'
|
|
6163
|
+
*
|
|
6164
|
+
* const hookData = buildForwardingHookData()
|
|
6165
|
+
* // Returns: '0x636374702d666f72776172640000000000000000000000000000000000000000'
|
|
6166
|
+
*
|
|
6167
|
+
* // Use with depositForBurnWithHook action
|
|
6168
|
+
* await adapter.action('cctp.v2.depositForBurnWithHook', {
|
|
6169
|
+
* amount: BigInt('1000000'),
|
|
6170
|
+
* mintRecipient: '0x...',
|
|
6171
|
+
* maxFee: BigInt('50000'),
|
|
6172
|
+
* minFinalityThreshold: 1000,
|
|
6173
|
+
* fromChain: ethereum,
|
|
6174
|
+
* toChain: base,
|
|
6175
|
+
* hookData
|
|
6176
|
+
* })
|
|
6177
|
+
* ```
|
|
6178
|
+
*/
|
|
6179
|
+
// Cached result for memoization (computed once on first call)
|
|
6180
|
+
let cachedHookDataHex = null;
|
|
5042
6181
|
function buildForwardingHookData() {
|
|
5043
6182
|
// Return cached result if already computed
|
|
5044
6183
|
if (cachedHookDataHex !== null) {
|
|
@@ -5542,6 +6681,21 @@ async function fetchUsdcFastBurnFee(sourceDomain, destinationDomain, isTestnet)
|
|
|
5542
6681
|
return minimumFee;
|
|
5543
6682
|
}
|
|
5544
6683
|
|
|
6684
|
+
/**
|
|
6685
|
+
* Well-known SPL Token program ID.
|
|
6686
|
+
* Duplicated here as a raw string to avoid a static import of \@core/adapter-solana
|
|
6687
|
+
* (which would transitively pull \@solana/web3.js into the top-level bundle and
|
|
6688
|
+
* break lazy-loading for EVM-only consumers).
|
|
6689
|
+
*
|
|
6690
|
+
* This MUST match TOKEN_PROGRAM_ID in @core/adapter-solana/src/utils/splTokenUtils.
|
|
6691
|
+
*/
|
|
6692
|
+
const TOKEN_PROGRAM_ID_BASE58 = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; // NOSONAR — public Solana program address
|
|
6693
|
+
/**
|
|
6694
|
+
* Well-known SPL Associated Token Account program ID (same rationale as above).
|
|
6695
|
+
*
|
|
6696
|
+
* This MUST match ASSOCIATED_TOKEN_PROGRAM_ID in @core/adapter-solana/src/utils/splTokenUtils.
|
|
6697
|
+
*/
|
|
6698
|
+
const ASSOCIATED_TOKEN_PROGRAM_ID_BASE58 = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'; // NOSONAR — public Solana program address
|
|
5545
6699
|
/**
|
|
5546
6700
|
* Get the token account address where USDC will be minted for the recipient.
|
|
5547
6701
|
*
|
|
@@ -5585,20 +6739,30 @@ mintAddress) => {
|
|
|
5585
6739
|
return rawAddress;
|
|
5586
6740
|
}
|
|
5587
6741
|
else {
|
|
5588
|
-
// Solana: derive the associated token account
|
|
5589
|
-
//
|
|
6742
|
+
// Solana: derive the associated token account.
|
|
6743
|
+
// Both @solana/web3.js and the program-ID constants are resolved lazily
|
|
6744
|
+
// so that EVM-only consumers never load Solana code.
|
|
6745
|
+
const { PublicKey } = await import('@solana/web3.js').catch(() => {
|
|
6746
|
+
throw new KitError({
|
|
6747
|
+
...InputError.VALIDATION_FAILED,
|
|
6748
|
+
recoverability: 'FATAL',
|
|
6749
|
+
message: 'Failed to load @solana/web3.js. Please ensure it is installed: npm install @solana/web3.js',
|
|
6750
|
+
});
|
|
6751
|
+
});
|
|
5590
6752
|
try {
|
|
5591
|
-
const [{ PublicKey }, { getAssociatedTokenAddressSync }] = await Promise.all([
|
|
5592
|
-
import('@solana/web3.js'),
|
|
5593
|
-
import('@solana/spl-token'),
|
|
5594
|
-
]);
|
|
5595
6753
|
const owner = new PublicKey(rawAddress);
|
|
5596
6754
|
const mintPub = new PublicKey(mintAddress);
|
|
5597
|
-
const
|
|
6755
|
+
const tokenProgramId = new PublicKey(TOKEN_PROGRAM_ID_BASE58);
|
|
6756
|
+
const ataProgramId = new PublicKey(ASSOCIATED_TOKEN_PROGRAM_ID_BASE58);
|
|
6757
|
+
const [ata] = PublicKey.findProgramAddressSync([owner.toBuffer(), tokenProgramId.toBuffer(), mintPub.toBuffer()], ataProgramId);
|
|
5598
6758
|
return ata.toBase58();
|
|
5599
6759
|
}
|
|
5600
|
-
catch {
|
|
5601
|
-
throw new
|
|
6760
|
+
catch (error) {
|
|
6761
|
+
throw new KitError({
|
|
6762
|
+
...InputError.INVALID_ADDRESS,
|
|
6763
|
+
recoverability: 'FATAL',
|
|
6764
|
+
message: `Failed to derive Solana Associated Token Account for recipient "${rawAddress}": ${error instanceof Error ? error.message : String(error)}`,
|
|
6765
|
+
});
|
|
5602
6766
|
}
|
|
5603
6767
|
}
|
|
5604
6768
|
};
|
|
@@ -7914,590 +9078,239 @@ function createLogger(options, stream) {
|
|
|
7914
9078
|
const finalOptions = redactConfig
|
|
7915
9079
|
? { ...pinoOptions, redact: redactConfig }
|
|
7916
9080
|
: pinoOptions;
|
|
7917
|
-
const pinoInstance = pino(finalOptions);
|
|
7918
|
-
return wrapPino(pinoInstance);
|
|
7919
|
-
}
|
|
7920
|
-
|
|
7921
|
-
/**
|
|
7922
|
-
* Factory for creating Runtime instances with defaults.
|
|
7923
|
-
*
|
|
7924
|
-
* @packageDocumentation
|
|
7925
|
-
*/
|
|
7926
|
-
// ============================================================================
|
|
7927
|
-
// Validation Schema
|
|
7928
|
-
// ============================================================================
|
|
7929
|
-
/**
|
|
7930
|
-
* Schema for validating {@link RuntimeOptions}.
|
|
7931
|
-
*
|
|
7932
|
-
* @remarks
|
|
7933
|
-
* Used internally by {@link createRuntime} to validate options from JS consumers.
|
|
7934
|
-
* Exported for advanced use cases where manual validation is needed.
|
|
7935
|
-
*/
|
|
7936
|
-
z
|
|
7937
|
-
.object({
|
|
7938
|
-
logger: loggerSchema.optional(),
|
|
7939
|
-
metrics: metricsSchema.optional(),
|
|
7940
|
-
})
|
|
7941
|
-
.passthrough();
|
|
7942
|
-
// ============================================================================
|
|
7943
|
-
// Factory
|
|
7944
|
-
// ============================================================================
|
|
7945
|
-
/**
|
|
7946
|
-
* Create a complete Runtime with sensible defaults.
|
|
7947
|
-
*
|
|
7948
|
-
* @param options - Optional configuration to override logger and metrics.
|
|
7949
|
-
* @returns A frozen, immutable Runtime with all services guaranteed present.
|
|
7950
|
-
* @throws KitError (INPUT_VALIDATION_FAILED) if options contain invalid services.
|
|
7951
|
-
*
|
|
7952
|
-
* @remarks
|
|
7953
|
-
* Creates a fully-configured runtime by merging provided options with defaults.
|
|
7954
|
-
* The returned runtime is frozen to enforce immutability.
|
|
7955
|
-
*
|
|
7956
|
-
* | Service | Default | Configurable |
|
|
7957
|
-
* |---------|---------|--------------|
|
|
7958
|
-
* | `logger` | pino logger (info level) | Yes |
|
|
7959
|
-
* | `metrics` | No-op metrics | Yes |
|
|
7960
|
-
* | `events` | Internal event bus | No |
|
|
7961
|
-
* | `clock` | `Date.now()` | No |
|
|
7962
|
-
*
|
|
7963
|
-
* **Why only logger and metrics?**
|
|
7964
|
-
*
|
|
7965
|
-
* - **Logger/Metrics**: Integration points with your infrastructure
|
|
7966
|
-
* - **Events**: Internal pub/sub mechanism - subscribe via `runtime.events.on()`
|
|
7967
|
-
* - **Clock**: Testing concern - use mock factories for tests
|
|
7968
|
-
*
|
|
7969
|
-
* @example
|
|
7970
|
-
* ```typescript
|
|
7971
|
-
* import { createRuntime, createLogger } from '@core/runtime'
|
|
7972
|
-
*
|
|
7973
|
-
* // Use all defaults
|
|
7974
|
-
* const runtime = createRuntime()
|
|
7975
|
-
*
|
|
7976
|
-
* // Custom logger
|
|
7977
|
-
* const runtime = createRuntime({
|
|
7978
|
-
* logger: createLogger({ level: 'debug' }),
|
|
7979
|
-
* })
|
|
7980
|
-
*
|
|
7981
|
-
* // Custom metrics (e.g., Prometheus)
|
|
7982
|
-
* const runtime = createRuntime({
|
|
7983
|
-
* metrics: myPrometheusMetrics,
|
|
7984
|
-
* })
|
|
7985
|
-
*
|
|
7986
|
-
* // Subscribe to events (don't replace the bus)
|
|
7987
|
-
* runtime.events.on('operation.*', (event) => {
|
|
7988
|
-
* console.log('Event:', event.name)
|
|
7989
|
-
* })
|
|
7990
|
-
* ```
|
|
7991
|
-
*/
|
|
7992
|
-
function createRuntime(options) {
|
|
7993
|
-
// Resolve logger first (events may need it)
|
|
7994
|
-
const logger = createLogger();
|
|
7995
|
-
// Internal services - not configurable
|
|
7996
|
-
const events = createEventBus({ logger });
|
|
7997
|
-
const clock = defaultClock;
|
|
7998
|
-
// Resolve metrics
|
|
7999
|
-
const metrics = noopMetrics;
|
|
8000
|
-
return Object.freeze({ logger, events, metrics, clock });
|
|
8001
|
-
}
|
|
8002
|
-
|
|
8003
|
-
/**
|
|
8004
|
-
* Invocation context resolution - resolves the **WHO/HOW** of an operation.
|
|
8005
|
-
*
|
|
8006
|
-
* @packageDocumentation
|
|
8007
|
-
*/
|
|
8008
|
-
// ============================================================================
|
|
8009
|
-
// Validation Schemas
|
|
8010
|
-
// ============================================================================
|
|
8011
|
-
/**
|
|
8012
|
-
* Schema for validating Caller.
|
|
8013
|
-
*/
|
|
8014
|
-
const callerSchema = z.object({
|
|
8015
|
-
type: z.string(),
|
|
8016
|
-
name: z.string(),
|
|
8017
|
-
version: z.string().optional(),
|
|
8018
|
-
});
|
|
8019
|
-
/**
|
|
8020
|
-
* Schema for validating InvocationMeta input.
|
|
8021
|
-
*/
|
|
8022
|
-
const invocationMetaSchema = z
|
|
8023
|
-
.object({
|
|
8024
|
-
traceId: z.string().optional(),
|
|
8025
|
-
runtime: z.object({}).passthrough().optional(),
|
|
8026
|
-
tokens: z.object({}).passthrough().optional(),
|
|
8027
|
-
callers: z.array(callerSchema).optional(),
|
|
8028
|
-
})
|
|
8029
|
-
.strict();
|
|
8030
|
-
// ============================================================================
|
|
8031
|
-
// Invocation Context Resolution
|
|
8032
|
-
// ============================================================================
|
|
8033
|
-
/**
|
|
8034
|
-
* Resolve invocation metadata to invocation context.
|
|
8035
|
-
*
|
|
8036
|
-
* @param meta - User-provided invocation metadata (**WHO/HOW**), optional.
|
|
8037
|
-
* @param defaults - Default runtime and tokens to use if not overridden.
|
|
8038
|
-
* @returns Frozen, immutable invocation context with guaranteed values.
|
|
8039
|
-
* @throws KitError when meta contains invalid properties.
|
|
8040
|
-
*
|
|
8041
|
-
* @remarks
|
|
8042
|
-
* Resolves the **WHO** called and **HOW** to observe:
|
|
8043
|
-
* - TraceId: Uses provided value or generates new one
|
|
8044
|
-
* - Runtime: Uses meta.runtime if provided, otherwise defaults.runtime
|
|
8045
|
-
* - Tokens: Uses meta.tokens if provided, otherwise defaults.tokens
|
|
8046
|
-
* - Callers: Uses provided array or empty array
|
|
8047
|
-
*
|
|
8048
|
-
* The returned context is frozen to enforce immutability.
|
|
8049
|
-
*
|
|
8050
|
-
* @example
|
|
8051
|
-
* ```typescript
|
|
8052
|
-
* import { resolveInvocationContext, createRuntime } from '@core/runtime'
|
|
8053
|
-
* import { createTokenRegistry } from '@core/tokens'
|
|
8054
|
-
*
|
|
8055
|
-
* const defaults = {
|
|
8056
|
-
* runtime: createRuntime(),
|
|
8057
|
-
* tokens: createTokenRegistry(),
|
|
8058
|
-
* }
|
|
8059
|
-
*
|
|
8060
|
-
* // Minimal - just using defaults
|
|
8061
|
-
* const ctx = resolveInvocationContext(undefined, defaults)
|
|
8062
|
-
*
|
|
8063
|
-
* // With trace ID and caller info
|
|
8064
|
-
* const ctx = resolveInvocationContext(
|
|
8065
|
-
* {
|
|
8066
|
-
* traceId: 'abc-123',
|
|
8067
|
-
* callers: [{ type: 'kit', name: 'BridgeKit', version: '1.0.0' }],
|
|
8068
|
-
* },
|
|
8069
|
-
* defaults
|
|
8070
|
-
* )
|
|
8071
|
-
*
|
|
8072
|
-
* // With runtime override (complete replacement)
|
|
8073
|
-
* const ctx = resolveInvocationContext(
|
|
8074
|
-
* { runtime: createRuntime({ logger: myLogger }) },
|
|
8075
|
-
* defaults
|
|
8076
|
-
* )
|
|
8077
|
-
* ```
|
|
8078
|
-
*/
|
|
8079
|
-
function resolveInvocationContext(meta, defaults) {
|
|
8080
|
-
// Validate meta input if provided
|
|
8081
|
-
if (meta !== undefined) {
|
|
8082
|
-
const result = invocationMetaSchema.safeParse(meta);
|
|
8083
|
-
if (!result.success) {
|
|
8084
|
-
throw createValidationFailedError('invocationMeta', meta, result.error.errors.map((e) => e.message).join(', '));
|
|
8085
|
-
}
|
|
8086
|
-
}
|
|
8087
|
-
// Generate trace ID if not provided
|
|
8088
|
-
const traceId = meta?.traceId ?? createTraceId();
|
|
8089
|
-
// Use meta overrides or fall back to defaults
|
|
8090
|
-
const runtime = meta?.runtime ?? defaults.runtime;
|
|
8091
|
-
const tokens = meta?.tokens ?? defaults.tokens;
|
|
8092
|
-
const callers = meta?.callers ?? [];
|
|
8093
|
-
return Object.freeze({ traceId, runtime, tokens, callers });
|
|
9081
|
+
const pinoInstance = pino(finalOptions);
|
|
9082
|
+
return wrapPino(pinoInstance);
|
|
8094
9083
|
}
|
|
8095
9084
|
|
|
8096
9085
|
/**
|
|
8097
|
-
*
|
|
9086
|
+
* Factory for creating Runtime instances with defaults.
|
|
8098
9087
|
*
|
|
8099
|
-
* @
|
|
8100
|
-
|
|
8101
|
-
|
|
9088
|
+
* @packageDocumentation
|
|
9089
|
+
*/
|
|
9090
|
+
// ============================================================================
|
|
9091
|
+
// Validation Schema
|
|
9092
|
+
// ============================================================================
|
|
9093
|
+
/**
|
|
9094
|
+
* Schema for validating {@link RuntimeOptions}.
|
|
8102
9095
|
*
|
|
8103
9096
|
* @remarks
|
|
8104
|
-
*
|
|
8105
|
-
*
|
|
8106
|
-
* (traceId, runtime, tokens).
|
|
8107
|
-
*
|
|
8108
|
-
* The returned context is frozen to enforce immutability.
|
|
8109
|
-
*
|
|
8110
|
-
* @example
|
|
8111
|
-
* ```typescript
|
|
8112
|
-
* import { extendInvocationContext } from '@core/runtime'
|
|
8113
|
-
*
|
|
8114
|
-
* const caller = { type: 'provider', name: 'CCTPV2', version: '1.0.0' }
|
|
8115
|
-
* const extended = extendInvocationContext(existingContext, caller)
|
|
8116
|
-
* // extended.callers === [...existingContext.callers, caller]
|
|
8117
|
-
* ```
|
|
9097
|
+
* Used internally by {@link createRuntime} to validate options from JS consumers.
|
|
9098
|
+
* Exported for advanced use cases where manual validation is needed.
|
|
8118
9099
|
*/
|
|
8119
|
-
function extendInvocationContext(context, caller) {
|
|
8120
|
-
return Object.freeze({
|
|
8121
|
-
traceId: context.traceId,
|
|
8122
|
-
runtime: context.runtime,
|
|
8123
|
-
tokens: context.tokens,
|
|
8124
|
-
callers: [...context.callers, caller],
|
|
8125
|
-
});
|
|
8126
|
-
}
|
|
8127
|
-
|
|
8128
|
-
// Clock - expose defaultClock for backward compatibility
|
|
8129
|
-
/** Clock validation schema (backward compatibility). */
|
|
8130
|
-
z.custom((val) => val !== null &&
|
|
8131
|
-
typeof val === 'object' &&
|
|
8132
|
-
'now' in val &&
|
|
8133
|
-
typeof val['now'] === 'function');
|
|
8134
|
-
/** EventBus validation schema (backward compatibility). */
|
|
8135
|
-
z.custom((val) => val !== null &&
|
|
8136
|
-
typeof val === 'object' &&
|
|
8137
|
-
'emit' in val &&
|
|
8138
|
-
typeof val['emit'] === 'function');
|
|
8139
|
-
/** Runtime validation schema (backward compatibility). */
|
|
8140
9100
|
z
|
|
8141
9101
|
.object({
|
|
8142
|
-
logger:
|
|
8143
|
-
|
|
8144
|
-
metrics: z.any().optional(),
|
|
8145
|
-
clock: z.any().optional(),
|
|
9102
|
+
logger: loggerSchema.optional(),
|
|
9103
|
+
metrics: metricsSchema.optional(),
|
|
8146
9104
|
})
|
|
8147
9105
|
.passthrough();
|
|
8148
|
-
|
|
9106
|
+
// ============================================================================
|
|
9107
|
+
// Factory
|
|
9108
|
+
// ============================================================================
|
|
8149
9109
|
/**
|
|
8150
|
-
* Create a
|
|
9110
|
+
* Create a complete Runtime with sensible defaults.
|
|
8151
9111
|
*
|
|
8152
|
-
* @
|
|
8153
|
-
*
|
|
8154
|
-
*
|
|
9112
|
+
* @param options - Optional configuration to override logger and metrics.
|
|
9113
|
+
* @returns A frozen, immutable Runtime with all services guaranteed present.
|
|
9114
|
+
* @throws KitError (INPUT_VALIDATION_FAILED) if options contain invalid services.
|
|
8155
9115
|
*
|
|
8156
|
-
* @
|
|
8157
|
-
*
|
|
8158
|
-
*
|
|
8159
|
-
* @param cause - The underlying error, if any (optional).
|
|
8160
|
-
* @returns A KitError with INPUT type and FATAL recoverability.
|
|
9116
|
+
* @remarks
|
|
9117
|
+
* Creates a fully-configured runtime by merging provided options with defaults.
|
|
9118
|
+
* The returned runtime is frozen to enforce immutability.
|
|
8161
9119
|
*
|
|
8162
|
-
*
|
|
8163
|
-
*
|
|
8164
|
-
*
|
|
8165
|
-
*
|
|
8166
|
-
*
|
|
8167
|
-
*
|
|
8168
|
-
* )
|
|
8169
|
-
* ```
|
|
8170
|
-
*/
|
|
8171
|
-
function createTokenResolutionError(message, selector, chainId, cause) {
|
|
8172
|
-
const trace = {
|
|
8173
|
-
selector,
|
|
8174
|
-
...(chainId === undefined ? {} : { chainId }),
|
|
8175
|
-
...({} ),
|
|
8176
|
-
};
|
|
8177
|
-
return new KitError({
|
|
8178
|
-
...InputError.INVALID_TOKEN,
|
|
8179
|
-
recoverability: 'FATAL',
|
|
8180
|
-
message,
|
|
8181
|
-
cause: { trace },
|
|
8182
|
-
});
|
|
8183
|
-
}
|
|
8184
|
-
|
|
8185
|
-
/**
|
|
8186
|
-
* USDC token definition with addresses and metadata.
|
|
9120
|
+
* | Service | Default | Configurable |
|
|
9121
|
+
* |---------|---------|--------------|
|
|
9122
|
+
* | `logger` | pino logger (info level) | Yes |
|
|
9123
|
+
* | `metrics` | No-op metrics | Yes |
|
|
9124
|
+
* | `events` | Internal event bus | No |
|
|
9125
|
+
* | `clock` | `Date.now()` | No |
|
|
8187
9126
|
*
|
|
8188
|
-
*
|
|
8189
|
-
* This is the built-in USDC definition used by the TokenRegistry.
|
|
8190
|
-
* Includes all known USDC addresses across supported chains.
|
|
9127
|
+
* **Why only logger and metrics?**
|
|
8191
9128
|
*
|
|
8192
|
-
*
|
|
8193
|
-
*
|
|
8194
|
-
* -
|
|
9129
|
+
* - **Logger/Metrics**: Integration points with your infrastructure
|
|
9130
|
+
* - **Events**: Internal pub/sub mechanism - subscribe via `runtime.events.on()`
|
|
9131
|
+
* - **Clock**: Testing concern - use mock factories for tests
|
|
8195
9132
|
*
|
|
8196
9133
|
* @example
|
|
8197
9134
|
* ```typescript
|
|
8198
|
-
* import {
|
|
8199
|
-
* import { Blockchain } from '@core/chains'
|
|
8200
|
-
*
|
|
8201
|
-
* console.log(USDC.symbol) // 'USDC'
|
|
8202
|
-
* console.log(USDC.decimals) // 6
|
|
8203
|
-
* console.log(USDC.locators[Blockchain.Ethereum])
|
|
8204
|
-
* // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
8205
|
-
* ```
|
|
8206
|
-
*/
|
|
8207
|
-
const USDC = {
|
|
8208
|
-
symbol: 'USDC',
|
|
8209
|
-
decimals: 6,
|
|
8210
|
-
locators: {
|
|
8211
|
-
// =========================================================================
|
|
8212
|
-
// Mainnets (alphabetically sorted)
|
|
8213
|
-
// =========================================================================
|
|
8214
|
-
[Blockchain.Arbitrum]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
8215
|
-
[Blockchain.Avalanche]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
8216
|
-
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
8217
|
-
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
8218
|
-
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
8219
|
-
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
8220
|
-
[Blockchain.Hedera]: '0.0.456858',
|
|
8221
|
-
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
8222
|
-
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
8223
|
-
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
8224
|
-
[Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
8225
|
-
[Blockchain.Noble]: 'uusdc',
|
|
8226
|
-
[Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
8227
|
-
[Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
8228
|
-
[Blockchain.Polkadot_Asset_Hub]: '1337',
|
|
8229
|
-
[Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
8230
|
-
[Blockchain.Sei]: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
8231
|
-
[Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
8232
|
-
[Blockchain.Sonic]: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
8233
|
-
[Blockchain.Stellar]: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
8234
|
-
[Blockchain.Sui]: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
8235
|
-
[Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
8236
|
-
[Blockchain.World_Chain]: '0x79A02482A880bCe3F13E09da970dC34dB4cD24D1',
|
|
8237
|
-
[Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
8238
|
-
[Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
8239
|
-
// =========================================================================
|
|
8240
|
-
// Testnets (alphabetically sorted)
|
|
8241
|
-
// =========================================================================
|
|
8242
|
-
[Blockchain.Arbitrum_Sepolia]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
8243
|
-
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
8244
|
-
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
8245
|
-
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
8246
|
-
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
8247
|
-
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
8248
|
-
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
8249
|
-
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
8250
|
-
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
8251
|
-
[Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
8252
|
-
[Blockchain.Noble_Testnet]: 'uusdc',
|
|
8253
|
-
[Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
8254
|
-
[Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
8255
|
-
[Blockchain.Polkadot_Westmint]: '31337',
|
|
8256
|
-
[Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
8257
|
-
[Blockchain.Sei_Testnet]: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
8258
|
-
[Blockchain.Solana_Devnet]: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
8259
|
-
[Blockchain.Sonic_Testnet]: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
8260
|
-
[Blockchain.Stellar_Testnet]: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
8261
|
-
[Blockchain.Sui_Testnet]: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
8262
|
-
[Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
8263
|
-
[Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
8264
|
-
[Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
8265
|
-
[Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
8266
|
-
},
|
|
8267
|
-
};
|
|
8268
|
-
|
|
8269
|
-
// Re-export for consumers
|
|
8270
|
-
/**
|
|
8271
|
-
* All default token definitions.
|
|
9135
|
+
* import { createRuntime, createLogger } from '@core/runtime'
|
|
8272
9136
|
*
|
|
8273
|
-
*
|
|
8274
|
-
*
|
|
8275
|
-
* without explicit defaults. Extensions can override these definitions.
|
|
9137
|
+
* // Use all defaults
|
|
9138
|
+
* const runtime = createRuntime()
|
|
8276
9139
|
*
|
|
8277
|
-
*
|
|
8278
|
-
*
|
|
8279
|
-
*
|
|
9140
|
+
* // Custom logger
|
|
9141
|
+
* const runtime = createRuntime({
|
|
9142
|
+
* logger: createLogger({ level: 'debug' }),
|
|
9143
|
+
* })
|
|
8280
9144
|
*
|
|
8281
|
-
* //
|
|
8282
|
-
* const
|
|
9145
|
+
* // Custom metrics (e.g., Prometheus)
|
|
9146
|
+
* const runtime = createRuntime({
|
|
9147
|
+
* metrics: myPrometheusMetrics,
|
|
9148
|
+
* })
|
|
8283
9149
|
*
|
|
8284
|
-
* //
|
|
8285
|
-
*
|
|
8286
|
-
*
|
|
9150
|
+
* // Subscribe to events (don't replace the bus)
|
|
9151
|
+
* runtime.events.on('operation.*', (event) => {
|
|
9152
|
+
* console.log('Event:', event.name)
|
|
8287
9153
|
* })
|
|
8288
9154
|
* ```
|
|
8289
9155
|
*/
|
|
8290
|
-
|
|
9156
|
+
function createRuntime(options) {
|
|
9157
|
+
// Resolve logger first (events may need it)
|
|
9158
|
+
const logger = createLogger();
|
|
9159
|
+
// Internal services - not configurable
|
|
9160
|
+
const events = createEventBus({ logger });
|
|
9161
|
+
const clock = defaultClock;
|
|
9162
|
+
// Resolve metrics
|
|
9163
|
+
const metrics = noopMetrics;
|
|
9164
|
+
return Object.freeze({ logger, events, metrics, clock });
|
|
9165
|
+
}
|
|
8291
9166
|
|
|
8292
9167
|
/**
|
|
8293
|
-
*
|
|
9168
|
+
* Invocation context resolution - resolves the **WHO/HOW** of an operation.
|
|
8294
9169
|
*
|
|
8295
|
-
* @
|
|
8296
|
-
* @returns True if the selector is a raw token selector.
|
|
9170
|
+
* @packageDocumentation
|
|
8297
9171
|
*/
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
9172
|
+
// ============================================================================
|
|
9173
|
+
// Validation Schemas
|
|
9174
|
+
// ============================================================================
|
|
9175
|
+
/**
|
|
9176
|
+
* Schema for validating Caller.
|
|
9177
|
+
*/
|
|
9178
|
+
const callerSchema = z.object({
|
|
9179
|
+
type: z.string(),
|
|
9180
|
+
name: z.string(),
|
|
9181
|
+
version: z.string().optional(),
|
|
9182
|
+
});
|
|
9183
|
+
/**
|
|
9184
|
+
* Schema for validating InvocationMeta input.
|
|
9185
|
+
*/
|
|
9186
|
+
const invocationMetaSchema = z
|
|
9187
|
+
.object({
|
|
9188
|
+
traceId: z.string().optional(),
|
|
9189
|
+
runtime: z.object({}).passthrough().optional(),
|
|
9190
|
+
tokens: z.object({}).passthrough().optional(),
|
|
9191
|
+
callers: z.array(callerSchema).optional(),
|
|
9192
|
+
})
|
|
9193
|
+
.strict();
|
|
9194
|
+
// ============================================================================
|
|
9195
|
+
// Invocation Context Resolution
|
|
9196
|
+
// ============================================================================
|
|
8301
9197
|
/**
|
|
8302
|
-
*
|
|
9198
|
+
* Resolve invocation metadata to invocation context.
|
|
8303
9199
|
*
|
|
8304
|
-
* @param
|
|
8305
|
-
* @
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
return symbol.toUpperCase();
|
|
8309
|
-
}
|
|
8310
|
-
/**
|
|
8311
|
-
* Create a token registry with built-in tokens and optional extensions.
|
|
9200
|
+
* @param meta - User-provided invocation metadata (**WHO/HOW**), optional.
|
|
9201
|
+
* @param defaults - Default runtime and tokens to use if not overridden.
|
|
9202
|
+
* @returns Frozen, immutable invocation context with guaranteed values.
|
|
9203
|
+
* @throws KitError when meta contains invalid properties.
|
|
8312
9204
|
*
|
|
8313
9205
|
* @remarks
|
|
8314
|
-
*
|
|
8315
|
-
*
|
|
8316
|
-
*
|
|
9206
|
+
* Resolves the **WHO** called and **HOW** to observe:
|
|
9207
|
+
* - TraceId: Uses provided value or generates new one
|
|
9208
|
+
* - Runtime: Uses meta.runtime if provided, otherwise defaults.runtime
|
|
9209
|
+
* - Tokens: Uses meta.tokens if provided, otherwise defaults.tokens
|
|
9210
|
+
* - Callers: Uses provided array or empty array
|
|
8317
9211
|
*
|
|
8318
|
-
*
|
|
8319
|
-
* @returns A token registry instance.
|
|
9212
|
+
* The returned context is frozen to enforce immutability.
|
|
8320
9213
|
*
|
|
8321
9214
|
* @example
|
|
8322
9215
|
* ```typescript
|
|
9216
|
+
* import { resolveInvocationContext, createRuntime } from '@core/runtime'
|
|
8323
9217
|
* import { createTokenRegistry } from '@core/tokens'
|
|
8324
9218
|
*
|
|
8325
|
-
*
|
|
8326
|
-
*
|
|
8327
|
-
*
|
|
8328
|
-
* // Resolve USDC on Ethereum
|
|
8329
|
-
* const usdc = registry.resolve('USDC', 'Ethereum')
|
|
8330
|
-
* console.log(usdc.locator) // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
8331
|
-
* console.log(usdc.decimals) // 6
|
|
8332
|
-
* ```
|
|
8333
|
-
*
|
|
8334
|
-
* @example
|
|
8335
|
-
* ```typescript
|
|
8336
|
-
* // Add custom tokens (built-ins are still included)
|
|
8337
|
-
* const myToken: TokenDefinition = {
|
|
8338
|
-
* symbol: 'MY',
|
|
8339
|
-
* decimals: 18,
|
|
8340
|
-
* locators: { Ethereum: '0x...' },
|
|
9219
|
+
* const defaults = {
|
|
9220
|
+
* runtime: createRuntime(),
|
|
9221
|
+
* tokens: createTokenRegistry(),
|
|
8341
9222
|
* }
|
|
8342
9223
|
*
|
|
8343
|
-
*
|
|
8344
|
-
*
|
|
8345
|
-
* registry.resolve('MY', 'Ethereum') // Also works
|
|
8346
|
-
* ```
|
|
8347
|
-
*
|
|
8348
|
-
* @example
|
|
8349
|
-
* ```typescript
|
|
8350
|
-
* // Override a built-in token
|
|
8351
|
-
* const customUsdc: TokenDefinition = {
|
|
8352
|
-
* symbol: 'USDC',
|
|
8353
|
-
* decimals: 6,
|
|
8354
|
-
* locators: { MyChain: '0xCustomAddress' },
|
|
8355
|
-
* }
|
|
9224
|
+
* // Minimal - just using defaults
|
|
9225
|
+
* const ctx = resolveInvocationContext(undefined, defaults)
|
|
8356
9226
|
*
|
|
8357
|
-
*
|
|
8358
|
-
*
|
|
8359
|
-
*
|
|
9227
|
+
* // With trace ID and caller info
|
|
9228
|
+
* const ctx = resolveInvocationContext(
|
|
9229
|
+
* {
|
|
9230
|
+
* traceId: 'abc-123',
|
|
9231
|
+
* callers: [{ type: 'kit', name: 'BridgeKit', version: '1.0.0' }],
|
|
9232
|
+
* },
|
|
9233
|
+
* defaults
|
|
9234
|
+
* )
|
|
8360
9235
|
*
|
|
8361
|
-
*
|
|
8362
|
-
*
|
|
8363
|
-
*
|
|
8364
|
-
*
|
|
8365
|
-
* const token = registry.resolve(
|
|
8366
|
-
* { locator: '0x1234...', decimals: 18 },
|
|
8367
|
-
* 'Ethereum'
|
|
9236
|
+
* // With runtime override (complete replacement)
|
|
9237
|
+
* const ctx = resolveInvocationContext(
|
|
9238
|
+
* { runtime: createRuntime({ logger: myLogger }) },
|
|
9239
|
+
* defaults
|
|
8368
9240
|
* )
|
|
8369
9241
|
* ```
|
|
8370
9242
|
*/
|
|
8371
|
-
function
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
8378
|
-
}
|
|
8379
|
-
// Custom tokens override built-ins
|
|
8380
|
-
for (const def of tokens) {
|
|
8381
|
-
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
8382
|
-
}
|
|
8383
|
-
/**
|
|
8384
|
-
* Resolve a symbol selector to token information.
|
|
8385
|
-
*/
|
|
8386
|
-
function resolveSymbol(symbol, chainId) {
|
|
8387
|
-
const normalizedSymbol = normalizeSymbol(symbol);
|
|
8388
|
-
const definition = tokenMap.get(normalizedSymbol);
|
|
8389
|
-
if (definition === undefined) {
|
|
8390
|
-
throw createTokenResolutionError(`Unknown token symbol: ${symbol}. Register it via createTokenRegistry({ tokens: [...] }) or use a raw selector.`, symbol, chainId);
|
|
8391
|
-
}
|
|
8392
|
-
const locator = definition.locators[chainId];
|
|
8393
|
-
if (locator === undefined || locator.trim() === '') {
|
|
8394
|
-
throw createTokenResolutionError(`Token ${symbol} has no locator for chain ${chainId}`, symbol, chainId);
|
|
8395
|
-
}
|
|
8396
|
-
return {
|
|
8397
|
-
symbol: definition.symbol,
|
|
8398
|
-
decimals: definition.decimals,
|
|
8399
|
-
locator,
|
|
8400
|
-
};
|
|
8401
|
-
}
|
|
8402
|
-
/**
|
|
8403
|
-
* Resolve a raw selector to token information.
|
|
8404
|
-
*/
|
|
8405
|
-
function resolveRaw(selector, chainId) {
|
|
8406
|
-
const { locator, decimals } = selector;
|
|
8407
|
-
// Validate locator
|
|
8408
|
-
if (!locator || typeof locator !== 'string') {
|
|
8409
|
-
throw createTokenResolutionError('Raw selector must have a valid locator string', selector, chainId);
|
|
8410
|
-
}
|
|
8411
|
-
// Decimals are always required for raw selectors
|
|
8412
|
-
if (decimals === undefined) {
|
|
8413
|
-
const message = requireDecimals
|
|
8414
|
-
? 'Decimals required for raw token selector (requireDecimals: true)'
|
|
8415
|
-
: 'Decimals required for raw token selector. Provide { locator, decimals }.';
|
|
8416
|
-
throw createTokenResolutionError(message, selector, chainId);
|
|
8417
|
-
}
|
|
8418
|
-
// Validate decimals
|
|
8419
|
-
if (typeof decimals !== 'number' ||
|
|
8420
|
-
decimals < 0 ||
|
|
8421
|
-
!Number.isInteger(decimals)) {
|
|
8422
|
-
throw createTokenResolutionError(`Invalid decimals: ${String(decimals)}. Must be a non-negative integer.`, selector, chainId);
|
|
9243
|
+
function resolveInvocationContext(meta, defaults) {
|
|
9244
|
+
// Validate meta input if provided
|
|
9245
|
+
if (meta !== undefined) {
|
|
9246
|
+
const result = invocationMetaSchema.safeParse(meta);
|
|
9247
|
+
if (!result.success) {
|
|
9248
|
+
throw createValidationFailedError('invocationMeta', meta, result.error.errors.map((e) => e.message).join(', '));
|
|
8423
9249
|
}
|
|
8424
|
-
return {
|
|
8425
|
-
decimals,
|
|
8426
|
-
locator,
|
|
8427
|
-
};
|
|
8428
9250
|
}
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
if (chainId === '' || typeof chainId !== 'string') {
|
|
8437
|
-
throw createTokenResolutionError('Chain ID is required for token resolution', selector, chainId);
|
|
8438
|
-
}
|
|
8439
|
-
// Dispatch based on selector type
|
|
8440
|
-
if (isRawSelector(selector)) {
|
|
8441
|
-
return resolveRaw(selector, chainId);
|
|
8442
|
-
}
|
|
8443
|
-
if (typeof selector === 'string') {
|
|
8444
|
-
return resolveSymbol(selector, chainId);
|
|
8445
|
-
}
|
|
8446
|
-
throw createTokenResolutionError(`Invalid selector type: ${typeof selector}. Expected string or object with locator.`, selector, chainId);
|
|
8447
|
-
},
|
|
8448
|
-
get(symbol) {
|
|
8449
|
-
if (!symbol || typeof symbol !== 'string') {
|
|
8450
|
-
return undefined;
|
|
8451
|
-
}
|
|
8452
|
-
return tokenMap.get(normalizeSymbol(symbol));
|
|
8453
|
-
},
|
|
8454
|
-
has(symbol) {
|
|
8455
|
-
if (!symbol || typeof symbol !== 'string') {
|
|
8456
|
-
return false;
|
|
8457
|
-
}
|
|
8458
|
-
return tokenMap.has(normalizeSymbol(symbol));
|
|
8459
|
-
},
|
|
8460
|
-
symbols() {
|
|
8461
|
-
return Array.from(tokenMap.values()).map((def) => def.symbol);
|
|
8462
|
-
},
|
|
8463
|
-
entries() {
|
|
8464
|
-
return Array.from(tokenMap.values());
|
|
8465
|
-
},
|
|
8466
|
-
};
|
|
9251
|
+
// Generate trace ID if not provided
|
|
9252
|
+
const traceId = meta?.traceId ?? createTraceId();
|
|
9253
|
+
// Use meta overrides or fall back to defaults
|
|
9254
|
+
const runtime = meta?.runtime ?? defaults.runtime;
|
|
9255
|
+
const tokens = meta?.tokens ?? defaults.tokens;
|
|
9256
|
+
const callers = meta?.callers ?? [];
|
|
9257
|
+
return Object.freeze({ traceId, runtime, tokens, callers });
|
|
8467
9258
|
}
|
|
8468
9259
|
|
|
8469
9260
|
/**
|
|
8470
|
-
*
|
|
9261
|
+
* Extend an invocation context by appending a caller to its call chain.
|
|
9262
|
+
*
|
|
9263
|
+
* @param context - The existing invocation context to extend.
|
|
9264
|
+
* @param caller - The caller to append to the call chain.
|
|
9265
|
+
* @returns A new frozen invocation context with the caller appended.
|
|
8471
9266
|
*
|
|
8472
9267
|
* @remarks
|
|
8473
|
-
*
|
|
9268
|
+
* This function creates a new immutable context with the caller appended
|
|
9269
|
+
* to the `callers` array while preserving all other context properties
|
|
9270
|
+
* (traceId, runtime, tokens).
|
|
9271
|
+
*
|
|
9272
|
+
* The returned context is frozen to enforce immutability.
|
|
8474
9273
|
*
|
|
8475
9274
|
* @example
|
|
8476
9275
|
* ```typescript
|
|
8477
|
-
* import {
|
|
8478
|
-
*
|
|
8479
|
-
* const registry = {
|
|
8480
|
-
* resolve: () => ({ locator: '0x0', decimals: 6 }),
|
|
8481
|
-
* }
|
|
9276
|
+
* import { extendInvocationContext } from '@core/runtime'
|
|
8482
9277
|
*
|
|
8483
|
-
*
|
|
9278
|
+
* const caller = { type: 'provider', name: 'CCTPV2', version: '1.0.0' }
|
|
9279
|
+
* const extended = extendInvocationContext(existingContext, caller)
|
|
9280
|
+
* // extended.callers === [...existingContext.callers, caller]
|
|
8484
9281
|
* ```
|
|
8485
9282
|
*/
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
9283
|
+
function extendInvocationContext(context, caller) {
|
|
9284
|
+
return Object.freeze({
|
|
9285
|
+
traceId: context.traceId,
|
|
9286
|
+
runtime: context.runtime,
|
|
9287
|
+
tokens: context.tokens,
|
|
9288
|
+
callers: [...context.callers, caller],
|
|
9289
|
+
});
|
|
9290
|
+
}
|
|
9291
|
+
|
|
9292
|
+
// Clock - expose defaultClock for backward compatibility
|
|
9293
|
+
/** Clock validation schema (backward compatibility). */
|
|
9294
|
+
z.custom((val) => val !== null &&
|
|
9295
|
+
typeof val === 'object' &&
|
|
9296
|
+
'now' in val &&
|
|
9297
|
+
typeof val['now'] === 'function');
|
|
9298
|
+
/** EventBus validation schema (backward compatibility). */
|
|
9299
|
+
z.custom((val) => val !== null &&
|
|
9300
|
+
typeof val === 'object' &&
|
|
9301
|
+
'emit' in val &&
|
|
9302
|
+
typeof val['emit'] === 'function');
|
|
9303
|
+
/** Runtime validation schema (backward compatibility). */
|
|
9304
|
+
z
|
|
9305
|
+
.object({
|
|
9306
|
+
logger: z.any().optional(),
|
|
9307
|
+
events: z.any().optional(),
|
|
9308
|
+
metrics: z.any().optional(),
|
|
9309
|
+
clock: z.any().optional(),
|
|
9310
|
+
})
|
|
9311
|
+
.passthrough();
|
|
8499
9312
|
|
|
8500
|
-
var version = "1.4.
|
|
9313
|
+
var version = "1.4.1";
|
|
8501
9314
|
var pkg = {
|
|
8502
9315
|
version: version};
|
|
8503
9316
|
|
|
@@ -8980,6 +9793,24 @@ const validateNativeBalanceForTransaction = async (params) => {
|
|
|
8980
9793
|
}
|
|
8981
9794
|
};
|
|
8982
9795
|
|
|
9796
|
+
/**
|
|
9797
|
+
* Permit signature standards for gasless token approvals.
|
|
9798
|
+
*
|
|
9799
|
+
* Defines the permit types that can be used to approve token spending
|
|
9800
|
+
* without requiring a separate approval transaction.
|
|
9801
|
+
*
|
|
9802
|
+
* @remarks
|
|
9803
|
+
* - NONE: No permit, tokens must be pre-approved via separate transaction
|
|
9804
|
+
* - EIP2612: Standard ERC-20 permit (USDC, DAI v2, and most modern tokens)
|
|
9805
|
+
*/
|
|
9806
|
+
var PermitType;
|
|
9807
|
+
(function (PermitType) {
|
|
9808
|
+
/** No permit required - tokens must be pre-approved */
|
|
9809
|
+
PermitType[PermitType["NONE"] = 0] = "NONE";
|
|
9810
|
+
/** EIP-2612 standard permit */
|
|
9811
|
+
PermitType[PermitType["EIP2612"] = 1] = "EIP2612";
|
|
9812
|
+
})(PermitType || (PermitType = {}));
|
|
9813
|
+
|
|
8983
9814
|
/**
|
|
8984
9815
|
* CCTP bridge step names that can occur in the bridging flow.
|
|
8985
9816
|
*
|