@circle-fin/provider-cctp-v2 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +9 -9
- package/index.cjs +1847 -824
- package/index.d.ts +659 -32
- package/index.mjs +1847 -824
- 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;
|
|
@@ -66,6 +66,8 @@ var Blockchain;
|
|
|
66
66
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
67
67
|
Blockchain["Codex"] = "Codex";
|
|
68
68
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
69
|
+
Blockchain["Edge"] = "Edge";
|
|
70
|
+
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
69
71
|
Blockchain["Ethereum"] = "Ethereum";
|
|
70
72
|
Blockchain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
71
73
|
Blockchain["Hedera"] = "Hedera";
|
|
@@ -78,6 +80,8 @@ var Blockchain;
|
|
|
78
80
|
Blockchain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
79
81
|
Blockchain["Monad"] = "Monad";
|
|
80
82
|
Blockchain["Monad_Testnet"] = "Monad_Testnet";
|
|
83
|
+
Blockchain["Morph"] = "Morph";
|
|
84
|
+
Blockchain["Morph_Testnet"] = "Morph_Testnet";
|
|
81
85
|
Blockchain["NEAR"] = "NEAR";
|
|
82
86
|
Blockchain["NEAR_Testnet"] = "NEAR_Testnet";
|
|
83
87
|
Blockchain["Noble"] = "Noble";
|
|
@@ -109,6 +113,122 @@ var Blockchain;
|
|
|
109
113
|
Blockchain["ZKSync_Era"] = "ZKSync_Era";
|
|
110
114
|
Blockchain["ZKSync_Sepolia"] = "ZKSync_Sepolia";
|
|
111
115
|
})(Blockchain || (Blockchain = {}));
|
|
116
|
+
/**
|
|
117
|
+
* Enum representing the subset of {@link Blockchain} that supports swap operations.
|
|
118
|
+
*
|
|
119
|
+
* This enum provides compile-time type safety for swap chain selection,
|
|
120
|
+
* ensuring only supported chains are available in IDE autocomplete
|
|
121
|
+
* when building swap parameters.
|
|
122
|
+
*
|
|
123
|
+
* @remarks
|
|
124
|
+
* Unlike the full {@link Blockchain} enum, SwapChain only includes networks
|
|
125
|
+
* where the swap functionality is actively supported by the library.
|
|
126
|
+
* Using this enum prevents runtime errors from attempting unsupported
|
|
127
|
+
* cross-chain swaps.
|
|
128
|
+
*
|
|
129
|
+
* Currently supports:
|
|
130
|
+
* - Ethereum mainnet
|
|
131
|
+
* - Base mainnet
|
|
132
|
+
* - Polygon mainnet
|
|
133
|
+
* - Solana mainnet
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* import { SwapChain, swap, createSwapKitContext } from '@circle-fin/swap-kit'
|
|
138
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
139
|
+
*
|
|
140
|
+
* const context = createSwapKitContext()
|
|
141
|
+
* const adapter = createViemAdapterFromPrivateKey({
|
|
142
|
+
* privateKey: process.env.PRIVATE_KEY
|
|
143
|
+
* })
|
|
144
|
+
*
|
|
145
|
+
* // ✅ Autocomplete shows only swap-supported chains
|
|
146
|
+
* const result = await swap(context, {
|
|
147
|
+
* from: {
|
|
148
|
+
* adapter,
|
|
149
|
+
* chain: SwapChain.Ethereum // Autocomplete: Ethereum, Base, Polygon, Solana
|
|
150
|
+
* },
|
|
151
|
+
* tokenIn: 'USDC',
|
|
152
|
+
* tokenOut: 'USDT',
|
|
153
|
+
* amount: '100.0'
|
|
154
|
+
* })
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* // String literals also work (constrained to SwapChain values)
|
|
160
|
+
* const result = await swap(context, {
|
|
161
|
+
* from: {
|
|
162
|
+
* adapter,
|
|
163
|
+
* chain: 'Ethereum' // ✅ Only SwapChain strings allowed
|
|
164
|
+
* },
|
|
165
|
+
* tokenIn: 'USDC',
|
|
166
|
+
* tokenOut: 'NATIVE',
|
|
167
|
+
* amount: '50.0'
|
|
168
|
+
* })
|
|
169
|
+
*
|
|
170
|
+
* // ❌ TypeScript error - Sui not in SwapChain enum
|
|
171
|
+
* const invalidResult = await swap(context, {
|
|
172
|
+
* from: {
|
|
173
|
+
* adapter,
|
|
174
|
+
* chain: 'Sui' // Compile-time error!
|
|
175
|
+
* },
|
|
176
|
+
* tokenIn: 'USDC',
|
|
177
|
+
* tokenOut: 'USDT',
|
|
178
|
+
* amount: '100.0'
|
|
179
|
+
* })
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
/**
|
|
183
|
+
* Enum representing chains that support same-chain swaps through the Swap Kit.
|
|
184
|
+
*
|
|
185
|
+
* Unlike the full {@link Blockchain} enum, SwapChain includes only mainnet
|
|
186
|
+
* networks where adapter contracts are deployed (CCTPv2 support).
|
|
187
|
+
*
|
|
188
|
+
* Dynamic validation via {@link isSwapSupportedChain} ensures chains
|
|
189
|
+
* automatically work when adapter contracts and supported tokens are deployed.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```typescript
|
|
193
|
+
* import { SwapChain } from '@core/chains'
|
|
194
|
+
* import { swap } from '@circle-fin/swap-kit'
|
|
195
|
+
*
|
|
196
|
+
* const result = await swap(context, {
|
|
197
|
+
* from: {
|
|
198
|
+
* adapter,
|
|
199
|
+
* chain: SwapChain.Arbitrum // Now supported!
|
|
200
|
+
* },
|
|
201
|
+
* tokenIn: 'USDC',
|
|
202
|
+
* tokenOut: 'WETH',
|
|
203
|
+
* amount: '100.0'
|
|
204
|
+
* })
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* @see {@link isSwapSupportedChain} for runtime validation
|
|
208
|
+
* @see {@link getSwapSupportedChains} for all supported chains
|
|
209
|
+
*/
|
|
210
|
+
var SwapChain;
|
|
211
|
+
(function (SwapChain) {
|
|
212
|
+
// Original 4 chains
|
|
213
|
+
SwapChain["Ethereum"] = "Ethereum";
|
|
214
|
+
SwapChain["Base"] = "Base";
|
|
215
|
+
SwapChain["Polygon"] = "Polygon";
|
|
216
|
+
SwapChain["Solana"] = "Solana";
|
|
217
|
+
// Additional supported chains
|
|
218
|
+
SwapChain["Arbitrum"] = "Arbitrum";
|
|
219
|
+
SwapChain["Optimism"] = "Optimism";
|
|
220
|
+
SwapChain["Avalanche"] = "Avalanche";
|
|
221
|
+
SwapChain["Linea"] = "Linea";
|
|
222
|
+
SwapChain["Ink"] = "Ink";
|
|
223
|
+
SwapChain["World_Chain"] = "World_Chain";
|
|
224
|
+
SwapChain["Unichain"] = "Unichain";
|
|
225
|
+
SwapChain["Plume"] = "Plume";
|
|
226
|
+
SwapChain["Sei"] = "Sei";
|
|
227
|
+
SwapChain["Sonic"] = "Sonic";
|
|
228
|
+
SwapChain["XDC"] = "XDC";
|
|
229
|
+
SwapChain["HyperEVM"] = "HyperEVM";
|
|
230
|
+
SwapChain["Monad"] = "Monad";
|
|
231
|
+
})(SwapChain || (SwapChain = {}));
|
|
112
232
|
// -----------------------------------------------------------------------------
|
|
113
233
|
// Bridge Chain Enum (CCTPv2 Supported Chains)
|
|
114
234
|
// -----------------------------------------------------------------------------
|
|
@@ -165,11 +285,13 @@ var BridgeChain;
|
|
|
165
285
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
166
286
|
BridgeChain["Base"] = "Base";
|
|
167
287
|
BridgeChain["Codex"] = "Codex";
|
|
288
|
+
BridgeChain["Edge"] = "Edge";
|
|
168
289
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
169
290
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
170
291
|
BridgeChain["Ink"] = "Ink";
|
|
171
292
|
BridgeChain["Linea"] = "Linea";
|
|
172
293
|
BridgeChain["Monad"] = "Monad";
|
|
294
|
+
BridgeChain["Morph"] = "Morph";
|
|
173
295
|
BridgeChain["Optimism"] = "Optimism";
|
|
174
296
|
BridgeChain["Plume"] = "Plume";
|
|
175
297
|
BridgeChain["Polygon"] = "Polygon";
|
|
@@ -185,11 +307,13 @@ var BridgeChain;
|
|
|
185
307
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
186
308
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
187
309
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
310
|
+
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
188
311
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
189
312
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
190
313
|
BridgeChain["Ink_Testnet"] = "Ink_Testnet";
|
|
191
314
|
BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
192
315
|
BridgeChain["Monad_Testnet"] = "Monad_Testnet";
|
|
316
|
+
BridgeChain["Morph_Testnet"] = "Morph_Testnet";
|
|
193
317
|
BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
|
|
194
318
|
BridgeChain["Plume_Testnet"] = "Plume_Testnet";
|
|
195
319
|
BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
|
|
@@ -260,6 +384,7 @@ const Algorand = defineChain({
|
|
|
260
384
|
rpcEndpoints: ['https://mainnet-api.algonode.cloud'],
|
|
261
385
|
eurcAddress: null,
|
|
262
386
|
usdcAddress: '31566704',
|
|
387
|
+
usdtAddress: null,
|
|
263
388
|
cctp: null,
|
|
264
389
|
});
|
|
265
390
|
|
|
@@ -283,6 +408,7 @@ const AlgorandTestnet = defineChain({
|
|
|
283
408
|
rpcEndpoints: ['https://testnet-api.algonode.cloud'],
|
|
284
409
|
eurcAddress: null,
|
|
285
410
|
usdcAddress: '10458941',
|
|
411
|
+
usdtAddress: null,
|
|
286
412
|
cctp: null,
|
|
287
413
|
});
|
|
288
414
|
|
|
@@ -306,6 +432,7 @@ const Aptos = defineChain({
|
|
|
306
432
|
rpcEndpoints: ['https://fullnode.mainnet.aptoslabs.com/v1'],
|
|
307
433
|
eurcAddress: null,
|
|
308
434
|
usdcAddress: '0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b',
|
|
435
|
+
usdtAddress: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
309
436
|
cctp: {
|
|
310
437
|
domain: 9,
|
|
311
438
|
contracts: {
|
|
@@ -343,6 +470,7 @@ const AptosTestnet = defineChain({
|
|
|
343
470
|
rpcEndpoints: ['https://fullnode.testnet.aptoslabs.com/v1'],
|
|
344
471
|
eurcAddress: null,
|
|
345
472
|
usdcAddress: '0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832',
|
|
473
|
+
usdtAddress: null,
|
|
346
474
|
cctp: {
|
|
347
475
|
domain: 9,
|
|
348
476
|
contracts: {
|
|
@@ -360,6 +488,121 @@ const AptosTestnet = defineChain({
|
|
|
360
488
|
},
|
|
361
489
|
});
|
|
362
490
|
|
|
491
|
+
/**
|
|
492
|
+
* Complete swap token registry - single source of truth for all swap-supported tokens.
|
|
493
|
+
*
|
|
494
|
+
* @remarks
|
|
495
|
+
* All packages should import from this registry for swap operations.
|
|
496
|
+
* Adding a new swap token requires updating only this registry.
|
|
497
|
+
*
|
|
498
|
+
* The NATIVE token is handled separately as it resolves dynamically based on chain.
|
|
499
|
+
*
|
|
500
|
+
* @example
|
|
501
|
+
* ```typescript
|
|
502
|
+
* import { SWAP_TOKEN_REGISTRY } from '@core/chains'
|
|
503
|
+
*
|
|
504
|
+
* // Get token decimals
|
|
505
|
+
* const decimals = SWAP_TOKEN_REGISTRY.USDC.decimals // 6
|
|
506
|
+
*
|
|
507
|
+
* // Check if token is stablecoin
|
|
508
|
+
* const isStable = SWAP_TOKEN_REGISTRY.DAI.category === 'stablecoin' // true
|
|
509
|
+
* ```
|
|
510
|
+
*/
|
|
511
|
+
const SWAP_TOKEN_REGISTRY = {
|
|
512
|
+
// ============================================================================
|
|
513
|
+
// Stablecoins (6 decimals)
|
|
514
|
+
// ============================================================================
|
|
515
|
+
USDC: {
|
|
516
|
+
symbol: 'USDC',
|
|
517
|
+
decimals: 6,
|
|
518
|
+
category: 'stablecoin',
|
|
519
|
+
description: 'USD Coin',
|
|
520
|
+
},
|
|
521
|
+
EURC: {
|
|
522
|
+
symbol: 'EURC',
|
|
523
|
+
decimals: 6,
|
|
524
|
+
category: 'stablecoin',
|
|
525
|
+
description: 'Euro Coin',
|
|
526
|
+
},
|
|
527
|
+
USDT: {
|
|
528
|
+
symbol: 'USDT',
|
|
529
|
+
decimals: 6,
|
|
530
|
+
category: 'stablecoin',
|
|
531
|
+
description: 'Tether USD',
|
|
532
|
+
},
|
|
533
|
+
PYUSD: {
|
|
534
|
+
symbol: 'PYUSD',
|
|
535
|
+
decimals: 6,
|
|
536
|
+
category: 'stablecoin',
|
|
537
|
+
description: 'PayPal USD',
|
|
538
|
+
},
|
|
539
|
+
// ============================================================================
|
|
540
|
+
// Stablecoins (18 decimals)
|
|
541
|
+
// ============================================================================
|
|
542
|
+
DAI: {
|
|
543
|
+
symbol: 'DAI',
|
|
544
|
+
decimals: 18,
|
|
545
|
+
category: 'stablecoin',
|
|
546
|
+
description: 'MakerDAO stablecoin',
|
|
547
|
+
},
|
|
548
|
+
USDE: {
|
|
549
|
+
symbol: 'USDE',
|
|
550
|
+
decimals: 18,
|
|
551
|
+
category: 'stablecoin',
|
|
552
|
+
description: 'Ethena USD (synthetic dollar)',
|
|
553
|
+
},
|
|
554
|
+
// ============================================================================
|
|
555
|
+
// Wrapped Tokens
|
|
556
|
+
// ============================================================================
|
|
557
|
+
WBTC: {
|
|
558
|
+
symbol: 'WBTC',
|
|
559
|
+
decimals: 8,
|
|
560
|
+
category: 'wrapped',
|
|
561
|
+
description: 'Wrapped Bitcoin',
|
|
562
|
+
},
|
|
563
|
+
WETH: {
|
|
564
|
+
symbol: 'WETH',
|
|
565
|
+
decimals: 18,
|
|
566
|
+
category: 'wrapped',
|
|
567
|
+
description: 'Wrapped Ethereum',
|
|
568
|
+
},
|
|
569
|
+
WSOL: {
|
|
570
|
+
symbol: 'WSOL',
|
|
571
|
+
decimals: 9,
|
|
572
|
+
category: 'wrapped',
|
|
573
|
+
description: 'Wrapped Solana',
|
|
574
|
+
},
|
|
575
|
+
WAVAX: {
|
|
576
|
+
symbol: 'WAVAX',
|
|
577
|
+
decimals: 18,
|
|
578
|
+
category: 'wrapped',
|
|
579
|
+
description: 'Wrapped Avalanche',
|
|
580
|
+
},
|
|
581
|
+
WPOL: {
|
|
582
|
+
symbol: 'WPOL',
|
|
583
|
+
decimals: 18,
|
|
584
|
+
category: 'wrapped',
|
|
585
|
+
description: 'Wrapped Polygon',
|
|
586
|
+
},
|
|
587
|
+
};
|
|
588
|
+
/**
|
|
589
|
+
* Special NATIVE token constant for swap operations.
|
|
590
|
+
*
|
|
591
|
+
* @remarks
|
|
592
|
+
* NATIVE is handled separately from SWAP_TOKEN_REGISTRY because it resolves
|
|
593
|
+
* dynamically based on the chain (ETH on Ethereum, SOL on Solana, etc.).
|
|
594
|
+
* Its decimals are chain-specific.
|
|
595
|
+
*/
|
|
596
|
+
const NATIVE_TOKEN = 'NATIVE';
|
|
597
|
+
/**
|
|
598
|
+
* Array of all supported swap token symbols including NATIVE.
|
|
599
|
+
* Useful for iteration, validation, and filtering.
|
|
600
|
+
*/
|
|
601
|
+
[
|
|
602
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
603
|
+
NATIVE_TOKEN,
|
|
604
|
+
];
|
|
605
|
+
|
|
363
606
|
/**
|
|
364
607
|
* The bridge contract address for EVM testnet networks.
|
|
365
608
|
*
|
|
@@ -376,6 +619,13 @@ const BRIDGE_CONTRACT_EVM_TESTNET = '0xC5567a5E3370d4DBfB0540025078e283e36A363d'
|
|
|
376
619
|
* USDC transfers on live networks.
|
|
377
620
|
*/
|
|
378
621
|
const BRIDGE_CONTRACT_EVM_MAINNET = '0xB3FA262d0fB521cc93bE83d87b322b8A23DAf3F0';
|
|
622
|
+
/**
|
|
623
|
+
* The adapter contract address for EVM mainnet networks.
|
|
624
|
+
*
|
|
625
|
+
* This contract serves as an adapter for integrating with various protocols
|
|
626
|
+
* on EVM-compatible chains. Use this address for mainnet adapter integrations.
|
|
627
|
+
*/
|
|
628
|
+
const ADAPTER_CONTRACT_EVM_MAINNET = '0x7FB8c7260b63934d8da38aF902f87ae6e284a845';
|
|
379
629
|
|
|
380
630
|
/**
|
|
381
631
|
* Arc Testnet chain definition
|
|
@@ -405,6 +655,7 @@ const ArcTestnet = defineChain({
|
|
|
405
655
|
rpcEndpoints: ['https://rpc.testnet.arc.network/'],
|
|
406
656
|
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
407
657
|
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
658
|
+
usdtAddress: null,
|
|
408
659
|
cctp: {
|
|
409
660
|
domain: 26,
|
|
410
661
|
contracts: {
|
|
@@ -447,6 +698,7 @@ const Arbitrum = defineChain({
|
|
|
447
698
|
rpcEndpoints: ['https://arb1.arbitrum.io/rpc'],
|
|
448
699
|
eurcAddress: null,
|
|
449
700
|
usdcAddress: '0xaf88d065e77c8cc2239327c5edb3a432268e5831',
|
|
701
|
+
usdtAddress: null,
|
|
450
702
|
cctp: {
|
|
451
703
|
domain: 3,
|
|
452
704
|
contracts: {
|
|
@@ -471,6 +723,7 @@ const Arbitrum = defineChain({
|
|
|
471
723
|
},
|
|
472
724
|
kitContracts: {
|
|
473
725
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
726
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
474
727
|
},
|
|
475
728
|
});
|
|
476
729
|
|
|
@@ -495,6 +748,7 @@ const ArbitrumSepolia = defineChain({
|
|
|
495
748
|
rpcEndpoints: ['https://sepolia-rollup.arbitrum.io/rpc'],
|
|
496
749
|
eurcAddress: null,
|
|
497
750
|
usdcAddress: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
751
|
+
usdtAddress: null,
|
|
498
752
|
cctp: {
|
|
499
753
|
domain: 3,
|
|
500
754
|
contracts: {
|
|
@@ -543,6 +797,7 @@ const Avalanche = defineChain({
|
|
|
543
797
|
rpcEndpoints: ['https://api.avax.network/ext/bc/C/rpc'],
|
|
544
798
|
eurcAddress: '0xc891eb4cbdeff6e073e859e987815ed1505c2acd',
|
|
545
799
|
usdcAddress: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
800
|
+
usdtAddress: '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7',
|
|
546
801
|
cctp: {
|
|
547
802
|
domain: 1,
|
|
548
803
|
contracts: {
|
|
@@ -567,6 +822,7 @@ const Avalanche = defineChain({
|
|
|
567
822
|
},
|
|
568
823
|
kitContracts: {
|
|
569
824
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
825
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
570
826
|
},
|
|
571
827
|
});
|
|
572
828
|
|
|
@@ -590,6 +846,7 @@ const AvalancheFuji = defineChain({
|
|
|
590
846
|
explorerUrl: 'https://subnets-test.avax.network/c-chain/tx/{hash}',
|
|
591
847
|
eurcAddress: '0x5e44db7996c682e92a960b65ac713a54ad815c6b',
|
|
592
848
|
usdcAddress: '0x5425890298aed601595a70ab815c96711a31bc65',
|
|
849
|
+
usdtAddress: null,
|
|
593
850
|
cctp: {
|
|
594
851
|
domain: 1,
|
|
595
852
|
contracts: {
|
|
@@ -639,6 +896,7 @@ const Base = defineChain({
|
|
|
639
896
|
rpcEndpoints: ['https://mainnet.base.org', 'https://base.publicnode.com'],
|
|
640
897
|
eurcAddress: '0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42',
|
|
641
898
|
usdcAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
899
|
+
usdtAddress: null,
|
|
642
900
|
cctp: {
|
|
643
901
|
domain: 6,
|
|
644
902
|
contracts: {
|
|
@@ -663,6 +921,7 @@ const Base = defineChain({
|
|
|
663
921
|
},
|
|
664
922
|
kitContracts: {
|
|
665
923
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
924
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
666
925
|
},
|
|
667
926
|
});
|
|
668
927
|
|
|
@@ -687,6 +946,7 @@ const BaseSepolia = defineChain({
|
|
|
687
946
|
rpcEndpoints: ['https://sepolia.base.org'],
|
|
688
947
|
eurcAddress: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
689
948
|
usdcAddress: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
949
|
+
usdtAddress: null,
|
|
690
950
|
cctp: {
|
|
691
951
|
domain: 6,
|
|
692
952
|
contracts: {
|
|
@@ -735,6 +995,7 @@ const Celo = defineChain({
|
|
|
735
995
|
rpcEndpoints: ['https://forno.celo.org'],
|
|
736
996
|
eurcAddress: null,
|
|
737
997
|
usdcAddress: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
998
|
+
usdtAddress: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
738
999
|
cctp: null,
|
|
739
1000
|
});
|
|
740
1001
|
|
|
@@ -759,6 +1020,7 @@ const CeloAlfajoresTestnet = defineChain({
|
|
|
759
1020
|
rpcEndpoints: ['https://alfajores-forno.celo-testnet.org'],
|
|
760
1021
|
eurcAddress: null,
|
|
761
1022
|
usdcAddress: '0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B',
|
|
1023
|
+
usdtAddress: null,
|
|
762
1024
|
cctp: null,
|
|
763
1025
|
});
|
|
764
1026
|
|
|
@@ -783,6 +1045,7 @@ const Codex = defineChain({
|
|
|
783
1045
|
rpcEndpoints: ['https://rpc.codex.xyz'],
|
|
784
1046
|
eurcAddress: null,
|
|
785
1047
|
usdcAddress: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
1048
|
+
usdtAddress: null,
|
|
786
1049
|
cctp: {
|
|
787
1050
|
domain: 12,
|
|
788
1051
|
contracts: {
|
|
@@ -825,6 +1088,7 @@ const CodexTestnet = defineChain({
|
|
|
825
1088
|
rpcEndpoints: ['https://rpc.codex-stg.xyz'],
|
|
826
1089
|
eurcAddress: null,
|
|
827
1090
|
usdcAddress: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
1091
|
+
usdtAddress: null,
|
|
828
1092
|
cctp: {
|
|
829
1093
|
domain: 12,
|
|
830
1094
|
contracts: {
|
|
@@ -846,6 +1110,94 @@ const CodexTestnet = defineChain({
|
|
|
846
1110
|
},
|
|
847
1111
|
});
|
|
848
1112
|
|
|
1113
|
+
/**
|
|
1114
|
+
* Edge Mainnet chain definition
|
|
1115
|
+
* @remarks
|
|
1116
|
+
* This represents the official production network for the Edge blockchain.
|
|
1117
|
+
* Edge is an EVM-compatible blockchain.
|
|
1118
|
+
*/
|
|
1119
|
+
const Edge = defineChain({
|
|
1120
|
+
type: 'evm',
|
|
1121
|
+
chain: Blockchain.Edge,
|
|
1122
|
+
name: 'Edge',
|
|
1123
|
+
title: 'Edge Mainnet',
|
|
1124
|
+
nativeCurrency: {
|
|
1125
|
+
name: 'Ether',
|
|
1126
|
+
symbol: 'ETH',
|
|
1127
|
+
decimals: 18,
|
|
1128
|
+
},
|
|
1129
|
+
chainId: 3343,
|
|
1130
|
+
isTestnet: false,
|
|
1131
|
+
explorerUrl: 'https://pro.edgex.exchange/en-US/explorer/tx/{hash}',
|
|
1132
|
+
rpcEndpoints: ['https://edge-mainnet.g.alchemy.com/public'],
|
|
1133
|
+
eurcAddress: null,
|
|
1134
|
+
usdcAddress: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
1135
|
+
usdtAddress: null,
|
|
1136
|
+
cctp: {
|
|
1137
|
+
domain: 28,
|
|
1138
|
+
contracts: {
|
|
1139
|
+
v2: {
|
|
1140
|
+
type: 'split',
|
|
1141
|
+
tokenMessenger: '0x98706A006bc632Df31CAdFCBD43F38887ce2ca5c',
|
|
1142
|
+
messageTransmitter: '0x5b61381Fc9e58E70EfC13a4A97516997019198ee',
|
|
1143
|
+
confirmations: 65,
|
|
1144
|
+
fastConfirmations: 1,
|
|
1145
|
+
},
|
|
1146
|
+
},
|
|
1147
|
+
forwarderSupported: {
|
|
1148
|
+
source: true,
|
|
1149
|
+
destination: true,
|
|
1150
|
+
},
|
|
1151
|
+
},
|
|
1152
|
+
kitContracts: {
|
|
1153
|
+
bridge: '0x6D1AaE1c34Aeb582022916a67f2A655C6f4eDFF2', //Unique bridge address as CCTP address for Edge is also unique
|
|
1154
|
+
},
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
/**
|
|
1158
|
+
* Edge Testnet chain definition
|
|
1159
|
+
* @remarks
|
|
1160
|
+
* This represents the official test network for the Edge blockchain.
|
|
1161
|
+
* Edge is an EVM-compatible blockchain.
|
|
1162
|
+
*/
|
|
1163
|
+
const EdgeTestnet = defineChain({
|
|
1164
|
+
type: 'evm',
|
|
1165
|
+
chain: Blockchain.Edge_Testnet,
|
|
1166
|
+
name: 'Edge Testnet',
|
|
1167
|
+
title: 'Edge Testnet',
|
|
1168
|
+
nativeCurrency: {
|
|
1169
|
+
name: 'Ether',
|
|
1170
|
+
symbol: 'ETH',
|
|
1171
|
+
decimals: 18,
|
|
1172
|
+
},
|
|
1173
|
+
chainId: 33431,
|
|
1174
|
+
isTestnet: true,
|
|
1175
|
+
explorerUrl: 'https://edge-testnet.explorer.alchemy.com/tx/{hash}',
|
|
1176
|
+
rpcEndpoints: ['https://edge-testnet.g.alchemy.com/public'],
|
|
1177
|
+
eurcAddress: null,
|
|
1178
|
+
usdcAddress: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
1179
|
+
usdtAddress: null,
|
|
1180
|
+
cctp: {
|
|
1181
|
+
domain: 28,
|
|
1182
|
+
contracts: {
|
|
1183
|
+
v2: {
|
|
1184
|
+
type: 'split',
|
|
1185
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
1186
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
1187
|
+
confirmations: 65,
|
|
1188
|
+
fastConfirmations: 1,
|
|
1189
|
+
},
|
|
1190
|
+
},
|
|
1191
|
+
forwarderSupported: {
|
|
1192
|
+
source: true,
|
|
1193
|
+
destination: true,
|
|
1194
|
+
},
|
|
1195
|
+
},
|
|
1196
|
+
kitContracts: {
|
|
1197
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
1198
|
+
},
|
|
1199
|
+
});
|
|
1200
|
+
|
|
849
1201
|
/**
|
|
850
1202
|
* Ethereum Mainnet chain definition
|
|
851
1203
|
* @remarks
|
|
@@ -867,6 +1219,7 @@ const Ethereum = defineChain({
|
|
|
867
1219
|
rpcEndpoints: ['https://eth.merkle.io', 'https://ethereum.publicnode.com'],
|
|
868
1220
|
eurcAddress: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
869
1221
|
usdcAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
1222
|
+
usdtAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7',
|
|
870
1223
|
cctp: {
|
|
871
1224
|
domain: 0,
|
|
872
1225
|
contracts: {
|
|
@@ -891,6 +1244,7 @@ const Ethereum = defineChain({
|
|
|
891
1244
|
},
|
|
892
1245
|
kitContracts: {
|
|
893
1246
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1247
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
894
1248
|
},
|
|
895
1249
|
});
|
|
896
1250
|
|
|
@@ -915,6 +1269,7 @@ const EthereumSepolia = defineChain({
|
|
|
915
1269
|
rpcEndpoints: ['https://sepolia.drpc.org'],
|
|
916
1270
|
eurcAddress: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4',
|
|
917
1271
|
usdcAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
1272
|
+
usdtAddress: null,
|
|
918
1273
|
cctp: {
|
|
919
1274
|
domain: 0,
|
|
920
1275
|
contracts: {
|
|
@@ -962,6 +1317,7 @@ const Hedera = defineChain({
|
|
|
962
1317
|
rpcEndpoints: ['https://mainnet.hashio.io/api'],
|
|
963
1318
|
eurcAddress: null,
|
|
964
1319
|
usdcAddress: '0.0.456858',
|
|
1320
|
+
usdtAddress: null,
|
|
965
1321
|
cctp: null,
|
|
966
1322
|
});
|
|
967
1323
|
|
|
@@ -985,6 +1341,7 @@ const HederaTestnet = defineChain({
|
|
|
985
1341
|
rpcEndpoints: ['https://testnet.hashio.io/api'],
|
|
986
1342
|
eurcAddress: null,
|
|
987
1343
|
usdcAddress: '0.0.429274',
|
|
1344
|
+
usdtAddress: null,
|
|
988
1345
|
cctp: null,
|
|
989
1346
|
});
|
|
990
1347
|
|
|
@@ -1011,6 +1368,7 @@ const HyperEVM = defineChain({
|
|
|
1011
1368
|
rpcEndpoints: ['https://rpc.hyperliquid.xyz/evm'],
|
|
1012
1369
|
eurcAddress: null,
|
|
1013
1370
|
usdcAddress: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
1371
|
+
usdtAddress: null,
|
|
1014
1372
|
cctp: {
|
|
1015
1373
|
domain: 19,
|
|
1016
1374
|
contracts: {
|
|
@@ -1029,6 +1387,7 @@ const HyperEVM = defineChain({
|
|
|
1029
1387
|
},
|
|
1030
1388
|
kitContracts: {
|
|
1031
1389
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1390
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1032
1391
|
},
|
|
1033
1392
|
});
|
|
1034
1393
|
|
|
@@ -1054,6 +1413,7 @@ const HyperEVMTestnet = defineChain({
|
|
|
1054
1413
|
rpcEndpoints: ['https://rpc.hyperliquid-testnet.xyz/evm'],
|
|
1055
1414
|
eurcAddress: null,
|
|
1056
1415
|
usdcAddress: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
1416
|
+
usdtAddress: null,
|
|
1057
1417
|
cctp: {
|
|
1058
1418
|
domain: 19,
|
|
1059
1419
|
contracts: {
|
|
@@ -1101,6 +1461,7 @@ const Ink = defineChain({
|
|
|
1101
1461
|
],
|
|
1102
1462
|
eurcAddress: null,
|
|
1103
1463
|
usdcAddress: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
1464
|
+
usdtAddress: null,
|
|
1104
1465
|
cctp: {
|
|
1105
1466
|
domain: 21,
|
|
1106
1467
|
contracts: {
|
|
@@ -1119,6 +1480,7 @@ const Ink = defineChain({
|
|
|
1119
1480
|
},
|
|
1120
1481
|
kitContracts: {
|
|
1121
1482
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1483
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1122
1484
|
},
|
|
1123
1485
|
});
|
|
1124
1486
|
|
|
@@ -1147,6 +1509,7 @@ const InkTestnet = defineChain({
|
|
|
1147
1509
|
],
|
|
1148
1510
|
eurcAddress: null,
|
|
1149
1511
|
usdcAddress: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
1512
|
+
usdtAddress: null,
|
|
1150
1513
|
cctp: {
|
|
1151
1514
|
domain: 21,
|
|
1152
1515
|
contracts: {
|
|
@@ -1189,6 +1552,7 @@ const Linea = defineChain({
|
|
|
1189
1552
|
rpcEndpoints: ['https://rpc.linea.build'],
|
|
1190
1553
|
eurcAddress: null,
|
|
1191
1554
|
usdcAddress: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
1555
|
+
usdtAddress: null,
|
|
1192
1556
|
cctp: {
|
|
1193
1557
|
domain: 11,
|
|
1194
1558
|
contracts: {
|
|
@@ -1207,6 +1571,7 @@ const Linea = defineChain({
|
|
|
1207
1571
|
},
|
|
1208
1572
|
kitContracts: {
|
|
1209
1573
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1574
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1210
1575
|
},
|
|
1211
1576
|
});
|
|
1212
1577
|
|
|
@@ -1231,6 +1596,7 @@ const LineaSepolia = defineChain({
|
|
|
1231
1596
|
rpcEndpoints: ['https://rpc.sepolia.linea.build'],
|
|
1232
1597
|
eurcAddress: null,
|
|
1233
1598
|
usdcAddress: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
1599
|
+
usdtAddress: null,
|
|
1234
1600
|
cctp: {
|
|
1235
1601
|
domain: 11,
|
|
1236
1602
|
contracts: {
|
|
@@ -1275,6 +1641,7 @@ const Monad = defineChain({
|
|
|
1275
1641
|
rpcEndpoints: ['https://rpc.monad.xyz'],
|
|
1276
1642
|
eurcAddress: null,
|
|
1277
1643
|
usdcAddress: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
1644
|
+
usdtAddress: null,
|
|
1278
1645
|
cctp: {
|
|
1279
1646
|
domain: 15,
|
|
1280
1647
|
contracts: {
|
|
@@ -1293,6 +1660,7 @@ const Monad = defineChain({
|
|
|
1293
1660
|
},
|
|
1294
1661
|
kitContracts: {
|
|
1295
1662
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1663
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1296
1664
|
},
|
|
1297
1665
|
});
|
|
1298
1666
|
|
|
@@ -1319,6 +1687,7 @@ const MonadTestnet = defineChain({
|
|
|
1319
1687
|
rpcEndpoints: ['https://testnet-rpc.monad.xyz'],
|
|
1320
1688
|
eurcAddress: null,
|
|
1321
1689
|
usdcAddress: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
1690
|
+
usdtAddress: null,
|
|
1322
1691
|
cctp: {
|
|
1323
1692
|
domain: 15,
|
|
1324
1693
|
contracts: {
|
|
@@ -1340,6 +1709,94 @@ const MonadTestnet = defineChain({
|
|
|
1340
1709
|
},
|
|
1341
1710
|
});
|
|
1342
1711
|
|
|
1712
|
+
/**
|
|
1713
|
+
* Morph Mainnet chain definition
|
|
1714
|
+
* @remarks
|
|
1715
|
+
* This represents the official production network for the Morph blockchain.
|
|
1716
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
1717
|
+
*/
|
|
1718
|
+
const Morph = defineChain({
|
|
1719
|
+
type: 'evm',
|
|
1720
|
+
chain: Blockchain.Morph,
|
|
1721
|
+
name: 'Morph',
|
|
1722
|
+
title: 'Morph Mainnet',
|
|
1723
|
+
nativeCurrency: {
|
|
1724
|
+
name: 'Ether',
|
|
1725
|
+
symbol: 'ETH',
|
|
1726
|
+
decimals: 18,
|
|
1727
|
+
},
|
|
1728
|
+
chainId: 2818,
|
|
1729
|
+
isTestnet: false,
|
|
1730
|
+
explorerUrl: 'https://explorer.morph.network/tx/{hash}',
|
|
1731
|
+
rpcEndpoints: ['https://rpc.morphl2.io'],
|
|
1732
|
+
eurcAddress: null,
|
|
1733
|
+
usdcAddress: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
1734
|
+
usdtAddress: null,
|
|
1735
|
+
cctp: {
|
|
1736
|
+
domain: 30,
|
|
1737
|
+
contracts: {
|
|
1738
|
+
v2: {
|
|
1739
|
+
type: 'split',
|
|
1740
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
1741
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
1742
|
+
confirmations: 64,
|
|
1743
|
+
fastConfirmations: 1,
|
|
1744
|
+
},
|
|
1745
|
+
},
|
|
1746
|
+
forwarderSupported: {
|
|
1747
|
+
source: false,
|
|
1748
|
+
destination: false,
|
|
1749
|
+
},
|
|
1750
|
+
},
|
|
1751
|
+
kitContracts: {
|
|
1752
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1753
|
+
},
|
|
1754
|
+
});
|
|
1755
|
+
|
|
1756
|
+
/**
|
|
1757
|
+
* Morph Hoodi Testnet chain definition
|
|
1758
|
+
* @remarks
|
|
1759
|
+
* This represents the official test network for the Morph blockchain.
|
|
1760
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
1761
|
+
*/
|
|
1762
|
+
const MorphTestnet = defineChain({
|
|
1763
|
+
type: 'evm',
|
|
1764
|
+
chain: Blockchain.Morph_Testnet,
|
|
1765
|
+
name: 'Morph Hoodi',
|
|
1766
|
+
title: 'Morph Hoodi Testnet',
|
|
1767
|
+
nativeCurrency: {
|
|
1768
|
+
name: 'Ether',
|
|
1769
|
+
symbol: 'ETH',
|
|
1770
|
+
decimals: 18,
|
|
1771
|
+
},
|
|
1772
|
+
chainId: 2910,
|
|
1773
|
+
isTestnet: true,
|
|
1774
|
+
explorerUrl: 'https://explorer-hoodi.morphl2.io/tx/{hash}',
|
|
1775
|
+
rpcEndpoints: ['https://rpc-hoodi.morphl2.io'],
|
|
1776
|
+
eurcAddress: null,
|
|
1777
|
+
usdcAddress: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
1778
|
+
usdtAddress: null,
|
|
1779
|
+
cctp: {
|
|
1780
|
+
domain: 30,
|
|
1781
|
+
contracts: {
|
|
1782
|
+
v2: {
|
|
1783
|
+
type: 'split',
|
|
1784
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
1785
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
1786
|
+
confirmations: 64,
|
|
1787
|
+
fastConfirmations: 1,
|
|
1788
|
+
},
|
|
1789
|
+
},
|
|
1790
|
+
forwarderSupported: {
|
|
1791
|
+
source: false,
|
|
1792
|
+
destination: false,
|
|
1793
|
+
},
|
|
1794
|
+
},
|
|
1795
|
+
kitContracts: {
|
|
1796
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
1797
|
+
},
|
|
1798
|
+
});
|
|
1799
|
+
|
|
1343
1800
|
/**
|
|
1344
1801
|
* NEAR Protocol Mainnet chain definition
|
|
1345
1802
|
* @remarks
|
|
@@ -1360,6 +1817,7 @@ const NEAR = defineChain({
|
|
|
1360
1817
|
rpcEndpoints: ['https://eth-rpc.mainnet.near.org'],
|
|
1361
1818
|
eurcAddress: null,
|
|
1362
1819
|
usdcAddress: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
1820
|
+
usdtAddress: 'usdt.tether-token.near',
|
|
1363
1821
|
cctp: null,
|
|
1364
1822
|
});
|
|
1365
1823
|
|
|
@@ -1383,6 +1841,7 @@ const NEARTestnet = defineChain({
|
|
|
1383
1841
|
rpcEndpoints: ['https://eth-rpc.testnet.near.org'],
|
|
1384
1842
|
eurcAddress: null,
|
|
1385
1843
|
usdcAddress: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
1844
|
+
usdtAddress: null,
|
|
1386
1845
|
cctp: null,
|
|
1387
1846
|
});
|
|
1388
1847
|
|
|
@@ -1406,6 +1865,7 @@ const Noble = defineChain({
|
|
|
1406
1865
|
rpcEndpoints: ['https://noble-rpc.polkachu.com'],
|
|
1407
1866
|
eurcAddress: null,
|
|
1408
1867
|
usdcAddress: 'uusdc',
|
|
1868
|
+
usdtAddress: null,
|
|
1409
1869
|
cctp: {
|
|
1410
1870
|
domain: 4,
|
|
1411
1871
|
contracts: {
|
|
@@ -1442,6 +1902,7 @@ const NobleTestnet = defineChain({
|
|
|
1442
1902
|
rpcEndpoints: ['https://noble-testnet-rpc.polkachu.com'],
|
|
1443
1903
|
eurcAddress: null,
|
|
1444
1904
|
usdcAddress: 'uusdc',
|
|
1905
|
+
usdtAddress: null,
|
|
1445
1906
|
cctp: {
|
|
1446
1907
|
domain: 4,
|
|
1447
1908
|
contracts: {
|
|
@@ -1479,6 +1940,7 @@ const Optimism = defineChain({
|
|
|
1479
1940
|
rpcEndpoints: ['https://mainnet.optimism.io'],
|
|
1480
1941
|
eurcAddress: null,
|
|
1481
1942
|
usdcAddress: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
1943
|
+
usdtAddress: null,
|
|
1482
1944
|
cctp: {
|
|
1483
1945
|
domain: 2,
|
|
1484
1946
|
contracts: {
|
|
@@ -1503,6 +1965,7 @@ const Optimism = defineChain({
|
|
|
1503
1965
|
},
|
|
1504
1966
|
kitContracts: {
|
|
1505
1967
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1968
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1506
1969
|
},
|
|
1507
1970
|
});
|
|
1508
1971
|
|
|
@@ -1527,6 +1990,7 @@ const OptimismSepolia = defineChain({
|
|
|
1527
1990
|
rpcEndpoints: ['https://sepolia.optimism.io'],
|
|
1528
1991
|
eurcAddress: null,
|
|
1529
1992
|
usdcAddress: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
1993
|
+
usdtAddress: null,
|
|
1530
1994
|
cctp: {
|
|
1531
1995
|
domain: 2,
|
|
1532
1996
|
contracts: {
|
|
@@ -1577,6 +2041,7 @@ const Plume = defineChain({
|
|
|
1577
2041
|
rpcEndpoints: ['https://rpc.plume.org'],
|
|
1578
2042
|
eurcAddress: null,
|
|
1579
2043
|
usdcAddress: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
2044
|
+
usdtAddress: null,
|
|
1580
2045
|
cctp: {
|
|
1581
2046
|
domain: 22,
|
|
1582
2047
|
contracts: {
|
|
@@ -1595,6 +2060,7 @@ const Plume = defineChain({
|
|
|
1595
2060
|
},
|
|
1596
2061
|
kitContracts: {
|
|
1597
2062
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2063
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1598
2064
|
},
|
|
1599
2065
|
});
|
|
1600
2066
|
|
|
@@ -1620,6 +2086,7 @@ const PlumeTestnet = defineChain({
|
|
|
1620
2086
|
rpcEndpoints: ['https://testnet-rpc.plume.org'],
|
|
1621
2087
|
eurcAddress: null,
|
|
1622
2088
|
usdcAddress: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
2089
|
+
usdtAddress: null,
|
|
1623
2090
|
cctp: {
|
|
1624
2091
|
domain: 22,
|
|
1625
2092
|
contracts: {
|
|
@@ -1661,6 +2128,7 @@ const PolkadotAssetHub = defineChain({
|
|
|
1661
2128
|
rpcEndpoints: ['https://asset-hub-polkadot-rpc.n.dwellir.com'],
|
|
1662
2129
|
eurcAddress: null,
|
|
1663
2130
|
usdcAddress: '1337',
|
|
2131
|
+
usdtAddress: '1984',
|
|
1664
2132
|
cctp: null,
|
|
1665
2133
|
});
|
|
1666
2134
|
|
|
@@ -1684,6 +2152,7 @@ const PolkadotWestmint = defineChain({
|
|
|
1684
2152
|
rpcEndpoints: ['https://westmint-rpc.polkadot.io'],
|
|
1685
2153
|
eurcAddress: null,
|
|
1686
2154
|
usdcAddress: 'Asset ID 31337',
|
|
2155
|
+
usdtAddress: null,
|
|
1687
2156
|
cctp: null,
|
|
1688
2157
|
});
|
|
1689
2158
|
|
|
@@ -1705,9 +2174,10 @@ const Polygon = defineChain({
|
|
|
1705
2174
|
chainId: 137,
|
|
1706
2175
|
isTestnet: false,
|
|
1707
2176
|
explorerUrl: 'https://polygonscan.com/tx/{hash}',
|
|
1708
|
-
rpcEndpoints: ['https://polygon
|
|
2177
|
+
rpcEndpoints: ['https://polygon.publicnode.com', 'https://polygon.drpc.org'],
|
|
1709
2178
|
eurcAddress: null,
|
|
1710
2179
|
usdcAddress: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
2180
|
+
usdtAddress: null,
|
|
1711
2181
|
cctp: {
|
|
1712
2182
|
domain: 7,
|
|
1713
2183
|
contracts: {
|
|
@@ -1732,6 +2202,7 @@ const Polygon = defineChain({
|
|
|
1732
2202
|
},
|
|
1733
2203
|
kitContracts: {
|
|
1734
2204
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2205
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1735
2206
|
},
|
|
1736
2207
|
});
|
|
1737
2208
|
|
|
@@ -1756,6 +2227,7 @@ const PolygonAmoy = defineChain({
|
|
|
1756
2227
|
rpcEndpoints: ['https://rpc-amoy.polygon.technology'],
|
|
1757
2228
|
eurcAddress: null,
|
|
1758
2229
|
usdcAddress: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
2230
|
+
usdtAddress: null,
|
|
1759
2231
|
cctp: {
|
|
1760
2232
|
domain: 7,
|
|
1761
2233
|
contracts: {
|
|
@@ -1806,6 +2278,7 @@ const Sei = defineChain({
|
|
|
1806
2278
|
rpcEndpoints: ['https://evm-rpc.sei-apis.com'],
|
|
1807
2279
|
eurcAddress: null,
|
|
1808
2280
|
usdcAddress: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
2281
|
+
usdtAddress: null,
|
|
1809
2282
|
cctp: {
|
|
1810
2283
|
domain: 16,
|
|
1811
2284
|
contracts: {
|
|
@@ -1824,6 +2297,7 @@ const Sei = defineChain({
|
|
|
1824
2297
|
},
|
|
1825
2298
|
kitContracts: {
|
|
1826
2299
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2300
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1827
2301
|
},
|
|
1828
2302
|
});
|
|
1829
2303
|
|
|
@@ -1849,6 +2323,7 @@ const SeiTestnet = defineChain({
|
|
|
1849
2323
|
rpcEndpoints: ['https://evm-rpc-testnet.sei-apis.com'],
|
|
1850
2324
|
eurcAddress: null,
|
|
1851
2325
|
usdcAddress: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
2326
|
+
usdtAddress: null,
|
|
1852
2327
|
cctp: {
|
|
1853
2328
|
domain: 16,
|
|
1854
2329
|
contracts: {
|
|
@@ -1891,6 +2366,7 @@ const Sonic = defineChain({
|
|
|
1891
2366
|
rpcEndpoints: ['https://rpc.soniclabs.com'],
|
|
1892
2367
|
eurcAddress: null,
|
|
1893
2368
|
usdcAddress: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
2369
|
+
usdtAddress: null,
|
|
1894
2370
|
cctp: {
|
|
1895
2371
|
domain: 13,
|
|
1896
2372
|
contracts: {
|
|
@@ -1909,6 +2385,7 @@ const Sonic = defineChain({
|
|
|
1909
2385
|
},
|
|
1910
2386
|
kitContracts: {
|
|
1911
2387
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2388
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1912
2389
|
},
|
|
1913
2390
|
});
|
|
1914
2391
|
|
|
@@ -1933,6 +2410,7 @@ const SonicTestnet = defineChain({
|
|
|
1933
2410
|
rpcEndpoints: ['https://rpc.testnet.soniclabs.com'],
|
|
1934
2411
|
eurcAddress: null,
|
|
1935
2412
|
usdcAddress: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
2413
|
+
usdtAddress: null,
|
|
1936
2414
|
cctp: {
|
|
1937
2415
|
domain: 13,
|
|
1938
2416
|
contracts: {
|
|
@@ -1974,6 +2452,7 @@ const Solana = defineChain({
|
|
|
1974
2452
|
rpcEndpoints: ['https://api.mainnet-beta.solana.com'],
|
|
1975
2453
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
1976
2454
|
usdcAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
2455
|
+
usdtAddress: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
1977
2456
|
cctp: {
|
|
1978
2457
|
domain: 5,
|
|
1979
2458
|
contracts: {
|
|
@@ -2020,6 +2499,7 @@ const SolanaDevnet = defineChain({
|
|
|
2020
2499
|
explorerUrl: 'https://solscan.io/tx/{hash}?cluster=devnet',
|
|
2021
2500
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
2022
2501
|
usdcAddress: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
2502
|
+
usdtAddress: null,
|
|
2023
2503
|
cctp: {
|
|
2024
2504
|
domain: 5,
|
|
2025
2505
|
contracts: {
|
|
@@ -2068,6 +2548,7 @@ const Stellar = defineChain({
|
|
|
2068
2548
|
rpcEndpoints: ['https://horizon.stellar.org'],
|
|
2069
2549
|
eurcAddress: 'EURC-GDHU6WRG4IEQXM5NZ4BMPKOXHW76MZM4Y2IEMFDVXBSDP6SJY4ITNPP2',
|
|
2070
2550
|
usdcAddress: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
2551
|
+
usdtAddress: null,
|
|
2071
2552
|
cctp: null,
|
|
2072
2553
|
});
|
|
2073
2554
|
|
|
@@ -2091,6 +2572,7 @@ const StellarTestnet = defineChain({
|
|
|
2091
2572
|
rpcEndpoints: ['https://horizon-testnet.stellar.org'],
|
|
2092
2573
|
eurcAddress: 'EURC-GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO',
|
|
2093
2574
|
usdcAddress: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
2575
|
+
usdtAddress: null,
|
|
2094
2576
|
cctp: null,
|
|
2095
2577
|
});
|
|
2096
2578
|
|
|
@@ -2114,6 +2596,7 @@ const Sui = defineChain({
|
|
|
2114
2596
|
rpcEndpoints: ['https://fullnode.mainnet.sui.io'],
|
|
2115
2597
|
eurcAddress: null,
|
|
2116
2598
|
usdcAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
2599
|
+
usdtAddress: null,
|
|
2117
2600
|
cctp: {
|
|
2118
2601
|
domain: 8,
|
|
2119
2602
|
contracts: {
|
|
@@ -2151,6 +2634,7 @@ const SuiTestnet = defineChain({
|
|
|
2151
2634
|
rpcEndpoints: ['https://fullnode.testnet.sui.io'],
|
|
2152
2635
|
eurcAddress: null,
|
|
2153
2636
|
usdcAddress: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
2637
|
+
usdtAddress: null,
|
|
2154
2638
|
cctp: {
|
|
2155
2639
|
domain: 8,
|
|
2156
2640
|
contracts: {
|
|
@@ -2189,6 +2673,7 @@ const Unichain = defineChain({
|
|
|
2189
2673
|
rpcEndpoints: ['https://mainnet.unichain.org'],
|
|
2190
2674
|
eurcAddress: null,
|
|
2191
2675
|
usdcAddress: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
2676
|
+
usdtAddress: null,
|
|
2192
2677
|
cctp: {
|
|
2193
2678
|
domain: 10,
|
|
2194
2679
|
contracts: {
|
|
@@ -2213,6 +2698,7 @@ const Unichain = defineChain({
|
|
|
2213
2698
|
},
|
|
2214
2699
|
kitContracts: {
|
|
2215
2700
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2701
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2216
2702
|
},
|
|
2217
2703
|
});
|
|
2218
2704
|
|
|
@@ -2237,6 +2723,7 @@ const UnichainSepolia = defineChain({
|
|
|
2237
2723
|
rpcEndpoints: ['https://sepolia.unichain.org'],
|
|
2238
2724
|
eurcAddress: null,
|
|
2239
2725
|
usdcAddress: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
2726
|
+
usdtAddress: null,
|
|
2240
2727
|
cctp: {
|
|
2241
2728
|
domain: 10,
|
|
2242
2729
|
contracts: {
|
|
@@ -2285,6 +2772,7 @@ const WorldChain = defineChain({
|
|
|
2285
2772
|
rpcEndpoints: ['https://worldchain-mainnet.g.alchemy.com/public'],
|
|
2286
2773
|
eurcAddress: null,
|
|
2287
2774
|
usdcAddress: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
2775
|
+
usdtAddress: null,
|
|
2288
2776
|
cctp: {
|
|
2289
2777
|
domain: 14,
|
|
2290
2778
|
contracts: {
|
|
@@ -2303,6 +2791,7 @@ const WorldChain = defineChain({
|
|
|
2303
2791
|
},
|
|
2304
2792
|
kitContracts: {
|
|
2305
2793
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2794
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2306
2795
|
},
|
|
2307
2796
|
});
|
|
2308
2797
|
|
|
@@ -2330,6 +2819,7 @@ const WorldChainSepolia = defineChain({
|
|
|
2330
2819
|
],
|
|
2331
2820
|
eurcAddress: null,
|
|
2332
2821
|
usdcAddress: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
2822
|
+
usdtAddress: null,
|
|
2333
2823
|
cctp: {
|
|
2334
2824
|
domain: 14,
|
|
2335
2825
|
contracts: {
|
|
@@ -2374,6 +2864,7 @@ const XDC = defineChain({
|
|
|
2374
2864
|
rpcEndpoints: ['https://erpc.xdcrpc.com', 'https://erpc.xinfin.network'],
|
|
2375
2865
|
eurcAddress: null,
|
|
2376
2866
|
usdcAddress: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
2867
|
+
usdtAddress: null,
|
|
2377
2868
|
cctp: {
|
|
2378
2869
|
domain: 18,
|
|
2379
2870
|
contracts: {
|
|
@@ -2392,6 +2883,7 @@ const XDC = defineChain({
|
|
|
2392
2883
|
},
|
|
2393
2884
|
kitContracts: {
|
|
2394
2885
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2886
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2395
2887
|
},
|
|
2396
2888
|
});
|
|
2397
2889
|
|
|
@@ -2416,6 +2908,7 @@ const XDCApothem = defineChain({
|
|
|
2416
2908
|
rpcEndpoints: ['https://erpc.apothem.network'],
|
|
2417
2909
|
eurcAddress: null,
|
|
2418
2910
|
usdcAddress: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
2911
|
+
usdtAddress: null,
|
|
2419
2912
|
cctp: {
|
|
2420
2913
|
domain: 18,
|
|
2421
2914
|
contracts: {
|
|
@@ -2458,6 +2951,7 @@ const ZKSyncEra = defineChain({
|
|
|
2458
2951
|
rpcEndpoints: ['https://mainnet.era.zksync.io'],
|
|
2459
2952
|
eurcAddress: null,
|
|
2460
2953
|
usdcAddress: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
2954
|
+
usdtAddress: null,
|
|
2461
2955
|
cctp: null,
|
|
2462
2956
|
});
|
|
2463
2957
|
|
|
@@ -2482,6 +2976,7 @@ const ZKSyncEraSepolia = defineChain({
|
|
|
2482
2976
|
rpcEndpoints: ['https://sepolia.era.zksync.dev'],
|
|
2483
2977
|
eurcAddress: null,
|
|
2484
2978
|
usdcAddress: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
2979
|
+
usdtAddress: null,
|
|
2485
2980
|
cctp: null,
|
|
2486
2981
|
});
|
|
2487
2982
|
|
|
@@ -2502,6 +2997,8 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
2502
2997
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
2503
2998
|
Codex: Codex,
|
|
2504
2999
|
CodexTestnet: CodexTestnet,
|
|
3000
|
+
Edge: Edge,
|
|
3001
|
+
EdgeTestnet: EdgeTestnet,
|
|
2505
3002
|
Ethereum: Ethereum,
|
|
2506
3003
|
EthereumSepolia: EthereumSepolia,
|
|
2507
3004
|
Hedera: Hedera,
|
|
@@ -2514,6 +3011,8 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
2514
3011
|
LineaSepolia: LineaSepolia,
|
|
2515
3012
|
Monad: Monad,
|
|
2516
3013
|
MonadTestnet: MonadTestnet,
|
|
3014
|
+
Morph: Morph,
|
|
3015
|
+
MorphTestnet: MorphTestnet,
|
|
2517
3016
|
NEAR: NEAR,
|
|
2518
3017
|
NEARTestnet: NEARTestnet,
|
|
2519
3018
|
Noble: Noble,
|
|
@@ -2649,10 +3148,12 @@ const baseChainDefinitionSchema = z.object({
|
|
|
2649
3148
|
rpcEndpoints: z.array(z.string()),
|
|
2650
3149
|
eurcAddress: z.string().nullable(),
|
|
2651
3150
|
usdcAddress: z.string().nullable(),
|
|
3151
|
+
usdtAddress: z.string().nullable(),
|
|
2652
3152
|
cctp: z.any().nullable(), // We'll accept any CCTP config structure
|
|
2653
3153
|
kitContracts: z
|
|
2654
3154
|
.object({
|
|
2655
3155
|
bridge: z.string().optional(),
|
|
3156
|
+
adapter: z.string().optional(),
|
|
2656
3157
|
})
|
|
2657
3158
|
.optional(),
|
|
2658
3159
|
});
|
|
@@ -2767,6 +3268,29 @@ z.union([
|
|
|
2767
3268
|
z.nativeEnum(Blockchain),
|
|
2768
3269
|
chainDefinitionSchema$2,
|
|
2769
3270
|
]);
|
|
3271
|
+
/**
|
|
3272
|
+
* Zod schema for validating swap-specific chain identifiers.
|
|
3273
|
+
*
|
|
3274
|
+
* Validates chains based on:
|
|
3275
|
+
* - CCTPv2 support (adapter contract deployed)
|
|
3276
|
+
* - Mainnet only (no testnets)
|
|
3277
|
+
* - At least one supported token available
|
|
3278
|
+
*
|
|
3279
|
+
*/
|
|
3280
|
+
z.union([
|
|
3281
|
+
// String blockchain identifier (accepts SwapChain enum values)
|
|
3282
|
+
z.string().refine((val) => val in SwapChain, (val) => ({
|
|
3283
|
+
message: `"${val}" is not a supported swap chain. ` +
|
|
3284
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
3285
|
+
})),
|
|
3286
|
+
// SwapChain enum
|
|
3287
|
+
z.nativeEnum(SwapChain),
|
|
3288
|
+
// ChainDefinition object (checks if chain.chain is in SwapChain)
|
|
3289
|
+
chainDefinitionSchema$2.refine((chain) => chain.chain in SwapChain, (chain) => ({
|
|
3290
|
+
message: `"${chain.chain}" is not a supported swap chain. ` +
|
|
3291
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
3292
|
+
})),
|
|
3293
|
+
]);
|
|
2770
3294
|
/**
|
|
2771
3295
|
* Zod schema for validating bridge chain identifiers.
|
|
2772
3296
|
*
|
|
@@ -2806,6 +3330,38 @@ z.union([
|
|
|
2806
3330
|
})),
|
|
2807
3331
|
]);
|
|
2808
3332
|
|
|
3333
|
+
/**
|
|
3334
|
+
* @packageDocumentation
|
|
3335
|
+
* @module SwapTokenSchemas
|
|
3336
|
+
*
|
|
3337
|
+
* Zod validation schemas for supported swap tokens.
|
|
3338
|
+
*/
|
|
3339
|
+
// Internal enum used after input normalization.
|
|
3340
|
+
const swapTokenEnumSchema = z.enum([
|
|
3341
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
3342
|
+
NATIVE_TOKEN,
|
|
3343
|
+
]);
|
|
3344
|
+
/**
|
|
3345
|
+
* Zod schema for validating supported swap token symbols.
|
|
3346
|
+
*
|
|
3347
|
+
* Accepts any token symbol from the SWAP_TOKEN_REGISTRY plus NATIVE.
|
|
3348
|
+
* Input matching is case-insensitive and normalized to uppercase.
|
|
3349
|
+
*
|
|
3350
|
+
* @example
|
|
3351
|
+
* ```typescript
|
|
3352
|
+
* import { supportedSwapTokenSchema } from '@core/chains'
|
|
3353
|
+
*
|
|
3354
|
+
* const result = supportedSwapTokenSchema.safeParse('USDC')
|
|
3355
|
+
* if (result.success) {
|
|
3356
|
+
* console.log('Valid swap token:', result.data)
|
|
3357
|
+
* }
|
|
3358
|
+
* ```
|
|
3359
|
+
*/
|
|
3360
|
+
z
|
|
3361
|
+
.string()
|
|
3362
|
+
.transform((value) => value.toUpperCase())
|
|
3363
|
+
.pipe(swapTokenEnumSchema);
|
|
3364
|
+
|
|
2809
3365
|
/**
|
|
2810
3366
|
* Retrieve a chain definition by its blockchain enum value.
|
|
2811
3367
|
*
|
|
@@ -2860,6 +3416,11 @@ const getChainByEnum = (blockchain) => {
|
|
|
2860
3416
|
* ```
|
|
2861
3417
|
*/
|
|
2862
3418
|
function resolveChainIdentifier(chainIdentifier) {
|
|
3419
|
+
// Handle null explicitly (typeof null === 'object' in JavaScript)
|
|
3420
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
3421
|
+
if (chainIdentifier === null) {
|
|
3422
|
+
throw new Error(`Invalid chain identifier type: null. Expected ChainDefinition object, Blockchain enum, or string literal.`);
|
|
3423
|
+
}
|
|
2863
3424
|
// If it's already a ChainDefinition object, return it unchanged
|
|
2864
3425
|
if (typeof chainIdentifier === 'object') {
|
|
2865
3426
|
return chainIdentifier;
|
|
@@ -3151,11 +3712,11 @@ const formatComponent = (nameWithVersion) => {
|
|
|
3151
3712
|
const createRequestContext = () => {
|
|
3152
3713
|
const context = {};
|
|
3153
3714
|
if (typeof globalThis !== 'undefined') {
|
|
3154
|
-
if (globalThis.
|
|
3155
|
-
context.externalPrefix = globalThis.
|
|
3715
|
+
if (globalThis.__APP_KITS_EXTERNAL_PREFIX__ !== undefined) {
|
|
3716
|
+
context.externalPrefix = globalThis.__APP_KITS_EXTERNAL_PREFIX__;
|
|
3156
3717
|
}
|
|
3157
|
-
if (globalThis.
|
|
3158
|
-
context.kit = globalThis.
|
|
3718
|
+
if (globalThis.__APP_KITS_CURRENT_KIT__ !== undefined) {
|
|
3719
|
+
context.kit = globalThis.__APP_KITS_CURRENT_KIT__;
|
|
3159
3720
|
}
|
|
3160
3721
|
}
|
|
3161
3722
|
return context;
|
|
@@ -3261,6 +3822,10 @@ const ERROR_TYPES = {
|
|
|
3261
3822
|
RPC: 'RPC',
|
|
3262
3823
|
/** Internet connectivity, DNS resolution, connection issues */
|
|
3263
3824
|
NETWORK: 'NETWORK',
|
|
3825
|
+
/** API throttling, request frequency limits errors */
|
|
3826
|
+
RATE_LIMIT: 'RATE_LIMIT',
|
|
3827
|
+
/** Service errors */
|
|
3828
|
+
SERVICE: 'SERVICE',
|
|
3264
3829
|
/** Catch-all for unrecognized errors (code 0) */
|
|
3265
3830
|
UNKNOWN: 'UNKNOWN',
|
|
3266
3831
|
};
|
|
@@ -3284,6 +3849,8 @@ const ERROR_CODE_RANGES = [
|
|
|
3284
3849
|
{ min: 3000, max: 3999, type: 'NETWORK' },
|
|
3285
3850
|
{ min: 4000, max: 4999, type: 'RPC' },
|
|
3286
3851
|
{ min: 5000, max: 5999, type: 'ONCHAIN' },
|
|
3852
|
+
{ min: 7000, max: 7999, type: 'RATE_LIMIT' },
|
|
3853
|
+
{ min: 8000, max: 8999, type: 'SERVICE' },
|
|
3287
3854
|
{ min: 9000, max: 9999, type: 'BALANCE' },
|
|
3288
3855
|
];
|
|
3289
3856
|
/** Special code for UNKNOWN errors */
|
|
@@ -3331,6 +3898,8 @@ const errorDetailsSchema = z.object({
|
|
|
3331
3898
|
* - 3000-3999: NETWORK errors - Connectivity issues
|
|
3332
3899
|
* - 4000-4999: RPC errors - Provider issues, gas estimation
|
|
3333
3900
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures
|
|
3901
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling
|
|
3902
|
+
* - 8000-8999: SERVICE errors - Internal service errors
|
|
3334
3903
|
* - 9000-9999: BALANCE errors - Insufficient funds
|
|
3335
3904
|
*/
|
|
3336
3905
|
code: z
|
|
@@ -3439,11 +4008,11 @@ const AMOUNT_FORMAT_ERROR_MESSAGE = 'Amount must be a numeric string with dot (.
|
|
|
3439
4008
|
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
4009
|
|
|
3441
4010
|
/**
|
|
3442
|
-
* Structured error class for
|
|
4011
|
+
* Structured error class for App Kit operations.
|
|
3443
4012
|
*
|
|
3444
4013
|
* This class extends the native Error class while implementing the ErrorDetails
|
|
3445
4014
|
* interface, providing a consistent error format for programmatic handling
|
|
3446
|
-
* across the
|
|
4015
|
+
* across the App Kits ecosystem. All properties are immutable to ensure
|
|
3447
4016
|
* error objects cannot be modified after creation.
|
|
3448
4017
|
*
|
|
3449
4018
|
* @example
|
|
@@ -3453,6 +4022,7 @@ const MAX_FEE_FORMAT_ERROR_MESSAGE = 'maxFee must be a numeric string with dot (
|
|
|
3453
4022
|
* const error = new KitError({
|
|
3454
4023
|
* code: 1001,
|
|
3455
4024
|
* name: 'INPUT_NETWORK_MISMATCH',
|
|
4025
|
+
* type: 'INPUT',
|
|
3456
4026
|
* recoverability: 'FATAL',
|
|
3457
4027
|
* message: 'Cannot bridge between mainnet and testnet'
|
|
3458
4028
|
* })
|
|
@@ -3470,7 +4040,8 @@ const MAX_FEE_FORMAT_ERROR_MESSAGE = 'maxFee must be a numeric string with dot (
|
|
|
3470
4040
|
* // Error with cause information
|
|
3471
4041
|
* const error = new KitError({
|
|
3472
4042
|
* code: 1002,
|
|
3473
|
-
* name: '
|
|
4043
|
+
* name: 'INPUT_INVALID_AMOUNT',
|
|
4044
|
+
* type: 'INPUT',
|
|
3474
4045
|
* recoverability: 'FATAL',
|
|
3475
4046
|
* message: 'Amount must be greater than zero',
|
|
3476
4047
|
* cause: {
|
|
@@ -3554,6 +4125,8 @@ class KitError extends Error {
|
|
|
3554
4125
|
* - 3000-3999: NETWORK errors - Internet connectivity, DNS, connection issues
|
|
3555
4126
|
* - 4000-4999: RPC errors - Blockchain provider issues, gas estimation, nonce errors
|
|
3556
4127
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures, gas exhaustion, reverts
|
|
4128
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling, request frequency limits
|
|
4129
|
+
* - 8000-8999: SERVICE errors - Internal service errors, server failures
|
|
3557
4130
|
* - 9000-9999: BALANCE errors - Insufficient funds, token balance, allowance
|
|
3558
4131
|
*/
|
|
3559
4132
|
/**
|
|
@@ -3614,10 +4187,22 @@ const InputError = {
|
|
|
3614
4187
|
name: 'INPUT_INVALID_CHAIN',
|
|
3615
4188
|
type: 'INPUT',
|
|
3616
4189
|
},
|
|
3617
|
-
/**
|
|
3618
|
-
|
|
4190
|
+
/** Unsupported token for chain */
|
|
4191
|
+
UNSUPPORTED_TOKEN: {
|
|
3619
4192
|
code: 1006,
|
|
3620
|
-
name: '
|
|
4193
|
+
name: 'INPUT_UNSUPPORTED_TOKEN',
|
|
4194
|
+
type: 'INPUT',
|
|
4195
|
+
},
|
|
4196
|
+
/** Insufficient swap amount for the token pair */
|
|
4197
|
+
INSUFFICIENT_SWAP_AMOUNT: {
|
|
4198
|
+
code: 1007,
|
|
4199
|
+
name: 'INPUT_INSUFFICIENT_SWAP_AMOUNT',
|
|
4200
|
+
type: 'INPUT',
|
|
4201
|
+
},
|
|
4202
|
+
/** Action not supported by this adapter / ecosystem */
|
|
4203
|
+
UNSUPPORTED_ACTION: {
|
|
4204
|
+
code: 1008,
|
|
4205
|
+
name: 'INPUT_UNSUPPORTED_ACTION',
|
|
3621
4206
|
type: 'INPUT',
|
|
3622
4207
|
},
|
|
3623
4208
|
/** General validation failure for complex validation rules */
|
|
@@ -3626,6 +4211,12 @@ const InputError = {
|
|
|
3626
4211
|
name: 'INPUT_VALIDATION_FAILED',
|
|
3627
4212
|
type: 'INPUT',
|
|
3628
4213
|
},
|
|
4214
|
+
/** User cancelled wallet interaction (signature, transaction, connection) */
|
|
4215
|
+
USER_CANCELLED: {
|
|
4216
|
+
code: 1099,
|
|
4217
|
+
name: 'INPUT_USER_CANCELLED',
|
|
4218
|
+
type: 'INPUT',
|
|
4219
|
+
},
|
|
3629
4220
|
};
|
|
3630
4221
|
/**
|
|
3631
4222
|
* Standardized error definitions for BALANCE type errors.
|
|
@@ -3713,8 +4304,7 @@ const NetworkError = {
|
|
|
3713
4304
|
code: 3004,
|
|
3714
4305
|
name: 'NETWORK_RELAYER_PENDING',
|
|
3715
4306
|
type: 'NETWORK',
|
|
3716
|
-
}
|
|
3717
|
-
};
|
|
4307
|
+
}};
|
|
3718
4308
|
|
|
3719
4309
|
/**
|
|
3720
4310
|
* Creates error for network type mismatch between source and destination.
|
|
@@ -3801,7 +4391,7 @@ function createInvalidChainError(chain, reason) {
|
|
|
3801
4391
|
const errorDetails = {
|
|
3802
4392
|
...InputError.INVALID_CHAIN,
|
|
3803
4393
|
recoverability: 'FATAL',
|
|
3804
|
-
message: `Invalid chain '${chain}': ${reason}
|
|
4394
|
+
message: `Invalid chain '${chain}': ${reason}.`,
|
|
3805
4395
|
cause: {
|
|
3806
4396
|
trace: { chain, reason },
|
|
3807
4397
|
},
|
|
@@ -4150,6 +4740,9 @@ function getErrorMessage(error) {
|
|
|
4150
4740
|
if (typeof error === 'string') {
|
|
4151
4741
|
return error;
|
|
4152
4742
|
}
|
|
4743
|
+
if (typeof error === 'object' && error !== null && 'message' in error) {
|
|
4744
|
+
return String(error.message);
|
|
4745
|
+
}
|
|
4153
4746
|
return 'An unknown error occurred';
|
|
4154
4747
|
}
|
|
4155
4748
|
/**
|
|
@@ -4206,6 +4799,9 @@ function extractErrorInfo(error) {
|
|
|
4206
4799
|
if (typeof err.code === 'number') {
|
|
4207
4800
|
info.code = err.code;
|
|
4208
4801
|
}
|
|
4802
|
+
if (isKitError(error)) {
|
|
4803
|
+
info.type = error.type;
|
|
4804
|
+
}
|
|
4209
4805
|
return info;
|
|
4210
4806
|
}
|
|
4211
4807
|
|
|
@@ -4328,7 +4924,17 @@ const makeApiRequest = async (url, method, isValidType, config, body) => {
|
|
|
4328
4924
|
const response = await fetch(url, requestInit);
|
|
4329
4925
|
clearTimeout(timeoutId);
|
|
4330
4926
|
if (!response.ok) {
|
|
4331
|
-
|
|
4927
|
+
let responseBody;
|
|
4928
|
+
try {
|
|
4929
|
+
responseBody = (await response.json());
|
|
4930
|
+
}
|
|
4931
|
+
catch {
|
|
4932
|
+
// Parse response body for diagnostics; continue even if malformed
|
|
4933
|
+
// so callers always receive HTTP status context
|
|
4934
|
+
}
|
|
4935
|
+
const httpError = new Error(`HTTP ${String(response.status)} - ${response.statusText}`);
|
|
4936
|
+
httpError.responseBody = responseBody;
|
|
4937
|
+
throw httpError;
|
|
4332
4938
|
}
|
|
4333
4939
|
const parsedJson = (await response.json());
|
|
4334
4940
|
if (!isValidType(parsedJson)) {
|
|
@@ -4900,7 +5506,7 @@ const convertAddress = (address, targetFormat) => {
|
|
|
4900
5506
|
*
|
|
4901
5507
|
* This function normalizes token values from their blockchain representation (where
|
|
4902
5508
|
* everything is stored as integers in the smallest denomination) to human-readable
|
|
4903
|
-
* decimal format. Uses the battle-tested implementation from
|
|
5509
|
+
* decimal format. Uses the battle-tested implementation from \@ethersproject/units.
|
|
4904
5510
|
*
|
|
4905
5511
|
* @param value - The value in smallest units (e.g., "1000000" for 1 USDC with 6 decimals)
|
|
4906
5512
|
* @param decimals - The number of decimal places for the unit conversion
|
|
@@ -4929,357 +5535,1082 @@ const formatUnits = (value, decimals) => {
|
|
|
4929
5535
|
};
|
|
4930
5536
|
|
|
4931
5537
|
/**
|
|
4932
|
-
*
|
|
5538
|
+
* Create a structured error for token resolution failures.
|
|
4933
5539
|
*
|
|
4934
|
-
*
|
|
4935
|
-
*
|
|
4936
|
-
*
|
|
5540
|
+
* @remarks
|
|
5541
|
+
* Returns a `KitError` with `INPUT_UNSUPPORTED_TOKEN` code (1006).
|
|
5542
|
+
* The error trace contains the selector and chain context for debugging.
|
|
4937
5543
|
*
|
|
4938
|
-
* @param
|
|
4939
|
-
* @param
|
|
4940
|
-
* @
|
|
4941
|
-
* @
|
|
4942
|
-
* @
|
|
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.
|
|
5544
|
+
* @param message - Human-readable error description.
|
|
5545
|
+
* @param selector - The token selector that failed to resolve.
|
|
5546
|
+
* @param chainId - The chain being resolved for (optional).
|
|
5547
|
+
* @param cause - The underlying error, if any (optional).
|
|
5548
|
+
* @returns A KitError with INPUT type and FATAL recoverability.
|
|
4946
5549
|
*
|
|
4947
5550
|
* @example
|
|
4948
5551
|
* ```typescript
|
|
4949
|
-
*
|
|
4950
|
-
*
|
|
4951
|
-
*
|
|
4952
|
-
*
|
|
4953
|
-
*
|
|
4954
|
-
* console.log(url) // 'https://etherscan.io/tx/0x1234567890abcdef...'
|
|
5552
|
+
* throw createTokenResolutionError(
|
|
5553
|
+
* 'Unknown token symbol: FAKE',
|
|
5554
|
+
* 'FAKE',
|
|
5555
|
+
* 'Ethereum'
|
|
5556
|
+
* )
|
|
4955
5557
|
* ```
|
|
5558
|
+
*/
|
|
5559
|
+
function createTokenResolutionError(message, selector, chainId, cause) {
|
|
5560
|
+
const trace = {
|
|
5561
|
+
selector,
|
|
5562
|
+
...(chainId === undefined ? {} : { chainId }),
|
|
5563
|
+
...({} ),
|
|
5564
|
+
};
|
|
5565
|
+
return new KitError({
|
|
5566
|
+
...InputError.UNSUPPORTED_TOKEN,
|
|
5567
|
+
recoverability: 'FATAL',
|
|
5568
|
+
message,
|
|
5569
|
+
cause: { trace },
|
|
5570
|
+
});
|
|
5571
|
+
}
|
|
5572
|
+
|
|
5573
|
+
/**
|
|
5574
|
+
* USDC token definition with addresses and metadata.
|
|
4956
5575
|
*
|
|
4957
|
-
* @
|
|
4958
|
-
*
|
|
4959
|
-
*
|
|
4960
|
-
* import { Solana } from '@core/chains'
|
|
5576
|
+
* @remarks
|
|
5577
|
+
* This is the built-in USDC definition used by the TokenRegistry.
|
|
5578
|
+
* Includes all known USDC addresses across supported chains.
|
|
4961
5579
|
*
|
|
4962
|
-
*
|
|
4963
|
-
*
|
|
4964
|
-
*
|
|
4965
|
-
* ```
|
|
5580
|
+
* Keys use the `Blockchain` enum for type safety. Both enum values
|
|
5581
|
+
* and string literals are supported:
|
|
5582
|
+
* - `Blockchain.Ethereum` or `'Ethereum'`
|
|
4966
5583
|
*
|
|
4967
5584
|
* @example
|
|
4968
5585
|
* ```typescript
|
|
4969
|
-
* import {
|
|
4970
|
-
* import {
|
|
5586
|
+
* import { USDC } from '@core/tokens'
|
|
5587
|
+
* import { Blockchain } from '@core/chains'
|
|
4971
5588
|
*
|
|
4972
|
-
* //
|
|
4973
|
-
*
|
|
4974
|
-
* console.log(
|
|
5589
|
+
* console.log(USDC.symbol) // 'USDC'
|
|
5590
|
+
* console.log(USDC.decimals) // 6
|
|
5591
|
+
* console.log(USDC.locators[Blockchain.Ethereum])
|
|
5592
|
+
* // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
4975
5593
|
* ```
|
|
4976
5594
|
*/
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
5595
|
+
const USDC = {
|
|
5596
|
+
symbol: 'USDC',
|
|
5597
|
+
decimals: 6,
|
|
5598
|
+
locators: {
|
|
5599
|
+
// =========================================================================
|
|
5600
|
+
// Mainnets (alphabetically sorted)
|
|
5601
|
+
// =========================================================================
|
|
5602
|
+
[Blockchain.Arbitrum]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
5603
|
+
[Blockchain.Avalanche]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
5604
|
+
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
5605
|
+
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
5606
|
+
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
5607
|
+
[Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
5608
|
+
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
5609
|
+
[Blockchain.Hedera]: '0.0.456858',
|
|
5610
|
+
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
5611
|
+
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
5612
|
+
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
5613
|
+
[Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
5614
|
+
[Blockchain.Morph]: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
5615
|
+
[Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
5616
|
+
[Blockchain.Noble]: 'uusdc',
|
|
5617
|
+
[Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
5618
|
+
[Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
5619
|
+
[Blockchain.Polkadot_Asset_Hub]: '1337',
|
|
5620
|
+
[Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
5621
|
+
[Blockchain.Sei]: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
5622
|
+
[Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
5623
|
+
[Blockchain.Sonic]: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
5624
|
+
[Blockchain.Stellar]: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
5625
|
+
[Blockchain.Sui]: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
5626
|
+
[Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
5627
|
+
[Blockchain.World_Chain]: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
5628
|
+
[Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
5629
|
+
[Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
5630
|
+
// =========================================================================
|
|
5631
|
+
// Testnets (alphabetically sorted)
|
|
5632
|
+
// =========================================================================
|
|
5633
|
+
[Blockchain.Arbitrum_Sepolia]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
5634
|
+
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
5635
|
+
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
5636
|
+
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
5637
|
+
[Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
5638
|
+
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
5639
|
+
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
5640
|
+
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
5641
|
+
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
5642
|
+
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
5643
|
+
[Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
5644
|
+
[Blockchain.Morph_Testnet]: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
5645
|
+
[Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
5646
|
+
[Blockchain.Noble_Testnet]: 'uusdc',
|
|
5647
|
+
[Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
5648
|
+
[Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
5649
|
+
[Blockchain.Polkadot_Westmint]: '31337',
|
|
5650
|
+
[Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
5651
|
+
[Blockchain.Sei_Testnet]: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
5652
|
+
[Blockchain.Solana_Devnet]: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
5653
|
+
[Blockchain.Sonic_Testnet]: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
5654
|
+
[Blockchain.Stellar_Testnet]: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
5655
|
+
[Blockchain.Sui_Testnet]: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
5656
|
+
[Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
5657
|
+
[Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
5658
|
+
[Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
5659
|
+
[Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
5660
|
+
},
|
|
5661
|
+
};
|
|
4988
5662
|
|
|
4989
5663
|
/**
|
|
4990
|
-
*
|
|
5664
|
+
* USDT (Tether) token definition with addresses and metadata.
|
|
4991
5665
|
*
|
|
4992
|
-
*
|
|
4993
|
-
*
|
|
5666
|
+
* @remarks
|
|
5667
|
+
* Built-in USDT definition for the TokenRegistry. Includes chain locators
|
|
5668
|
+
* for swap-supported chains.
|
|
4994
5669
|
*/
|
|
4995
|
-
const
|
|
5670
|
+
const USDT = {
|
|
5671
|
+
symbol: 'USDT',
|
|
5672
|
+
decimals: 6,
|
|
5673
|
+
locators: {
|
|
5674
|
+
[Blockchain.Aptos]: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
5675
|
+
[Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
|
|
5676
|
+
[Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
|
|
5677
|
+
[Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
5678
|
+
[Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
|
5679
|
+
[Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
|
|
5680
|
+
[Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
|
|
5681
|
+
[Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
|
|
5682
|
+
[Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
|
|
5683
|
+
[Blockchain.NEAR]: 'usdt.tether-token.near',
|
|
5684
|
+
[Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
|
|
5685
|
+
[Blockchain.Polkadot_Asset_Hub]: '1984',
|
|
5686
|
+
[Blockchain.Polygon]: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
|
5687
|
+
[Blockchain.Sei]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
5688
|
+
[Blockchain.Solana]: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
5689
|
+
[Blockchain.Unichain]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
5690
|
+
},
|
|
5691
|
+
};
|
|
5692
|
+
|
|
4996
5693
|
/**
|
|
4997
|
-
*
|
|
5694
|
+
* EURC (Euro Coin) token definition with addresses and metadata.
|
|
4998
5695
|
*
|
|
4999
|
-
*
|
|
5696
|
+
* @remarks
|
|
5697
|
+
* Built-in EURC definition for the TokenRegistry. Includes chain locators
|
|
5698
|
+
* for swap-supported chains.
|
|
5000
5699
|
*/
|
|
5001
|
-
const
|
|
5700
|
+
const EURC = {
|
|
5701
|
+
symbol: 'EURC',
|
|
5702
|
+
decimals: 6,
|
|
5703
|
+
locators: {
|
|
5704
|
+
[Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
5705
|
+
[Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
5706
|
+
[Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
5707
|
+
[Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
5708
|
+
[Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
5709
|
+
},
|
|
5710
|
+
};
|
|
5711
|
+
|
|
5002
5712
|
/**
|
|
5003
|
-
*
|
|
5713
|
+
* DAI (Maker DAO) stablecoin token definition with addresses and metadata.
|
|
5004
5714
|
*
|
|
5005
|
-
*
|
|
5715
|
+
* @remarks
|
|
5716
|
+
* Built-in DAI definition for the TokenRegistry. Includes chain locators
|
|
5717
|
+
* for swap-supported chains.
|
|
5006
5718
|
*/
|
|
5007
|
-
const
|
|
5719
|
+
const DAI = {
|
|
5720
|
+
symbol: 'DAI',
|
|
5721
|
+
decimals: 18,
|
|
5722
|
+
chainDecimals: {
|
|
5723
|
+
[Blockchain.Solana]: 8,
|
|
5724
|
+
},
|
|
5725
|
+
locators: {
|
|
5726
|
+
[Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
5727
|
+
[Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
|
|
5728
|
+
[Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
|
|
5729
|
+
[Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
5730
|
+
[Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
|
|
5731
|
+
[Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
5732
|
+
[Blockchain.Polygon]: '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063',
|
|
5733
|
+
[Blockchain.Solana]: 'EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o',
|
|
5734
|
+
},
|
|
5735
|
+
};
|
|
5736
|
+
|
|
5008
5737
|
/**
|
|
5009
|
-
*
|
|
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.
|
|
5013
|
-
*
|
|
5014
|
-
* The hookData format is:
|
|
5015
|
-
* - Bytes 0-23: ASCII "cctp-forward" right-padded to 24 bytes with zeros
|
|
5016
|
-
* - Bytes 24-27: uint32 version (big-endian) - currently 0
|
|
5017
|
-
* - Bytes 28-31: uint32 length (big-endian) - 0 for basic forwarding
|
|
5018
|
-
*
|
|
5019
|
-
* @returns A 0x-prefixed hex string representing the 32-byte hookData
|
|
5020
|
-
*
|
|
5021
|
-
* @example
|
|
5022
|
-
* ```typescript
|
|
5023
|
-
* import { buildForwardingHookData } from '@core/utils'
|
|
5738
|
+
* USDe (Ethena) synthetic dollar token definition with addresses and metadata.
|
|
5024
5739
|
*
|
|
5025
|
-
*
|
|
5026
|
-
*
|
|
5740
|
+
* @remarks
|
|
5741
|
+
* Built-in USDE definition for the TokenRegistry. Includes chain locators
|
|
5742
|
+
* for swap-supported chains.
|
|
5743
|
+
*/
|
|
5744
|
+
const USDE = {
|
|
5745
|
+
symbol: 'USDe',
|
|
5746
|
+
decimals: 18,
|
|
5747
|
+
chainDecimals: {
|
|
5748
|
+
[Blockchain.Solana]: 9,
|
|
5749
|
+
},
|
|
5750
|
+
locators: {
|
|
5751
|
+
[Blockchain.Arbitrum]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5752
|
+
[Blockchain.Base]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5753
|
+
[Blockchain.Ethereum]: '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3',
|
|
5754
|
+
[Blockchain.Linea]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5755
|
+
[Blockchain.Optimism]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5756
|
+
[Blockchain.Solana]: 'DEkqHyPN7GMRJ5cArtQFAWefqbZb33Hyf6s5iCwjEonT',
|
|
5757
|
+
},
|
|
5758
|
+
};
|
|
5759
|
+
|
|
5760
|
+
/**
|
|
5761
|
+
* PYUSD (PayPal USD) stablecoin token definition with addresses and metadata.
|
|
5027
5762
|
*
|
|
5028
|
-
*
|
|
5029
|
-
*
|
|
5030
|
-
*
|
|
5031
|
-
* mintRecipient: '0x...',
|
|
5032
|
-
* maxFee: BigInt('50000'),
|
|
5033
|
-
* minFinalityThreshold: 1000,
|
|
5034
|
-
* fromChain: ethereum,
|
|
5035
|
-
* toChain: base,
|
|
5036
|
-
* hookData
|
|
5037
|
-
* })
|
|
5038
|
-
* ```
|
|
5763
|
+
* @remarks
|
|
5764
|
+
* Built-in PYUSD definition for the TokenRegistry. Includes chain locators
|
|
5765
|
+
* for swap-supported chains.
|
|
5039
5766
|
*/
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
// Write the magic prefix ("cctp-forward") - 12 bytes, rest of 24-byte section is zero-padded
|
|
5050
|
-
const encoder = new TextEncoder();
|
|
5051
|
-
const magicBytes = encoder.encode(CCTP_FORWARD_MAGIC_PREFIX);
|
|
5052
|
-
buffer.set(magicBytes, 0);
|
|
5053
|
-
// Bytes 12-23 are already zero (right-padding)
|
|
5054
|
-
// Write uint32 version at bytes 24-27 (big-endian)
|
|
5055
|
-
const versionView = new DataView(buffer.buffer);
|
|
5056
|
-
versionView.setUint32(24, CCTP_FORWARD_VERSION, false); // false = big-endian
|
|
5057
|
-
// Write uint32 length at bytes 28-31 (big-endian)
|
|
5058
|
-
versionView.setUint32(28, CCTP_FORWARD_PAYLOAD_LENGTH, false); // false = big-endian
|
|
5059
|
-
// Convert to hex string with 0x prefix and cache
|
|
5060
|
-
cachedHookDataHex =
|
|
5061
|
-
'0x' +
|
|
5062
|
-
Array.from(buffer)
|
|
5063
|
-
.map((b) => b.toString(16).padStart(2, '0'))
|
|
5064
|
-
.join('');
|
|
5065
|
-
return cachedHookDataHex;
|
|
5066
|
-
}
|
|
5767
|
+
const PYUSD = {
|
|
5768
|
+
symbol: 'PYUSD',
|
|
5769
|
+
decimals: 6,
|
|
5770
|
+
locators: {
|
|
5771
|
+
[Blockchain.Arbitrum]: '0x46850aD61C2B7d64d08c9C754F45254596696984',
|
|
5772
|
+
[Blockchain.Ethereum]: '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8',
|
|
5773
|
+
[Blockchain.Solana]: '2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo',
|
|
5774
|
+
},
|
|
5775
|
+
};
|
|
5067
5776
|
|
|
5068
5777
|
/**
|
|
5069
|
-
*
|
|
5778
|
+
* WETH (Wrapped Ether) token definition with addresses and metadata.
|
|
5070
5779
|
*
|
|
5071
|
-
*
|
|
5072
|
-
*
|
|
5780
|
+
* @remarks
|
|
5781
|
+
* Built-in WETH definition for the TokenRegistry. Includes chain locators
|
|
5782
|
+
* for swap-supported chains where WETH is available.
|
|
5073
5783
|
*/
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5784
|
+
const WETH = {
|
|
5785
|
+
symbol: 'WETH',
|
|
5786
|
+
decimals: 18,
|
|
5787
|
+
chainDecimals: {
|
|
5788
|
+
[Blockchain.Solana]: 9,
|
|
5789
|
+
},
|
|
5790
|
+
locators: {
|
|
5791
|
+
[Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
|
|
5792
|
+
[Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
|
|
5793
|
+
[Blockchain.Base]: '0x4200000000000000000000000000000000000006',
|
|
5794
|
+
[Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
5795
|
+
[Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
|
|
5796
|
+
[Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
|
|
5797
|
+
[Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs',
|
|
5798
|
+
},
|
|
5799
|
+
};
|
|
5081
5800
|
|
|
5082
5801
|
/**
|
|
5083
|
-
*
|
|
5084
|
-
* Only accepts dot (.) as the decimal separator. Thousand separators are not allowed.
|
|
5802
|
+
* WBTC (Wrapped Bitcoin) token definition with addresses and metadata.
|
|
5085
5803
|
*
|
|
5086
|
-
*
|
|
5087
|
-
*
|
|
5088
|
-
*
|
|
5804
|
+
* @remarks
|
|
5805
|
+
* Built-in WBTC definition for the TokenRegistry. Includes chain locators
|
|
5806
|
+
* for swap-supported chains where WBTC is available.
|
|
5807
|
+
*/
|
|
5808
|
+
const WBTC = {
|
|
5809
|
+
symbol: 'WBTC',
|
|
5810
|
+
decimals: 8,
|
|
5811
|
+
locators: {
|
|
5812
|
+
[Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
|
|
5813
|
+
[Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
|
|
5814
|
+
[Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218',
|
|
5815
|
+
},
|
|
5816
|
+
};
|
|
5817
|
+
|
|
5818
|
+
/**
|
|
5819
|
+
* WSOL (Wrapped SOL) token definition with addresses and metadata.
|
|
5089
5820
|
*
|
|
5090
|
-
*
|
|
5091
|
-
* -
|
|
5092
|
-
* -
|
|
5093
|
-
|
|
5094
|
-
|
|
5821
|
+
* @remarks
|
|
5822
|
+
* Built-in WSOL definition for the TokenRegistry. Includes chain locators
|
|
5823
|
+
* for swap-supported chains where WSOL is available.
|
|
5824
|
+
*/
|
|
5825
|
+
const WSOL = {
|
|
5826
|
+
symbol: 'WSOL',
|
|
5827
|
+
decimals: 9,
|
|
5828
|
+
locators: {
|
|
5829
|
+
[Blockchain.Solana]: 'So11111111111111111111111111111111111111112',
|
|
5830
|
+
},
|
|
5831
|
+
};
|
|
5832
|
+
|
|
5833
|
+
/**
|
|
5834
|
+
* WAVAX (Wrapped AVAX) token definition with addresses and metadata.
|
|
5095
5835
|
*
|
|
5096
|
-
*
|
|
5097
|
-
* -
|
|
5098
|
-
* -
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5836
|
+
* @remarks
|
|
5837
|
+
* Built-in WAVAX definition for the TokenRegistry. Includes chain locators
|
|
5838
|
+
* for swap-supported chains where WAVAX is available.
|
|
5839
|
+
*/
|
|
5840
|
+
const WAVAX = {
|
|
5841
|
+
symbol: 'WAVAX',
|
|
5842
|
+
decimals: 18,
|
|
5843
|
+
locators: {
|
|
5844
|
+
[Blockchain.Avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7',
|
|
5845
|
+
},
|
|
5846
|
+
};
|
|
5847
|
+
|
|
5848
|
+
/**
|
|
5849
|
+
* WPOL (Wrapped POL) token definition with addresses and metadata.
|
|
5102
5850
|
*
|
|
5103
|
-
*
|
|
5104
|
-
* -
|
|
5105
|
-
* -
|
|
5106
|
-
* - maxDecimals: maximum number of decimal places allowed (e.g., 6 for USDC).
|
|
5851
|
+
* @remarks
|
|
5852
|
+
* Built-in WPOL definition for the TokenRegistry. Includes chain locators
|
|
5853
|
+
* for swap-supported chains where WPOL is available.
|
|
5107
5854
|
*/
|
|
5108
|
-
const
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
.superRefine((val, ctx) => {
|
|
5115
|
-
const amount = Number.parseFloat(val);
|
|
5116
|
-
if (Number.isNaN(amount)) {
|
|
5117
|
-
ctx.addIssue({
|
|
5118
|
-
code: z.ZodIssueCode.custom,
|
|
5119
|
-
message: options.regexMessage,
|
|
5120
|
-
});
|
|
5121
|
-
return;
|
|
5122
|
-
}
|
|
5123
|
-
// Check decimal precision if maxDecimals is specified
|
|
5124
|
-
if (options.maxDecimals !== undefined) {
|
|
5125
|
-
const decimalPart = val.split('.')[1];
|
|
5126
|
-
if (decimalPart && decimalPart.length > options.maxDecimals) {
|
|
5127
|
-
ctx.addIssue({
|
|
5128
|
-
code: z.ZodIssueCode.custom,
|
|
5129
|
-
message: `Maximum supported decimal places: ${options.maxDecimals.toString()}`,
|
|
5130
|
-
});
|
|
5131
|
-
return;
|
|
5132
|
-
}
|
|
5133
|
-
}
|
|
5134
|
-
if (options.allowZero && amount < 0) {
|
|
5135
|
-
ctx.addIssue({
|
|
5136
|
-
code: z.ZodIssueCode.custom,
|
|
5137
|
-
message: `${capitalizedAttributeName} must be non-negative`,
|
|
5138
|
-
});
|
|
5139
|
-
}
|
|
5140
|
-
else if (!options.allowZero && amount <= 0) {
|
|
5141
|
-
ctx.addIssue({
|
|
5142
|
-
code: z.ZodIssueCode.custom,
|
|
5143
|
-
message: `${capitalizedAttributeName} must be greater than 0`,
|
|
5144
|
-
});
|
|
5145
|
-
}
|
|
5146
|
-
});
|
|
5855
|
+
const WPOL = {
|
|
5856
|
+
symbol: 'WPOL',
|
|
5857
|
+
decimals: 18,
|
|
5858
|
+
locators: {
|
|
5859
|
+
[Blockchain.Polygon]: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
|
|
5860
|
+
},
|
|
5147
5861
|
};
|
|
5862
|
+
|
|
5148
5863
|
/**
|
|
5149
|
-
*
|
|
5150
|
-
* This ensures the basic structure of a chain definition is valid.
|
|
5151
|
-
* A chain definition must include at minimum a name and type.
|
|
5864
|
+
* ETH (native Ether alias) token definition with metadata.
|
|
5152
5865
|
*
|
|
5153
|
-
* @
|
|
5866
|
+
* @remarks
|
|
5867
|
+
* Built-in ETH definition for the TokenRegistry. Used as a symbol alias
|
|
5868
|
+
* for native ETH (e.g. in swap flows). Chain locators are TBD and will
|
|
5869
|
+
* be added when addresses are available. Use raw selector with
|
|
5870
|
+
* locator + decimals where native gas token is represented as a contract.
|
|
5871
|
+
*/
|
|
5872
|
+
const ETH = {
|
|
5873
|
+
symbol: 'ETH',
|
|
5874
|
+
decimals: 18,
|
|
5875
|
+
locators: {},
|
|
5876
|
+
};
|
|
5877
|
+
|
|
5878
|
+
/**
|
|
5879
|
+
* POL (Polygon native token) token definition with addresses and metadata.
|
|
5880
|
+
*
|
|
5881
|
+
* @remarks
|
|
5882
|
+
* Built-in POL definition for the TokenRegistry. Includes chain locators
|
|
5883
|
+
* where POL is available as a bridged/wrapped asset.
|
|
5884
|
+
*/
|
|
5885
|
+
const POL = {
|
|
5886
|
+
symbol: 'POL',
|
|
5887
|
+
decimals: 18,
|
|
5888
|
+
locators: {
|
|
5889
|
+
[Blockchain.Ethereum]: '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6',
|
|
5890
|
+
},
|
|
5891
|
+
};
|
|
5892
|
+
|
|
5893
|
+
/**
|
|
5894
|
+
* PLUME (Plume network token) token definition with addresses and metadata.
|
|
5895
|
+
*
|
|
5896
|
+
* @remarks
|
|
5897
|
+
* Built-in PLUME definition for the TokenRegistry. Includes chain locators
|
|
5898
|
+
* where PLUME is available.
|
|
5899
|
+
*/
|
|
5900
|
+
const PLUME = {
|
|
5901
|
+
symbol: 'PLUME',
|
|
5902
|
+
decimals: 18,
|
|
5903
|
+
locators: {
|
|
5904
|
+
[Blockchain.Ethereum]: '0x4C1746A800D224393fE2470C70A35717eD4eA5F1',
|
|
5905
|
+
},
|
|
5906
|
+
};
|
|
5907
|
+
|
|
5908
|
+
/**
|
|
5909
|
+
* MON token definition with Solana mint metadata.
|
|
5910
|
+
*
|
|
5911
|
+
* @remarks
|
|
5912
|
+
* Built-in MON definition for the TokenRegistry. Includes chain locators
|
|
5913
|
+
* for swap-supported chains.
|
|
5914
|
+
*/
|
|
5915
|
+
const MON = {
|
|
5916
|
+
symbol: 'MON',
|
|
5917
|
+
decimals: 18,
|
|
5918
|
+
chainDecimals: {
|
|
5919
|
+
[Blockchain.Solana]: 8,
|
|
5920
|
+
},
|
|
5921
|
+
locators: {
|
|
5922
|
+
[Blockchain.Solana]: 'CrAr4RRJMBVwRsZtT62pEhfA9H5utymC2mVx8e7FreP2',
|
|
5923
|
+
},
|
|
5924
|
+
};
|
|
5925
|
+
|
|
5926
|
+
// Re-export for consumers
|
|
5927
|
+
/**
|
|
5928
|
+
* All default token definitions.
|
|
5929
|
+
*
|
|
5930
|
+
* @remarks
|
|
5931
|
+
* These tokens are automatically included in the TokenRegistry when created
|
|
5932
|
+
* without explicit defaults. Extensions can override these definitions.
|
|
5933
|
+
* Includes USDC, USDT, EURC, DAI, USDE, PYUSD, WETH, WBTC, WSOL, WAVAX,
|
|
5934
|
+
* WPOL, ETH, POL, PLUME, and MON.
|
|
5154
5935
|
*
|
|
5155
5936
|
* @example
|
|
5156
5937
|
* ```typescript
|
|
5157
|
-
* import {
|
|
5938
|
+
* import { createTokenRegistry } from '@core/tokens'
|
|
5158
5939
|
*
|
|
5159
|
-
*
|
|
5160
|
-
*
|
|
5161
|
-
* type: 'evm'
|
|
5162
|
-
* }
|
|
5940
|
+
* // Registry uses these by default
|
|
5941
|
+
* const registry = createTokenRegistry()
|
|
5163
5942
|
*
|
|
5164
|
-
*
|
|
5165
|
-
*
|
|
5943
|
+
* // Add custom tokens (built-ins are still included)
|
|
5944
|
+
* const customRegistry = createTokenRegistry({
|
|
5945
|
+
* tokens: [myCustomToken],
|
|
5946
|
+
* })
|
|
5166
5947
|
* ```
|
|
5167
5948
|
*/
|
|
5168
|
-
const
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5949
|
+
const DEFAULT_TOKENS = [
|
|
5950
|
+
USDC,
|
|
5951
|
+
USDT,
|
|
5952
|
+
EURC,
|
|
5953
|
+
DAI,
|
|
5954
|
+
USDE,
|
|
5955
|
+
PYUSD,
|
|
5956
|
+
WETH,
|
|
5957
|
+
WBTC,
|
|
5958
|
+
WSOL,
|
|
5959
|
+
WAVAX,
|
|
5960
|
+
WPOL,
|
|
5961
|
+
ETH,
|
|
5962
|
+
POL,
|
|
5963
|
+
PLUME,
|
|
5964
|
+
MON,
|
|
5965
|
+
];
|
|
5172
5966
|
/**
|
|
5173
|
-
*
|
|
5174
|
-
* This ensures all required fields are present and properly typed.
|
|
5175
|
-
* A wallet context must include:
|
|
5176
|
-
* - A valid adapter with prepare and execute methods
|
|
5177
|
-
* - A valid Ethereum address
|
|
5178
|
-
* - A valid chain definition with required properties
|
|
5967
|
+
* Uppercased token symbols approved for swap fee collection.
|
|
5179
5968
|
*
|
|
5180
|
-
* @
|
|
5969
|
+
* @remarks
|
|
5970
|
+
* Derived from {@link DEFAULT_TOKENS} so all consumers share a single
|
|
5971
|
+
* allowlist source and stay in sync when defaults change.
|
|
5972
|
+
*/
|
|
5973
|
+
new Set(DEFAULT_TOKENS.map((t) => t.symbol.toUpperCase()));
|
|
5974
|
+
|
|
5975
|
+
/**
|
|
5976
|
+
* Resolve the effective decimals for a token on a specific chain.
|
|
5977
|
+
*
|
|
5978
|
+
* Returns the chain-specific override from `chainDecimals` when available,
|
|
5979
|
+
* otherwise falls back to the token's default `decimals`.
|
|
5980
|
+
*
|
|
5981
|
+
* @param token - The token definition to resolve decimals for.
|
|
5982
|
+
* @param chain - Optional chain identifier. When omitted, the default decimals are returned.
|
|
5983
|
+
* @returns The number of decimal places for the token on the given chain.
|
|
5181
5984
|
*
|
|
5182
5985
|
* @example
|
|
5183
5986
|
* ```typescript
|
|
5184
|
-
* import {
|
|
5987
|
+
* import { resolveTokenDecimals } from '\@core/tokens'
|
|
5185
5988
|
*
|
|
5186
|
-
*
|
|
5187
|
-
*
|
|
5188
|
-
*
|
|
5189
|
-
*
|
|
5190
|
-
* },
|
|
5191
|
-
* address: '0x1234567890123456789012345678901234567890',
|
|
5192
|
-
* chain: {
|
|
5193
|
-
* name: 'Ethereum',
|
|
5194
|
-
* type: 'evm',
|
|
5195
|
-
* isTestnet: false
|
|
5196
|
-
* }
|
|
5197
|
-
* }
|
|
5198
|
-
*
|
|
5199
|
-
* const result = walletContextSchema.safeParse(validContext)
|
|
5200
|
-
* console.log(result.success) // true
|
|
5989
|
+
* // DAI: 18 decimals on EVM, 8 on Solana
|
|
5990
|
+
* resolveTokenDecimals(DAI) // 18 (default)
|
|
5991
|
+
* resolveTokenDecimals(DAI, 'Solana') // 8 (chain override)
|
|
5992
|
+
* resolveTokenDecimals(DAI, 'Ethereum') // 18 (no override, falls back)
|
|
5201
5993
|
* ```
|
|
5202
5994
|
*/
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
name: z.string(),
|
|
5211
|
-
type: z.string(),
|
|
5212
|
-
isTestnet: z.boolean(),
|
|
5213
|
-
}),
|
|
5214
|
-
});
|
|
5995
|
+
function resolveTokenDecimals(token, chain) {
|
|
5996
|
+
if (chain === undefined) {
|
|
5997
|
+
return token.decimals;
|
|
5998
|
+
}
|
|
5999
|
+
return token.chainDecimals?.[chain] ?? token.decimals;
|
|
6000
|
+
}
|
|
6001
|
+
|
|
5215
6002
|
/**
|
|
5216
|
-
*
|
|
5217
|
-
* Extends walletContextSchema with optional useForwarder flag.
|
|
6003
|
+
* Check if a selector is a raw token selector (object form).
|
|
5218
6004
|
*
|
|
5219
|
-
* @
|
|
6005
|
+
* @param selector - The token selector to check.
|
|
6006
|
+
* @returns True if the selector is a raw token selector.
|
|
5220
6007
|
*/
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
});
|
|
6008
|
+
function isRawSelector(selector) {
|
|
6009
|
+
return typeof selector === 'object' && 'locator' in selector;
|
|
6010
|
+
}
|
|
5225
6011
|
/**
|
|
5226
|
-
*
|
|
5227
|
-
* Used when useForwarder is true and no adapter is provided.
|
|
5228
|
-
* Requires chain definition and recipientAddress.
|
|
6012
|
+
* Normalize a symbol to uppercase for case-insensitive lookup.
|
|
5229
6013
|
*
|
|
5230
|
-
*
|
|
5231
|
-
*
|
|
6014
|
+
* @param symbol - The symbol to normalize.
|
|
6015
|
+
* @returns The normalized (uppercase) symbol.
|
|
6016
|
+
*/
|
|
6017
|
+
function normalizeSymbol(symbol) {
|
|
6018
|
+
return symbol.toUpperCase();
|
|
6019
|
+
}
|
|
6020
|
+
/**
|
|
6021
|
+
* Normalize a locator for stable chain-aware lookup.
|
|
5232
6022
|
*
|
|
5233
|
-
* @
|
|
6023
|
+
* @remarks
|
|
6024
|
+
* EVM-style addresses (`0x...`) are normalized to lowercase for
|
|
6025
|
+
* case-insensitive matching. Non-EVM locators keep original casing.
|
|
5234
6026
|
*/
|
|
5235
|
-
|
|
5236
|
-
.
|
|
5237
|
-
|
|
5238
|
-
isTestnet: z.boolean(),
|
|
5239
|
-
}),
|
|
5240
|
-
recipientAddress: z
|
|
5241
|
-
.string()
|
|
5242
|
-
.min(1, 'Recipient address is required for forwarder-only destination'),
|
|
5243
|
-
useForwarder: z.literal(true),
|
|
5244
|
-
})
|
|
5245
|
-
.superRefine((data, ctx) => {
|
|
5246
|
-
// Pass chain name as string - isValidAddressForChain will use name-based matching
|
|
5247
|
-
if (!isValidAddressForChain(data.recipientAddress, data.chain.name)) {
|
|
5248
|
-
ctx.addIssue({
|
|
5249
|
-
code: z.ZodIssueCode.custom,
|
|
5250
|
-
message: `Invalid recipient address format for chain ${data.chain.name}`,
|
|
5251
|
-
path: ['recipientAddress'],
|
|
5252
|
-
});
|
|
6027
|
+
function normalizeLocator(locator) {
|
|
6028
|
+
if (locator.startsWith('0x') || locator.startsWith('0X')) {
|
|
6029
|
+
return locator.toLowerCase();
|
|
5253
6030
|
}
|
|
5254
|
-
|
|
6031
|
+
return locator;
|
|
6032
|
+
}
|
|
5255
6033
|
/**
|
|
5256
|
-
*
|
|
6034
|
+
* Build a stable map key for a chain + locator pair.
|
|
5257
6035
|
*/
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
]);
|
|
6036
|
+
function buildAddressKey(chainId, locator) {
|
|
6037
|
+
return `${chainId}::${normalizeLocator(locator)}`;
|
|
6038
|
+
}
|
|
5262
6039
|
/**
|
|
5263
|
-
*
|
|
5264
|
-
* Validates the simplified CustomFee interface which includes:
|
|
5265
|
-
* - An optional fee amount as string
|
|
5266
|
-
* - An optional fee recipient as string address
|
|
6040
|
+
* Create a token registry with built-in tokens and optional extensions.
|
|
5267
6041
|
*
|
|
5268
|
-
* @
|
|
6042
|
+
* @remarks
|
|
6043
|
+
* The registry always includes built-in tokens (DEFAULT_TOKENS) like USDC.
|
|
6044
|
+
* Custom tokens are merged on top - use this to add new tokens or override
|
|
6045
|
+
* built-in definitions.
|
|
6046
|
+
*
|
|
6047
|
+
* @param options - Configuration options for the registry.
|
|
6048
|
+
* @returns A token registry instance.
|
|
5269
6049
|
*
|
|
5270
6050
|
* @example
|
|
5271
6051
|
* ```typescript
|
|
5272
|
-
* import {
|
|
6052
|
+
* import { createTokenRegistry } from '@core/tokens'
|
|
5273
6053
|
*
|
|
5274
|
-
*
|
|
5275
|
-
*
|
|
5276
|
-
* recipientAddress: '0x1234567890123456789012345678901234567890'
|
|
5277
|
-
* }
|
|
6054
|
+
* // Create registry with built-in tokens (USDC, etc.)
|
|
6055
|
+
* const registry = createTokenRegistry()
|
|
5278
6056
|
*
|
|
5279
|
-
*
|
|
5280
|
-
*
|
|
6057
|
+
* // Resolve USDC on Ethereum
|
|
6058
|
+
* const usdc = registry.resolve('USDC', 'Ethereum')
|
|
6059
|
+
* console.log(usdc.locator) // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
6060
|
+
* console.log(usdc.decimals) // 6
|
|
5281
6061
|
* ```
|
|
5282
|
-
|
|
6062
|
+
*
|
|
6063
|
+
* @example
|
|
6064
|
+
* ```typescript
|
|
6065
|
+
* // Add custom tokens (built-ins are still included)
|
|
6066
|
+
* const myToken: TokenDefinition = {
|
|
6067
|
+
* symbol: 'MY',
|
|
6068
|
+
* decimals: 18,
|
|
6069
|
+
* locators: { Ethereum: '0x...' },
|
|
6070
|
+
* }
|
|
6071
|
+
*
|
|
6072
|
+
* const registry = createTokenRegistry({ tokens: [myToken] })
|
|
6073
|
+
* registry.resolve('USDC', 'Ethereum') // Still works!
|
|
6074
|
+
* registry.resolve('MY', 'Ethereum') // Also works
|
|
6075
|
+
* ```
|
|
6076
|
+
*
|
|
6077
|
+
* @example
|
|
6078
|
+
* ```typescript
|
|
6079
|
+
* // Override a built-in token
|
|
6080
|
+
* const customUsdc: TokenDefinition = {
|
|
6081
|
+
* symbol: 'USDC',
|
|
6082
|
+
* decimals: 6,
|
|
6083
|
+
* locators: { MyChain: '0xCustomAddress' },
|
|
6084
|
+
* }
|
|
6085
|
+
*
|
|
6086
|
+
* const registry = createTokenRegistry({ tokens: [customUsdc] })
|
|
6087
|
+
* // Now USDC resolves to customUsdc definition
|
|
6088
|
+
* ```
|
|
6089
|
+
*
|
|
6090
|
+
* @example
|
|
6091
|
+
* ```typescript
|
|
6092
|
+
* // Resolve arbitrary tokens by raw locator
|
|
6093
|
+
* const registry = createTokenRegistry()
|
|
6094
|
+
* const token = registry.resolve(
|
|
6095
|
+
* { locator: '0x1234...', decimals: 18 },
|
|
6096
|
+
* 'Ethereum'
|
|
6097
|
+
* )
|
|
6098
|
+
* ```
|
|
6099
|
+
*/
|
|
6100
|
+
function createTokenRegistry(options = {}) {
|
|
6101
|
+
const { tokens = [], requireDecimals = false } = options;
|
|
6102
|
+
// Build the token map: always start with DEFAULT_TOKENS, then add custom tokens
|
|
6103
|
+
const tokenMap = new Map();
|
|
6104
|
+
// Add built-in tokens first
|
|
6105
|
+
for (const def of DEFAULT_TOKENS) {
|
|
6106
|
+
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
6107
|
+
}
|
|
6108
|
+
// Custom tokens override built-ins
|
|
6109
|
+
for (const def of tokens) {
|
|
6110
|
+
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
6111
|
+
}
|
|
6112
|
+
// Build an address index from the resolved token map so overrides win.
|
|
6113
|
+
const addressMap = new Map();
|
|
6114
|
+
for (const token of tokenMap.values()) {
|
|
6115
|
+
for (const [chainId, locator] of Object.entries(token.locators)) {
|
|
6116
|
+
if (typeof locator !== 'string' || locator.trim() === '') {
|
|
6117
|
+
continue;
|
|
6118
|
+
}
|
|
6119
|
+
addressMap.set(buildAddressKey(chainId, locator), token);
|
|
6120
|
+
}
|
|
6121
|
+
}
|
|
6122
|
+
/**
|
|
6123
|
+
* Resolve a symbol selector to token information.
|
|
6124
|
+
*/
|
|
6125
|
+
function resolveSymbol(symbol, chainId) {
|
|
6126
|
+
const normalizedSymbol = normalizeSymbol(symbol);
|
|
6127
|
+
const definition = tokenMap.get(normalizedSymbol);
|
|
6128
|
+
if (definition === undefined) {
|
|
6129
|
+
throw createTokenResolutionError(`Unknown token symbol: ${symbol}. Register it via createTokenRegistry({ tokens: [...] }) or use a raw selector.`, symbol, chainId);
|
|
6130
|
+
}
|
|
6131
|
+
const locator = definition.locators[chainId];
|
|
6132
|
+
if (locator === undefined || locator.trim() === '') {
|
|
6133
|
+
throw createTokenResolutionError(`Token ${symbol} has no locator for chain ${chainId}`, symbol, chainId);
|
|
6134
|
+
}
|
|
6135
|
+
const decimals = resolveTokenDecimals(definition, chainId);
|
|
6136
|
+
return {
|
|
6137
|
+
symbol: definition.symbol,
|
|
6138
|
+
decimals,
|
|
6139
|
+
locator: normalizeLocator(locator),
|
|
6140
|
+
};
|
|
6141
|
+
}
|
|
6142
|
+
/**
|
|
6143
|
+
* Resolve a raw selector to token information.
|
|
6144
|
+
*/
|
|
6145
|
+
function resolveRaw(selector, chainId) {
|
|
6146
|
+
const { locator, decimals } = selector;
|
|
6147
|
+
// Validate locator
|
|
6148
|
+
if (!locator || typeof locator !== 'string') {
|
|
6149
|
+
throw createTokenResolutionError('Raw selector must have a valid locator string', selector, chainId);
|
|
6150
|
+
}
|
|
6151
|
+
// Decimals are always required for raw selectors
|
|
6152
|
+
if (decimals === undefined) {
|
|
6153
|
+
const message = requireDecimals
|
|
6154
|
+
? 'Decimals required for raw token selector (requireDecimals: true)'
|
|
6155
|
+
: 'Decimals required for raw token selector. Provide { locator, decimals }.';
|
|
6156
|
+
throw createTokenResolutionError(message, selector, chainId);
|
|
6157
|
+
}
|
|
6158
|
+
// Validate decimals
|
|
6159
|
+
if (typeof decimals !== 'number' ||
|
|
6160
|
+
decimals < 0 ||
|
|
6161
|
+
!Number.isInteger(decimals)) {
|
|
6162
|
+
throw createTokenResolutionError(`Invalid decimals: ${String(decimals)}. Must be a non-negative integer.`, selector, chainId);
|
|
6163
|
+
}
|
|
6164
|
+
return {
|
|
6165
|
+
decimals,
|
|
6166
|
+
locator: normalizeLocator(locator),
|
|
6167
|
+
};
|
|
6168
|
+
}
|
|
6169
|
+
return {
|
|
6170
|
+
resolve(selector, chainId) {
|
|
6171
|
+
// Runtime validation of inputs - these checks are for JS consumers
|
|
6172
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
6173
|
+
if (selector === null || selector === undefined) {
|
|
6174
|
+
throw createTokenResolutionError('Token selector cannot be null or undefined', selector, chainId);
|
|
6175
|
+
}
|
|
6176
|
+
if (chainId === '' || typeof chainId !== 'string') {
|
|
6177
|
+
throw createTokenResolutionError('Chain ID is required for token resolution', selector, chainId);
|
|
6178
|
+
}
|
|
6179
|
+
// Dispatch based on selector type
|
|
6180
|
+
if (isRawSelector(selector)) {
|
|
6181
|
+
return resolveRaw(selector, chainId);
|
|
6182
|
+
}
|
|
6183
|
+
if (typeof selector === 'string') {
|
|
6184
|
+
return resolveSymbol(selector, chainId);
|
|
6185
|
+
}
|
|
6186
|
+
throw createTokenResolutionError(`Invalid selector type: ${typeof selector}. Expected string or object with locator.`, selector, chainId);
|
|
6187
|
+
},
|
|
6188
|
+
resolveByAddress(address, chainId) {
|
|
6189
|
+
if (!address || typeof address !== 'string') {
|
|
6190
|
+
throw createTokenResolutionError('Token address is required for address resolution', { locator: address }, chainId);
|
|
6191
|
+
}
|
|
6192
|
+
if (chainId === '' || typeof chainId !== 'string') {
|
|
6193
|
+
throw createTokenResolutionError('Chain ID is required for token resolution', { locator: address }, chainId);
|
|
6194
|
+
}
|
|
6195
|
+
const definition = addressMap.get(buildAddressKey(chainId, address));
|
|
6196
|
+
if (definition === undefined) {
|
|
6197
|
+
throw createTokenResolutionError(`Unknown token address: ${address} for chain ${chainId}`, { locator: address }, chainId);
|
|
6198
|
+
}
|
|
6199
|
+
const locator = definition.locators[chainId];
|
|
6200
|
+
if (locator === undefined || locator.trim() === '') {
|
|
6201
|
+
throw createTokenResolutionError(`Token ${definition.symbol} has no locator for chain ${chainId}`, definition.symbol, chainId);
|
|
6202
|
+
}
|
|
6203
|
+
const decimals = resolveTokenDecimals(definition, chainId);
|
|
6204
|
+
return {
|
|
6205
|
+
symbol: definition.symbol,
|
|
6206
|
+
decimals,
|
|
6207
|
+
locator: normalizeLocator(locator),
|
|
6208
|
+
};
|
|
6209
|
+
},
|
|
6210
|
+
get(symbol) {
|
|
6211
|
+
if (!symbol || typeof symbol !== 'string') {
|
|
6212
|
+
return undefined;
|
|
6213
|
+
}
|
|
6214
|
+
return tokenMap.get(normalizeSymbol(symbol));
|
|
6215
|
+
},
|
|
6216
|
+
has(symbol) {
|
|
6217
|
+
if (!symbol || typeof symbol !== 'string') {
|
|
6218
|
+
return false;
|
|
6219
|
+
}
|
|
6220
|
+
return tokenMap.has(normalizeSymbol(symbol));
|
|
6221
|
+
},
|
|
6222
|
+
symbols() {
|
|
6223
|
+
return Array.from(tokenMap.values()).map((def) => def.symbol);
|
|
6224
|
+
},
|
|
6225
|
+
entries() {
|
|
6226
|
+
return Array.from(tokenMap.values());
|
|
6227
|
+
},
|
|
6228
|
+
};
|
|
6229
|
+
}
|
|
6230
|
+
|
|
6231
|
+
/**
|
|
6232
|
+
* Define a schema for token registry interfaces.
|
|
6233
|
+
*
|
|
6234
|
+
* @remarks
|
|
6235
|
+
* Validate that a registry exposes the `resolve()` API used by adapters.
|
|
6236
|
+
*
|
|
6237
|
+
* @example
|
|
6238
|
+
* ```typescript
|
|
6239
|
+
* import { tokenRegistrySchema } from '@core/tokens'
|
|
6240
|
+
*
|
|
6241
|
+
* const registry = {
|
|
6242
|
+
* resolve: () => ({ locator: '0x0', decimals: 6 }),
|
|
6243
|
+
* }
|
|
6244
|
+
*
|
|
6245
|
+
* tokenRegistrySchema.parse(registry)
|
|
6246
|
+
* ```
|
|
6247
|
+
*/
|
|
6248
|
+
z.custom((value) => {
|
|
6249
|
+
if (value === null || typeof value !== 'object') {
|
|
6250
|
+
return false;
|
|
6251
|
+
}
|
|
6252
|
+
const record = value;
|
|
6253
|
+
return (typeof record['resolve'] === 'function' &&
|
|
6254
|
+
typeof record['get'] === 'function' &&
|
|
6255
|
+
typeof record['has'] === 'function' &&
|
|
6256
|
+
typeof record['symbols'] === 'function' &&
|
|
6257
|
+
typeof record['entries'] === 'function');
|
|
6258
|
+
}, {
|
|
6259
|
+
message: 'Invalid token registry',
|
|
6260
|
+
});
|
|
6261
|
+
|
|
6262
|
+
/**
|
|
6263
|
+
* Build a complete explorer URL from a chain definition and transaction hash.
|
|
6264
|
+
*
|
|
6265
|
+
* This function takes a chain definition containing an explorer URL template
|
|
6266
|
+
* and replaces the `{hash}` placeholder with the provided transaction hash
|
|
6267
|
+
* to create a complete, valid explorer URL.
|
|
6268
|
+
*
|
|
6269
|
+
* @param chainDef - The chain definition containing the explorer URL template.
|
|
6270
|
+
* @param txHash - The transaction hash to insert into the URL template.
|
|
6271
|
+
* @returns A complete explorer URL with the transaction hash inserted.
|
|
6272
|
+
* @throws Error if the chain definition is null/undefined.
|
|
6273
|
+
* @throws Error if the transaction hash is null/undefined/empty.
|
|
6274
|
+
* @throws Error if the explorer URL template is missing or empty.
|
|
6275
|
+
* @throws Error if the explorer URL template doesn't contain the {hash} placeholder.
|
|
6276
|
+
* @throws Error if the resulting URL is invalid.
|
|
6277
|
+
*
|
|
6278
|
+
* @example
|
|
6279
|
+
* ```typescript
|
|
6280
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6281
|
+
* import { Ethereum } from '@core/chains'
|
|
6282
|
+
*
|
|
6283
|
+
* // Build URL for Ethereum transaction
|
|
6284
|
+
* const url = buildExplorerUrl(Ethereum, '0x1234567890abcdef...')
|
|
6285
|
+
* console.log(url) // 'https://etherscan.io/tx/0x1234567890abcdef...'
|
|
6286
|
+
* ```
|
|
6287
|
+
*
|
|
6288
|
+
* @example
|
|
6289
|
+
* ```typescript
|
|
6290
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6291
|
+
* import { Solana } from '@core/chains'
|
|
6292
|
+
*
|
|
6293
|
+
* // Build URL for Solana transaction
|
|
6294
|
+
* const url = buildExplorerUrl(Solana, 'abc123def456...')
|
|
6295
|
+
* console.log(url) // 'https://solscan.io/tx/abc123def456...'
|
|
6296
|
+
* ```
|
|
6297
|
+
*
|
|
6298
|
+
* @example
|
|
6299
|
+
* ```typescript
|
|
6300
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6301
|
+
* import { Aptos } from '@core/chains'
|
|
6302
|
+
*
|
|
6303
|
+
* // Build URL for Aptos transaction with query parameters
|
|
6304
|
+
* const url = buildExplorerUrl(Aptos, '0xabc123...')
|
|
6305
|
+
* console.log(url) // 'https://explorer.aptoslabs.com/txn/0xabc123...?network=mainnet'
|
|
6306
|
+
* ```
|
|
6307
|
+
*/
|
|
6308
|
+
function buildExplorerUrl(chainDef, txHash) {
|
|
6309
|
+
// Validate input parameters using our standard validation pattern
|
|
6310
|
+
validateOrThrow({ chainDef, txHash }, buildExplorerUrlParamsSchema, 'Invalid buildExplorerUrl parameters');
|
|
6311
|
+
// Parse and transform input parameters (e.g., trim whitespace from txHash)
|
|
6312
|
+
const { chainDef: validChainDef, txHash: validTxHash } = buildExplorerUrlParamsSchema.parse({ chainDef, txHash });
|
|
6313
|
+
// Replace all occurrences of the placeholder with the transaction hash
|
|
6314
|
+
const explorerUrl = validChainDef.explorerUrl.replace(/{hash}/g, validTxHash);
|
|
6315
|
+
// Validate the resulting URL
|
|
6316
|
+
validate(explorerUrl, explorerUrlSchema, 'explorer URL');
|
|
6317
|
+
return explorerUrl;
|
|
6318
|
+
}
|
|
6319
|
+
|
|
6320
|
+
/**
|
|
6321
|
+
* CCTP forwarding magic bytes prefix.
|
|
6322
|
+
*
|
|
6323
|
+
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
6324
|
+
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
6325
|
+
*/
|
|
6326
|
+
const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
6327
|
+
/**
|
|
6328
|
+
* CCTP forwarding version number.
|
|
6329
|
+
*
|
|
6330
|
+
* Version 0 is used for basic forwarding requests.
|
|
6331
|
+
*/
|
|
6332
|
+
const CCTP_FORWARD_VERSION = 0;
|
|
6333
|
+
/**
|
|
6334
|
+
* Length of Circle-reserved payload for basic forwarding (0 bytes).
|
|
6335
|
+
*
|
|
6336
|
+
* Set to 0 when no additional Circle-reserved data is needed.
|
|
6337
|
+
*/
|
|
6338
|
+
const CCTP_FORWARD_PAYLOAD_LENGTH = 0;
|
|
6339
|
+
/**
|
|
6340
|
+
* Build the hookData bytes for CCTP forwarding.
|
|
6341
|
+
*
|
|
6342
|
+
* Constructs a 32-byte hookData payload that signals to Circle's Orbit relayer
|
|
6343
|
+
* that the user wants automated attestation fetching and destination mint execution.
|
|
6344
|
+
*
|
|
6345
|
+
* The hookData format is:
|
|
6346
|
+
* - Bytes 0-23: ASCII "cctp-forward" right-padded to 24 bytes with zeros
|
|
6347
|
+
* - Bytes 24-27: uint32 version (big-endian) - currently 0
|
|
6348
|
+
* - Bytes 28-31: uint32 length (big-endian) - 0 for basic forwarding
|
|
6349
|
+
*
|
|
6350
|
+
* @returns A 0x-prefixed hex string representing the 32-byte hookData
|
|
6351
|
+
*
|
|
6352
|
+
* @example
|
|
6353
|
+
* ```typescript
|
|
6354
|
+
* import { buildForwardingHookData } from '@core/utils'
|
|
6355
|
+
*
|
|
6356
|
+
* const hookData = buildForwardingHookData()
|
|
6357
|
+
* // Returns: '0x636374702d666f72776172640000000000000000000000000000000000000000'
|
|
6358
|
+
*
|
|
6359
|
+
* // Use with depositForBurnWithHook action
|
|
6360
|
+
* await adapter.action('cctp.v2.depositForBurnWithHook', {
|
|
6361
|
+
* amount: BigInt('1000000'),
|
|
6362
|
+
* mintRecipient: '0x...',
|
|
6363
|
+
* maxFee: BigInt('50000'),
|
|
6364
|
+
* minFinalityThreshold: 1000,
|
|
6365
|
+
* fromChain: ethereum,
|
|
6366
|
+
* toChain: base,
|
|
6367
|
+
* hookData
|
|
6368
|
+
* })
|
|
6369
|
+
* ```
|
|
6370
|
+
*/
|
|
6371
|
+
// Cached result for memoization (computed once on first call)
|
|
6372
|
+
let cachedHookDataHex = null;
|
|
6373
|
+
function buildForwardingHookData() {
|
|
6374
|
+
// Return cached result if already computed
|
|
6375
|
+
if (cachedHookDataHex !== null) {
|
|
6376
|
+
return cachedHookDataHex;
|
|
6377
|
+
}
|
|
6378
|
+
// Create a 32-byte buffer
|
|
6379
|
+
const buffer = new Uint8Array(32);
|
|
6380
|
+
// Write the magic prefix ("cctp-forward") - 12 bytes, rest of 24-byte section is zero-padded
|
|
6381
|
+
const encoder = new TextEncoder();
|
|
6382
|
+
const magicBytes = encoder.encode(CCTP_FORWARD_MAGIC_PREFIX);
|
|
6383
|
+
buffer.set(magicBytes, 0);
|
|
6384
|
+
// Bytes 12-23 are already zero (right-padding)
|
|
6385
|
+
// Write uint32 version at bytes 24-27 (big-endian)
|
|
6386
|
+
const versionView = new DataView(buffer.buffer);
|
|
6387
|
+
versionView.setUint32(24, CCTP_FORWARD_VERSION, false); // false = big-endian
|
|
6388
|
+
// Write uint32 length at bytes 28-31 (big-endian)
|
|
6389
|
+
versionView.setUint32(28, CCTP_FORWARD_PAYLOAD_LENGTH, false); // false = big-endian
|
|
6390
|
+
// Convert to hex string with 0x prefix and cache
|
|
6391
|
+
cachedHookDataHex =
|
|
6392
|
+
'0x' +
|
|
6393
|
+
Array.from(buffer)
|
|
6394
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
6395
|
+
.join('');
|
|
6396
|
+
return cachedHookDataHex;
|
|
6397
|
+
}
|
|
6398
|
+
|
|
6399
|
+
/**
|
|
6400
|
+
* Transfer speed options for cross-chain operations.
|
|
6401
|
+
*
|
|
6402
|
+
* Defines the available speed modes for CCTPv2 transfers, affecting
|
|
6403
|
+
* both transfer time and potential fee implications.
|
|
6404
|
+
*/
|
|
6405
|
+
var TransferSpeed;
|
|
6406
|
+
(function (TransferSpeed) {
|
|
6407
|
+
/** Fast burn mode - reduces transfer time but may have different fee implications */
|
|
6408
|
+
TransferSpeed["FAST"] = "FAST";
|
|
6409
|
+
/** Standard burn mode - normal transfer time with standard fees */
|
|
6410
|
+
TransferSpeed["SLOW"] = "SLOW";
|
|
6411
|
+
})(TransferSpeed || (TransferSpeed = {}));
|
|
6412
|
+
|
|
6413
|
+
/**
|
|
6414
|
+
* Factory to validate a numeric string with strict dot-decimal notation.
|
|
6415
|
+
* Only accepts dot (.) as the decimal separator. Thousand separators are not allowed.
|
|
6416
|
+
*
|
|
6417
|
+
* This enforces an unambiguous format for SDK inputs. Internationalization concerns
|
|
6418
|
+
* (comma vs dot decimal separators) should be handled in the UI layer before passing
|
|
6419
|
+
* values to the SDK.
|
|
6420
|
+
*
|
|
6421
|
+
* Accepts the following formats:
|
|
6422
|
+
* - Whole numbers: "1", "100", "1000"
|
|
6423
|
+
* - Leading zero decimals: "0.1", "0.5", "0.001"
|
|
6424
|
+
* - Shorthand decimals: ".1", ".5", ".001"
|
|
6425
|
+
* - Standard decimals: "1.23", "100.50"
|
|
6426
|
+
*
|
|
6427
|
+
* Does NOT accept:
|
|
6428
|
+
* - Comma decimal separator: "1,5" (use "1.5" instead)
|
|
6429
|
+
* - Thousand separators: "1,000.50" or "1.000,50" (use "1000.50" instead)
|
|
6430
|
+
* - Multiple decimal points: "1.2.3"
|
|
6431
|
+
* - Negative numbers: "-100"
|
|
6432
|
+
* - Non-numeric characters: "abc", "100a"
|
|
6433
|
+
*
|
|
6434
|
+
* Behavior differences controlled by options:
|
|
6435
|
+
* - allowZero: when false, value must be strictly greater than 0; when true, non-negative.
|
|
6436
|
+
* - regexMessage: error message when the basic numeric format fails.
|
|
6437
|
+
* - maxDecimals: maximum number of decimal places allowed (e.g., 6 for USDC).
|
|
6438
|
+
*/
|
|
6439
|
+
const createDecimalStringValidator = (options) => (schema) => {
|
|
6440
|
+
// Capitalize first letter of attribute name for error messages
|
|
6441
|
+
const capitalizedAttributeName = options.attributeName.charAt(0).toUpperCase() +
|
|
6442
|
+
options.attributeName.slice(1);
|
|
6443
|
+
return schema
|
|
6444
|
+
.regex(/^-?(?:\d+(?:\.\d+)?|\.\d+)$/, options.regexMessage)
|
|
6445
|
+
.superRefine((val, ctx) => {
|
|
6446
|
+
const amount = Number.parseFloat(val);
|
|
6447
|
+
if (Number.isNaN(amount)) {
|
|
6448
|
+
ctx.addIssue({
|
|
6449
|
+
code: z.ZodIssueCode.custom,
|
|
6450
|
+
message: options.regexMessage,
|
|
6451
|
+
});
|
|
6452
|
+
return;
|
|
6453
|
+
}
|
|
6454
|
+
// Check decimal precision if maxDecimals is specified
|
|
6455
|
+
if (options.maxDecimals !== undefined) {
|
|
6456
|
+
const decimalPart = val.split('.')[1];
|
|
6457
|
+
if (decimalPart && decimalPart.length > options.maxDecimals) {
|
|
6458
|
+
ctx.addIssue({
|
|
6459
|
+
code: z.ZodIssueCode.custom,
|
|
6460
|
+
message: `Maximum supported decimal places: ${options.maxDecimals.toString()}`,
|
|
6461
|
+
});
|
|
6462
|
+
return;
|
|
6463
|
+
}
|
|
6464
|
+
}
|
|
6465
|
+
if (options.allowZero && amount < 0) {
|
|
6466
|
+
ctx.addIssue({
|
|
6467
|
+
code: z.ZodIssueCode.custom,
|
|
6468
|
+
message: `${capitalizedAttributeName} must be non-negative`,
|
|
6469
|
+
});
|
|
6470
|
+
}
|
|
6471
|
+
else if (!options.allowZero && amount <= 0) {
|
|
6472
|
+
ctx.addIssue({
|
|
6473
|
+
code: z.ZodIssueCode.custom,
|
|
6474
|
+
message: `${capitalizedAttributeName} must be greater than 0`,
|
|
6475
|
+
});
|
|
6476
|
+
}
|
|
6477
|
+
});
|
|
6478
|
+
};
|
|
6479
|
+
/**
|
|
6480
|
+
* Schema for validating chain definitions.
|
|
6481
|
+
* This ensures the basic structure of a chain definition is valid.
|
|
6482
|
+
* A chain definition must include at minimum a name and type.
|
|
6483
|
+
*
|
|
6484
|
+
* @throws KitError if validation fails
|
|
6485
|
+
*
|
|
6486
|
+
* @example
|
|
6487
|
+
* ```typescript
|
|
6488
|
+
* import { chainDefinitionSchema } from '@core/provider'
|
|
6489
|
+
*
|
|
6490
|
+
* const validChain = {
|
|
6491
|
+
* name: 'Ethereum',
|
|
6492
|
+
* type: 'evm'
|
|
6493
|
+
* }
|
|
6494
|
+
*
|
|
6495
|
+
* const result = chainDefinitionSchema.safeParse(validChain)
|
|
6496
|
+
* console.log(result.success) // true
|
|
6497
|
+
* ```
|
|
6498
|
+
*/
|
|
6499
|
+
const chainDefinitionSchema = z.object({
|
|
6500
|
+
name: z.string().min(1, 'Chain name is required'),
|
|
6501
|
+
type: z.string().min(1, 'Chain type is required'),
|
|
6502
|
+
});
|
|
6503
|
+
/**
|
|
6504
|
+
* Schema for validating wallet contexts.
|
|
6505
|
+
* This ensures all required fields are present and properly typed.
|
|
6506
|
+
* A wallet context must include:
|
|
6507
|
+
* - A valid adapter with prepare and execute methods
|
|
6508
|
+
* - A valid Ethereum address
|
|
6509
|
+
* - A valid chain definition with required properties
|
|
6510
|
+
*
|
|
6511
|
+
* @throws KitError if validation fails
|
|
6512
|
+
*
|
|
6513
|
+
* @example
|
|
6514
|
+
* ```typescript
|
|
6515
|
+
* import { walletContextSchema } from '@core/provider'
|
|
6516
|
+
*
|
|
6517
|
+
* const validContext = {
|
|
6518
|
+
* adapter: {
|
|
6519
|
+
* prepare: () => Promise.resolve({}),
|
|
6520
|
+
* waitForTransaction: () => Promise.resolve({})
|
|
6521
|
+
* },
|
|
6522
|
+
* address: '0x1234567890123456789012345678901234567890',
|
|
6523
|
+
* chain: {
|
|
6524
|
+
* name: 'Ethereum',
|
|
6525
|
+
* type: 'evm',
|
|
6526
|
+
* isTestnet: false
|
|
6527
|
+
* }
|
|
6528
|
+
* }
|
|
6529
|
+
*
|
|
6530
|
+
* const result = walletContextSchema.safeParse(validContext)
|
|
6531
|
+
* console.log(result.success) // true
|
|
6532
|
+
* ```
|
|
6533
|
+
*/
|
|
6534
|
+
const walletContextSchema = z.object({
|
|
6535
|
+
adapter: z.object({
|
|
6536
|
+
prepare: z.function().returns(z.any()),
|
|
6537
|
+
waitForTransaction: z.function().returns(z.any()),
|
|
6538
|
+
}),
|
|
6539
|
+
address: z.string().min(1),
|
|
6540
|
+
chain: z.object({
|
|
6541
|
+
name: z.string(),
|
|
6542
|
+
type: z.string(),
|
|
6543
|
+
isTestnet: z.boolean(),
|
|
6544
|
+
}),
|
|
6545
|
+
});
|
|
6546
|
+
/**
|
|
6547
|
+
* Schema for validating destination wallet contexts.
|
|
6548
|
+
* Extends walletContextSchema with optional useForwarder flag.
|
|
6549
|
+
*
|
|
6550
|
+
* @throws KitError if validation fails
|
|
6551
|
+
*/
|
|
6552
|
+
const destinationContextSchema = walletContextSchema.extend({
|
|
6553
|
+
useForwarder: z.boolean().optional(),
|
|
6554
|
+
recipientAddress: z.string().optional(),
|
|
6555
|
+
});
|
|
6556
|
+
/**
|
|
6557
|
+
* Schema for validating forwarder-only destination contexts.
|
|
6558
|
+
* Used when useForwarder is true and no adapter is provided.
|
|
6559
|
+
* Requires chain definition and recipientAddress.
|
|
6560
|
+
*
|
|
6561
|
+
* Validates that recipientAddress format is correct for the destination chain
|
|
6562
|
+
* (EVM hex address or Solana base58 address).
|
|
6563
|
+
*
|
|
6564
|
+
* @throws KitError if validation fails
|
|
6565
|
+
*/
|
|
6566
|
+
const forwarderOnlyDestinationSchema = z
|
|
6567
|
+
.object({
|
|
6568
|
+
chain: chainDefinitionSchema.extend({
|
|
6569
|
+
isTestnet: z.boolean(),
|
|
6570
|
+
}),
|
|
6571
|
+
recipientAddress: z
|
|
6572
|
+
.string()
|
|
6573
|
+
.min(1, 'Recipient address is required for forwarder-only destination'),
|
|
6574
|
+
useForwarder: z.literal(true),
|
|
6575
|
+
})
|
|
6576
|
+
.superRefine((data, ctx) => {
|
|
6577
|
+
// Pass chain name as string - isValidAddressForChain will use name-based matching
|
|
6578
|
+
if (!isValidAddressForChain(data.recipientAddress, data.chain.name)) {
|
|
6579
|
+
ctx.addIssue({
|
|
6580
|
+
code: z.ZodIssueCode.custom,
|
|
6581
|
+
message: `Invalid recipient address format for chain ${data.chain.name}`,
|
|
6582
|
+
path: ['recipientAddress'],
|
|
6583
|
+
});
|
|
6584
|
+
}
|
|
6585
|
+
});
|
|
6586
|
+
/**
|
|
6587
|
+
* Schema for validating any destination - either with adapter or forwarder-only.
|
|
6588
|
+
*/
|
|
6589
|
+
const bridgeDestinationSchema = z.union([
|
|
6590
|
+
destinationContextSchema,
|
|
6591
|
+
forwarderOnlyDestinationSchema,
|
|
6592
|
+
]);
|
|
6593
|
+
/**
|
|
6594
|
+
* Schema for validating a custom fee configuration.
|
|
6595
|
+
* Validates the simplified CustomFee interface which includes:
|
|
6596
|
+
* - An optional fee amount as string
|
|
6597
|
+
* - An optional fee recipient as string address
|
|
6598
|
+
*
|
|
6599
|
+
* @throws KitError if validation fails
|
|
6600
|
+
*
|
|
6601
|
+
* @example
|
|
6602
|
+
* ```typescript
|
|
6603
|
+
* import { customFeeSchema } from '@core/provider'
|
|
6604
|
+
*
|
|
6605
|
+
* const validConfig = {
|
|
6606
|
+
* value: '1000000',
|
|
6607
|
+
* recipientAddress: '0x1234567890123456789012345678901234567890'
|
|
6608
|
+
* }
|
|
6609
|
+
*
|
|
6610
|
+
* const result = customFeeSchema.safeParse(validConfig)
|
|
6611
|
+
* console.log(result.success) // true
|
|
6612
|
+
* ```
|
|
6613
|
+
*/
|
|
5283
6614
|
const customFeeSchema = z
|
|
5284
6615
|
.object({
|
|
5285
6616
|
/**
|
|
@@ -5542,6 +6873,21 @@ async function fetchUsdcFastBurnFee(sourceDomain, destinationDomain, isTestnet)
|
|
|
5542
6873
|
return minimumFee;
|
|
5543
6874
|
}
|
|
5544
6875
|
|
|
6876
|
+
/**
|
|
6877
|
+
* Well-known SPL Token program ID.
|
|
6878
|
+
* Duplicated here as a raw string to avoid a static import of \@core/adapter-solana
|
|
6879
|
+
* (which would transitively pull \@solana/web3.js into the top-level bundle and
|
|
6880
|
+
* break lazy-loading for EVM-only consumers).
|
|
6881
|
+
*
|
|
6882
|
+
* This MUST match TOKEN_PROGRAM_ID in @core/adapter-solana/src/utils/splTokenUtils.
|
|
6883
|
+
*/
|
|
6884
|
+
const TOKEN_PROGRAM_ID_BASE58 = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; // NOSONAR — public Solana program address
|
|
6885
|
+
/**
|
|
6886
|
+
* Well-known SPL Associated Token Account program ID (same rationale as above).
|
|
6887
|
+
*
|
|
6888
|
+
* This MUST match ASSOCIATED_TOKEN_PROGRAM_ID in @core/adapter-solana/src/utils/splTokenUtils.
|
|
6889
|
+
*/
|
|
6890
|
+
const ASSOCIATED_TOKEN_PROGRAM_ID_BASE58 = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'; // NOSONAR — public Solana program address
|
|
5545
6891
|
/**
|
|
5546
6892
|
* Get the token account address where USDC will be minted for the recipient.
|
|
5547
6893
|
*
|
|
@@ -5585,20 +6931,30 @@ mintAddress) => {
|
|
|
5585
6931
|
return rawAddress;
|
|
5586
6932
|
}
|
|
5587
6933
|
else {
|
|
5588
|
-
// Solana: derive the associated token account
|
|
5589
|
-
//
|
|
6934
|
+
// Solana: derive the associated token account.
|
|
6935
|
+
// Both @solana/web3.js and the program-ID constants are resolved lazily
|
|
6936
|
+
// so that EVM-only consumers never load Solana code.
|
|
6937
|
+
const { PublicKey } = await import('@solana/web3.js').catch(() => {
|
|
6938
|
+
throw new KitError({
|
|
6939
|
+
...InputError.VALIDATION_FAILED,
|
|
6940
|
+
recoverability: 'FATAL',
|
|
6941
|
+
message: 'Failed to load @solana/web3.js. Please ensure it is installed: npm install @solana/web3.js',
|
|
6942
|
+
});
|
|
6943
|
+
});
|
|
5590
6944
|
try {
|
|
5591
|
-
const [{ PublicKey }, { getAssociatedTokenAddressSync }] = await Promise.all([
|
|
5592
|
-
import('@solana/web3.js'),
|
|
5593
|
-
import('@solana/spl-token'),
|
|
5594
|
-
]);
|
|
5595
6945
|
const owner = new PublicKey(rawAddress);
|
|
5596
6946
|
const mintPub = new PublicKey(mintAddress);
|
|
5597
|
-
const
|
|
6947
|
+
const tokenProgramId = new PublicKey(TOKEN_PROGRAM_ID_BASE58);
|
|
6948
|
+
const ataProgramId = new PublicKey(ASSOCIATED_TOKEN_PROGRAM_ID_BASE58);
|
|
6949
|
+
const [ata] = PublicKey.findProgramAddressSync([owner.toBuffer(), tokenProgramId.toBuffer(), mintPub.toBuffer()], ataProgramId);
|
|
5598
6950
|
return ata.toBase58();
|
|
5599
6951
|
}
|
|
5600
|
-
catch {
|
|
5601
|
-
throw new
|
|
6952
|
+
catch (error) {
|
|
6953
|
+
throw new KitError({
|
|
6954
|
+
...InputError.INVALID_ADDRESS,
|
|
6955
|
+
recoverability: 'FATAL',
|
|
6956
|
+
message: `Failed to derive Solana Associated Token Account for recipient "${rawAddress}": ${error instanceof Error ? error.message : String(error)}`,
|
|
6957
|
+
});
|
|
5602
6958
|
}
|
|
5603
6959
|
}
|
|
5604
6960
|
};
|
|
@@ -7914,590 +9270,239 @@ function createLogger(options, stream) {
|
|
|
7914
9270
|
const finalOptions = redactConfig
|
|
7915
9271
|
? { ...pinoOptions, redact: redactConfig }
|
|
7916
9272
|
: 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 });
|
|
9273
|
+
const pinoInstance = pino(finalOptions);
|
|
9274
|
+
return wrapPino(pinoInstance);
|
|
8094
9275
|
}
|
|
8095
9276
|
|
|
8096
9277
|
/**
|
|
8097
|
-
*
|
|
9278
|
+
* Factory for creating Runtime instances with defaults.
|
|
8098
9279
|
*
|
|
8099
|
-
* @
|
|
8100
|
-
|
|
8101
|
-
|
|
9280
|
+
* @packageDocumentation
|
|
9281
|
+
*/
|
|
9282
|
+
// ============================================================================
|
|
9283
|
+
// Validation Schema
|
|
9284
|
+
// ============================================================================
|
|
9285
|
+
/**
|
|
9286
|
+
* Schema for validating {@link RuntimeOptions}.
|
|
8102
9287
|
*
|
|
8103
9288
|
* @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
|
-
* ```
|
|
9289
|
+
* Used internally by {@link createRuntime} to validate options from JS consumers.
|
|
9290
|
+
* Exported for advanced use cases where manual validation is needed.
|
|
8118
9291
|
*/
|
|
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
9292
|
z
|
|
8141
9293
|
.object({
|
|
8142
|
-
logger:
|
|
8143
|
-
|
|
8144
|
-
metrics: z.any().optional(),
|
|
8145
|
-
clock: z.any().optional(),
|
|
9294
|
+
logger: loggerSchema.optional(),
|
|
9295
|
+
metrics: metricsSchema.optional(),
|
|
8146
9296
|
})
|
|
8147
9297
|
.passthrough();
|
|
8148
|
-
|
|
9298
|
+
// ============================================================================
|
|
9299
|
+
// Factory
|
|
9300
|
+
// ============================================================================
|
|
8149
9301
|
/**
|
|
8150
|
-
* Create a
|
|
9302
|
+
* Create a complete Runtime with sensible defaults.
|
|
8151
9303
|
*
|
|
8152
|
-
* @
|
|
8153
|
-
*
|
|
8154
|
-
*
|
|
9304
|
+
* @param options - Optional configuration to override logger and metrics.
|
|
9305
|
+
* @returns A frozen, immutable Runtime with all services guaranteed present.
|
|
9306
|
+
* @throws KitError (INPUT_VALIDATION_FAILED) if options contain invalid services.
|
|
8155
9307
|
*
|
|
8156
|
-
* @
|
|
8157
|
-
*
|
|
8158
|
-
*
|
|
8159
|
-
* @param cause - The underlying error, if any (optional).
|
|
8160
|
-
* @returns A KitError with INPUT type and FATAL recoverability.
|
|
9308
|
+
* @remarks
|
|
9309
|
+
* Creates a fully-configured runtime by merging provided options with defaults.
|
|
9310
|
+
* The returned runtime is frozen to enforce immutability.
|
|
8161
9311
|
*
|
|
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.
|
|
9312
|
+
* | Service | Default | Configurable |
|
|
9313
|
+
* |---------|---------|--------------|
|
|
9314
|
+
* | `logger` | pino logger (info level) | Yes |
|
|
9315
|
+
* | `metrics` | No-op metrics | Yes |
|
|
9316
|
+
* | `events` | Internal event bus | No |
|
|
9317
|
+
* | `clock` | `Date.now()` | No |
|
|
8187
9318
|
*
|
|
8188
|
-
*
|
|
8189
|
-
* This is the built-in USDC definition used by the TokenRegistry.
|
|
8190
|
-
* Includes all known USDC addresses across supported chains.
|
|
9319
|
+
* **Why only logger and metrics?**
|
|
8191
9320
|
*
|
|
8192
|
-
*
|
|
8193
|
-
*
|
|
8194
|
-
* -
|
|
9321
|
+
* - **Logger/Metrics**: Integration points with your infrastructure
|
|
9322
|
+
* - **Events**: Internal pub/sub mechanism - subscribe via `runtime.events.on()`
|
|
9323
|
+
* - **Clock**: Testing concern - use mock factories for tests
|
|
8195
9324
|
*
|
|
8196
9325
|
* @example
|
|
8197
9326
|
* ```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.
|
|
9327
|
+
* import { createRuntime, createLogger } from '@core/runtime'
|
|
8272
9328
|
*
|
|
8273
|
-
*
|
|
8274
|
-
*
|
|
8275
|
-
* without explicit defaults. Extensions can override these definitions.
|
|
9329
|
+
* // Use all defaults
|
|
9330
|
+
* const runtime = createRuntime()
|
|
8276
9331
|
*
|
|
8277
|
-
*
|
|
8278
|
-
*
|
|
8279
|
-
*
|
|
9332
|
+
* // Custom logger
|
|
9333
|
+
* const runtime = createRuntime({
|
|
9334
|
+
* logger: createLogger({ level: 'debug' }),
|
|
9335
|
+
* })
|
|
8280
9336
|
*
|
|
8281
|
-
* //
|
|
8282
|
-
* const
|
|
9337
|
+
* // Custom metrics (e.g., Prometheus)
|
|
9338
|
+
* const runtime = createRuntime({
|
|
9339
|
+
* metrics: myPrometheusMetrics,
|
|
9340
|
+
* })
|
|
8283
9341
|
*
|
|
8284
|
-
* //
|
|
8285
|
-
*
|
|
8286
|
-
*
|
|
9342
|
+
* // Subscribe to events (don't replace the bus)
|
|
9343
|
+
* runtime.events.on('operation.*', (event) => {
|
|
9344
|
+
* console.log('Event:', event.name)
|
|
8287
9345
|
* })
|
|
8288
9346
|
* ```
|
|
8289
9347
|
*/
|
|
8290
|
-
|
|
9348
|
+
function createRuntime(options) {
|
|
9349
|
+
// Resolve logger first (events may need it)
|
|
9350
|
+
const logger = createLogger();
|
|
9351
|
+
// Internal services - not configurable
|
|
9352
|
+
const events = createEventBus({ logger });
|
|
9353
|
+
const clock = defaultClock;
|
|
9354
|
+
// Resolve metrics
|
|
9355
|
+
const metrics = noopMetrics;
|
|
9356
|
+
return Object.freeze({ logger, events, metrics, clock });
|
|
9357
|
+
}
|
|
8291
9358
|
|
|
8292
9359
|
/**
|
|
8293
|
-
*
|
|
9360
|
+
* Invocation context resolution - resolves the **WHO/HOW** of an operation.
|
|
8294
9361
|
*
|
|
8295
|
-
* @
|
|
8296
|
-
* @returns True if the selector is a raw token selector.
|
|
9362
|
+
* @packageDocumentation
|
|
8297
9363
|
*/
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
9364
|
+
// ============================================================================
|
|
9365
|
+
// Validation Schemas
|
|
9366
|
+
// ============================================================================
|
|
9367
|
+
/**
|
|
9368
|
+
* Schema for validating Caller.
|
|
9369
|
+
*/
|
|
9370
|
+
const callerSchema = z.object({
|
|
9371
|
+
type: z.string(),
|
|
9372
|
+
name: z.string(),
|
|
9373
|
+
version: z.string().optional(),
|
|
9374
|
+
});
|
|
9375
|
+
/**
|
|
9376
|
+
* Schema for validating InvocationMeta input.
|
|
9377
|
+
*/
|
|
9378
|
+
const invocationMetaSchema = z
|
|
9379
|
+
.object({
|
|
9380
|
+
traceId: z.string().optional(),
|
|
9381
|
+
runtime: z.object({}).passthrough().optional(),
|
|
9382
|
+
tokens: z.object({}).passthrough().optional(),
|
|
9383
|
+
callers: z.array(callerSchema).optional(),
|
|
9384
|
+
})
|
|
9385
|
+
.strict();
|
|
9386
|
+
// ============================================================================
|
|
9387
|
+
// Invocation Context Resolution
|
|
9388
|
+
// ============================================================================
|
|
8301
9389
|
/**
|
|
8302
|
-
*
|
|
9390
|
+
* Resolve invocation metadata to invocation context.
|
|
8303
9391
|
*
|
|
8304
|
-
* @param
|
|
8305
|
-
* @
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
return symbol.toUpperCase();
|
|
8309
|
-
}
|
|
8310
|
-
/**
|
|
8311
|
-
* Create a token registry with built-in tokens and optional extensions.
|
|
9392
|
+
* @param meta - User-provided invocation metadata (**WHO/HOW**), optional.
|
|
9393
|
+
* @param defaults - Default runtime and tokens to use if not overridden.
|
|
9394
|
+
* @returns Frozen, immutable invocation context with guaranteed values.
|
|
9395
|
+
* @throws KitError when meta contains invalid properties.
|
|
8312
9396
|
*
|
|
8313
9397
|
* @remarks
|
|
8314
|
-
*
|
|
8315
|
-
*
|
|
8316
|
-
*
|
|
9398
|
+
* Resolves the **WHO** called and **HOW** to observe:
|
|
9399
|
+
* - TraceId: Uses provided value or generates new one
|
|
9400
|
+
* - Runtime: Uses meta.runtime if provided, otherwise defaults.runtime
|
|
9401
|
+
* - Tokens: Uses meta.tokens if provided, otherwise defaults.tokens
|
|
9402
|
+
* - Callers: Uses provided array or empty array
|
|
8317
9403
|
*
|
|
8318
|
-
*
|
|
8319
|
-
* @returns A token registry instance.
|
|
9404
|
+
* The returned context is frozen to enforce immutability.
|
|
8320
9405
|
*
|
|
8321
9406
|
* @example
|
|
8322
9407
|
* ```typescript
|
|
9408
|
+
* import { resolveInvocationContext, createRuntime } from '@core/runtime'
|
|
8323
9409
|
* import { createTokenRegistry } from '@core/tokens'
|
|
8324
9410
|
*
|
|
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...' },
|
|
9411
|
+
* const defaults = {
|
|
9412
|
+
* runtime: createRuntime(),
|
|
9413
|
+
* tokens: createTokenRegistry(),
|
|
8341
9414
|
* }
|
|
8342
9415
|
*
|
|
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
|
-
* }
|
|
9416
|
+
* // Minimal - just using defaults
|
|
9417
|
+
* const ctx = resolveInvocationContext(undefined, defaults)
|
|
8356
9418
|
*
|
|
8357
|
-
*
|
|
8358
|
-
*
|
|
8359
|
-
*
|
|
9419
|
+
* // With trace ID and caller info
|
|
9420
|
+
* const ctx = resolveInvocationContext(
|
|
9421
|
+
* {
|
|
9422
|
+
* traceId: 'abc-123',
|
|
9423
|
+
* callers: [{ type: 'kit', name: 'BridgeKit', version: '1.0.0' }],
|
|
9424
|
+
* },
|
|
9425
|
+
* defaults
|
|
9426
|
+
* )
|
|
8360
9427
|
*
|
|
8361
|
-
*
|
|
8362
|
-
*
|
|
8363
|
-
*
|
|
8364
|
-
*
|
|
8365
|
-
* const token = registry.resolve(
|
|
8366
|
-
* { locator: '0x1234...', decimals: 18 },
|
|
8367
|
-
* 'Ethereum'
|
|
9428
|
+
* // With runtime override (complete replacement)
|
|
9429
|
+
* const ctx = resolveInvocationContext(
|
|
9430
|
+
* { runtime: createRuntime({ logger: myLogger }) },
|
|
9431
|
+
* defaults
|
|
8368
9432
|
* )
|
|
8369
9433
|
* ```
|
|
8370
9434
|
*/
|
|
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);
|
|
9435
|
+
function resolveInvocationContext(meta, defaults) {
|
|
9436
|
+
// Validate meta input if provided
|
|
9437
|
+
if (meta !== undefined) {
|
|
9438
|
+
const result = invocationMetaSchema.safeParse(meta);
|
|
9439
|
+
if (!result.success) {
|
|
9440
|
+
throw createValidationFailedError('invocationMeta', meta, result.error.errors.map((e) => e.message).join(', '));
|
|
8423
9441
|
}
|
|
8424
|
-
return {
|
|
8425
|
-
decimals,
|
|
8426
|
-
locator,
|
|
8427
|
-
};
|
|
8428
9442
|
}
|
|
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
|
-
};
|
|
9443
|
+
// Generate trace ID if not provided
|
|
9444
|
+
const traceId = meta?.traceId ?? createTraceId();
|
|
9445
|
+
// Use meta overrides or fall back to defaults
|
|
9446
|
+
const runtime = meta?.runtime ?? defaults.runtime;
|
|
9447
|
+
const tokens = meta?.tokens ?? defaults.tokens;
|
|
9448
|
+
const callers = meta?.callers ?? [];
|
|
9449
|
+
return Object.freeze({ traceId, runtime, tokens, callers });
|
|
8467
9450
|
}
|
|
8468
9451
|
|
|
8469
9452
|
/**
|
|
8470
|
-
*
|
|
9453
|
+
* Extend an invocation context by appending a caller to its call chain.
|
|
9454
|
+
*
|
|
9455
|
+
* @param context - The existing invocation context to extend.
|
|
9456
|
+
* @param caller - The caller to append to the call chain.
|
|
9457
|
+
* @returns A new frozen invocation context with the caller appended.
|
|
8471
9458
|
*
|
|
8472
9459
|
* @remarks
|
|
8473
|
-
*
|
|
9460
|
+
* This function creates a new immutable context with the caller appended
|
|
9461
|
+
* to the `callers` array while preserving all other context properties
|
|
9462
|
+
* (traceId, runtime, tokens).
|
|
9463
|
+
*
|
|
9464
|
+
* The returned context is frozen to enforce immutability.
|
|
8474
9465
|
*
|
|
8475
9466
|
* @example
|
|
8476
9467
|
* ```typescript
|
|
8477
|
-
* import {
|
|
8478
|
-
*
|
|
8479
|
-
* const registry = {
|
|
8480
|
-
* resolve: () => ({ locator: '0x0', decimals: 6 }),
|
|
8481
|
-
* }
|
|
9468
|
+
* import { extendInvocationContext } from '@core/runtime'
|
|
8482
9469
|
*
|
|
8483
|
-
*
|
|
9470
|
+
* const caller = { type: 'provider', name: 'CCTPV2', version: '1.0.0' }
|
|
9471
|
+
* const extended = extendInvocationContext(existingContext, caller)
|
|
9472
|
+
* // extended.callers === [...existingContext.callers, caller]
|
|
8484
9473
|
* ```
|
|
8485
9474
|
*/
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
9475
|
+
function extendInvocationContext(context, caller) {
|
|
9476
|
+
return Object.freeze({
|
|
9477
|
+
traceId: context.traceId,
|
|
9478
|
+
runtime: context.runtime,
|
|
9479
|
+
tokens: context.tokens,
|
|
9480
|
+
callers: [...context.callers, caller],
|
|
9481
|
+
});
|
|
9482
|
+
}
|
|
9483
|
+
|
|
9484
|
+
// Clock - expose defaultClock for backward compatibility
|
|
9485
|
+
/** Clock validation schema (backward compatibility). */
|
|
9486
|
+
z.custom((val) => val !== null &&
|
|
9487
|
+
typeof val === 'object' &&
|
|
9488
|
+
'now' in val &&
|
|
9489
|
+
typeof val['now'] === 'function');
|
|
9490
|
+
/** EventBus validation schema (backward compatibility). */
|
|
9491
|
+
z.custom((val) => val !== null &&
|
|
9492
|
+
typeof val === 'object' &&
|
|
9493
|
+
'emit' in val &&
|
|
9494
|
+
typeof val['emit'] === 'function');
|
|
9495
|
+
/** Runtime validation schema (backward compatibility). */
|
|
9496
|
+
z
|
|
9497
|
+
.object({
|
|
9498
|
+
logger: z.any().optional(),
|
|
9499
|
+
events: z.any().optional(),
|
|
9500
|
+
metrics: z.any().optional(),
|
|
9501
|
+
clock: z.any().optional(),
|
|
9502
|
+
})
|
|
9503
|
+
.passthrough();
|
|
8499
9504
|
|
|
8500
|
-
var version = "1.
|
|
9505
|
+
var version = "1.5.0";
|
|
8501
9506
|
var pkg = {
|
|
8502
9507
|
version: version};
|
|
8503
9508
|
|
|
@@ -8980,6 +9985,24 @@ const validateNativeBalanceForTransaction = async (params) => {
|
|
|
8980
9985
|
}
|
|
8981
9986
|
};
|
|
8982
9987
|
|
|
9988
|
+
/**
|
|
9989
|
+
* Permit signature standards for gasless token approvals.
|
|
9990
|
+
*
|
|
9991
|
+
* Defines the permit types that can be used to approve token spending
|
|
9992
|
+
* without requiring a separate approval transaction.
|
|
9993
|
+
*
|
|
9994
|
+
* @remarks
|
|
9995
|
+
* - NONE: No permit, tokens must be pre-approved via separate transaction
|
|
9996
|
+
* - EIP2612: Standard ERC-20 permit (USDC, DAI v2, and most modern tokens)
|
|
9997
|
+
*/
|
|
9998
|
+
var PermitType;
|
|
9999
|
+
(function (PermitType) {
|
|
10000
|
+
/** No permit required - tokens must be pre-approved */
|
|
10001
|
+
PermitType[PermitType["NONE"] = 0] = "NONE";
|
|
10002
|
+
/** EIP-2612 standard permit */
|
|
10003
|
+
PermitType[PermitType["EIP2612"] = 1] = "EIP2612";
|
|
10004
|
+
})(PermitType || (PermitType = {}));
|
|
10005
|
+
|
|
8983
10006
|
/**
|
|
8984
10007
|
* CCTP bridge step names that can occur in the bridging flow.
|
|
8985
10008
|
*
|