@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.cjs
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
'use strict';
|
|
20
20
|
|
|
21
21
|
// Buffer polyfill setup - executes before any other code
|
|
22
|
-
// Ensures globalThis.Buffer is available for
|
|
22
|
+
// Ensures globalThis.Buffer is available for Solana libraries
|
|
23
23
|
const { Buffer } = require('buffer');
|
|
24
24
|
if (typeof globalThis !== 'undefined' && typeof globalThis.Buffer === 'undefined') {
|
|
25
25
|
globalThis.Buffer = Buffer;
|
|
@@ -73,6 +73,8 @@ var Blockchain;
|
|
|
73
73
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
74
74
|
Blockchain["Codex"] = "Codex";
|
|
75
75
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
76
|
+
Blockchain["Edge"] = "Edge";
|
|
77
|
+
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
76
78
|
Blockchain["Ethereum"] = "Ethereum";
|
|
77
79
|
Blockchain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
78
80
|
Blockchain["Hedera"] = "Hedera";
|
|
@@ -85,6 +87,8 @@ var Blockchain;
|
|
|
85
87
|
Blockchain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
86
88
|
Blockchain["Monad"] = "Monad";
|
|
87
89
|
Blockchain["Monad_Testnet"] = "Monad_Testnet";
|
|
90
|
+
Blockchain["Morph"] = "Morph";
|
|
91
|
+
Blockchain["Morph_Testnet"] = "Morph_Testnet";
|
|
88
92
|
Blockchain["NEAR"] = "NEAR";
|
|
89
93
|
Blockchain["NEAR_Testnet"] = "NEAR_Testnet";
|
|
90
94
|
Blockchain["Noble"] = "Noble";
|
|
@@ -116,6 +120,122 @@ var Blockchain;
|
|
|
116
120
|
Blockchain["ZKSync_Era"] = "ZKSync_Era";
|
|
117
121
|
Blockchain["ZKSync_Sepolia"] = "ZKSync_Sepolia";
|
|
118
122
|
})(Blockchain || (Blockchain = {}));
|
|
123
|
+
/**
|
|
124
|
+
* Enum representing the subset of {@link Blockchain} that supports swap operations.
|
|
125
|
+
*
|
|
126
|
+
* This enum provides compile-time type safety for swap chain selection,
|
|
127
|
+
* ensuring only supported chains are available in IDE autocomplete
|
|
128
|
+
* when building swap parameters.
|
|
129
|
+
*
|
|
130
|
+
* @remarks
|
|
131
|
+
* Unlike the full {@link Blockchain} enum, SwapChain only includes networks
|
|
132
|
+
* where the swap functionality is actively supported by the library.
|
|
133
|
+
* Using this enum prevents runtime errors from attempting unsupported
|
|
134
|
+
* cross-chain swaps.
|
|
135
|
+
*
|
|
136
|
+
* Currently supports:
|
|
137
|
+
* - Ethereum mainnet
|
|
138
|
+
* - Base mainnet
|
|
139
|
+
* - Polygon mainnet
|
|
140
|
+
* - Solana mainnet
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* import { SwapChain, swap, createSwapKitContext } from '@circle-fin/swap-kit'
|
|
145
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
146
|
+
*
|
|
147
|
+
* const context = createSwapKitContext()
|
|
148
|
+
* const adapter = createViemAdapterFromPrivateKey({
|
|
149
|
+
* privateKey: process.env.PRIVATE_KEY
|
|
150
|
+
* })
|
|
151
|
+
*
|
|
152
|
+
* // ✅ Autocomplete shows only swap-supported chains
|
|
153
|
+
* const result = await swap(context, {
|
|
154
|
+
* from: {
|
|
155
|
+
* adapter,
|
|
156
|
+
* chain: SwapChain.Ethereum // Autocomplete: Ethereum, Base, Polygon, Solana
|
|
157
|
+
* },
|
|
158
|
+
* tokenIn: 'USDC',
|
|
159
|
+
* tokenOut: 'USDT',
|
|
160
|
+
* amount: '100.0'
|
|
161
|
+
* })
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* // String literals also work (constrained to SwapChain values)
|
|
167
|
+
* const result = await swap(context, {
|
|
168
|
+
* from: {
|
|
169
|
+
* adapter,
|
|
170
|
+
* chain: 'Ethereum' // ✅ Only SwapChain strings allowed
|
|
171
|
+
* },
|
|
172
|
+
* tokenIn: 'USDC',
|
|
173
|
+
* tokenOut: 'NATIVE',
|
|
174
|
+
* amount: '50.0'
|
|
175
|
+
* })
|
|
176
|
+
*
|
|
177
|
+
* // ❌ TypeScript error - Sui not in SwapChain enum
|
|
178
|
+
* const invalidResult = await swap(context, {
|
|
179
|
+
* from: {
|
|
180
|
+
* adapter,
|
|
181
|
+
* chain: 'Sui' // Compile-time error!
|
|
182
|
+
* },
|
|
183
|
+
* tokenIn: 'USDC',
|
|
184
|
+
* tokenOut: 'USDT',
|
|
185
|
+
* amount: '100.0'
|
|
186
|
+
* })
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
/**
|
|
190
|
+
* Enum representing chains that support same-chain swaps through the Swap Kit.
|
|
191
|
+
*
|
|
192
|
+
* Unlike the full {@link Blockchain} enum, SwapChain includes only mainnet
|
|
193
|
+
* networks where adapter contracts are deployed (CCTPv2 support).
|
|
194
|
+
*
|
|
195
|
+
* Dynamic validation via {@link isSwapSupportedChain} ensures chains
|
|
196
|
+
* automatically work when adapter contracts and supported tokens are deployed.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```typescript
|
|
200
|
+
* import { SwapChain } from '@core/chains'
|
|
201
|
+
* import { swap } from '@circle-fin/swap-kit'
|
|
202
|
+
*
|
|
203
|
+
* const result = await swap(context, {
|
|
204
|
+
* from: {
|
|
205
|
+
* adapter,
|
|
206
|
+
* chain: SwapChain.Arbitrum // Now supported!
|
|
207
|
+
* },
|
|
208
|
+
* tokenIn: 'USDC',
|
|
209
|
+
* tokenOut: 'WETH',
|
|
210
|
+
* amount: '100.0'
|
|
211
|
+
* })
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
214
|
+
* @see {@link isSwapSupportedChain} for runtime validation
|
|
215
|
+
* @see {@link getSwapSupportedChains} for all supported chains
|
|
216
|
+
*/
|
|
217
|
+
var SwapChain;
|
|
218
|
+
(function (SwapChain) {
|
|
219
|
+
// Original 4 chains
|
|
220
|
+
SwapChain["Ethereum"] = "Ethereum";
|
|
221
|
+
SwapChain["Base"] = "Base";
|
|
222
|
+
SwapChain["Polygon"] = "Polygon";
|
|
223
|
+
SwapChain["Solana"] = "Solana";
|
|
224
|
+
// Additional supported chains
|
|
225
|
+
SwapChain["Arbitrum"] = "Arbitrum";
|
|
226
|
+
SwapChain["Optimism"] = "Optimism";
|
|
227
|
+
SwapChain["Avalanche"] = "Avalanche";
|
|
228
|
+
SwapChain["Linea"] = "Linea";
|
|
229
|
+
SwapChain["Ink"] = "Ink";
|
|
230
|
+
SwapChain["World_Chain"] = "World_Chain";
|
|
231
|
+
SwapChain["Unichain"] = "Unichain";
|
|
232
|
+
SwapChain["Plume"] = "Plume";
|
|
233
|
+
SwapChain["Sei"] = "Sei";
|
|
234
|
+
SwapChain["Sonic"] = "Sonic";
|
|
235
|
+
SwapChain["XDC"] = "XDC";
|
|
236
|
+
SwapChain["HyperEVM"] = "HyperEVM";
|
|
237
|
+
SwapChain["Monad"] = "Monad";
|
|
238
|
+
})(SwapChain || (SwapChain = {}));
|
|
119
239
|
// -----------------------------------------------------------------------------
|
|
120
240
|
// Bridge Chain Enum (CCTPv2 Supported Chains)
|
|
121
241
|
// -----------------------------------------------------------------------------
|
|
@@ -172,11 +292,13 @@ var BridgeChain;
|
|
|
172
292
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
173
293
|
BridgeChain["Base"] = "Base";
|
|
174
294
|
BridgeChain["Codex"] = "Codex";
|
|
295
|
+
BridgeChain["Edge"] = "Edge";
|
|
175
296
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
176
297
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
177
298
|
BridgeChain["Ink"] = "Ink";
|
|
178
299
|
BridgeChain["Linea"] = "Linea";
|
|
179
300
|
BridgeChain["Monad"] = "Monad";
|
|
301
|
+
BridgeChain["Morph"] = "Morph";
|
|
180
302
|
BridgeChain["Optimism"] = "Optimism";
|
|
181
303
|
BridgeChain["Plume"] = "Plume";
|
|
182
304
|
BridgeChain["Polygon"] = "Polygon";
|
|
@@ -192,11 +314,13 @@ var BridgeChain;
|
|
|
192
314
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
193
315
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
194
316
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
317
|
+
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
195
318
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
196
319
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
197
320
|
BridgeChain["Ink_Testnet"] = "Ink_Testnet";
|
|
198
321
|
BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
199
322
|
BridgeChain["Monad_Testnet"] = "Monad_Testnet";
|
|
323
|
+
BridgeChain["Morph_Testnet"] = "Morph_Testnet";
|
|
200
324
|
BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
|
|
201
325
|
BridgeChain["Plume_Testnet"] = "Plume_Testnet";
|
|
202
326
|
BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
|
|
@@ -267,6 +391,7 @@ const Algorand = defineChain({
|
|
|
267
391
|
rpcEndpoints: ['https://mainnet-api.algonode.cloud'],
|
|
268
392
|
eurcAddress: null,
|
|
269
393
|
usdcAddress: '31566704',
|
|
394
|
+
usdtAddress: null,
|
|
270
395
|
cctp: null,
|
|
271
396
|
});
|
|
272
397
|
|
|
@@ -290,6 +415,7 @@ const AlgorandTestnet = defineChain({
|
|
|
290
415
|
rpcEndpoints: ['https://testnet-api.algonode.cloud'],
|
|
291
416
|
eurcAddress: null,
|
|
292
417
|
usdcAddress: '10458941',
|
|
418
|
+
usdtAddress: null,
|
|
293
419
|
cctp: null,
|
|
294
420
|
});
|
|
295
421
|
|
|
@@ -313,6 +439,7 @@ const Aptos = defineChain({
|
|
|
313
439
|
rpcEndpoints: ['https://fullnode.mainnet.aptoslabs.com/v1'],
|
|
314
440
|
eurcAddress: null,
|
|
315
441
|
usdcAddress: '0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b',
|
|
442
|
+
usdtAddress: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
316
443
|
cctp: {
|
|
317
444
|
domain: 9,
|
|
318
445
|
contracts: {
|
|
@@ -350,6 +477,7 @@ const AptosTestnet = defineChain({
|
|
|
350
477
|
rpcEndpoints: ['https://fullnode.testnet.aptoslabs.com/v1'],
|
|
351
478
|
eurcAddress: null,
|
|
352
479
|
usdcAddress: '0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832',
|
|
480
|
+
usdtAddress: null,
|
|
353
481
|
cctp: {
|
|
354
482
|
domain: 9,
|
|
355
483
|
contracts: {
|
|
@@ -367,6 +495,121 @@ const AptosTestnet = defineChain({
|
|
|
367
495
|
},
|
|
368
496
|
});
|
|
369
497
|
|
|
498
|
+
/**
|
|
499
|
+
* Complete swap token registry - single source of truth for all swap-supported tokens.
|
|
500
|
+
*
|
|
501
|
+
* @remarks
|
|
502
|
+
* All packages should import from this registry for swap operations.
|
|
503
|
+
* Adding a new swap token requires updating only this registry.
|
|
504
|
+
*
|
|
505
|
+
* The NATIVE token is handled separately as it resolves dynamically based on chain.
|
|
506
|
+
*
|
|
507
|
+
* @example
|
|
508
|
+
* ```typescript
|
|
509
|
+
* import { SWAP_TOKEN_REGISTRY } from '@core/chains'
|
|
510
|
+
*
|
|
511
|
+
* // Get token decimals
|
|
512
|
+
* const decimals = SWAP_TOKEN_REGISTRY.USDC.decimals // 6
|
|
513
|
+
*
|
|
514
|
+
* // Check if token is stablecoin
|
|
515
|
+
* const isStable = SWAP_TOKEN_REGISTRY.DAI.category === 'stablecoin' // true
|
|
516
|
+
* ```
|
|
517
|
+
*/
|
|
518
|
+
const SWAP_TOKEN_REGISTRY = {
|
|
519
|
+
// ============================================================================
|
|
520
|
+
// Stablecoins (6 decimals)
|
|
521
|
+
// ============================================================================
|
|
522
|
+
USDC: {
|
|
523
|
+
symbol: 'USDC',
|
|
524
|
+
decimals: 6,
|
|
525
|
+
category: 'stablecoin',
|
|
526
|
+
description: 'USD Coin',
|
|
527
|
+
},
|
|
528
|
+
EURC: {
|
|
529
|
+
symbol: 'EURC',
|
|
530
|
+
decimals: 6,
|
|
531
|
+
category: 'stablecoin',
|
|
532
|
+
description: 'Euro Coin',
|
|
533
|
+
},
|
|
534
|
+
USDT: {
|
|
535
|
+
symbol: 'USDT',
|
|
536
|
+
decimals: 6,
|
|
537
|
+
category: 'stablecoin',
|
|
538
|
+
description: 'Tether USD',
|
|
539
|
+
},
|
|
540
|
+
PYUSD: {
|
|
541
|
+
symbol: 'PYUSD',
|
|
542
|
+
decimals: 6,
|
|
543
|
+
category: 'stablecoin',
|
|
544
|
+
description: 'PayPal USD',
|
|
545
|
+
},
|
|
546
|
+
// ============================================================================
|
|
547
|
+
// Stablecoins (18 decimals)
|
|
548
|
+
// ============================================================================
|
|
549
|
+
DAI: {
|
|
550
|
+
symbol: 'DAI',
|
|
551
|
+
decimals: 18,
|
|
552
|
+
category: 'stablecoin',
|
|
553
|
+
description: 'MakerDAO stablecoin',
|
|
554
|
+
},
|
|
555
|
+
USDE: {
|
|
556
|
+
symbol: 'USDE',
|
|
557
|
+
decimals: 18,
|
|
558
|
+
category: 'stablecoin',
|
|
559
|
+
description: 'Ethena USD (synthetic dollar)',
|
|
560
|
+
},
|
|
561
|
+
// ============================================================================
|
|
562
|
+
// Wrapped Tokens
|
|
563
|
+
// ============================================================================
|
|
564
|
+
WBTC: {
|
|
565
|
+
symbol: 'WBTC',
|
|
566
|
+
decimals: 8,
|
|
567
|
+
category: 'wrapped',
|
|
568
|
+
description: 'Wrapped Bitcoin',
|
|
569
|
+
},
|
|
570
|
+
WETH: {
|
|
571
|
+
symbol: 'WETH',
|
|
572
|
+
decimals: 18,
|
|
573
|
+
category: 'wrapped',
|
|
574
|
+
description: 'Wrapped Ethereum',
|
|
575
|
+
},
|
|
576
|
+
WSOL: {
|
|
577
|
+
symbol: 'WSOL',
|
|
578
|
+
decimals: 9,
|
|
579
|
+
category: 'wrapped',
|
|
580
|
+
description: 'Wrapped Solana',
|
|
581
|
+
},
|
|
582
|
+
WAVAX: {
|
|
583
|
+
symbol: 'WAVAX',
|
|
584
|
+
decimals: 18,
|
|
585
|
+
category: 'wrapped',
|
|
586
|
+
description: 'Wrapped Avalanche',
|
|
587
|
+
},
|
|
588
|
+
WPOL: {
|
|
589
|
+
symbol: 'WPOL',
|
|
590
|
+
decimals: 18,
|
|
591
|
+
category: 'wrapped',
|
|
592
|
+
description: 'Wrapped Polygon',
|
|
593
|
+
},
|
|
594
|
+
};
|
|
595
|
+
/**
|
|
596
|
+
* Special NATIVE token constant for swap operations.
|
|
597
|
+
*
|
|
598
|
+
* @remarks
|
|
599
|
+
* NATIVE is handled separately from SWAP_TOKEN_REGISTRY because it resolves
|
|
600
|
+
* dynamically based on the chain (ETH on Ethereum, SOL on Solana, etc.).
|
|
601
|
+
* Its decimals are chain-specific.
|
|
602
|
+
*/
|
|
603
|
+
const NATIVE_TOKEN = 'NATIVE';
|
|
604
|
+
/**
|
|
605
|
+
* Array of all supported swap token symbols including NATIVE.
|
|
606
|
+
* Useful for iteration, validation, and filtering.
|
|
607
|
+
*/
|
|
608
|
+
[
|
|
609
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
610
|
+
NATIVE_TOKEN,
|
|
611
|
+
];
|
|
612
|
+
|
|
370
613
|
/**
|
|
371
614
|
* The bridge contract address for EVM testnet networks.
|
|
372
615
|
*
|
|
@@ -383,6 +626,13 @@ const BRIDGE_CONTRACT_EVM_TESTNET = '0xC5567a5E3370d4DBfB0540025078e283e36A363d'
|
|
|
383
626
|
* USDC transfers on live networks.
|
|
384
627
|
*/
|
|
385
628
|
const BRIDGE_CONTRACT_EVM_MAINNET = '0xB3FA262d0fB521cc93bE83d87b322b8A23DAf3F0';
|
|
629
|
+
/**
|
|
630
|
+
* The adapter contract address for EVM mainnet networks.
|
|
631
|
+
*
|
|
632
|
+
* This contract serves as an adapter for integrating with various protocols
|
|
633
|
+
* on EVM-compatible chains. Use this address for mainnet adapter integrations.
|
|
634
|
+
*/
|
|
635
|
+
const ADAPTER_CONTRACT_EVM_MAINNET = '0x7FB8c7260b63934d8da38aF902f87ae6e284a845';
|
|
386
636
|
|
|
387
637
|
/**
|
|
388
638
|
* Arc Testnet chain definition
|
|
@@ -412,6 +662,7 @@ const ArcTestnet = defineChain({
|
|
|
412
662
|
rpcEndpoints: ['https://rpc.testnet.arc.network/'],
|
|
413
663
|
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
414
664
|
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
665
|
+
usdtAddress: null,
|
|
415
666
|
cctp: {
|
|
416
667
|
domain: 26,
|
|
417
668
|
contracts: {
|
|
@@ -454,6 +705,7 @@ const Arbitrum = defineChain({
|
|
|
454
705
|
rpcEndpoints: ['https://arb1.arbitrum.io/rpc'],
|
|
455
706
|
eurcAddress: null,
|
|
456
707
|
usdcAddress: '0xaf88d065e77c8cc2239327c5edb3a432268e5831',
|
|
708
|
+
usdtAddress: null,
|
|
457
709
|
cctp: {
|
|
458
710
|
domain: 3,
|
|
459
711
|
contracts: {
|
|
@@ -478,6 +730,7 @@ const Arbitrum = defineChain({
|
|
|
478
730
|
},
|
|
479
731
|
kitContracts: {
|
|
480
732
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
733
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
481
734
|
},
|
|
482
735
|
});
|
|
483
736
|
|
|
@@ -502,6 +755,7 @@ const ArbitrumSepolia = defineChain({
|
|
|
502
755
|
rpcEndpoints: ['https://sepolia-rollup.arbitrum.io/rpc'],
|
|
503
756
|
eurcAddress: null,
|
|
504
757
|
usdcAddress: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
758
|
+
usdtAddress: null,
|
|
505
759
|
cctp: {
|
|
506
760
|
domain: 3,
|
|
507
761
|
contracts: {
|
|
@@ -550,6 +804,7 @@ const Avalanche = defineChain({
|
|
|
550
804
|
rpcEndpoints: ['https://api.avax.network/ext/bc/C/rpc'],
|
|
551
805
|
eurcAddress: '0xc891eb4cbdeff6e073e859e987815ed1505c2acd',
|
|
552
806
|
usdcAddress: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
807
|
+
usdtAddress: '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7',
|
|
553
808
|
cctp: {
|
|
554
809
|
domain: 1,
|
|
555
810
|
contracts: {
|
|
@@ -574,6 +829,7 @@ const Avalanche = defineChain({
|
|
|
574
829
|
},
|
|
575
830
|
kitContracts: {
|
|
576
831
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
832
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
577
833
|
},
|
|
578
834
|
});
|
|
579
835
|
|
|
@@ -597,6 +853,7 @@ const AvalancheFuji = defineChain({
|
|
|
597
853
|
explorerUrl: 'https://subnets-test.avax.network/c-chain/tx/{hash}',
|
|
598
854
|
eurcAddress: '0x5e44db7996c682e92a960b65ac713a54ad815c6b',
|
|
599
855
|
usdcAddress: '0x5425890298aed601595a70ab815c96711a31bc65',
|
|
856
|
+
usdtAddress: null,
|
|
600
857
|
cctp: {
|
|
601
858
|
domain: 1,
|
|
602
859
|
contracts: {
|
|
@@ -646,6 +903,7 @@ const Base = defineChain({
|
|
|
646
903
|
rpcEndpoints: ['https://mainnet.base.org', 'https://base.publicnode.com'],
|
|
647
904
|
eurcAddress: '0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42',
|
|
648
905
|
usdcAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
906
|
+
usdtAddress: null,
|
|
649
907
|
cctp: {
|
|
650
908
|
domain: 6,
|
|
651
909
|
contracts: {
|
|
@@ -670,6 +928,7 @@ const Base = defineChain({
|
|
|
670
928
|
},
|
|
671
929
|
kitContracts: {
|
|
672
930
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
931
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
673
932
|
},
|
|
674
933
|
});
|
|
675
934
|
|
|
@@ -694,6 +953,7 @@ const BaseSepolia = defineChain({
|
|
|
694
953
|
rpcEndpoints: ['https://sepolia.base.org'],
|
|
695
954
|
eurcAddress: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
696
955
|
usdcAddress: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
956
|
+
usdtAddress: null,
|
|
697
957
|
cctp: {
|
|
698
958
|
domain: 6,
|
|
699
959
|
contracts: {
|
|
@@ -742,6 +1002,7 @@ const Celo = defineChain({
|
|
|
742
1002
|
rpcEndpoints: ['https://forno.celo.org'],
|
|
743
1003
|
eurcAddress: null,
|
|
744
1004
|
usdcAddress: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
1005
|
+
usdtAddress: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
745
1006
|
cctp: null,
|
|
746
1007
|
});
|
|
747
1008
|
|
|
@@ -766,6 +1027,7 @@ const CeloAlfajoresTestnet = defineChain({
|
|
|
766
1027
|
rpcEndpoints: ['https://alfajores-forno.celo-testnet.org'],
|
|
767
1028
|
eurcAddress: null,
|
|
768
1029
|
usdcAddress: '0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B',
|
|
1030
|
+
usdtAddress: null,
|
|
769
1031
|
cctp: null,
|
|
770
1032
|
});
|
|
771
1033
|
|
|
@@ -790,6 +1052,7 @@ const Codex = defineChain({
|
|
|
790
1052
|
rpcEndpoints: ['https://rpc.codex.xyz'],
|
|
791
1053
|
eurcAddress: null,
|
|
792
1054
|
usdcAddress: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
1055
|
+
usdtAddress: null,
|
|
793
1056
|
cctp: {
|
|
794
1057
|
domain: 12,
|
|
795
1058
|
contracts: {
|
|
@@ -832,6 +1095,7 @@ const CodexTestnet = defineChain({
|
|
|
832
1095
|
rpcEndpoints: ['https://rpc.codex-stg.xyz'],
|
|
833
1096
|
eurcAddress: null,
|
|
834
1097
|
usdcAddress: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
1098
|
+
usdtAddress: null,
|
|
835
1099
|
cctp: {
|
|
836
1100
|
domain: 12,
|
|
837
1101
|
contracts: {
|
|
@@ -853,6 +1117,94 @@ const CodexTestnet = defineChain({
|
|
|
853
1117
|
},
|
|
854
1118
|
});
|
|
855
1119
|
|
|
1120
|
+
/**
|
|
1121
|
+
* Edge Mainnet chain definition
|
|
1122
|
+
* @remarks
|
|
1123
|
+
* This represents the official production network for the Edge blockchain.
|
|
1124
|
+
* Edge is an EVM-compatible blockchain.
|
|
1125
|
+
*/
|
|
1126
|
+
const Edge = defineChain({
|
|
1127
|
+
type: 'evm',
|
|
1128
|
+
chain: Blockchain.Edge,
|
|
1129
|
+
name: 'Edge',
|
|
1130
|
+
title: 'Edge Mainnet',
|
|
1131
|
+
nativeCurrency: {
|
|
1132
|
+
name: 'Ether',
|
|
1133
|
+
symbol: 'ETH',
|
|
1134
|
+
decimals: 18,
|
|
1135
|
+
},
|
|
1136
|
+
chainId: 3343,
|
|
1137
|
+
isTestnet: false,
|
|
1138
|
+
explorerUrl: 'https://pro.edgex.exchange/en-US/explorer/tx/{hash}',
|
|
1139
|
+
rpcEndpoints: ['https://edge-mainnet.g.alchemy.com/public'],
|
|
1140
|
+
eurcAddress: null,
|
|
1141
|
+
usdcAddress: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
1142
|
+
usdtAddress: null,
|
|
1143
|
+
cctp: {
|
|
1144
|
+
domain: 28,
|
|
1145
|
+
contracts: {
|
|
1146
|
+
v2: {
|
|
1147
|
+
type: 'split',
|
|
1148
|
+
tokenMessenger: '0x98706A006bc632Df31CAdFCBD43F38887ce2ca5c',
|
|
1149
|
+
messageTransmitter: '0x5b61381Fc9e58E70EfC13a4A97516997019198ee',
|
|
1150
|
+
confirmations: 65,
|
|
1151
|
+
fastConfirmations: 1,
|
|
1152
|
+
},
|
|
1153
|
+
},
|
|
1154
|
+
forwarderSupported: {
|
|
1155
|
+
source: true,
|
|
1156
|
+
destination: true,
|
|
1157
|
+
},
|
|
1158
|
+
},
|
|
1159
|
+
kitContracts: {
|
|
1160
|
+
bridge: '0x6D1AaE1c34Aeb582022916a67f2A655C6f4eDFF2', //Unique bridge address as CCTP address for Edge is also unique
|
|
1161
|
+
},
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* Edge Testnet chain definition
|
|
1166
|
+
* @remarks
|
|
1167
|
+
* This represents the official test network for the Edge blockchain.
|
|
1168
|
+
* Edge is an EVM-compatible blockchain.
|
|
1169
|
+
*/
|
|
1170
|
+
const EdgeTestnet = defineChain({
|
|
1171
|
+
type: 'evm',
|
|
1172
|
+
chain: Blockchain.Edge_Testnet,
|
|
1173
|
+
name: 'Edge Testnet',
|
|
1174
|
+
title: 'Edge Testnet',
|
|
1175
|
+
nativeCurrency: {
|
|
1176
|
+
name: 'Ether',
|
|
1177
|
+
symbol: 'ETH',
|
|
1178
|
+
decimals: 18,
|
|
1179
|
+
},
|
|
1180
|
+
chainId: 33431,
|
|
1181
|
+
isTestnet: true,
|
|
1182
|
+
explorerUrl: 'https://edge-testnet.explorer.alchemy.com/tx/{hash}',
|
|
1183
|
+
rpcEndpoints: ['https://edge-testnet.g.alchemy.com/public'],
|
|
1184
|
+
eurcAddress: null,
|
|
1185
|
+
usdcAddress: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
1186
|
+
usdtAddress: null,
|
|
1187
|
+
cctp: {
|
|
1188
|
+
domain: 28,
|
|
1189
|
+
contracts: {
|
|
1190
|
+
v2: {
|
|
1191
|
+
type: 'split',
|
|
1192
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
1193
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
1194
|
+
confirmations: 65,
|
|
1195
|
+
fastConfirmations: 1,
|
|
1196
|
+
},
|
|
1197
|
+
},
|
|
1198
|
+
forwarderSupported: {
|
|
1199
|
+
source: true,
|
|
1200
|
+
destination: true,
|
|
1201
|
+
},
|
|
1202
|
+
},
|
|
1203
|
+
kitContracts: {
|
|
1204
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
1205
|
+
},
|
|
1206
|
+
});
|
|
1207
|
+
|
|
856
1208
|
/**
|
|
857
1209
|
* Ethereum Mainnet chain definition
|
|
858
1210
|
* @remarks
|
|
@@ -874,6 +1226,7 @@ const Ethereum = defineChain({
|
|
|
874
1226
|
rpcEndpoints: ['https://eth.merkle.io', 'https://ethereum.publicnode.com'],
|
|
875
1227
|
eurcAddress: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
876
1228
|
usdcAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
1229
|
+
usdtAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7',
|
|
877
1230
|
cctp: {
|
|
878
1231
|
domain: 0,
|
|
879
1232
|
contracts: {
|
|
@@ -898,6 +1251,7 @@ const Ethereum = defineChain({
|
|
|
898
1251
|
},
|
|
899
1252
|
kitContracts: {
|
|
900
1253
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1254
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
901
1255
|
},
|
|
902
1256
|
});
|
|
903
1257
|
|
|
@@ -922,6 +1276,7 @@ const EthereumSepolia = defineChain({
|
|
|
922
1276
|
rpcEndpoints: ['https://sepolia.drpc.org'],
|
|
923
1277
|
eurcAddress: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4',
|
|
924
1278
|
usdcAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
1279
|
+
usdtAddress: null,
|
|
925
1280
|
cctp: {
|
|
926
1281
|
domain: 0,
|
|
927
1282
|
contracts: {
|
|
@@ -969,6 +1324,7 @@ const Hedera = defineChain({
|
|
|
969
1324
|
rpcEndpoints: ['https://mainnet.hashio.io/api'],
|
|
970
1325
|
eurcAddress: null,
|
|
971
1326
|
usdcAddress: '0.0.456858',
|
|
1327
|
+
usdtAddress: null,
|
|
972
1328
|
cctp: null,
|
|
973
1329
|
});
|
|
974
1330
|
|
|
@@ -992,6 +1348,7 @@ const HederaTestnet = defineChain({
|
|
|
992
1348
|
rpcEndpoints: ['https://testnet.hashio.io/api'],
|
|
993
1349
|
eurcAddress: null,
|
|
994
1350
|
usdcAddress: '0.0.429274',
|
|
1351
|
+
usdtAddress: null,
|
|
995
1352
|
cctp: null,
|
|
996
1353
|
});
|
|
997
1354
|
|
|
@@ -1018,6 +1375,7 @@ const HyperEVM = defineChain({
|
|
|
1018
1375
|
rpcEndpoints: ['https://rpc.hyperliquid.xyz/evm'],
|
|
1019
1376
|
eurcAddress: null,
|
|
1020
1377
|
usdcAddress: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
1378
|
+
usdtAddress: null,
|
|
1021
1379
|
cctp: {
|
|
1022
1380
|
domain: 19,
|
|
1023
1381
|
contracts: {
|
|
@@ -1036,6 +1394,7 @@ const HyperEVM = defineChain({
|
|
|
1036
1394
|
},
|
|
1037
1395
|
kitContracts: {
|
|
1038
1396
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1397
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1039
1398
|
},
|
|
1040
1399
|
});
|
|
1041
1400
|
|
|
@@ -1061,6 +1420,7 @@ const HyperEVMTestnet = defineChain({
|
|
|
1061
1420
|
rpcEndpoints: ['https://rpc.hyperliquid-testnet.xyz/evm'],
|
|
1062
1421
|
eurcAddress: null,
|
|
1063
1422
|
usdcAddress: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
1423
|
+
usdtAddress: null,
|
|
1064
1424
|
cctp: {
|
|
1065
1425
|
domain: 19,
|
|
1066
1426
|
contracts: {
|
|
@@ -1108,6 +1468,7 @@ const Ink = defineChain({
|
|
|
1108
1468
|
],
|
|
1109
1469
|
eurcAddress: null,
|
|
1110
1470
|
usdcAddress: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
1471
|
+
usdtAddress: null,
|
|
1111
1472
|
cctp: {
|
|
1112
1473
|
domain: 21,
|
|
1113
1474
|
contracts: {
|
|
@@ -1126,6 +1487,7 @@ const Ink = defineChain({
|
|
|
1126
1487
|
},
|
|
1127
1488
|
kitContracts: {
|
|
1128
1489
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1490
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1129
1491
|
},
|
|
1130
1492
|
});
|
|
1131
1493
|
|
|
@@ -1154,6 +1516,7 @@ const InkTestnet = defineChain({
|
|
|
1154
1516
|
],
|
|
1155
1517
|
eurcAddress: null,
|
|
1156
1518
|
usdcAddress: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
1519
|
+
usdtAddress: null,
|
|
1157
1520
|
cctp: {
|
|
1158
1521
|
domain: 21,
|
|
1159
1522
|
contracts: {
|
|
@@ -1196,6 +1559,7 @@ const Linea = defineChain({
|
|
|
1196
1559
|
rpcEndpoints: ['https://rpc.linea.build'],
|
|
1197
1560
|
eurcAddress: null,
|
|
1198
1561
|
usdcAddress: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
1562
|
+
usdtAddress: null,
|
|
1199
1563
|
cctp: {
|
|
1200
1564
|
domain: 11,
|
|
1201
1565
|
contracts: {
|
|
@@ -1214,6 +1578,7 @@ const Linea = defineChain({
|
|
|
1214
1578
|
},
|
|
1215
1579
|
kitContracts: {
|
|
1216
1580
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1581
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1217
1582
|
},
|
|
1218
1583
|
});
|
|
1219
1584
|
|
|
@@ -1238,6 +1603,7 @@ const LineaSepolia = defineChain({
|
|
|
1238
1603
|
rpcEndpoints: ['https://rpc.sepolia.linea.build'],
|
|
1239
1604
|
eurcAddress: null,
|
|
1240
1605
|
usdcAddress: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
1606
|
+
usdtAddress: null,
|
|
1241
1607
|
cctp: {
|
|
1242
1608
|
domain: 11,
|
|
1243
1609
|
contracts: {
|
|
@@ -1282,6 +1648,7 @@ const Monad = defineChain({
|
|
|
1282
1648
|
rpcEndpoints: ['https://rpc.monad.xyz'],
|
|
1283
1649
|
eurcAddress: null,
|
|
1284
1650
|
usdcAddress: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
1651
|
+
usdtAddress: null,
|
|
1285
1652
|
cctp: {
|
|
1286
1653
|
domain: 15,
|
|
1287
1654
|
contracts: {
|
|
@@ -1300,6 +1667,7 @@ const Monad = defineChain({
|
|
|
1300
1667
|
},
|
|
1301
1668
|
kitContracts: {
|
|
1302
1669
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1670
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1303
1671
|
},
|
|
1304
1672
|
});
|
|
1305
1673
|
|
|
@@ -1326,6 +1694,7 @@ const MonadTestnet = defineChain({
|
|
|
1326
1694
|
rpcEndpoints: ['https://testnet-rpc.monad.xyz'],
|
|
1327
1695
|
eurcAddress: null,
|
|
1328
1696
|
usdcAddress: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
1697
|
+
usdtAddress: null,
|
|
1329
1698
|
cctp: {
|
|
1330
1699
|
domain: 15,
|
|
1331
1700
|
contracts: {
|
|
@@ -1347,6 +1716,94 @@ const MonadTestnet = defineChain({
|
|
|
1347
1716
|
},
|
|
1348
1717
|
});
|
|
1349
1718
|
|
|
1719
|
+
/**
|
|
1720
|
+
* Morph Mainnet chain definition
|
|
1721
|
+
* @remarks
|
|
1722
|
+
* This represents the official production network for the Morph blockchain.
|
|
1723
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
1724
|
+
*/
|
|
1725
|
+
const Morph = defineChain({
|
|
1726
|
+
type: 'evm',
|
|
1727
|
+
chain: Blockchain.Morph,
|
|
1728
|
+
name: 'Morph',
|
|
1729
|
+
title: 'Morph Mainnet',
|
|
1730
|
+
nativeCurrency: {
|
|
1731
|
+
name: 'Ether',
|
|
1732
|
+
symbol: 'ETH',
|
|
1733
|
+
decimals: 18,
|
|
1734
|
+
},
|
|
1735
|
+
chainId: 2818,
|
|
1736
|
+
isTestnet: false,
|
|
1737
|
+
explorerUrl: 'https://explorer.morph.network/tx/{hash}',
|
|
1738
|
+
rpcEndpoints: ['https://rpc.morphl2.io'],
|
|
1739
|
+
eurcAddress: null,
|
|
1740
|
+
usdcAddress: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
1741
|
+
usdtAddress: null,
|
|
1742
|
+
cctp: {
|
|
1743
|
+
domain: 30,
|
|
1744
|
+
contracts: {
|
|
1745
|
+
v2: {
|
|
1746
|
+
type: 'split',
|
|
1747
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
1748
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
1749
|
+
confirmations: 64,
|
|
1750
|
+
fastConfirmations: 1,
|
|
1751
|
+
},
|
|
1752
|
+
},
|
|
1753
|
+
forwarderSupported: {
|
|
1754
|
+
source: false,
|
|
1755
|
+
destination: false,
|
|
1756
|
+
},
|
|
1757
|
+
},
|
|
1758
|
+
kitContracts: {
|
|
1759
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1760
|
+
},
|
|
1761
|
+
});
|
|
1762
|
+
|
|
1763
|
+
/**
|
|
1764
|
+
* Morph Hoodi Testnet chain definition
|
|
1765
|
+
* @remarks
|
|
1766
|
+
* This represents the official test network for the Morph blockchain.
|
|
1767
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
1768
|
+
*/
|
|
1769
|
+
const MorphTestnet = defineChain({
|
|
1770
|
+
type: 'evm',
|
|
1771
|
+
chain: Blockchain.Morph_Testnet,
|
|
1772
|
+
name: 'Morph Hoodi',
|
|
1773
|
+
title: 'Morph Hoodi Testnet',
|
|
1774
|
+
nativeCurrency: {
|
|
1775
|
+
name: 'Ether',
|
|
1776
|
+
symbol: 'ETH',
|
|
1777
|
+
decimals: 18,
|
|
1778
|
+
},
|
|
1779
|
+
chainId: 2910,
|
|
1780
|
+
isTestnet: true,
|
|
1781
|
+
explorerUrl: 'https://explorer-hoodi.morphl2.io/tx/{hash}',
|
|
1782
|
+
rpcEndpoints: ['https://rpc-hoodi.morphl2.io'],
|
|
1783
|
+
eurcAddress: null,
|
|
1784
|
+
usdcAddress: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
1785
|
+
usdtAddress: null,
|
|
1786
|
+
cctp: {
|
|
1787
|
+
domain: 30,
|
|
1788
|
+
contracts: {
|
|
1789
|
+
v2: {
|
|
1790
|
+
type: 'split',
|
|
1791
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
1792
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
1793
|
+
confirmations: 64,
|
|
1794
|
+
fastConfirmations: 1,
|
|
1795
|
+
},
|
|
1796
|
+
},
|
|
1797
|
+
forwarderSupported: {
|
|
1798
|
+
source: false,
|
|
1799
|
+
destination: false,
|
|
1800
|
+
},
|
|
1801
|
+
},
|
|
1802
|
+
kitContracts: {
|
|
1803
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
1804
|
+
},
|
|
1805
|
+
});
|
|
1806
|
+
|
|
1350
1807
|
/**
|
|
1351
1808
|
* NEAR Protocol Mainnet chain definition
|
|
1352
1809
|
* @remarks
|
|
@@ -1367,6 +1824,7 @@ const NEAR = defineChain({
|
|
|
1367
1824
|
rpcEndpoints: ['https://eth-rpc.mainnet.near.org'],
|
|
1368
1825
|
eurcAddress: null,
|
|
1369
1826
|
usdcAddress: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
1827
|
+
usdtAddress: 'usdt.tether-token.near',
|
|
1370
1828
|
cctp: null,
|
|
1371
1829
|
});
|
|
1372
1830
|
|
|
@@ -1390,6 +1848,7 @@ const NEARTestnet = defineChain({
|
|
|
1390
1848
|
rpcEndpoints: ['https://eth-rpc.testnet.near.org'],
|
|
1391
1849
|
eurcAddress: null,
|
|
1392
1850
|
usdcAddress: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
1851
|
+
usdtAddress: null,
|
|
1393
1852
|
cctp: null,
|
|
1394
1853
|
});
|
|
1395
1854
|
|
|
@@ -1413,6 +1872,7 @@ const Noble = defineChain({
|
|
|
1413
1872
|
rpcEndpoints: ['https://noble-rpc.polkachu.com'],
|
|
1414
1873
|
eurcAddress: null,
|
|
1415
1874
|
usdcAddress: 'uusdc',
|
|
1875
|
+
usdtAddress: null,
|
|
1416
1876
|
cctp: {
|
|
1417
1877
|
domain: 4,
|
|
1418
1878
|
contracts: {
|
|
@@ -1449,6 +1909,7 @@ const NobleTestnet = defineChain({
|
|
|
1449
1909
|
rpcEndpoints: ['https://noble-testnet-rpc.polkachu.com'],
|
|
1450
1910
|
eurcAddress: null,
|
|
1451
1911
|
usdcAddress: 'uusdc',
|
|
1912
|
+
usdtAddress: null,
|
|
1452
1913
|
cctp: {
|
|
1453
1914
|
domain: 4,
|
|
1454
1915
|
contracts: {
|
|
@@ -1486,6 +1947,7 @@ const Optimism = defineChain({
|
|
|
1486
1947
|
rpcEndpoints: ['https://mainnet.optimism.io'],
|
|
1487
1948
|
eurcAddress: null,
|
|
1488
1949
|
usdcAddress: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
1950
|
+
usdtAddress: null,
|
|
1489
1951
|
cctp: {
|
|
1490
1952
|
domain: 2,
|
|
1491
1953
|
contracts: {
|
|
@@ -1510,6 +1972,7 @@ const Optimism = defineChain({
|
|
|
1510
1972
|
},
|
|
1511
1973
|
kitContracts: {
|
|
1512
1974
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
1975
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1513
1976
|
},
|
|
1514
1977
|
});
|
|
1515
1978
|
|
|
@@ -1534,6 +1997,7 @@ const OptimismSepolia = defineChain({
|
|
|
1534
1997
|
rpcEndpoints: ['https://sepolia.optimism.io'],
|
|
1535
1998
|
eurcAddress: null,
|
|
1536
1999
|
usdcAddress: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
2000
|
+
usdtAddress: null,
|
|
1537
2001
|
cctp: {
|
|
1538
2002
|
domain: 2,
|
|
1539
2003
|
contracts: {
|
|
@@ -1584,6 +2048,7 @@ const Plume = defineChain({
|
|
|
1584
2048
|
rpcEndpoints: ['https://rpc.plume.org'],
|
|
1585
2049
|
eurcAddress: null,
|
|
1586
2050
|
usdcAddress: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
2051
|
+
usdtAddress: null,
|
|
1587
2052
|
cctp: {
|
|
1588
2053
|
domain: 22,
|
|
1589
2054
|
contracts: {
|
|
@@ -1602,6 +2067,7 @@ const Plume = defineChain({
|
|
|
1602
2067
|
},
|
|
1603
2068
|
kitContracts: {
|
|
1604
2069
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2070
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1605
2071
|
},
|
|
1606
2072
|
});
|
|
1607
2073
|
|
|
@@ -1627,6 +2093,7 @@ const PlumeTestnet = defineChain({
|
|
|
1627
2093
|
rpcEndpoints: ['https://testnet-rpc.plume.org'],
|
|
1628
2094
|
eurcAddress: null,
|
|
1629
2095
|
usdcAddress: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
2096
|
+
usdtAddress: null,
|
|
1630
2097
|
cctp: {
|
|
1631
2098
|
domain: 22,
|
|
1632
2099
|
contracts: {
|
|
@@ -1668,6 +2135,7 @@ const PolkadotAssetHub = defineChain({
|
|
|
1668
2135
|
rpcEndpoints: ['https://asset-hub-polkadot-rpc.n.dwellir.com'],
|
|
1669
2136
|
eurcAddress: null,
|
|
1670
2137
|
usdcAddress: '1337',
|
|
2138
|
+
usdtAddress: '1984',
|
|
1671
2139
|
cctp: null,
|
|
1672
2140
|
});
|
|
1673
2141
|
|
|
@@ -1691,6 +2159,7 @@ const PolkadotWestmint = defineChain({
|
|
|
1691
2159
|
rpcEndpoints: ['https://westmint-rpc.polkadot.io'],
|
|
1692
2160
|
eurcAddress: null,
|
|
1693
2161
|
usdcAddress: 'Asset ID 31337',
|
|
2162
|
+
usdtAddress: null,
|
|
1694
2163
|
cctp: null,
|
|
1695
2164
|
});
|
|
1696
2165
|
|
|
@@ -1712,9 +2181,10 @@ const Polygon = defineChain({
|
|
|
1712
2181
|
chainId: 137,
|
|
1713
2182
|
isTestnet: false,
|
|
1714
2183
|
explorerUrl: 'https://polygonscan.com/tx/{hash}',
|
|
1715
|
-
rpcEndpoints: ['https://polygon
|
|
2184
|
+
rpcEndpoints: ['https://polygon.publicnode.com', 'https://polygon.drpc.org'],
|
|
1716
2185
|
eurcAddress: null,
|
|
1717
2186
|
usdcAddress: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
2187
|
+
usdtAddress: null,
|
|
1718
2188
|
cctp: {
|
|
1719
2189
|
domain: 7,
|
|
1720
2190
|
contracts: {
|
|
@@ -1739,6 +2209,7 @@ const Polygon = defineChain({
|
|
|
1739
2209
|
},
|
|
1740
2210
|
kitContracts: {
|
|
1741
2211
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2212
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1742
2213
|
},
|
|
1743
2214
|
});
|
|
1744
2215
|
|
|
@@ -1763,6 +2234,7 @@ const PolygonAmoy = defineChain({
|
|
|
1763
2234
|
rpcEndpoints: ['https://rpc-amoy.polygon.technology'],
|
|
1764
2235
|
eurcAddress: null,
|
|
1765
2236
|
usdcAddress: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
2237
|
+
usdtAddress: null,
|
|
1766
2238
|
cctp: {
|
|
1767
2239
|
domain: 7,
|
|
1768
2240
|
contracts: {
|
|
@@ -1813,6 +2285,7 @@ const Sei = defineChain({
|
|
|
1813
2285
|
rpcEndpoints: ['https://evm-rpc.sei-apis.com'],
|
|
1814
2286
|
eurcAddress: null,
|
|
1815
2287
|
usdcAddress: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
2288
|
+
usdtAddress: null,
|
|
1816
2289
|
cctp: {
|
|
1817
2290
|
domain: 16,
|
|
1818
2291
|
contracts: {
|
|
@@ -1831,6 +2304,7 @@ const Sei = defineChain({
|
|
|
1831
2304
|
},
|
|
1832
2305
|
kitContracts: {
|
|
1833
2306
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2307
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1834
2308
|
},
|
|
1835
2309
|
});
|
|
1836
2310
|
|
|
@@ -1856,6 +2330,7 @@ const SeiTestnet = defineChain({
|
|
|
1856
2330
|
rpcEndpoints: ['https://evm-rpc-testnet.sei-apis.com'],
|
|
1857
2331
|
eurcAddress: null,
|
|
1858
2332
|
usdcAddress: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
2333
|
+
usdtAddress: null,
|
|
1859
2334
|
cctp: {
|
|
1860
2335
|
domain: 16,
|
|
1861
2336
|
contracts: {
|
|
@@ -1898,6 +2373,7 @@ const Sonic = defineChain({
|
|
|
1898
2373
|
rpcEndpoints: ['https://rpc.soniclabs.com'],
|
|
1899
2374
|
eurcAddress: null,
|
|
1900
2375
|
usdcAddress: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
2376
|
+
usdtAddress: null,
|
|
1901
2377
|
cctp: {
|
|
1902
2378
|
domain: 13,
|
|
1903
2379
|
contracts: {
|
|
@@ -1916,6 +2392,7 @@ const Sonic = defineChain({
|
|
|
1916
2392
|
},
|
|
1917
2393
|
kitContracts: {
|
|
1918
2394
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2395
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1919
2396
|
},
|
|
1920
2397
|
});
|
|
1921
2398
|
|
|
@@ -1940,6 +2417,7 @@ const SonicTestnet = defineChain({
|
|
|
1940
2417
|
rpcEndpoints: ['https://rpc.testnet.soniclabs.com'],
|
|
1941
2418
|
eurcAddress: null,
|
|
1942
2419
|
usdcAddress: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
2420
|
+
usdtAddress: null,
|
|
1943
2421
|
cctp: {
|
|
1944
2422
|
domain: 13,
|
|
1945
2423
|
contracts: {
|
|
@@ -1981,6 +2459,7 @@ const Solana = defineChain({
|
|
|
1981
2459
|
rpcEndpoints: ['https://api.mainnet-beta.solana.com'],
|
|
1982
2460
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
1983
2461
|
usdcAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
2462
|
+
usdtAddress: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
1984
2463
|
cctp: {
|
|
1985
2464
|
domain: 5,
|
|
1986
2465
|
contracts: {
|
|
@@ -2027,6 +2506,7 @@ const SolanaDevnet = defineChain({
|
|
|
2027
2506
|
explorerUrl: 'https://solscan.io/tx/{hash}?cluster=devnet',
|
|
2028
2507
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
2029
2508
|
usdcAddress: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
2509
|
+
usdtAddress: null,
|
|
2030
2510
|
cctp: {
|
|
2031
2511
|
domain: 5,
|
|
2032
2512
|
contracts: {
|
|
@@ -2075,6 +2555,7 @@ const Stellar = defineChain({
|
|
|
2075
2555
|
rpcEndpoints: ['https://horizon.stellar.org'],
|
|
2076
2556
|
eurcAddress: 'EURC-GDHU6WRG4IEQXM5NZ4BMPKOXHW76MZM4Y2IEMFDVXBSDP6SJY4ITNPP2',
|
|
2077
2557
|
usdcAddress: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
2558
|
+
usdtAddress: null,
|
|
2078
2559
|
cctp: null,
|
|
2079
2560
|
});
|
|
2080
2561
|
|
|
@@ -2098,6 +2579,7 @@ const StellarTestnet = defineChain({
|
|
|
2098
2579
|
rpcEndpoints: ['https://horizon-testnet.stellar.org'],
|
|
2099
2580
|
eurcAddress: 'EURC-GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO',
|
|
2100
2581
|
usdcAddress: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
2582
|
+
usdtAddress: null,
|
|
2101
2583
|
cctp: null,
|
|
2102
2584
|
});
|
|
2103
2585
|
|
|
@@ -2121,6 +2603,7 @@ const Sui = defineChain({
|
|
|
2121
2603
|
rpcEndpoints: ['https://fullnode.mainnet.sui.io'],
|
|
2122
2604
|
eurcAddress: null,
|
|
2123
2605
|
usdcAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
2606
|
+
usdtAddress: null,
|
|
2124
2607
|
cctp: {
|
|
2125
2608
|
domain: 8,
|
|
2126
2609
|
contracts: {
|
|
@@ -2158,6 +2641,7 @@ const SuiTestnet = defineChain({
|
|
|
2158
2641
|
rpcEndpoints: ['https://fullnode.testnet.sui.io'],
|
|
2159
2642
|
eurcAddress: null,
|
|
2160
2643
|
usdcAddress: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
2644
|
+
usdtAddress: null,
|
|
2161
2645
|
cctp: {
|
|
2162
2646
|
domain: 8,
|
|
2163
2647
|
contracts: {
|
|
@@ -2196,6 +2680,7 @@ const Unichain = defineChain({
|
|
|
2196
2680
|
rpcEndpoints: ['https://mainnet.unichain.org'],
|
|
2197
2681
|
eurcAddress: null,
|
|
2198
2682
|
usdcAddress: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
2683
|
+
usdtAddress: null,
|
|
2199
2684
|
cctp: {
|
|
2200
2685
|
domain: 10,
|
|
2201
2686
|
contracts: {
|
|
@@ -2220,6 +2705,7 @@ const Unichain = defineChain({
|
|
|
2220
2705
|
},
|
|
2221
2706
|
kitContracts: {
|
|
2222
2707
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2708
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2223
2709
|
},
|
|
2224
2710
|
});
|
|
2225
2711
|
|
|
@@ -2244,6 +2730,7 @@ const UnichainSepolia = defineChain({
|
|
|
2244
2730
|
rpcEndpoints: ['https://sepolia.unichain.org'],
|
|
2245
2731
|
eurcAddress: null,
|
|
2246
2732
|
usdcAddress: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
2733
|
+
usdtAddress: null,
|
|
2247
2734
|
cctp: {
|
|
2248
2735
|
domain: 10,
|
|
2249
2736
|
contracts: {
|
|
@@ -2292,6 +2779,7 @@ const WorldChain = defineChain({
|
|
|
2292
2779
|
rpcEndpoints: ['https://worldchain-mainnet.g.alchemy.com/public'],
|
|
2293
2780
|
eurcAddress: null,
|
|
2294
2781
|
usdcAddress: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
2782
|
+
usdtAddress: null,
|
|
2295
2783
|
cctp: {
|
|
2296
2784
|
domain: 14,
|
|
2297
2785
|
contracts: {
|
|
@@ -2310,6 +2798,7 @@ const WorldChain = defineChain({
|
|
|
2310
2798
|
},
|
|
2311
2799
|
kitContracts: {
|
|
2312
2800
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2801
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2313
2802
|
},
|
|
2314
2803
|
});
|
|
2315
2804
|
|
|
@@ -2337,6 +2826,7 @@ const WorldChainSepolia = defineChain({
|
|
|
2337
2826
|
],
|
|
2338
2827
|
eurcAddress: null,
|
|
2339
2828
|
usdcAddress: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
2829
|
+
usdtAddress: null,
|
|
2340
2830
|
cctp: {
|
|
2341
2831
|
domain: 14,
|
|
2342
2832
|
contracts: {
|
|
@@ -2381,6 +2871,7 @@ const XDC = defineChain({
|
|
|
2381
2871
|
rpcEndpoints: ['https://erpc.xdcrpc.com', 'https://erpc.xinfin.network'],
|
|
2382
2872
|
eurcAddress: null,
|
|
2383
2873
|
usdcAddress: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
2874
|
+
usdtAddress: null,
|
|
2384
2875
|
cctp: {
|
|
2385
2876
|
domain: 18,
|
|
2386
2877
|
contracts: {
|
|
@@ -2399,6 +2890,7 @@ const XDC = defineChain({
|
|
|
2399
2890
|
},
|
|
2400
2891
|
kitContracts: {
|
|
2401
2892
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2893
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2402
2894
|
},
|
|
2403
2895
|
});
|
|
2404
2896
|
|
|
@@ -2423,6 +2915,7 @@ const XDCApothem = defineChain({
|
|
|
2423
2915
|
rpcEndpoints: ['https://erpc.apothem.network'],
|
|
2424
2916
|
eurcAddress: null,
|
|
2425
2917
|
usdcAddress: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
2918
|
+
usdtAddress: null,
|
|
2426
2919
|
cctp: {
|
|
2427
2920
|
domain: 18,
|
|
2428
2921
|
contracts: {
|
|
@@ -2465,6 +2958,7 @@ const ZKSyncEra = defineChain({
|
|
|
2465
2958
|
rpcEndpoints: ['https://mainnet.era.zksync.io'],
|
|
2466
2959
|
eurcAddress: null,
|
|
2467
2960
|
usdcAddress: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
2961
|
+
usdtAddress: null,
|
|
2468
2962
|
cctp: null,
|
|
2469
2963
|
});
|
|
2470
2964
|
|
|
@@ -2489,6 +2983,7 @@ const ZKSyncEraSepolia = defineChain({
|
|
|
2489
2983
|
rpcEndpoints: ['https://sepolia.era.zksync.dev'],
|
|
2490
2984
|
eurcAddress: null,
|
|
2491
2985
|
usdcAddress: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
2986
|
+
usdtAddress: null,
|
|
2492
2987
|
cctp: null,
|
|
2493
2988
|
});
|
|
2494
2989
|
|
|
@@ -2509,6 +3004,8 @@ var Chains = {
|
|
|
2509
3004
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
2510
3005
|
Codex: Codex,
|
|
2511
3006
|
CodexTestnet: CodexTestnet,
|
|
3007
|
+
Edge: Edge,
|
|
3008
|
+
EdgeTestnet: EdgeTestnet,
|
|
2512
3009
|
Ethereum: Ethereum,
|
|
2513
3010
|
EthereumSepolia: EthereumSepolia,
|
|
2514
3011
|
Hedera: Hedera,
|
|
@@ -2521,6 +3018,8 @@ var Chains = {
|
|
|
2521
3018
|
LineaSepolia: LineaSepolia,
|
|
2522
3019
|
Monad: Monad,
|
|
2523
3020
|
MonadTestnet: MonadTestnet,
|
|
3021
|
+
Morph: Morph,
|
|
3022
|
+
MorphTestnet: MorphTestnet,
|
|
2524
3023
|
NEAR: NEAR,
|
|
2525
3024
|
NEARTestnet: NEARTestnet,
|
|
2526
3025
|
Noble: Noble,
|
|
@@ -2656,10 +3155,12 @@ const baseChainDefinitionSchema = zod.z.object({
|
|
|
2656
3155
|
rpcEndpoints: zod.z.array(zod.z.string()),
|
|
2657
3156
|
eurcAddress: zod.z.string().nullable(),
|
|
2658
3157
|
usdcAddress: zod.z.string().nullable(),
|
|
3158
|
+
usdtAddress: zod.z.string().nullable(),
|
|
2659
3159
|
cctp: zod.z.any().nullable(), // We'll accept any CCTP config structure
|
|
2660
3160
|
kitContracts: zod.z
|
|
2661
3161
|
.object({
|
|
2662
3162
|
bridge: zod.z.string().optional(),
|
|
3163
|
+
adapter: zod.z.string().optional(),
|
|
2663
3164
|
})
|
|
2664
3165
|
.optional(),
|
|
2665
3166
|
});
|
|
@@ -2774,6 +3275,29 @@ zod.z.union([
|
|
|
2774
3275
|
zod.z.nativeEnum(Blockchain),
|
|
2775
3276
|
chainDefinitionSchema$2,
|
|
2776
3277
|
]);
|
|
3278
|
+
/**
|
|
3279
|
+
* Zod schema for validating swap-specific chain identifiers.
|
|
3280
|
+
*
|
|
3281
|
+
* Validates chains based on:
|
|
3282
|
+
* - CCTPv2 support (adapter contract deployed)
|
|
3283
|
+
* - Mainnet only (no testnets)
|
|
3284
|
+
* - At least one supported token available
|
|
3285
|
+
*
|
|
3286
|
+
*/
|
|
3287
|
+
zod.z.union([
|
|
3288
|
+
// String blockchain identifier (accepts SwapChain enum values)
|
|
3289
|
+
zod.z.string().refine((val) => val in SwapChain, (val) => ({
|
|
3290
|
+
message: `"${val}" is not a supported swap chain. ` +
|
|
3291
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
3292
|
+
})),
|
|
3293
|
+
// SwapChain enum
|
|
3294
|
+
zod.z.nativeEnum(SwapChain),
|
|
3295
|
+
// ChainDefinition object (checks if chain.chain is in SwapChain)
|
|
3296
|
+
chainDefinitionSchema$2.refine((chain) => chain.chain in SwapChain, (chain) => ({
|
|
3297
|
+
message: `"${chain.chain}" is not a supported swap chain. ` +
|
|
3298
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
3299
|
+
})),
|
|
3300
|
+
]);
|
|
2777
3301
|
/**
|
|
2778
3302
|
* Zod schema for validating bridge chain identifiers.
|
|
2779
3303
|
*
|
|
@@ -2813,6 +3337,38 @@ zod.z.union([
|
|
|
2813
3337
|
})),
|
|
2814
3338
|
]);
|
|
2815
3339
|
|
|
3340
|
+
/**
|
|
3341
|
+
* @packageDocumentation
|
|
3342
|
+
* @module SwapTokenSchemas
|
|
3343
|
+
*
|
|
3344
|
+
* Zod validation schemas for supported swap tokens.
|
|
3345
|
+
*/
|
|
3346
|
+
// Internal enum used after input normalization.
|
|
3347
|
+
const swapTokenEnumSchema = zod.z.enum([
|
|
3348
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
3349
|
+
NATIVE_TOKEN,
|
|
3350
|
+
]);
|
|
3351
|
+
/**
|
|
3352
|
+
* Zod schema for validating supported swap token symbols.
|
|
3353
|
+
*
|
|
3354
|
+
* Accepts any token symbol from the SWAP_TOKEN_REGISTRY plus NATIVE.
|
|
3355
|
+
* Input matching is case-insensitive and normalized to uppercase.
|
|
3356
|
+
*
|
|
3357
|
+
* @example
|
|
3358
|
+
* ```typescript
|
|
3359
|
+
* import { supportedSwapTokenSchema } from '@core/chains'
|
|
3360
|
+
*
|
|
3361
|
+
* const result = supportedSwapTokenSchema.safeParse('USDC')
|
|
3362
|
+
* if (result.success) {
|
|
3363
|
+
* console.log('Valid swap token:', result.data)
|
|
3364
|
+
* }
|
|
3365
|
+
* ```
|
|
3366
|
+
*/
|
|
3367
|
+
zod.z
|
|
3368
|
+
.string()
|
|
3369
|
+
.transform((value) => value.toUpperCase())
|
|
3370
|
+
.pipe(swapTokenEnumSchema);
|
|
3371
|
+
|
|
2816
3372
|
/**
|
|
2817
3373
|
* Retrieve a chain definition by its blockchain enum value.
|
|
2818
3374
|
*
|
|
@@ -2867,6 +3423,11 @@ const getChainByEnum = (blockchain) => {
|
|
|
2867
3423
|
* ```
|
|
2868
3424
|
*/
|
|
2869
3425
|
function resolveChainIdentifier(chainIdentifier) {
|
|
3426
|
+
// Handle null explicitly (typeof null === 'object' in JavaScript)
|
|
3427
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
3428
|
+
if (chainIdentifier === null) {
|
|
3429
|
+
throw new Error(`Invalid chain identifier type: null. Expected ChainDefinition object, Blockchain enum, or string literal.`);
|
|
3430
|
+
}
|
|
2870
3431
|
// If it's already a ChainDefinition object, return it unchanged
|
|
2871
3432
|
if (typeof chainIdentifier === 'object') {
|
|
2872
3433
|
return chainIdentifier;
|
|
@@ -3158,11 +3719,11 @@ const formatComponent = (nameWithVersion) => {
|
|
|
3158
3719
|
const createRequestContext = () => {
|
|
3159
3720
|
const context = {};
|
|
3160
3721
|
if (typeof globalThis !== 'undefined') {
|
|
3161
|
-
if (globalThis.
|
|
3162
|
-
context.externalPrefix = globalThis.
|
|
3722
|
+
if (globalThis.__APP_KITS_EXTERNAL_PREFIX__ !== undefined) {
|
|
3723
|
+
context.externalPrefix = globalThis.__APP_KITS_EXTERNAL_PREFIX__;
|
|
3163
3724
|
}
|
|
3164
|
-
if (globalThis.
|
|
3165
|
-
context.kit = globalThis.
|
|
3725
|
+
if (globalThis.__APP_KITS_CURRENT_KIT__ !== undefined) {
|
|
3726
|
+
context.kit = globalThis.__APP_KITS_CURRENT_KIT__;
|
|
3166
3727
|
}
|
|
3167
3728
|
}
|
|
3168
3729
|
return context;
|
|
@@ -3268,6 +3829,10 @@ const ERROR_TYPES = {
|
|
|
3268
3829
|
RPC: 'RPC',
|
|
3269
3830
|
/** Internet connectivity, DNS resolution, connection issues */
|
|
3270
3831
|
NETWORK: 'NETWORK',
|
|
3832
|
+
/** API throttling, request frequency limits errors */
|
|
3833
|
+
RATE_LIMIT: 'RATE_LIMIT',
|
|
3834
|
+
/** Service errors */
|
|
3835
|
+
SERVICE: 'SERVICE',
|
|
3271
3836
|
/** Catch-all for unrecognized errors (code 0) */
|
|
3272
3837
|
UNKNOWN: 'UNKNOWN',
|
|
3273
3838
|
};
|
|
@@ -3291,6 +3856,8 @@ const ERROR_CODE_RANGES = [
|
|
|
3291
3856
|
{ min: 3000, max: 3999, type: 'NETWORK' },
|
|
3292
3857
|
{ min: 4000, max: 4999, type: 'RPC' },
|
|
3293
3858
|
{ min: 5000, max: 5999, type: 'ONCHAIN' },
|
|
3859
|
+
{ min: 7000, max: 7999, type: 'RATE_LIMIT' },
|
|
3860
|
+
{ min: 8000, max: 8999, type: 'SERVICE' },
|
|
3294
3861
|
{ min: 9000, max: 9999, type: 'BALANCE' },
|
|
3295
3862
|
];
|
|
3296
3863
|
/** Special code for UNKNOWN errors */
|
|
@@ -3338,6 +3905,8 @@ const errorDetailsSchema = zod.z.object({
|
|
|
3338
3905
|
* - 3000-3999: NETWORK errors - Connectivity issues
|
|
3339
3906
|
* - 4000-4999: RPC errors - Provider issues, gas estimation
|
|
3340
3907
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures
|
|
3908
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling
|
|
3909
|
+
* - 8000-8999: SERVICE errors - Internal service errors
|
|
3341
3910
|
* - 9000-9999: BALANCE errors - Insufficient funds
|
|
3342
3911
|
*/
|
|
3343
3912
|
code: zod.z
|
|
@@ -3446,11 +4015,11 @@ const AMOUNT_FORMAT_ERROR_MESSAGE = 'Amount must be a numeric string with dot (.
|
|
|
3446
4015
|
const MAX_FEE_FORMAT_ERROR_MESSAGE = 'maxFee must be a numeric string with dot (.) as decimal separator (e.g., "1", "0.5", ".5", "1.5"), with no thousand separators or comma decimals';
|
|
3447
4016
|
|
|
3448
4017
|
/**
|
|
3449
|
-
* Structured error class for
|
|
4018
|
+
* Structured error class for App Kit operations.
|
|
3450
4019
|
*
|
|
3451
4020
|
* This class extends the native Error class while implementing the ErrorDetails
|
|
3452
4021
|
* interface, providing a consistent error format for programmatic handling
|
|
3453
|
-
* across the
|
|
4022
|
+
* across the App Kits ecosystem. All properties are immutable to ensure
|
|
3454
4023
|
* error objects cannot be modified after creation.
|
|
3455
4024
|
*
|
|
3456
4025
|
* @example
|
|
@@ -3460,6 +4029,7 @@ const MAX_FEE_FORMAT_ERROR_MESSAGE = 'maxFee must be a numeric string with dot (
|
|
|
3460
4029
|
* const error = new KitError({
|
|
3461
4030
|
* code: 1001,
|
|
3462
4031
|
* name: 'INPUT_NETWORK_MISMATCH',
|
|
4032
|
+
* type: 'INPUT',
|
|
3463
4033
|
* recoverability: 'FATAL',
|
|
3464
4034
|
* message: 'Cannot bridge between mainnet and testnet'
|
|
3465
4035
|
* })
|
|
@@ -3477,7 +4047,8 @@ const MAX_FEE_FORMAT_ERROR_MESSAGE = 'maxFee must be a numeric string with dot (
|
|
|
3477
4047
|
* // Error with cause information
|
|
3478
4048
|
* const error = new KitError({
|
|
3479
4049
|
* code: 1002,
|
|
3480
|
-
* name: '
|
|
4050
|
+
* name: 'INPUT_INVALID_AMOUNT',
|
|
4051
|
+
* type: 'INPUT',
|
|
3481
4052
|
* recoverability: 'FATAL',
|
|
3482
4053
|
* message: 'Amount must be greater than zero',
|
|
3483
4054
|
* cause: {
|
|
@@ -3561,6 +4132,8 @@ class KitError extends Error {
|
|
|
3561
4132
|
* - 3000-3999: NETWORK errors - Internet connectivity, DNS, connection issues
|
|
3562
4133
|
* - 4000-4999: RPC errors - Blockchain provider issues, gas estimation, nonce errors
|
|
3563
4134
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures, gas exhaustion, reverts
|
|
4135
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling, request frequency limits
|
|
4136
|
+
* - 8000-8999: SERVICE errors - Internal service errors, server failures
|
|
3564
4137
|
* - 9000-9999: BALANCE errors - Insufficient funds, token balance, allowance
|
|
3565
4138
|
*/
|
|
3566
4139
|
/**
|
|
@@ -3621,10 +4194,22 @@ const InputError = {
|
|
|
3621
4194
|
name: 'INPUT_INVALID_CHAIN',
|
|
3622
4195
|
type: 'INPUT',
|
|
3623
4196
|
},
|
|
3624
|
-
/**
|
|
3625
|
-
|
|
4197
|
+
/** Unsupported token for chain */
|
|
4198
|
+
UNSUPPORTED_TOKEN: {
|
|
3626
4199
|
code: 1006,
|
|
3627
|
-
name: '
|
|
4200
|
+
name: 'INPUT_UNSUPPORTED_TOKEN',
|
|
4201
|
+
type: 'INPUT',
|
|
4202
|
+
},
|
|
4203
|
+
/** Insufficient swap amount for the token pair */
|
|
4204
|
+
INSUFFICIENT_SWAP_AMOUNT: {
|
|
4205
|
+
code: 1007,
|
|
4206
|
+
name: 'INPUT_INSUFFICIENT_SWAP_AMOUNT',
|
|
4207
|
+
type: 'INPUT',
|
|
4208
|
+
},
|
|
4209
|
+
/** Action not supported by this adapter / ecosystem */
|
|
4210
|
+
UNSUPPORTED_ACTION: {
|
|
4211
|
+
code: 1008,
|
|
4212
|
+
name: 'INPUT_UNSUPPORTED_ACTION',
|
|
3628
4213
|
type: 'INPUT',
|
|
3629
4214
|
},
|
|
3630
4215
|
/** General validation failure for complex validation rules */
|
|
@@ -3633,6 +4218,12 @@ const InputError = {
|
|
|
3633
4218
|
name: 'INPUT_VALIDATION_FAILED',
|
|
3634
4219
|
type: 'INPUT',
|
|
3635
4220
|
},
|
|
4221
|
+
/** User cancelled wallet interaction (signature, transaction, connection) */
|
|
4222
|
+
USER_CANCELLED: {
|
|
4223
|
+
code: 1099,
|
|
4224
|
+
name: 'INPUT_USER_CANCELLED',
|
|
4225
|
+
type: 'INPUT',
|
|
4226
|
+
},
|
|
3636
4227
|
};
|
|
3637
4228
|
/**
|
|
3638
4229
|
* Standardized error definitions for BALANCE type errors.
|
|
@@ -3720,8 +4311,7 @@ const NetworkError = {
|
|
|
3720
4311
|
code: 3004,
|
|
3721
4312
|
name: 'NETWORK_RELAYER_PENDING',
|
|
3722
4313
|
type: 'NETWORK',
|
|
3723
|
-
}
|
|
3724
|
-
};
|
|
4314
|
+
}};
|
|
3725
4315
|
|
|
3726
4316
|
/**
|
|
3727
4317
|
* Creates error for network type mismatch between source and destination.
|
|
@@ -3808,7 +4398,7 @@ function createInvalidChainError(chain, reason) {
|
|
|
3808
4398
|
const errorDetails = {
|
|
3809
4399
|
...InputError.INVALID_CHAIN,
|
|
3810
4400
|
recoverability: 'FATAL',
|
|
3811
|
-
message: `Invalid chain '${chain}': ${reason}
|
|
4401
|
+
message: `Invalid chain '${chain}': ${reason}.`,
|
|
3812
4402
|
cause: {
|
|
3813
4403
|
trace: { chain, reason },
|
|
3814
4404
|
},
|
|
@@ -4157,6 +4747,9 @@ function getErrorMessage(error) {
|
|
|
4157
4747
|
if (typeof error === 'string') {
|
|
4158
4748
|
return error;
|
|
4159
4749
|
}
|
|
4750
|
+
if (typeof error === 'object' && error !== null && 'message' in error) {
|
|
4751
|
+
return String(error.message);
|
|
4752
|
+
}
|
|
4160
4753
|
return 'An unknown error occurred';
|
|
4161
4754
|
}
|
|
4162
4755
|
/**
|
|
@@ -4213,6 +4806,9 @@ function extractErrorInfo(error) {
|
|
|
4213
4806
|
if (typeof err.code === 'number') {
|
|
4214
4807
|
info.code = err.code;
|
|
4215
4808
|
}
|
|
4809
|
+
if (isKitError(error)) {
|
|
4810
|
+
info.type = error.type;
|
|
4811
|
+
}
|
|
4216
4812
|
return info;
|
|
4217
4813
|
}
|
|
4218
4814
|
|
|
@@ -4335,7 +4931,17 @@ const makeApiRequest = async (url, method, isValidType, config, body) => {
|
|
|
4335
4931
|
const response = await fetch(url, requestInit);
|
|
4336
4932
|
clearTimeout(timeoutId);
|
|
4337
4933
|
if (!response.ok) {
|
|
4338
|
-
|
|
4934
|
+
let responseBody;
|
|
4935
|
+
try {
|
|
4936
|
+
responseBody = (await response.json());
|
|
4937
|
+
}
|
|
4938
|
+
catch {
|
|
4939
|
+
// Parse response body for diagnostics; continue even if malformed
|
|
4940
|
+
// so callers always receive HTTP status context
|
|
4941
|
+
}
|
|
4942
|
+
const httpError = new Error(`HTTP ${String(response.status)} - ${response.statusText}`);
|
|
4943
|
+
httpError.responseBody = responseBody;
|
|
4944
|
+
throw httpError;
|
|
4339
4945
|
}
|
|
4340
4946
|
const parsedJson = (await response.json());
|
|
4341
4947
|
if (!isValidType(parsedJson)) {
|
|
@@ -4907,7 +5513,7 @@ const convertAddress = (address, targetFormat) => {
|
|
|
4907
5513
|
*
|
|
4908
5514
|
* This function normalizes token values from their blockchain representation (where
|
|
4909
5515
|
* everything is stored as integers in the smallest denomination) to human-readable
|
|
4910
|
-
* decimal format. Uses the battle-tested implementation from
|
|
5516
|
+
* decimal format. Uses the battle-tested implementation from \@ethersproject/units.
|
|
4911
5517
|
*
|
|
4912
5518
|
* @param value - The value in smallest units (e.g., "1000000" for 1 USDC with 6 decimals)
|
|
4913
5519
|
* @param decimals - The number of decimal places for the unit conversion
|
|
@@ -4936,357 +5542,1082 @@ const formatUnits = (value, decimals) => {
|
|
|
4936
5542
|
};
|
|
4937
5543
|
|
|
4938
5544
|
/**
|
|
4939
|
-
*
|
|
5545
|
+
* Create a structured error for token resolution failures.
|
|
4940
5546
|
*
|
|
4941
|
-
*
|
|
4942
|
-
*
|
|
4943
|
-
*
|
|
5547
|
+
* @remarks
|
|
5548
|
+
* Returns a `KitError` with `INPUT_UNSUPPORTED_TOKEN` code (1006).
|
|
5549
|
+
* The error trace contains the selector and chain context for debugging.
|
|
4944
5550
|
*
|
|
4945
|
-
* @param
|
|
4946
|
-
* @param
|
|
4947
|
-
* @
|
|
4948
|
-
* @
|
|
4949
|
-
* @
|
|
4950
|
-
* @throws Error if the explorer URL template is missing or empty.
|
|
4951
|
-
* @throws Error if the explorer URL template doesn't contain the {hash} placeholder.
|
|
4952
|
-
* @throws Error if the resulting URL is invalid.
|
|
5551
|
+
* @param message - Human-readable error description.
|
|
5552
|
+
* @param selector - The token selector that failed to resolve.
|
|
5553
|
+
* @param chainId - The chain being resolved for (optional).
|
|
5554
|
+
* @param cause - The underlying error, if any (optional).
|
|
5555
|
+
* @returns A KitError with INPUT type and FATAL recoverability.
|
|
4953
5556
|
*
|
|
4954
5557
|
* @example
|
|
4955
5558
|
* ```typescript
|
|
4956
|
-
*
|
|
4957
|
-
*
|
|
4958
|
-
*
|
|
4959
|
-
*
|
|
4960
|
-
*
|
|
4961
|
-
* console.log(url) // 'https://etherscan.io/tx/0x1234567890abcdef...'
|
|
5559
|
+
* throw createTokenResolutionError(
|
|
5560
|
+
* 'Unknown token symbol: FAKE',
|
|
5561
|
+
* 'FAKE',
|
|
5562
|
+
* 'Ethereum'
|
|
5563
|
+
* )
|
|
4962
5564
|
* ```
|
|
5565
|
+
*/
|
|
5566
|
+
function createTokenResolutionError(message, selector, chainId, cause) {
|
|
5567
|
+
const trace = {
|
|
5568
|
+
selector,
|
|
5569
|
+
...(chainId === undefined ? {} : { chainId }),
|
|
5570
|
+
...({} ),
|
|
5571
|
+
};
|
|
5572
|
+
return new KitError({
|
|
5573
|
+
...InputError.UNSUPPORTED_TOKEN,
|
|
5574
|
+
recoverability: 'FATAL',
|
|
5575
|
+
message,
|
|
5576
|
+
cause: { trace },
|
|
5577
|
+
});
|
|
5578
|
+
}
|
|
5579
|
+
|
|
5580
|
+
/**
|
|
5581
|
+
* USDC token definition with addresses and metadata.
|
|
4963
5582
|
*
|
|
4964
|
-
* @
|
|
4965
|
-
*
|
|
4966
|
-
*
|
|
4967
|
-
* import { Solana } from '@core/chains'
|
|
5583
|
+
* @remarks
|
|
5584
|
+
* This is the built-in USDC definition used by the TokenRegistry.
|
|
5585
|
+
* Includes all known USDC addresses across supported chains.
|
|
4968
5586
|
*
|
|
4969
|
-
*
|
|
4970
|
-
*
|
|
4971
|
-
*
|
|
4972
|
-
* ```
|
|
5587
|
+
* Keys use the `Blockchain` enum for type safety. Both enum values
|
|
5588
|
+
* and string literals are supported:
|
|
5589
|
+
* - `Blockchain.Ethereum` or `'Ethereum'`
|
|
4973
5590
|
*
|
|
4974
5591
|
* @example
|
|
4975
5592
|
* ```typescript
|
|
4976
|
-
* import {
|
|
4977
|
-
* import {
|
|
5593
|
+
* import { USDC } from '@core/tokens'
|
|
5594
|
+
* import { Blockchain } from '@core/chains'
|
|
4978
5595
|
*
|
|
4979
|
-
* //
|
|
4980
|
-
*
|
|
4981
|
-
* console.log(
|
|
5596
|
+
* console.log(USDC.symbol) // 'USDC'
|
|
5597
|
+
* console.log(USDC.decimals) // 6
|
|
5598
|
+
* console.log(USDC.locators[Blockchain.Ethereum])
|
|
5599
|
+
* // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
4982
5600
|
* ```
|
|
4983
5601
|
*/
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
5602
|
+
const USDC = {
|
|
5603
|
+
symbol: 'USDC',
|
|
5604
|
+
decimals: 6,
|
|
5605
|
+
locators: {
|
|
5606
|
+
// =========================================================================
|
|
5607
|
+
// Mainnets (alphabetically sorted)
|
|
5608
|
+
// =========================================================================
|
|
5609
|
+
[Blockchain.Arbitrum]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
5610
|
+
[Blockchain.Avalanche]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
5611
|
+
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
5612
|
+
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
5613
|
+
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
5614
|
+
[Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
5615
|
+
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
5616
|
+
[Blockchain.Hedera]: '0.0.456858',
|
|
5617
|
+
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
5618
|
+
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
5619
|
+
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
5620
|
+
[Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
5621
|
+
[Blockchain.Morph]: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
5622
|
+
[Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
5623
|
+
[Blockchain.Noble]: 'uusdc',
|
|
5624
|
+
[Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
5625
|
+
[Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
5626
|
+
[Blockchain.Polkadot_Asset_Hub]: '1337',
|
|
5627
|
+
[Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
5628
|
+
[Blockchain.Sei]: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
5629
|
+
[Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
5630
|
+
[Blockchain.Sonic]: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
5631
|
+
[Blockchain.Stellar]: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
5632
|
+
[Blockchain.Sui]: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
5633
|
+
[Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
5634
|
+
[Blockchain.World_Chain]: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
5635
|
+
[Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
5636
|
+
[Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
5637
|
+
// =========================================================================
|
|
5638
|
+
// Testnets (alphabetically sorted)
|
|
5639
|
+
// =========================================================================
|
|
5640
|
+
[Blockchain.Arbitrum_Sepolia]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
5641
|
+
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
5642
|
+
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
5643
|
+
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
5644
|
+
[Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
5645
|
+
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
5646
|
+
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
5647
|
+
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
5648
|
+
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
5649
|
+
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
5650
|
+
[Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
5651
|
+
[Blockchain.Morph_Testnet]: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
5652
|
+
[Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
5653
|
+
[Blockchain.Noble_Testnet]: 'uusdc',
|
|
5654
|
+
[Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
5655
|
+
[Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
5656
|
+
[Blockchain.Polkadot_Westmint]: '31337',
|
|
5657
|
+
[Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
5658
|
+
[Blockchain.Sei_Testnet]: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
5659
|
+
[Blockchain.Solana_Devnet]: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
5660
|
+
[Blockchain.Sonic_Testnet]: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
5661
|
+
[Blockchain.Stellar_Testnet]: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
5662
|
+
[Blockchain.Sui_Testnet]: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
5663
|
+
[Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
5664
|
+
[Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
5665
|
+
[Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
5666
|
+
[Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
5667
|
+
},
|
|
5668
|
+
};
|
|
4995
5669
|
|
|
4996
5670
|
/**
|
|
4997
|
-
*
|
|
5671
|
+
* USDT (Tether) token definition with addresses and metadata.
|
|
4998
5672
|
*
|
|
4999
|
-
*
|
|
5000
|
-
*
|
|
5673
|
+
* @remarks
|
|
5674
|
+
* Built-in USDT definition for the TokenRegistry. Includes chain locators
|
|
5675
|
+
* for swap-supported chains.
|
|
5001
5676
|
*/
|
|
5002
|
-
const
|
|
5677
|
+
const USDT = {
|
|
5678
|
+
symbol: 'USDT',
|
|
5679
|
+
decimals: 6,
|
|
5680
|
+
locators: {
|
|
5681
|
+
[Blockchain.Aptos]: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
5682
|
+
[Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
|
|
5683
|
+
[Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
|
|
5684
|
+
[Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
5685
|
+
[Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
|
5686
|
+
[Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
|
|
5687
|
+
[Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
|
|
5688
|
+
[Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
|
|
5689
|
+
[Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
|
|
5690
|
+
[Blockchain.NEAR]: 'usdt.tether-token.near',
|
|
5691
|
+
[Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
|
|
5692
|
+
[Blockchain.Polkadot_Asset_Hub]: '1984',
|
|
5693
|
+
[Blockchain.Polygon]: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
|
5694
|
+
[Blockchain.Sei]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
5695
|
+
[Blockchain.Solana]: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
5696
|
+
[Blockchain.Unichain]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
5697
|
+
},
|
|
5698
|
+
};
|
|
5699
|
+
|
|
5003
5700
|
/**
|
|
5004
|
-
*
|
|
5701
|
+
* EURC (Euro Coin) token definition with addresses and metadata.
|
|
5005
5702
|
*
|
|
5006
|
-
*
|
|
5703
|
+
* @remarks
|
|
5704
|
+
* Built-in EURC definition for the TokenRegistry. Includes chain locators
|
|
5705
|
+
* for swap-supported chains.
|
|
5007
5706
|
*/
|
|
5008
|
-
const
|
|
5707
|
+
const EURC = {
|
|
5708
|
+
symbol: 'EURC',
|
|
5709
|
+
decimals: 6,
|
|
5710
|
+
locators: {
|
|
5711
|
+
[Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
5712
|
+
[Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
5713
|
+
[Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
5714
|
+
[Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
5715
|
+
[Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
5716
|
+
},
|
|
5717
|
+
};
|
|
5718
|
+
|
|
5009
5719
|
/**
|
|
5010
|
-
*
|
|
5720
|
+
* DAI (Maker DAO) stablecoin token definition with addresses and metadata.
|
|
5011
5721
|
*
|
|
5012
|
-
*
|
|
5722
|
+
* @remarks
|
|
5723
|
+
* Built-in DAI definition for the TokenRegistry. Includes chain locators
|
|
5724
|
+
* for swap-supported chains.
|
|
5013
5725
|
*/
|
|
5014
|
-
const
|
|
5726
|
+
const DAI = {
|
|
5727
|
+
symbol: 'DAI',
|
|
5728
|
+
decimals: 18,
|
|
5729
|
+
chainDecimals: {
|
|
5730
|
+
[Blockchain.Solana]: 8,
|
|
5731
|
+
},
|
|
5732
|
+
locators: {
|
|
5733
|
+
[Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
5734
|
+
[Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
|
|
5735
|
+
[Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
|
|
5736
|
+
[Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
5737
|
+
[Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
|
|
5738
|
+
[Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
5739
|
+
[Blockchain.Polygon]: '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063',
|
|
5740
|
+
[Blockchain.Solana]: 'EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o',
|
|
5741
|
+
},
|
|
5742
|
+
};
|
|
5743
|
+
|
|
5015
5744
|
/**
|
|
5016
|
-
*
|
|
5017
|
-
*
|
|
5018
|
-
* Constructs a 32-byte hookData payload that signals to Circle's Orbit relayer
|
|
5019
|
-
* that the user wants automated attestation fetching and destination mint execution.
|
|
5020
|
-
*
|
|
5021
|
-
* The hookData format is:
|
|
5022
|
-
* - Bytes 0-23: ASCII "cctp-forward" right-padded to 24 bytes with zeros
|
|
5023
|
-
* - Bytes 24-27: uint32 version (big-endian) - currently 0
|
|
5024
|
-
* - Bytes 28-31: uint32 length (big-endian) - 0 for basic forwarding
|
|
5025
|
-
*
|
|
5026
|
-
* @returns A 0x-prefixed hex string representing the 32-byte hookData
|
|
5027
|
-
*
|
|
5028
|
-
* @example
|
|
5029
|
-
* ```typescript
|
|
5030
|
-
* import { buildForwardingHookData } from '@core/utils'
|
|
5745
|
+
* USDe (Ethena) synthetic dollar token definition with addresses and metadata.
|
|
5031
5746
|
*
|
|
5032
|
-
*
|
|
5033
|
-
*
|
|
5747
|
+
* @remarks
|
|
5748
|
+
* Built-in USDE definition for the TokenRegistry. Includes chain locators
|
|
5749
|
+
* for swap-supported chains.
|
|
5750
|
+
*/
|
|
5751
|
+
const USDE = {
|
|
5752
|
+
symbol: 'USDe',
|
|
5753
|
+
decimals: 18,
|
|
5754
|
+
chainDecimals: {
|
|
5755
|
+
[Blockchain.Solana]: 9,
|
|
5756
|
+
},
|
|
5757
|
+
locators: {
|
|
5758
|
+
[Blockchain.Arbitrum]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5759
|
+
[Blockchain.Base]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5760
|
+
[Blockchain.Ethereum]: '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3',
|
|
5761
|
+
[Blockchain.Linea]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5762
|
+
[Blockchain.Optimism]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
5763
|
+
[Blockchain.Solana]: 'DEkqHyPN7GMRJ5cArtQFAWefqbZb33Hyf6s5iCwjEonT',
|
|
5764
|
+
},
|
|
5765
|
+
};
|
|
5766
|
+
|
|
5767
|
+
/**
|
|
5768
|
+
* PYUSD (PayPal USD) stablecoin token definition with addresses and metadata.
|
|
5034
5769
|
*
|
|
5035
|
-
*
|
|
5036
|
-
*
|
|
5037
|
-
*
|
|
5038
|
-
* mintRecipient: '0x...',
|
|
5039
|
-
* maxFee: BigInt('50000'),
|
|
5040
|
-
* minFinalityThreshold: 1000,
|
|
5041
|
-
* fromChain: ethereum,
|
|
5042
|
-
* toChain: base,
|
|
5043
|
-
* hookData
|
|
5044
|
-
* })
|
|
5045
|
-
* ```
|
|
5770
|
+
* @remarks
|
|
5771
|
+
* Built-in PYUSD definition for the TokenRegistry. Includes chain locators
|
|
5772
|
+
* for swap-supported chains.
|
|
5046
5773
|
*/
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
// Write the magic prefix ("cctp-forward") - 12 bytes, rest of 24-byte section is zero-padded
|
|
5057
|
-
const encoder = new TextEncoder();
|
|
5058
|
-
const magicBytes = encoder.encode(CCTP_FORWARD_MAGIC_PREFIX);
|
|
5059
|
-
buffer.set(magicBytes, 0);
|
|
5060
|
-
// Bytes 12-23 are already zero (right-padding)
|
|
5061
|
-
// Write uint32 version at bytes 24-27 (big-endian)
|
|
5062
|
-
const versionView = new DataView(buffer.buffer);
|
|
5063
|
-
versionView.setUint32(24, CCTP_FORWARD_VERSION, false); // false = big-endian
|
|
5064
|
-
// Write uint32 length at bytes 28-31 (big-endian)
|
|
5065
|
-
versionView.setUint32(28, CCTP_FORWARD_PAYLOAD_LENGTH, false); // false = big-endian
|
|
5066
|
-
// Convert to hex string with 0x prefix and cache
|
|
5067
|
-
cachedHookDataHex =
|
|
5068
|
-
'0x' +
|
|
5069
|
-
Array.from(buffer)
|
|
5070
|
-
.map((b) => b.toString(16).padStart(2, '0'))
|
|
5071
|
-
.join('');
|
|
5072
|
-
return cachedHookDataHex;
|
|
5073
|
-
}
|
|
5774
|
+
const PYUSD = {
|
|
5775
|
+
symbol: 'PYUSD',
|
|
5776
|
+
decimals: 6,
|
|
5777
|
+
locators: {
|
|
5778
|
+
[Blockchain.Arbitrum]: '0x46850aD61C2B7d64d08c9C754F45254596696984',
|
|
5779
|
+
[Blockchain.Ethereum]: '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8',
|
|
5780
|
+
[Blockchain.Solana]: '2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo',
|
|
5781
|
+
},
|
|
5782
|
+
};
|
|
5074
5783
|
|
|
5075
5784
|
/**
|
|
5076
|
-
*
|
|
5785
|
+
* WETH (Wrapped Ether) token definition with addresses and metadata.
|
|
5077
5786
|
*
|
|
5078
|
-
*
|
|
5079
|
-
*
|
|
5787
|
+
* @remarks
|
|
5788
|
+
* Built-in WETH definition for the TokenRegistry. Includes chain locators
|
|
5789
|
+
* for swap-supported chains where WETH is available.
|
|
5080
5790
|
*/
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5791
|
+
const WETH = {
|
|
5792
|
+
symbol: 'WETH',
|
|
5793
|
+
decimals: 18,
|
|
5794
|
+
chainDecimals: {
|
|
5795
|
+
[Blockchain.Solana]: 9,
|
|
5796
|
+
},
|
|
5797
|
+
locators: {
|
|
5798
|
+
[Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
|
|
5799
|
+
[Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
|
|
5800
|
+
[Blockchain.Base]: '0x4200000000000000000000000000000000000006',
|
|
5801
|
+
[Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
5802
|
+
[Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
|
|
5803
|
+
[Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
|
|
5804
|
+
[Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs',
|
|
5805
|
+
},
|
|
5806
|
+
};
|
|
5088
5807
|
|
|
5089
5808
|
/**
|
|
5090
|
-
*
|
|
5091
|
-
* Only accepts dot (.) as the decimal separator. Thousand separators are not allowed.
|
|
5809
|
+
* WBTC (Wrapped Bitcoin) token definition with addresses and metadata.
|
|
5092
5810
|
*
|
|
5093
|
-
*
|
|
5094
|
-
*
|
|
5095
|
-
*
|
|
5811
|
+
* @remarks
|
|
5812
|
+
* Built-in WBTC definition for the TokenRegistry. Includes chain locators
|
|
5813
|
+
* for swap-supported chains where WBTC is available.
|
|
5814
|
+
*/
|
|
5815
|
+
const WBTC = {
|
|
5816
|
+
symbol: 'WBTC',
|
|
5817
|
+
decimals: 8,
|
|
5818
|
+
locators: {
|
|
5819
|
+
[Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
|
|
5820
|
+
[Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
|
|
5821
|
+
[Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218',
|
|
5822
|
+
},
|
|
5823
|
+
};
|
|
5824
|
+
|
|
5825
|
+
/**
|
|
5826
|
+
* WSOL (Wrapped SOL) token definition with addresses and metadata.
|
|
5096
5827
|
*
|
|
5097
|
-
*
|
|
5098
|
-
* -
|
|
5099
|
-
* -
|
|
5100
|
-
|
|
5101
|
-
|
|
5828
|
+
* @remarks
|
|
5829
|
+
* Built-in WSOL definition for the TokenRegistry. Includes chain locators
|
|
5830
|
+
* for swap-supported chains where WSOL is available.
|
|
5831
|
+
*/
|
|
5832
|
+
const WSOL = {
|
|
5833
|
+
symbol: 'WSOL',
|
|
5834
|
+
decimals: 9,
|
|
5835
|
+
locators: {
|
|
5836
|
+
[Blockchain.Solana]: 'So11111111111111111111111111111111111111112',
|
|
5837
|
+
},
|
|
5838
|
+
};
|
|
5839
|
+
|
|
5840
|
+
/**
|
|
5841
|
+
* WAVAX (Wrapped AVAX) token definition with addresses and metadata.
|
|
5102
5842
|
*
|
|
5103
|
-
*
|
|
5104
|
-
* -
|
|
5105
|
-
* -
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5843
|
+
* @remarks
|
|
5844
|
+
* Built-in WAVAX definition for the TokenRegistry. Includes chain locators
|
|
5845
|
+
* for swap-supported chains where WAVAX is available.
|
|
5846
|
+
*/
|
|
5847
|
+
const WAVAX = {
|
|
5848
|
+
symbol: 'WAVAX',
|
|
5849
|
+
decimals: 18,
|
|
5850
|
+
locators: {
|
|
5851
|
+
[Blockchain.Avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7',
|
|
5852
|
+
},
|
|
5853
|
+
};
|
|
5854
|
+
|
|
5855
|
+
/**
|
|
5856
|
+
* WPOL (Wrapped POL) token definition with addresses and metadata.
|
|
5109
5857
|
*
|
|
5110
|
-
*
|
|
5111
|
-
* -
|
|
5112
|
-
* -
|
|
5113
|
-
* - maxDecimals: maximum number of decimal places allowed (e.g., 6 for USDC).
|
|
5858
|
+
* @remarks
|
|
5859
|
+
* Built-in WPOL definition for the TokenRegistry. Includes chain locators
|
|
5860
|
+
* for swap-supported chains where WPOL is available.
|
|
5114
5861
|
*/
|
|
5115
|
-
const
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
.superRefine((val, ctx) => {
|
|
5122
|
-
const amount = Number.parseFloat(val);
|
|
5123
|
-
if (Number.isNaN(amount)) {
|
|
5124
|
-
ctx.addIssue({
|
|
5125
|
-
code: zod.z.ZodIssueCode.custom,
|
|
5126
|
-
message: options.regexMessage,
|
|
5127
|
-
});
|
|
5128
|
-
return;
|
|
5129
|
-
}
|
|
5130
|
-
// Check decimal precision if maxDecimals is specified
|
|
5131
|
-
if (options.maxDecimals !== undefined) {
|
|
5132
|
-
const decimalPart = val.split('.')[1];
|
|
5133
|
-
if (decimalPart && decimalPart.length > options.maxDecimals) {
|
|
5134
|
-
ctx.addIssue({
|
|
5135
|
-
code: zod.z.ZodIssueCode.custom,
|
|
5136
|
-
message: `Maximum supported decimal places: ${options.maxDecimals.toString()}`,
|
|
5137
|
-
});
|
|
5138
|
-
return;
|
|
5139
|
-
}
|
|
5140
|
-
}
|
|
5141
|
-
if (options.allowZero && amount < 0) {
|
|
5142
|
-
ctx.addIssue({
|
|
5143
|
-
code: zod.z.ZodIssueCode.custom,
|
|
5144
|
-
message: `${capitalizedAttributeName} must be non-negative`,
|
|
5145
|
-
});
|
|
5146
|
-
}
|
|
5147
|
-
else if (!options.allowZero && amount <= 0) {
|
|
5148
|
-
ctx.addIssue({
|
|
5149
|
-
code: zod.z.ZodIssueCode.custom,
|
|
5150
|
-
message: `${capitalizedAttributeName} must be greater than 0`,
|
|
5151
|
-
});
|
|
5152
|
-
}
|
|
5153
|
-
});
|
|
5862
|
+
const WPOL = {
|
|
5863
|
+
symbol: 'WPOL',
|
|
5864
|
+
decimals: 18,
|
|
5865
|
+
locators: {
|
|
5866
|
+
[Blockchain.Polygon]: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
|
|
5867
|
+
},
|
|
5154
5868
|
};
|
|
5869
|
+
|
|
5155
5870
|
/**
|
|
5156
|
-
*
|
|
5157
|
-
* This ensures the basic structure of a chain definition is valid.
|
|
5158
|
-
* A chain definition must include at minimum a name and type.
|
|
5871
|
+
* ETH (native Ether alias) token definition with metadata.
|
|
5159
5872
|
*
|
|
5160
|
-
* @
|
|
5873
|
+
* @remarks
|
|
5874
|
+
* Built-in ETH definition for the TokenRegistry. Used as a symbol alias
|
|
5875
|
+
* for native ETH (e.g. in swap flows). Chain locators are TBD and will
|
|
5876
|
+
* be added when addresses are available. Use raw selector with
|
|
5877
|
+
* locator + decimals where native gas token is represented as a contract.
|
|
5878
|
+
*/
|
|
5879
|
+
const ETH = {
|
|
5880
|
+
symbol: 'ETH',
|
|
5881
|
+
decimals: 18,
|
|
5882
|
+
locators: {},
|
|
5883
|
+
};
|
|
5884
|
+
|
|
5885
|
+
/**
|
|
5886
|
+
* POL (Polygon native token) token definition with addresses and metadata.
|
|
5887
|
+
*
|
|
5888
|
+
* @remarks
|
|
5889
|
+
* Built-in POL definition for the TokenRegistry. Includes chain locators
|
|
5890
|
+
* where POL is available as a bridged/wrapped asset.
|
|
5891
|
+
*/
|
|
5892
|
+
const POL = {
|
|
5893
|
+
symbol: 'POL',
|
|
5894
|
+
decimals: 18,
|
|
5895
|
+
locators: {
|
|
5896
|
+
[Blockchain.Ethereum]: '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6',
|
|
5897
|
+
},
|
|
5898
|
+
};
|
|
5899
|
+
|
|
5900
|
+
/**
|
|
5901
|
+
* PLUME (Plume network token) token definition with addresses and metadata.
|
|
5902
|
+
*
|
|
5903
|
+
* @remarks
|
|
5904
|
+
* Built-in PLUME definition for the TokenRegistry. Includes chain locators
|
|
5905
|
+
* where PLUME is available.
|
|
5906
|
+
*/
|
|
5907
|
+
const PLUME = {
|
|
5908
|
+
symbol: 'PLUME',
|
|
5909
|
+
decimals: 18,
|
|
5910
|
+
locators: {
|
|
5911
|
+
[Blockchain.Ethereum]: '0x4C1746A800D224393fE2470C70A35717eD4eA5F1',
|
|
5912
|
+
},
|
|
5913
|
+
};
|
|
5914
|
+
|
|
5915
|
+
/**
|
|
5916
|
+
* MON token definition with Solana mint metadata.
|
|
5917
|
+
*
|
|
5918
|
+
* @remarks
|
|
5919
|
+
* Built-in MON definition for the TokenRegistry. Includes chain locators
|
|
5920
|
+
* for swap-supported chains.
|
|
5921
|
+
*/
|
|
5922
|
+
const MON = {
|
|
5923
|
+
symbol: 'MON',
|
|
5924
|
+
decimals: 18,
|
|
5925
|
+
chainDecimals: {
|
|
5926
|
+
[Blockchain.Solana]: 8,
|
|
5927
|
+
},
|
|
5928
|
+
locators: {
|
|
5929
|
+
[Blockchain.Solana]: 'CrAr4RRJMBVwRsZtT62pEhfA9H5utymC2mVx8e7FreP2',
|
|
5930
|
+
},
|
|
5931
|
+
};
|
|
5932
|
+
|
|
5933
|
+
// Re-export for consumers
|
|
5934
|
+
/**
|
|
5935
|
+
* All default token definitions.
|
|
5936
|
+
*
|
|
5937
|
+
* @remarks
|
|
5938
|
+
* These tokens are automatically included in the TokenRegistry when created
|
|
5939
|
+
* without explicit defaults. Extensions can override these definitions.
|
|
5940
|
+
* Includes USDC, USDT, EURC, DAI, USDE, PYUSD, WETH, WBTC, WSOL, WAVAX,
|
|
5941
|
+
* WPOL, ETH, POL, PLUME, and MON.
|
|
5161
5942
|
*
|
|
5162
5943
|
* @example
|
|
5163
5944
|
* ```typescript
|
|
5164
|
-
* import {
|
|
5945
|
+
* import { createTokenRegistry } from '@core/tokens'
|
|
5165
5946
|
*
|
|
5166
|
-
*
|
|
5167
|
-
*
|
|
5168
|
-
* type: 'evm'
|
|
5169
|
-
* }
|
|
5947
|
+
* // Registry uses these by default
|
|
5948
|
+
* const registry = createTokenRegistry()
|
|
5170
5949
|
*
|
|
5171
|
-
*
|
|
5172
|
-
*
|
|
5950
|
+
* // Add custom tokens (built-ins are still included)
|
|
5951
|
+
* const customRegistry = createTokenRegistry({
|
|
5952
|
+
* tokens: [myCustomToken],
|
|
5953
|
+
* })
|
|
5173
5954
|
* ```
|
|
5174
5955
|
*/
|
|
5175
|
-
const
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5956
|
+
const DEFAULT_TOKENS = [
|
|
5957
|
+
USDC,
|
|
5958
|
+
USDT,
|
|
5959
|
+
EURC,
|
|
5960
|
+
DAI,
|
|
5961
|
+
USDE,
|
|
5962
|
+
PYUSD,
|
|
5963
|
+
WETH,
|
|
5964
|
+
WBTC,
|
|
5965
|
+
WSOL,
|
|
5966
|
+
WAVAX,
|
|
5967
|
+
WPOL,
|
|
5968
|
+
ETH,
|
|
5969
|
+
POL,
|
|
5970
|
+
PLUME,
|
|
5971
|
+
MON,
|
|
5972
|
+
];
|
|
5179
5973
|
/**
|
|
5180
|
-
*
|
|
5181
|
-
* This ensures all required fields are present and properly typed.
|
|
5182
|
-
* A wallet context must include:
|
|
5183
|
-
* - A valid adapter with prepare and execute methods
|
|
5184
|
-
* - A valid Ethereum address
|
|
5185
|
-
* - A valid chain definition with required properties
|
|
5974
|
+
* Uppercased token symbols approved for swap fee collection.
|
|
5186
5975
|
*
|
|
5187
|
-
* @
|
|
5976
|
+
* @remarks
|
|
5977
|
+
* Derived from {@link DEFAULT_TOKENS} so all consumers share a single
|
|
5978
|
+
* allowlist source and stay in sync when defaults change.
|
|
5979
|
+
*/
|
|
5980
|
+
new Set(DEFAULT_TOKENS.map((t) => t.symbol.toUpperCase()));
|
|
5981
|
+
|
|
5982
|
+
/**
|
|
5983
|
+
* Resolve the effective decimals for a token on a specific chain.
|
|
5984
|
+
*
|
|
5985
|
+
* Returns the chain-specific override from `chainDecimals` when available,
|
|
5986
|
+
* otherwise falls back to the token's default `decimals`.
|
|
5987
|
+
*
|
|
5988
|
+
* @param token - The token definition to resolve decimals for.
|
|
5989
|
+
* @param chain - Optional chain identifier. When omitted, the default decimals are returned.
|
|
5990
|
+
* @returns The number of decimal places for the token on the given chain.
|
|
5188
5991
|
*
|
|
5189
5992
|
* @example
|
|
5190
5993
|
* ```typescript
|
|
5191
|
-
* import {
|
|
5994
|
+
* import { resolveTokenDecimals } from '\@core/tokens'
|
|
5192
5995
|
*
|
|
5193
|
-
*
|
|
5194
|
-
*
|
|
5195
|
-
*
|
|
5196
|
-
*
|
|
5197
|
-
* },
|
|
5198
|
-
* address: '0x1234567890123456789012345678901234567890',
|
|
5199
|
-
* chain: {
|
|
5200
|
-
* name: 'Ethereum',
|
|
5201
|
-
* type: 'evm',
|
|
5202
|
-
* isTestnet: false
|
|
5203
|
-
* }
|
|
5204
|
-
* }
|
|
5205
|
-
*
|
|
5206
|
-
* const result = walletContextSchema.safeParse(validContext)
|
|
5207
|
-
* console.log(result.success) // true
|
|
5996
|
+
* // DAI: 18 decimals on EVM, 8 on Solana
|
|
5997
|
+
* resolveTokenDecimals(DAI) // 18 (default)
|
|
5998
|
+
* resolveTokenDecimals(DAI, 'Solana') // 8 (chain override)
|
|
5999
|
+
* resolveTokenDecimals(DAI, 'Ethereum') // 18 (no override, falls back)
|
|
5208
6000
|
* ```
|
|
5209
6001
|
*/
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
name: zod.z.string(),
|
|
5218
|
-
type: zod.z.string(),
|
|
5219
|
-
isTestnet: zod.z.boolean(),
|
|
5220
|
-
}),
|
|
5221
|
-
});
|
|
6002
|
+
function resolveTokenDecimals(token, chain) {
|
|
6003
|
+
if (chain === undefined) {
|
|
6004
|
+
return token.decimals;
|
|
6005
|
+
}
|
|
6006
|
+
return token.chainDecimals?.[chain] ?? token.decimals;
|
|
6007
|
+
}
|
|
6008
|
+
|
|
5222
6009
|
/**
|
|
5223
|
-
*
|
|
5224
|
-
* Extends walletContextSchema with optional useForwarder flag.
|
|
6010
|
+
* Check if a selector is a raw token selector (object form).
|
|
5225
6011
|
*
|
|
5226
|
-
* @
|
|
6012
|
+
* @param selector - The token selector to check.
|
|
6013
|
+
* @returns True if the selector is a raw token selector.
|
|
5227
6014
|
*/
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
});
|
|
6015
|
+
function isRawSelector(selector) {
|
|
6016
|
+
return typeof selector === 'object' && 'locator' in selector;
|
|
6017
|
+
}
|
|
5232
6018
|
/**
|
|
5233
|
-
*
|
|
5234
|
-
* Used when useForwarder is true and no adapter is provided.
|
|
5235
|
-
* Requires chain definition and recipientAddress.
|
|
6019
|
+
* Normalize a symbol to uppercase for case-insensitive lookup.
|
|
5236
6020
|
*
|
|
5237
|
-
*
|
|
5238
|
-
*
|
|
6021
|
+
* @param symbol - The symbol to normalize.
|
|
6022
|
+
* @returns The normalized (uppercase) symbol.
|
|
6023
|
+
*/
|
|
6024
|
+
function normalizeSymbol(symbol) {
|
|
6025
|
+
return symbol.toUpperCase();
|
|
6026
|
+
}
|
|
6027
|
+
/**
|
|
6028
|
+
* Normalize a locator for stable chain-aware lookup.
|
|
5239
6029
|
*
|
|
5240
|
-
* @
|
|
6030
|
+
* @remarks
|
|
6031
|
+
* EVM-style addresses (`0x...`) are normalized to lowercase for
|
|
6032
|
+
* case-insensitive matching. Non-EVM locators keep original casing.
|
|
5241
6033
|
*/
|
|
5242
|
-
|
|
5243
|
-
.
|
|
5244
|
-
|
|
5245
|
-
isTestnet: zod.z.boolean(),
|
|
5246
|
-
}),
|
|
5247
|
-
recipientAddress: zod.z
|
|
5248
|
-
.string()
|
|
5249
|
-
.min(1, 'Recipient address is required for forwarder-only destination'),
|
|
5250
|
-
useForwarder: zod.z.literal(true),
|
|
5251
|
-
})
|
|
5252
|
-
.superRefine((data, ctx) => {
|
|
5253
|
-
// Pass chain name as string - isValidAddressForChain will use name-based matching
|
|
5254
|
-
if (!isValidAddressForChain(data.recipientAddress, data.chain.name)) {
|
|
5255
|
-
ctx.addIssue({
|
|
5256
|
-
code: zod.z.ZodIssueCode.custom,
|
|
5257
|
-
message: `Invalid recipient address format for chain ${data.chain.name}`,
|
|
5258
|
-
path: ['recipientAddress'],
|
|
5259
|
-
});
|
|
6034
|
+
function normalizeLocator(locator) {
|
|
6035
|
+
if (locator.startsWith('0x') || locator.startsWith('0X')) {
|
|
6036
|
+
return locator.toLowerCase();
|
|
5260
6037
|
}
|
|
5261
|
-
|
|
6038
|
+
return locator;
|
|
6039
|
+
}
|
|
5262
6040
|
/**
|
|
5263
|
-
*
|
|
6041
|
+
* Build a stable map key for a chain + locator pair.
|
|
5264
6042
|
*/
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
]);
|
|
6043
|
+
function buildAddressKey(chainId, locator) {
|
|
6044
|
+
return `${chainId}::${normalizeLocator(locator)}`;
|
|
6045
|
+
}
|
|
5269
6046
|
/**
|
|
5270
|
-
*
|
|
5271
|
-
* Validates the simplified CustomFee interface which includes:
|
|
5272
|
-
* - An optional fee amount as string
|
|
5273
|
-
* - An optional fee recipient as string address
|
|
6047
|
+
* Create a token registry with built-in tokens and optional extensions.
|
|
5274
6048
|
*
|
|
5275
|
-
* @
|
|
6049
|
+
* @remarks
|
|
6050
|
+
* The registry always includes built-in tokens (DEFAULT_TOKENS) like USDC.
|
|
6051
|
+
* Custom tokens are merged on top - use this to add new tokens or override
|
|
6052
|
+
* built-in definitions.
|
|
6053
|
+
*
|
|
6054
|
+
* @param options - Configuration options for the registry.
|
|
6055
|
+
* @returns A token registry instance.
|
|
5276
6056
|
*
|
|
5277
6057
|
* @example
|
|
5278
6058
|
* ```typescript
|
|
5279
|
-
* import {
|
|
6059
|
+
* import { createTokenRegistry } from '@core/tokens'
|
|
5280
6060
|
*
|
|
5281
|
-
*
|
|
5282
|
-
*
|
|
5283
|
-
* recipientAddress: '0x1234567890123456789012345678901234567890'
|
|
5284
|
-
* }
|
|
6061
|
+
* // Create registry with built-in tokens (USDC, etc.)
|
|
6062
|
+
* const registry = createTokenRegistry()
|
|
5285
6063
|
*
|
|
5286
|
-
*
|
|
5287
|
-
*
|
|
6064
|
+
* // Resolve USDC on Ethereum
|
|
6065
|
+
* const usdc = registry.resolve('USDC', 'Ethereum')
|
|
6066
|
+
* console.log(usdc.locator) // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
6067
|
+
* console.log(usdc.decimals) // 6
|
|
5288
6068
|
* ```
|
|
5289
|
-
|
|
6069
|
+
*
|
|
6070
|
+
* @example
|
|
6071
|
+
* ```typescript
|
|
6072
|
+
* // Add custom tokens (built-ins are still included)
|
|
6073
|
+
* const myToken: TokenDefinition = {
|
|
6074
|
+
* symbol: 'MY',
|
|
6075
|
+
* decimals: 18,
|
|
6076
|
+
* locators: { Ethereum: '0x...' },
|
|
6077
|
+
* }
|
|
6078
|
+
*
|
|
6079
|
+
* const registry = createTokenRegistry({ tokens: [myToken] })
|
|
6080
|
+
* registry.resolve('USDC', 'Ethereum') // Still works!
|
|
6081
|
+
* registry.resolve('MY', 'Ethereum') // Also works
|
|
6082
|
+
* ```
|
|
6083
|
+
*
|
|
6084
|
+
* @example
|
|
6085
|
+
* ```typescript
|
|
6086
|
+
* // Override a built-in token
|
|
6087
|
+
* const customUsdc: TokenDefinition = {
|
|
6088
|
+
* symbol: 'USDC',
|
|
6089
|
+
* decimals: 6,
|
|
6090
|
+
* locators: { MyChain: '0xCustomAddress' },
|
|
6091
|
+
* }
|
|
6092
|
+
*
|
|
6093
|
+
* const registry = createTokenRegistry({ tokens: [customUsdc] })
|
|
6094
|
+
* // Now USDC resolves to customUsdc definition
|
|
6095
|
+
* ```
|
|
6096
|
+
*
|
|
6097
|
+
* @example
|
|
6098
|
+
* ```typescript
|
|
6099
|
+
* // Resolve arbitrary tokens by raw locator
|
|
6100
|
+
* const registry = createTokenRegistry()
|
|
6101
|
+
* const token = registry.resolve(
|
|
6102
|
+
* { locator: '0x1234...', decimals: 18 },
|
|
6103
|
+
* 'Ethereum'
|
|
6104
|
+
* )
|
|
6105
|
+
* ```
|
|
6106
|
+
*/
|
|
6107
|
+
function createTokenRegistry(options = {}) {
|
|
6108
|
+
const { tokens = [], requireDecimals = false } = options;
|
|
6109
|
+
// Build the token map: always start with DEFAULT_TOKENS, then add custom tokens
|
|
6110
|
+
const tokenMap = new Map();
|
|
6111
|
+
// Add built-in tokens first
|
|
6112
|
+
for (const def of DEFAULT_TOKENS) {
|
|
6113
|
+
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
6114
|
+
}
|
|
6115
|
+
// Custom tokens override built-ins
|
|
6116
|
+
for (const def of tokens) {
|
|
6117
|
+
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
6118
|
+
}
|
|
6119
|
+
// Build an address index from the resolved token map so overrides win.
|
|
6120
|
+
const addressMap = new Map();
|
|
6121
|
+
for (const token of tokenMap.values()) {
|
|
6122
|
+
for (const [chainId, locator] of Object.entries(token.locators)) {
|
|
6123
|
+
if (typeof locator !== 'string' || locator.trim() === '') {
|
|
6124
|
+
continue;
|
|
6125
|
+
}
|
|
6126
|
+
addressMap.set(buildAddressKey(chainId, locator), token);
|
|
6127
|
+
}
|
|
6128
|
+
}
|
|
6129
|
+
/**
|
|
6130
|
+
* Resolve a symbol selector to token information.
|
|
6131
|
+
*/
|
|
6132
|
+
function resolveSymbol(symbol, chainId) {
|
|
6133
|
+
const normalizedSymbol = normalizeSymbol(symbol);
|
|
6134
|
+
const definition = tokenMap.get(normalizedSymbol);
|
|
6135
|
+
if (definition === undefined) {
|
|
6136
|
+
throw createTokenResolutionError(`Unknown token symbol: ${symbol}. Register it via createTokenRegistry({ tokens: [...] }) or use a raw selector.`, symbol, chainId);
|
|
6137
|
+
}
|
|
6138
|
+
const locator = definition.locators[chainId];
|
|
6139
|
+
if (locator === undefined || locator.trim() === '') {
|
|
6140
|
+
throw createTokenResolutionError(`Token ${symbol} has no locator for chain ${chainId}`, symbol, chainId);
|
|
6141
|
+
}
|
|
6142
|
+
const decimals = resolveTokenDecimals(definition, chainId);
|
|
6143
|
+
return {
|
|
6144
|
+
symbol: definition.symbol,
|
|
6145
|
+
decimals,
|
|
6146
|
+
locator: normalizeLocator(locator),
|
|
6147
|
+
};
|
|
6148
|
+
}
|
|
6149
|
+
/**
|
|
6150
|
+
* Resolve a raw selector to token information.
|
|
6151
|
+
*/
|
|
6152
|
+
function resolveRaw(selector, chainId) {
|
|
6153
|
+
const { locator, decimals } = selector;
|
|
6154
|
+
// Validate locator
|
|
6155
|
+
if (!locator || typeof locator !== 'string') {
|
|
6156
|
+
throw createTokenResolutionError('Raw selector must have a valid locator string', selector, chainId);
|
|
6157
|
+
}
|
|
6158
|
+
// Decimals are always required for raw selectors
|
|
6159
|
+
if (decimals === undefined) {
|
|
6160
|
+
const message = requireDecimals
|
|
6161
|
+
? 'Decimals required for raw token selector (requireDecimals: true)'
|
|
6162
|
+
: 'Decimals required for raw token selector. Provide { locator, decimals }.';
|
|
6163
|
+
throw createTokenResolutionError(message, selector, chainId);
|
|
6164
|
+
}
|
|
6165
|
+
// Validate decimals
|
|
6166
|
+
if (typeof decimals !== 'number' ||
|
|
6167
|
+
decimals < 0 ||
|
|
6168
|
+
!Number.isInteger(decimals)) {
|
|
6169
|
+
throw createTokenResolutionError(`Invalid decimals: ${String(decimals)}. Must be a non-negative integer.`, selector, chainId);
|
|
6170
|
+
}
|
|
6171
|
+
return {
|
|
6172
|
+
decimals,
|
|
6173
|
+
locator: normalizeLocator(locator),
|
|
6174
|
+
};
|
|
6175
|
+
}
|
|
6176
|
+
return {
|
|
6177
|
+
resolve(selector, chainId) {
|
|
6178
|
+
// Runtime validation of inputs - these checks are for JS consumers
|
|
6179
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
6180
|
+
if (selector === null || selector === undefined) {
|
|
6181
|
+
throw createTokenResolutionError('Token selector cannot be null or undefined', selector, chainId);
|
|
6182
|
+
}
|
|
6183
|
+
if (chainId === '' || typeof chainId !== 'string') {
|
|
6184
|
+
throw createTokenResolutionError('Chain ID is required for token resolution', selector, chainId);
|
|
6185
|
+
}
|
|
6186
|
+
// Dispatch based on selector type
|
|
6187
|
+
if (isRawSelector(selector)) {
|
|
6188
|
+
return resolveRaw(selector, chainId);
|
|
6189
|
+
}
|
|
6190
|
+
if (typeof selector === 'string') {
|
|
6191
|
+
return resolveSymbol(selector, chainId);
|
|
6192
|
+
}
|
|
6193
|
+
throw createTokenResolutionError(`Invalid selector type: ${typeof selector}. Expected string or object with locator.`, selector, chainId);
|
|
6194
|
+
},
|
|
6195
|
+
resolveByAddress(address, chainId) {
|
|
6196
|
+
if (!address || typeof address !== 'string') {
|
|
6197
|
+
throw createTokenResolutionError('Token address is required for address resolution', { locator: address }, chainId);
|
|
6198
|
+
}
|
|
6199
|
+
if (chainId === '' || typeof chainId !== 'string') {
|
|
6200
|
+
throw createTokenResolutionError('Chain ID is required for token resolution', { locator: address }, chainId);
|
|
6201
|
+
}
|
|
6202
|
+
const definition = addressMap.get(buildAddressKey(chainId, address));
|
|
6203
|
+
if (definition === undefined) {
|
|
6204
|
+
throw createTokenResolutionError(`Unknown token address: ${address} for chain ${chainId}`, { locator: address }, chainId);
|
|
6205
|
+
}
|
|
6206
|
+
const locator = definition.locators[chainId];
|
|
6207
|
+
if (locator === undefined || locator.trim() === '') {
|
|
6208
|
+
throw createTokenResolutionError(`Token ${definition.symbol} has no locator for chain ${chainId}`, definition.symbol, chainId);
|
|
6209
|
+
}
|
|
6210
|
+
const decimals = resolveTokenDecimals(definition, chainId);
|
|
6211
|
+
return {
|
|
6212
|
+
symbol: definition.symbol,
|
|
6213
|
+
decimals,
|
|
6214
|
+
locator: normalizeLocator(locator),
|
|
6215
|
+
};
|
|
6216
|
+
},
|
|
6217
|
+
get(symbol) {
|
|
6218
|
+
if (!symbol || typeof symbol !== 'string') {
|
|
6219
|
+
return undefined;
|
|
6220
|
+
}
|
|
6221
|
+
return tokenMap.get(normalizeSymbol(symbol));
|
|
6222
|
+
},
|
|
6223
|
+
has(symbol) {
|
|
6224
|
+
if (!symbol || typeof symbol !== 'string') {
|
|
6225
|
+
return false;
|
|
6226
|
+
}
|
|
6227
|
+
return tokenMap.has(normalizeSymbol(symbol));
|
|
6228
|
+
},
|
|
6229
|
+
symbols() {
|
|
6230
|
+
return Array.from(tokenMap.values()).map((def) => def.symbol);
|
|
6231
|
+
},
|
|
6232
|
+
entries() {
|
|
6233
|
+
return Array.from(tokenMap.values());
|
|
6234
|
+
},
|
|
6235
|
+
};
|
|
6236
|
+
}
|
|
6237
|
+
|
|
6238
|
+
/**
|
|
6239
|
+
* Define a schema for token registry interfaces.
|
|
6240
|
+
*
|
|
6241
|
+
* @remarks
|
|
6242
|
+
* Validate that a registry exposes the `resolve()` API used by adapters.
|
|
6243
|
+
*
|
|
6244
|
+
* @example
|
|
6245
|
+
* ```typescript
|
|
6246
|
+
* import { tokenRegistrySchema } from '@core/tokens'
|
|
6247
|
+
*
|
|
6248
|
+
* const registry = {
|
|
6249
|
+
* resolve: () => ({ locator: '0x0', decimals: 6 }),
|
|
6250
|
+
* }
|
|
6251
|
+
*
|
|
6252
|
+
* tokenRegistrySchema.parse(registry)
|
|
6253
|
+
* ```
|
|
6254
|
+
*/
|
|
6255
|
+
zod.z.custom((value) => {
|
|
6256
|
+
if (value === null || typeof value !== 'object') {
|
|
6257
|
+
return false;
|
|
6258
|
+
}
|
|
6259
|
+
const record = value;
|
|
6260
|
+
return (typeof record['resolve'] === 'function' &&
|
|
6261
|
+
typeof record['get'] === 'function' &&
|
|
6262
|
+
typeof record['has'] === 'function' &&
|
|
6263
|
+
typeof record['symbols'] === 'function' &&
|
|
6264
|
+
typeof record['entries'] === 'function');
|
|
6265
|
+
}, {
|
|
6266
|
+
message: 'Invalid token registry',
|
|
6267
|
+
});
|
|
6268
|
+
|
|
6269
|
+
/**
|
|
6270
|
+
* Build a complete explorer URL from a chain definition and transaction hash.
|
|
6271
|
+
*
|
|
6272
|
+
* This function takes a chain definition containing an explorer URL template
|
|
6273
|
+
* and replaces the `{hash}` placeholder with the provided transaction hash
|
|
6274
|
+
* to create a complete, valid explorer URL.
|
|
6275
|
+
*
|
|
6276
|
+
* @param chainDef - The chain definition containing the explorer URL template.
|
|
6277
|
+
* @param txHash - The transaction hash to insert into the URL template.
|
|
6278
|
+
* @returns A complete explorer URL with the transaction hash inserted.
|
|
6279
|
+
* @throws Error if the chain definition is null/undefined.
|
|
6280
|
+
* @throws Error if the transaction hash is null/undefined/empty.
|
|
6281
|
+
* @throws Error if the explorer URL template is missing or empty.
|
|
6282
|
+
* @throws Error if the explorer URL template doesn't contain the {hash} placeholder.
|
|
6283
|
+
* @throws Error if the resulting URL is invalid.
|
|
6284
|
+
*
|
|
6285
|
+
* @example
|
|
6286
|
+
* ```typescript
|
|
6287
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6288
|
+
* import { Ethereum } from '@core/chains'
|
|
6289
|
+
*
|
|
6290
|
+
* // Build URL for Ethereum transaction
|
|
6291
|
+
* const url = buildExplorerUrl(Ethereum, '0x1234567890abcdef...')
|
|
6292
|
+
* console.log(url) // 'https://etherscan.io/tx/0x1234567890abcdef...'
|
|
6293
|
+
* ```
|
|
6294
|
+
*
|
|
6295
|
+
* @example
|
|
6296
|
+
* ```typescript
|
|
6297
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6298
|
+
* import { Solana } from '@core/chains'
|
|
6299
|
+
*
|
|
6300
|
+
* // Build URL for Solana transaction
|
|
6301
|
+
* const url = buildExplorerUrl(Solana, 'abc123def456...')
|
|
6302
|
+
* console.log(url) // 'https://solscan.io/tx/abc123def456...'
|
|
6303
|
+
* ```
|
|
6304
|
+
*
|
|
6305
|
+
* @example
|
|
6306
|
+
* ```typescript
|
|
6307
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
6308
|
+
* import { Aptos } from '@core/chains'
|
|
6309
|
+
*
|
|
6310
|
+
* // Build URL for Aptos transaction with query parameters
|
|
6311
|
+
* const url = buildExplorerUrl(Aptos, '0xabc123...')
|
|
6312
|
+
* console.log(url) // 'https://explorer.aptoslabs.com/txn/0xabc123...?network=mainnet'
|
|
6313
|
+
* ```
|
|
6314
|
+
*/
|
|
6315
|
+
function buildExplorerUrl(chainDef, txHash) {
|
|
6316
|
+
// Validate input parameters using our standard validation pattern
|
|
6317
|
+
validateOrThrow({ chainDef, txHash }, buildExplorerUrlParamsSchema, 'Invalid buildExplorerUrl parameters');
|
|
6318
|
+
// Parse and transform input parameters (e.g., trim whitespace from txHash)
|
|
6319
|
+
const { chainDef: validChainDef, txHash: validTxHash } = buildExplorerUrlParamsSchema.parse({ chainDef, txHash });
|
|
6320
|
+
// Replace all occurrences of the placeholder with the transaction hash
|
|
6321
|
+
const explorerUrl = validChainDef.explorerUrl.replace(/{hash}/g, validTxHash);
|
|
6322
|
+
// Validate the resulting URL
|
|
6323
|
+
validate(explorerUrl, explorerUrlSchema, 'explorer URL');
|
|
6324
|
+
return explorerUrl;
|
|
6325
|
+
}
|
|
6326
|
+
|
|
6327
|
+
/**
|
|
6328
|
+
* CCTP forwarding magic bytes prefix.
|
|
6329
|
+
*
|
|
6330
|
+
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
6331
|
+
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
6332
|
+
*/
|
|
6333
|
+
const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
6334
|
+
/**
|
|
6335
|
+
* CCTP forwarding version number.
|
|
6336
|
+
*
|
|
6337
|
+
* Version 0 is used for basic forwarding requests.
|
|
6338
|
+
*/
|
|
6339
|
+
const CCTP_FORWARD_VERSION = 0;
|
|
6340
|
+
/**
|
|
6341
|
+
* Length of Circle-reserved payload for basic forwarding (0 bytes).
|
|
6342
|
+
*
|
|
6343
|
+
* Set to 0 when no additional Circle-reserved data is needed.
|
|
6344
|
+
*/
|
|
6345
|
+
const CCTP_FORWARD_PAYLOAD_LENGTH = 0;
|
|
6346
|
+
/**
|
|
6347
|
+
* Build the hookData bytes for CCTP forwarding.
|
|
6348
|
+
*
|
|
6349
|
+
* Constructs a 32-byte hookData payload that signals to Circle's Orbit relayer
|
|
6350
|
+
* that the user wants automated attestation fetching and destination mint execution.
|
|
6351
|
+
*
|
|
6352
|
+
* The hookData format is:
|
|
6353
|
+
* - Bytes 0-23: ASCII "cctp-forward" right-padded to 24 bytes with zeros
|
|
6354
|
+
* - Bytes 24-27: uint32 version (big-endian) - currently 0
|
|
6355
|
+
* - Bytes 28-31: uint32 length (big-endian) - 0 for basic forwarding
|
|
6356
|
+
*
|
|
6357
|
+
* @returns A 0x-prefixed hex string representing the 32-byte hookData
|
|
6358
|
+
*
|
|
6359
|
+
* @example
|
|
6360
|
+
* ```typescript
|
|
6361
|
+
* import { buildForwardingHookData } from '@core/utils'
|
|
6362
|
+
*
|
|
6363
|
+
* const hookData = buildForwardingHookData()
|
|
6364
|
+
* // Returns: '0x636374702d666f72776172640000000000000000000000000000000000000000'
|
|
6365
|
+
*
|
|
6366
|
+
* // Use with depositForBurnWithHook action
|
|
6367
|
+
* await adapter.action('cctp.v2.depositForBurnWithHook', {
|
|
6368
|
+
* amount: BigInt('1000000'),
|
|
6369
|
+
* mintRecipient: '0x...',
|
|
6370
|
+
* maxFee: BigInt('50000'),
|
|
6371
|
+
* minFinalityThreshold: 1000,
|
|
6372
|
+
* fromChain: ethereum,
|
|
6373
|
+
* toChain: base,
|
|
6374
|
+
* hookData
|
|
6375
|
+
* })
|
|
6376
|
+
* ```
|
|
6377
|
+
*/
|
|
6378
|
+
// Cached result for memoization (computed once on first call)
|
|
6379
|
+
let cachedHookDataHex = null;
|
|
6380
|
+
function buildForwardingHookData() {
|
|
6381
|
+
// Return cached result if already computed
|
|
6382
|
+
if (cachedHookDataHex !== null) {
|
|
6383
|
+
return cachedHookDataHex;
|
|
6384
|
+
}
|
|
6385
|
+
// Create a 32-byte buffer
|
|
6386
|
+
const buffer = new Uint8Array(32);
|
|
6387
|
+
// Write the magic prefix ("cctp-forward") - 12 bytes, rest of 24-byte section is zero-padded
|
|
6388
|
+
const encoder = new TextEncoder();
|
|
6389
|
+
const magicBytes = encoder.encode(CCTP_FORWARD_MAGIC_PREFIX);
|
|
6390
|
+
buffer.set(magicBytes, 0);
|
|
6391
|
+
// Bytes 12-23 are already zero (right-padding)
|
|
6392
|
+
// Write uint32 version at bytes 24-27 (big-endian)
|
|
6393
|
+
const versionView = new DataView(buffer.buffer);
|
|
6394
|
+
versionView.setUint32(24, CCTP_FORWARD_VERSION, false); // false = big-endian
|
|
6395
|
+
// Write uint32 length at bytes 28-31 (big-endian)
|
|
6396
|
+
versionView.setUint32(28, CCTP_FORWARD_PAYLOAD_LENGTH, false); // false = big-endian
|
|
6397
|
+
// Convert to hex string with 0x prefix and cache
|
|
6398
|
+
cachedHookDataHex =
|
|
6399
|
+
'0x' +
|
|
6400
|
+
Array.from(buffer)
|
|
6401
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
6402
|
+
.join('');
|
|
6403
|
+
return cachedHookDataHex;
|
|
6404
|
+
}
|
|
6405
|
+
|
|
6406
|
+
/**
|
|
6407
|
+
* Transfer speed options for cross-chain operations.
|
|
6408
|
+
*
|
|
6409
|
+
* Defines the available speed modes for CCTPv2 transfers, affecting
|
|
6410
|
+
* both transfer time and potential fee implications.
|
|
6411
|
+
*/
|
|
6412
|
+
var TransferSpeed;
|
|
6413
|
+
(function (TransferSpeed) {
|
|
6414
|
+
/** Fast burn mode - reduces transfer time but may have different fee implications */
|
|
6415
|
+
TransferSpeed["FAST"] = "FAST";
|
|
6416
|
+
/** Standard burn mode - normal transfer time with standard fees */
|
|
6417
|
+
TransferSpeed["SLOW"] = "SLOW";
|
|
6418
|
+
})(TransferSpeed || (TransferSpeed = {}));
|
|
6419
|
+
|
|
6420
|
+
/**
|
|
6421
|
+
* Factory to validate a numeric string with strict dot-decimal notation.
|
|
6422
|
+
* Only accepts dot (.) as the decimal separator. Thousand separators are not allowed.
|
|
6423
|
+
*
|
|
6424
|
+
* This enforces an unambiguous format for SDK inputs. Internationalization concerns
|
|
6425
|
+
* (comma vs dot decimal separators) should be handled in the UI layer before passing
|
|
6426
|
+
* values to the SDK.
|
|
6427
|
+
*
|
|
6428
|
+
* Accepts the following formats:
|
|
6429
|
+
* - Whole numbers: "1", "100", "1000"
|
|
6430
|
+
* - Leading zero decimals: "0.1", "0.5", "0.001"
|
|
6431
|
+
* - Shorthand decimals: ".1", ".5", ".001"
|
|
6432
|
+
* - Standard decimals: "1.23", "100.50"
|
|
6433
|
+
*
|
|
6434
|
+
* Does NOT accept:
|
|
6435
|
+
* - Comma decimal separator: "1,5" (use "1.5" instead)
|
|
6436
|
+
* - Thousand separators: "1,000.50" or "1.000,50" (use "1000.50" instead)
|
|
6437
|
+
* - Multiple decimal points: "1.2.3"
|
|
6438
|
+
* - Negative numbers: "-100"
|
|
6439
|
+
* - Non-numeric characters: "abc", "100a"
|
|
6440
|
+
*
|
|
6441
|
+
* Behavior differences controlled by options:
|
|
6442
|
+
* - allowZero: when false, value must be strictly greater than 0; when true, non-negative.
|
|
6443
|
+
* - regexMessage: error message when the basic numeric format fails.
|
|
6444
|
+
* - maxDecimals: maximum number of decimal places allowed (e.g., 6 for USDC).
|
|
6445
|
+
*/
|
|
6446
|
+
const createDecimalStringValidator = (options) => (schema) => {
|
|
6447
|
+
// Capitalize first letter of attribute name for error messages
|
|
6448
|
+
const capitalizedAttributeName = options.attributeName.charAt(0).toUpperCase() +
|
|
6449
|
+
options.attributeName.slice(1);
|
|
6450
|
+
return schema
|
|
6451
|
+
.regex(/^-?(?:\d+(?:\.\d+)?|\.\d+)$/, options.regexMessage)
|
|
6452
|
+
.superRefine((val, ctx) => {
|
|
6453
|
+
const amount = Number.parseFloat(val);
|
|
6454
|
+
if (Number.isNaN(amount)) {
|
|
6455
|
+
ctx.addIssue({
|
|
6456
|
+
code: zod.z.ZodIssueCode.custom,
|
|
6457
|
+
message: options.regexMessage,
|
|
6458
|
+
});
|
|
6459
|
+
return;
|
|
6460
|
+
}
|
|
6461
|
+
// Check decimal precision if maxDecimals is specified
|
|
6462
|
+
if (options.maxDecimals !== undefined) {
|
|
6463
|
+
const decimalPart = val.split('.')[1];
|
|
6464
|
+
if (decimalPart && decimalPart.length > options.maxDecimals) {
|
|
6465
|
+
ctx.addIssue({
|
|
6466
|
+
code: zod.z.ZodIssueCode.custom,
|
|
6467
|
+
message: `Maximum supported decimal places: ${options.maxDecimals.toString()}`,
|
|
6468
|
+
});
|
|
6469
|
+
return;
|
|
6470
|
+
}
|
|
6471
|
+
}
|
|
6472
|
+
if (options.allowZero && amount < 0) {
|
|
6473
|
+
ctx.addIssue({
|
|
6474
|
+
code: zod.z.ZodIssueCode.custom,
|
|
6475
|
+
message: `${capitalizedAttributeName} must be non-negative`,
|
|
6476
|
+
});
|
|
6477
|
+
}
|
|
6478
|
+
else if (!options.allowZero && amount <= 0) {
|
|
6479
|
+
ctx.addIssue({
|
|
6480
|
+
code: zod.z.ZodIssueCode.custom,
|
|
6481
|
+
message: `${capitalizedAttributeName} must be greater than 0`,
|
|
6482
|
+
});
|
|
6483
|
+
}
|
|
6484
|
+
});
|
|
6485
|
+
};
|
|
6486
|
+
/**
|
|
6487
|
+
* Schema for validating chain definitions.
|
|
6488
|
+
* This ensures the basic structure of a chain definition is valid.
|
|
6489
|
+
* A chain definition must include at minimum a name and type.
|
|
6490
|
+
*
|
|
6491
|
+
* @throws KitError if validation fails
|
|
6492
|
+
*
|
|
6493
|
+
* @example
|
|
6494
|
+
* ```typescript
|
|
6495
|
+
* import { chainDefinitionSchema } from '@core/provider'
|
|
6496
|
+
*
|
|
6497
|
+
* const validChain = {
|
|
6498
|
+
* name: 'Ethereum',
|
|
6499
|
+
* type: 'evm'
|
|
6500
|
+
* }
|
|
6501
|
+
*
|
|
6502
|
+
* const result = chainDefinitionSchema.safeParse(validChain)
|
|
6503
|
+
* console.log(result.success) // true
|
|
6504
|
+
* ```
|
|
6505
|
+
*/
|
|
6506
|
+
const chainDefinitionSchema = zod.z.object({
|
|
6507
|
+
name: zod.z.string().min(1, 'Chain name is required'),
|
|
6508
|
+
type: zod.z.string().min(1, 'Chain type is required'),
|
|
6509
|
+
});
|
|
6510
|
+
/**
|
|
6511
|
+
* Schema for validating wallet contexts.
|
|
6512
|
+
* This ensures all required fields are present and properly typed.
|
|
6513
|
+
* A wallet context must include:
|
|
6514
|
+
* - A valid adapter with prepare and execute methods
|
|
6515
|
+
* - A valid Ethereum address
|
|
6516
|
+
* - A valid chain definition with required properties
|
|
6517
|
+
*
|
|
6518
|
+
* @throws KitError if validation fails
|
|
6519
|
+
*
|
|
6520
|
+
* @example
|
|
6521
|
+
* ```typescript
|
|
6522
|
+
* import { walletContextSchema } from '@core/provider'
|
|
6523
|
+
*
|
|
6524
|
+
* const validContext = {
|
|
6525
|
+
* adapter: {
|
|
6526
|
+
* prepare: () => Promise.resolve({}),
|
|
6527
|
+
* waitForTransaction: () => Promise.resolve({})
|
|
6528
|
+
* },
|
|
6529
|
+
* address: '0x1234567890123456789012345678901234567890',
|
|
6530
|
+
* chain: {
|
|
6531
|
+
* name: 'Ethereum',
|
|
6532
|
+
* type: 'evm',
|
|
6533
|
+
* isTestnet: false
|
|
6534
|
+
* }
|
|
6535
|
+
* }
|
|
6536
|
+
*
|
|
6537
|
+
* const result = walletContextSchema.safeParse(validContext)
|
|
6538
|
+
* console.log(result.success) // true
|
|
6539
|
+
* ```
|
|
6540
|
+
*/
|
|
6541
|
+
const walletContextSchema = zod.z.object({
|
|
6542
|
+
adapter: zod.z.object({
|
|
6543
|
+
prepare: zod.z.function().returns(zod.z.any()),
|
|
6544
|
+
waitForTransaction: zod.z.function().returns(zod.z.any()),
|
|
6545
|
+
}),
|
|
6546
|
+
address: zod.z.string().min(1),
|
|
6547
|
+
chain: zod.z.object({
|
|
6548
|
+
name: zod.z.string(),
|
|
6549
|
+
type: zod.z.string(),
|
|
6550
|
+
isTestnet: zod.z.boolean(),
|
|
6551
|
+
}),
|
|
6552
|
+
});
|
|
6553
|
+
/**
|
|
6554
|
+
* Schema for validating destination wallet contexts.
|
|
6555
|
+
* Extends walletContextSchema with optional useForwarder flag.
|
|
6556
|
+
*
|
|
6557
|
+
* @throws KitError if validation fails
|
|
6558
|
+
*/
|
|
6559
|
+
const destinationContextSchema = walletContextSchema.extend({
|
|
6560
|
+
useForwarder: zod.z.boolean().optional(),
|
|
6561
|
+
recipientAddress: zod.z.string().optional(),
|
|
6562
|
+
});
|
|
6563
|
+
/**
|
|
6564
|
+
* Schema for validating forwarder-only destination contexts.
|
|
6565
|
+
* Used when useForwarder is true and no adapter is provided.
|
|
6566
|
+
* Requires chain definition and recipientAddress.
|
|
6567
|
+
*
|
|
6568
|
+
* Validates that recipientAddress format is correct for the destination chain
|
|
6569
|
+
* (EVM hex address or Solana base58 address).
|
|
6570
|
+
*
|
|
6571
|
+
* @throws KitError if validation fails
|
|
6572
|
+
*/
|
|
6573
|
+
const forwarderOnlyDestinationSchema = zod.z
|
|
6574
|
+
.object({
|
|
6575
|
+
chain: chainDefinitionSchema.extend({
|
|
6576
|
+
isTestnet: zod.z.boolean(),
|
|
6577
|
+
}),
|
|
6578
|
+
recipientAddress: zod.z
|
|
6579
|
+
.string()
|
|
6580
|
+
.min(1, 'Recipient address is required for forwarder-only destination'),
|
|
6581
|
+
useForwarder: zod.z.literal(true),
|
|
6582
|
+
})
|
|
6583
|
+
.superRefine((data, ctx) => {
|
|
6584
|
+
// Pass chain name as string - isValidAddressForChain will use name-based matching
|
|
6585
|
+
if (!isValidAddressForChain(data.recipientAddress, data.chain.name)) {
|
|
6586
|
+
ctx.addIssue({
|
|
6587
|
+
code: zod.z.ZodIssueCode.custom,
|
|
6588
|
+
message: `Invalid recipient address format for chain ${data.chain.name}`,
|
|
6589
|
+
path: ['recipientAddress'],
|
|
6590
|
+
});
|
|
6591
|
+
}
|
|
6592
|
+
});
|
|
6593
|
+
/**
|
|
6594
|
+
* Schema for validating any destination - either with adapter or forwarder-only.
|
|
6595
|
+
*/
|
|
6596
|
+
const bridgeDestinationSchema = zod.z.union([
|
|
6597
|
+
destinationContextSchema,
|
|
6598
|
+
forwarderOnlyDestinationSchema,
|
|
6599
|
+
]);
|
|
6600
|
+
/**
|
|
6601
|
+
* Schema for validating a custom fee configuration.
|
|
6602
|
+
* Validates the simplified CustomFee interface which includes:
|
|
6603
|
+
* - An optional fee amount as string
|
|
6604
|
+
* - An optional fee recipient as string address
|
|
6605
|
+
*
|
|
6606
|
+
* @throws KitError if validation fails
|
|
6607
|
+
*
|
|
6608
|
+
* @example
|
|
6609
|
+
* ```typescript
|
|
6610
|
+
* import { customFeeSchema } from '@core/provider'
|
|
6611
|
+
*
|
|
6612
|
+
* const validConfig = {
|
|
6613
|
+
* value: '1000000',
|
|
6614
|
+
* recipientAddress: '0x1234567890123456789012345678901234567890'
|
|
6615
|
+
* }
|
|
6616
|
+
*
|
|
6617
|
+
* const result = customFeeSchema.safeParse(validConfig)
|
|
6618
|
+
* console.log(result.success) // true
|
|
6619
|
+
* ```
|
|
6620
|
+
*/
|
|
5290
6621
|
const customFeeSchema = zod.z
|
|
5291
6622
|
.object({
|
|
5292
6623
|
/**
|
|
@@ -5549,6 +6880,21 @@ async function fetchUsdcFastBurnFee(sourceDomain, destinationDomain, isTestnet)
|
|
|
5549
6880
|
return minimumFee;
|
|
5550
6881
|
}
|
|
5551
6882
|
|
|
6883
|
+
/**
|
|
6884
|
+
* Well-known SPL Token program ID.
|
|
6885
|
+
* Duplicated here as a raw string to avoid a static import of \@core/adapter-solana
|
|
6886
|
+
* (which would transitively pull \@solana/web3.js into the top-level bundle and
|
|
6887
|
+
* break lazy-loading for EVM-only consumers).
|
|
6888
|
+
*
|
|
6889
|
+
* This MUST match TOKEN_PROGRAM_ID in @core/adapter-solana/src/utils/splTokenUtils.
|
|
6890
|
+
*/
|
|
6891
|
+
const TOKEN_PROGRAM_ID_BASE58 = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'; // NOSONAR — public Solana program address
|
|
6892
|
+
/**
|
|
6893
|
+
* Well-known SPL Associated Token Account program ID (same rationale as above).
|
|
6894
|
+
*
|
|
6895
|
+
* This MUST match ASSOCIATED_TOKEN_PROGRAM_ID in @core/adapter-solana/src/utils/splTokenUtils.
|
|
6896
|
+
*/
|
|
6897
|
+
const ASSOCIATED_TOKEN_PROGRAM_ID_BASE58 = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'; // NOSONAR — public Solana program address
|
|
5552
6898
|
/**
|
|
5553
6899
|
* Get the token account address where USDC will be minted for the recipient.
|
|
5554
6900
|
*
|
|
@@ -5592,20 +6938,30 @@ mintAddress) => {
|
|
|
5592
6938
|
return rawAddress;
|
|
5593
6939
|
}
|
|
5594
6940
|
else {
|
|
5595
|
-
// Solana: derive the associated token account
|
|
5596
|
-
//
|
|
6941
|
+
// Solana: derive the associated token account.
|
|
6942
|
+
// Both @solana/web3.js and the program-ID constants are resolved lazily
|
|
6943
|
+
// so that EVM-only consumers never load Solana code.
|
|
6944
|
+
const { PublicKey } = await import('@solana/web3.js').catch(() => {
|
|
6945
|
+
throw new KitError({
|
|
6946
|
+
...InputError.VALIDATION_FAILED,
|
|
6947
|
+
recoverability: 'FATAL',
|
|
6948
|
+
message: 'Failed to load @solana/web3.js. Please ensure it is installed: npm install @solana/web3.js',
|
|
6949
|
+
});
|
|
6950
|
+
});
|
|
5597
6951
|
try {
|
|
5598
|
-
const [{ PublicKey }, { getAssociatedTokenAddressSync }] = await Promise.all([
|
|
5599
|
-
import('@solana/web3.js'),
|
|
5600
|
-
import('@solana/spl-token'),
|
|
5601
|
-
]);
|
|
5602
6952
|
const owner = new PublicKey(rawAddress);
|
|
5603
6953
|
const mintPub = new PublicKey(mintAddress);
|
|
5604
|
-
const
|
|
6954
|
+
const tokenProgramId = new PublicKey(TOKEN_PROGRAM_ID_BASE58);
|
|
6955
|
+
const ataProgramId = new PublicKey(ASSOCIATED_TOKEN_PROGRAM_ID_BASE58);
|
|
6956
|
+
const [ata] = PublicKey.findProgramAddressSync([owner.toBuffer(), tokenProgramId.toBuffer(), mintPub.toBuffer()], ataProgramId);
|
|
5605
6957
|
return ata.toBase58();
|
|
5606
6958
|
}
|
|
5607
|
-
catch {
|
|
5608
|
-
throw new
|
|
6959
|
+
catch (error) {
|
|
6960
|
+
throw new KitError({
|
|
6961
|
+
...InputError.INVALID_ADDRESS,
|
|
6962
|
+
recoverability: 'FATAL',
|
|
6963
|
+
message: `Failed to derive Solana Associated Token Account for recipient "${rawAddress}": ${error instanceof Error ? error.message : String(error)}`,
|
|
6964
|
+
});
|
|
5609
6965
|
}
|
|
5610
6966
|
}
|
|
5611
6967
|
};
|
|
@@ -7921,590 +9277,239 @@ function createLogger(options, stream) {
|
|
|
7921
9277
|
const finalOptions = redactConfig
|
|
7922
9278
|
? { ...pinoOptions, redact: redactConfig }
|
|
7923
9279
|
: pinoOptions;
|
|
7924
|
-
const pinoInstance = pino__default(finalOptions);
|
|
7925
|
-
return wrapPino(pinoInstance);
|
|
7926
|
-
}
|
|
7927
|
-
|
|
7928
|
-
/**
|
|
7929
|
-
* Factory for creating Runtime instances with defaults.
|
|
7930
|
-
*
|
|
7931
|
-
* @packageDocumentation
|
|
7932
|
-
*/
|
|
7933
|
-
// ============================================================================
|
|
7934
|
-
// Validation Schema
|
|
7935
|
-
// ============================================================================
|
|
7936
|
-
/**
|
|
7937
|
-
* Schema for validating {@link RuntimeOptions}.
|
|
7938
|
-
*
|
|
7939
|
-
* @remarks
|
|
7940
|
-
* Used internally by {@link createRuntime} to validate options from JS consumers.
|
|
7941
|
-
* Exported for advanced use cases where manual validation is needed.
|
|
7942
|
-
*/
|
|
7943
|
-
zod.z
|
|
7944
|
-
.object({
|
|
7945
|
-
logger: loggerSchema.optional(),
|
|
7946
|
-
metrics: metricsSchema.optional(),
|
|
7947
|
-
})
|
|
7948
|
-
.passthrough();
|
|
7949
|
-
// ============================================================================
|
|
7950
|
-
// Factory
|
|
7951
|
-
// ============================================================================
|
|
7952
|
-
/**
|
|
7953
|
-
* Create a complete Runtime with sensible defaults.
|
|
7954
|
-
*
|
|
7955
|
-
* @param options - Optional configuration to override logger and metrics.
|
|
7956
|
-
* @returns A frozen, immutable Runtime with all services guaranteed present.
|
|
7957
|
-
* @throws KitError (INPUT_VALIDATION_FAILED) if options contain invalid services.
|
|
7958
|
-
*
|
|
7959
|
-
* @remarks
|
|
7960
|
-
* Creates a fully-configured runtime by merging provided options with defaults.
|
|
7961
|
-
* The returned runtime is frozen to enforce immutability.
|
|
7962
|
-
*
|
|
7963
|
-
* | Service | Default | Configurable |
|
|
7964
|
-
* |---------|---------|--------------|
|
|
7965
|
-
* | `logger` | pino logger (info level) | Yes |
|
|
7966
|
-
* | `metrics` | No-op metrics | Yes |
|
|
7967
|
-
* | `events` | Internal event bus | No |
|
|
7968
|
-
* | `clock` | `Date.now()` | No |
|
|
7969
|
-
*
|
|
7970
|
-
* **Why only logger and metrics?**
|
|
7971
|
-
*
|
|
7972
|
-
* - **Logger/Metrics**: Integration points with your infrastructure
|
|
7973
|
-
* - **Events**: Internal pub/sub mechanism - subscribe via `runtime.events.on()`
|
|
7974
|
-
* - **Clock**: Testing concern - use mock factories for tests
|
|
7975
|
-
*
|
|
7976
|
-
* @example
|
|
7977
|
-
* ```typescript
|
|
7978
|
-
* import { createRuntime, createLogger } from '@core/runtime'
|
|
7979
|
-
*
|
|
7980
|
-
* // Use all defaults
|
|
7981
|
-
* const runtime = createRuntime()
|
|
7982
|
-
*
|
|
7983
|
-
* // Custom logger
|
|
7984
|
-
* const runtime = createRuntime({
|
|
7985
|
-
* logger: createLogger({ level: 'debug' }),
|
|
7986
|
-
* })
|
|
7987
|
-
*
|
|
7988
|
-
* // Custom metrics (e.g., Prometheus)
|
|
7989
|
-
* const runtime = createRuntime({
|
|
7990
|
-
* metrics: myPrometheusMetrics,
|
|
7991
|
-
* })
|
|
7992
|
-
*
|
|
7993
|
-
* // Subscribe to events (don't replace the bus)
|
|
7994
|
-
* runtime.events.on('operation.*', (event) => {
|
|
7995
|
-
* console.log('Event:', event.name)
|
|
7996
|
-
* })
|
|
7997
|
-
* ```
|
|
7998
|
-
*/
|
|
7999
|
-
function createRuntime(options) {
|
|
8000
|
-
// Resolve logger first (events may need it)
|
|
8001
|
-
const logger = createLogger();
|
|
8002
|
-
// Internal services - not configurable
|
|
8003
|
-
const events = createEventBus({ logger });
|
|
8004
|
-
const clock = defaultClock;
|
|
8005
|
-
// Resolve metrics
|
|
8006
|
-
const metrics = noopMetrics;
|
|
8007
|
-
return Object.freeze({ logger, events, metrics, clock });
|
|
8008
|
-
}
|
|
8009
|
-
|
|
8010
|
-
/**
|
|
8011
|
-
* Invocation context resolution - resolves the **WHO/HOW** of an operation.
|
|
8012
|
-
*
|
|
8013
|
-
* @packageDocumentation
|
|
8014
|
-
*/
|
|
8015
|
-
// ============================================================================
|
|
8016
|
-
// Validation Schemas
|
|
8017
|
-
// ============================================================================
|
|
8018
|
-
/**
|
|
8019
|
-
* Schema for validating Caller.
|
|
8020
|
-
*/
|
|
8021
|
-
const callerSchema = zod.z.object({
|
|
8022
|
-
type: zod.z.string(),
|
|
8023
|
-
name: zod.z.string(),
|
|
8024
|
-
version: zod.z.string().optional(),
|
|
8025
|
-
});
|
|
8026
|
-
/**
|
|
8027
|
-
* Schema for validating InvocationMeta input.
|
|
8028
|
-
*/
|
|
8029
|
-
const invocationMetaSchema = zod.z
|
|
8030
|
-
.object({
|
|
8031
|
-
traceId: zod.z.string().optional(),
|
|
8032
|
-
runtime: zod.z.object({}).passthrough().optional(),
|
|
8033
|
-
tokens: zod.z.object({}).passthrough().optional(),
|
|
8034
|
-
callers: zod.z.array(callerSchema).optional(),
|
|
8035
|
-
})
|
|
8036
|
-
.strict();
|
|
8037
|
-
// ============================================================================
|
|
8038
|
-
// Invocation Context Resolution
|
|
8039
|
-
// ============================================================================
|
|
8040
|
-
/**
|
|
8041
|
-
* Resolve invocation metadata to invocation context.
|
|
8042
|
-
*
|
|
8043
|
-
* @param meta - User-provided invocation metadata (**WHO/HOW**), optional.
|
|
8044
|
-
* @param defaults - Default runtime and tokens to use if not overridden.
|
|
8045
|
-
* @returns Frozen, immutable invocation context with guaranteed values.
|
|
8046
|
-
* @throws KitError when meta contains invalid properties.
|
|
8047
|
-
*
|
|
8048
|
-
* @remarks
|
|
8049
|
-
* Resolves the **WHO** called and **HOW** to observe:
|
|
8050
|
-
* - TraceId: Uses provided value or generates new one
|
|
8051
|
-
* - Runtime: Uses meta.runtime if provided, otherwise defaults.runtime
|
|
8052
|
-
* - Tokens: Uses meta.tokens if provided, otherwise defaults.tokens
|
|
8053
|
-
* - Callers: Uses provided array or empty array
|
|
8054
|
-
*
|
|
8055
|
-
* The returned context is frozen to enforce immutability.
|
|
8056
|
-
*
|
|
8057
|
-
* @example
|
|
8058
|
-
* ```typescript
|
|
8059
|
-
* import { resolveInvocationContext, createRuntime } from '@core/runtime'
|
|
8060
|
-
* import { createTokenRegistry } from '@core/tokens'
|
|
8061
|
-
*
|
|
8062
|
-
* const defaults = {
|
|
8063
|
-
* runtime: createRuntime(),
|
|
8064
|
-
* tokens: createTokenRegistry(),
|
|
8065
|
-
* }
|
|
8066
|
-
*
|
|
8067
|
-
* // Minimal - just using defaults
|
|
8068
|
-
* const ctx = resolveInvocationContext(undefined, defaults)
|
|
8069
|
-
*
|
|
8070
|
-
* // With trace ID and caller info
|
|
8071
|
-
* const ctx = resolveInvocationContext(
|
|
8072
|
-
* {
|
|
8073
|
-
* traceId: 'abc-123',
|
|
8074
|
-
* callers: [{ type: 'kit', name: 'BridgeKit', version: '1.0.0' }],
|
|
8075
|
-
* },
|
|
8076
|
-
* defaults
|
|
8077
|
-
* )
|
|
8078
|
-
*
|
|
8079
|
-
* // With runtime override (complete replacement)
|
|
8080
|
-
* const ctx = resolveInvocationContext(
|
|
8081
|
-
* { runtime: createRuntime({ logger: myLogger }) },
|
|
8082
|
-
* defaults
|
|
8083
|
-
* )
|
|
8084
|
-
* ```
|
|
8085
|
-
*/
|
|
8086
|
-
function resolveInvocationContext(meta, defaults) {
|
|
8087
|
-
// Validate meta input if provided
|
|
8088
|
-
if (meta !== undefined) {
|
|
8089
|
-
const result = invocationMetaSchema.safeParse(meta);
|
|
8090
|
-
if (!result.success) {
|
|
8091
|
-
throw createValidationFailedError('invocationMeta', meta, result.error.errors.map((e) => e.message).join(', '));
|
|
8092
|
-
}
|
|
8093
|
-
}
|
|
8094
|
-
// Generate trace ID if not provided
|
|
8095
|
-
const traceId = meta?.traceId ?? createTraceId();
|
|
8096
|
-
// Use meta overrides or fall back to defaults
|
|
8097
|
-
const runtime = meta?.runtime ?? defaults.runtime;
|
|
8098
|
-
const tokens = meta?.tokens ?? defaults.tokens;
|
|
8099
|
-
const callers = meta?.callers ?? [];
|
|
8100
|
-
return Object.freeze({ traceId, runtime, tokens, callers });
|
|
9280
|
+
const pinoInstance = pino__default(finalOptions);
|
|
9281
|
+
return wrapPino(pinoInstance);
|
|
8101
9282
|
}
|
|
8102
9283
|
|
|
8103
9284
|
/**
|
|
8104
|
-
*
|
|
9285
|
+
* Factory for creating Runtime instances with defaults.
|
|
8105
9286
|
*
|
|
8106
|
-
* @
|
|
8107
|
-
|
|
8108
|
-
|
|
9287
|
+
* @packageDocumentation
|
|
9288
|
+
*/
|
|
9289
|
+
// ============================================================================
|
|
9290
|
+
// Validation Schema
|
|
9291
|
+
// ============================================================================
|
|
9292
|
+
/**
|
|
9293
|
+
* Schema for validating {@link RuntimeOptions}.
|
|
8109
9294
|
*
|
|
8110
9295
|
* @remarks
|
|
8111
|
-
*
|
|
8112
|
-
*
|
|
8113
|
-
* (traceId, runtime, tokens).
|
|
8114
|
-
*
|
|
8115
|
-
* The returned context is frozen to enforce immutability.
|
|
8116
|
-
*
|
|
8117
|
-
* @example
|
|
8118
|
-
* ```typescript
|
|
8119
|
-
* import { extendInvocationContext } from '@core/runtime'
|
|
8120
|
-
*
|
|
8121
|
-
* const caller = { type: 'provider', name: 'CCTPV2', version: '1.0.0' }
|
|
8122
|
-
* const extended = extendInvocationContext(existingContext, caller)
|
|
8123
|
-
* // extended.callers === [...existingContext.callers, caller]
|
|
8124
|
-
* ```
|
|
9296
|
+
* Used internally by {@link createRuntime} to validate options from JS consumers.
|
|
9297
|
+
* Exported for advanced use cases where manual validation is needed.
|
|
8125
9298
|
*/
|
|
8126
|
-
function extendInvocationContext(context, caller) {
|
|
8127
|
-
return Object.freeze({
|
|
8128
|
-
traceId: context.traceId,
|
|
8129
|
-
runtime: context.runtime,
|
|
8130
|
-
tokens: context.tokens,
|
|
8131
|
-
callers: [...context.callers, caller],
|
|
8132
|
-
});
|
|
8133
|
-
}
|
|
8134
|
-
|
|
8135
|
-
// Clock - expose defaultClock for backward compatibility
|
|
8136
|
-
/** Clock validation schema (backward compatibility). */
|
|
8137
|
-
zod.z.custom((val) => val !== null &&
|
|
8138
|
-
typeof val === 'object' &&
|
|
8139
|
-
'now' in val &&
|
|
8140
|
-
typeof val['now'] === 'function');
|
|
8141
|
-
/** EventBus validation schema (backward compatibility). */
|
|
8142
|
-
zod.z.custom((val) => val !== null &&
|
|
8143
|
-
typeof val === 'object' &&
|
|
8144
|
-
'emit' in val &&
|
|
8145
|
-
typeof val['emit'] === 'function');
|
|
8146
|
-
/** Runtime validation schema (backward compatibility). */
|
|
8147
9299
|
zod.z
|
|
8148
9300
|
.object({
|
|
8149
|
-
logger:
|
|
8150
|
-
|
|
8151
|
-
metrics: zod.z.any().optional(),
|
|
8152
|
-
clock: zod.z.any().optional(),
|
|
9301
|
+
logger: loggerSchema.optional(),
|
|
9302
|
+
metrics: metricsSchema.optional(),
|
|
8153
9303
|
})
|
|
8154
9304
|
.passthrough();
|
|
8155
|
-
|
|
9305
|
+
// ============================================================================
|
|
9306
|
+
// Factory
|
|
9307
|
+
// ============================================================================
|
|
8156
9308
|
/**
|
|
8157
|
-
* Create a
|
|
9309
|
+
* Create a complete Runtime with sensible defaults.
|
|
8158
9310
|
*
|
|
8159
|
-
* @
|
|
8160
|
-
*
|
|
8161
|
-
*
|
|
9311
|
+
* @param options - Optional configuration to override logger and metrics.
|
|
9312
|
+
* @returns A frozen, immutable Runtime with all services guaranteed present.
|
|
9313
|
+
* @throws KitError (INPUT_VALIDATION_FAILED) if options contain invalid services.
|
|
8162
9314
|
*
|
|
8163
|
-
* @
|
|
8164
|
-
*
|
|
8165
|
-
*
|
|
8166
|
-
* @param cause - The underlying error, if any (optional).
|
|
8167
|
-
* @returns A KitError with INPUT type and FATAL recoverability.
|
|
9315
|
+
* @remarks
|
|
9316
|
+
* Creates a fully-configured runtime by merging provided options with defaults.
|
|
9317
|
+
* The returned runtime is frozen to enforce immutability.
|
|
8168
9318
|
*
|
|
8169
|
-
*
|
|
8170
|
-
*
|
|
8171
|
-
*
|
|
8172
|
-
*
|
|
8173
|
-
*
|
|
8174
|
-
*
|
|
8175
|
-
* )
|
|
8176
|
-
* ```
|
|
8177
|
-
*/
|
|
8178
|
-
function createTokenResolutionError(message, selector, chainId, cause) {
|
|
8179
|
-
const trace = {
|
|
8180
|
-
selector,
|
|
8181
|
-
...(chainId === undefined ? {} : { chainId }),
|
|
8182
|
-
...({} ),
|
|
8183
|
-
};
|
|
8184
|
-
return new KitError({
|
|
8185
|
-
...InputError.INVALID_TOKEN,
|
|
8186
|
-
recoverability: 'FATAL',
|
|
8187
|
-
message,
|
|
8188
|
-
cause: { trace },
|
|
8189
|
-
});
|
|
8190
|
-
}
|
|
8191
|
-
|
|
8192
|
-
/**
|
|
8193
|
-
* USDC token definition with addresses and metadata.
|
|
9319
|
+
* | Service | Default | Configurable |
|
|
9320
|
+
* |---------|---------|--------------|
|
|
9321
|
+
* | `logger` | pino logger (info level) | Yes |
|
|
9322
|
+
* | `metrics` | No-op metrics | Yes |
|
|
9323
|
+
* | `events` | Internal event bus | No |
|
|
9324
|
+
* | `clock` | `Date.now()` | No |
|
|
8194
9325
|
*
|
|
8195
|
-
*
|
|
8196
|
-
* This is the built-in USDC definition used by the TokenRegistry.
|
|
8197
|
-
* Includes all known USDC addresses across supported chains.
|
|
9326
|
+
* **Why only logger and metrics?**
|
|
8198
9327
|
*
|
|
8199
|
-
*
|
|
8200
|
-
*
|
|
8201
|
-
* -
|
|
9328
|
+
* - **Logger/Metrics**: Integration points with your infrastructure
|
|
9329
|
+
* - **Events**: Internal pub/sub mechanism - subscribe via `runtime.events.on()`
|
|
9330
|
+
* - **Clock**: Testing concern - use mock factories for tests
|
|
8202
9331
|
*
|
|
8203
9332
|
* @example
|
|
8204
9333
|
* ```typescript
|
|
8205
|
-
* import {
|
|
8206
|
-
* import { Blockchain } from '@core/chains'
|
|
8207
|
-
*
|
|
8208
|
-
* console.log(USDC.symbol) // 'USDC'
|
|
8209
|
-
* console.log(USDC.decimals) // 6
|
|
8210
|
-
* console.log(USDC.locators[Blockchain.Ethereum])
|
|
8211
|
-
* // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
8212
|
-
* ```
|
|
8213
|
-
*/
|
|
8214
|
-
const USDC = {
|
|
8215
|
-
symbol: 'USDC',
|
|
8216
|
-
decimals: 6,
|
|
8217
|
-
locators: {
|
|
8218
|
-
// =========================================================================
|
|
8219
|
-
// Mainnets (alphabetically sorted)
|
|
8220
|
-
// =========================================================================
|
|
8221
|
-
[Blockchain.Arbitrum]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
8222
|
-
[Blockchain.Avalanche]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
8223
|
-
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
8224
|
-
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
8225
|
-
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
8226
|
-
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
8227
|
-
[Blockchain.Hedera]: '0.0.456858',
|
|
8228
|
-
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
8229
|
-
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
8230
|
-
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
8231
|
-
[Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
8232
|
-
[Blockchain.Noble]: 'uusdc',
|
|
8233
|
-
[Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
8234
|
-
[Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
8235
|
-
[Blockchain.Polkadot_Asset_Hub]: '1337',
|
|
8236
|
-
[Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
8237
|
-
[Blockchain.Sei]: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
8238
|
-
[Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
8239
|
-
[Blockchain.Sonic]: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
8240
|
-
[Blockchain.Stellar]: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
8241
|
-
[Blockchain.Sui]: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
8242
|
-
[Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
8243
|
-
[Blockchain.World_Chain]: '0x79A02482A880bCe3F13E09da970dC34dB4cD24D1',
|
|
8244
|
-
[Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
8245
|
-
[Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
8246
|
-
// =========================================================================
|
|
8247
|
-
// Testnets (alphabetically sorted)
|
|
8248
|
-
// =========================================================================
|
|
8249
|
-
[Blockchain.Arbitrum_Sepolia]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
8250
|
-
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
8251
|
-
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
8252
|
-
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
8253
|
-
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
8254
|
-
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
8255
|
-
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
8256
|
-
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
8257
|
-
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
8258
|
-
[Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
8259
|
-
[Blockchain.Noble_Testnet]: 'uusdc',
|
|
8260
|
-
[Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
8261
|
-
[Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
8262
|
-
[Blockchain.Polkadot_Westmint]: '31337',
|
|
8263
|
-
[Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
8264
|
-
[Blockchain.Sei_Testnet]: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
8265
|
-
[Blockchain.Solana_Devnet]: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
8266
|
-
[Blockchain.Sonic_Testnet]: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
8267
|
-
[Blockchain.Stellar_Testnet]: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
8268
|
-
[Blockchain.Sui_Testnet]: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
8269
|
-
[Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
8270
|
-
[Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
8271
|
-
[Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
8272
|
-
[Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
8273
|
-
},
|
|
8274
|
-
};
|
|
8275
|
-
|
|
8276
|
-
// Re-export for consumers
|
|
8277
|
-
/**
|
|
8278
|
-
* All default token definitions.
|
|
9334
|
+
* import { createRuntime, createLogger } from '@core/runtime'
|
|
8279
9335
|
*
|
|
8280
|
-
*
|
|
8281
|
-
*
|
|
8282
|
-
* without explicit defaults. Extensions can override these definitions.
|
|
9336
|
+
* // Use all defaults
|
|
9337
|
+
* const runtime = createRuntime()
|
|
8283
9338
|
*
|
|
8284
|
-
*
|
|
8285
|
-
*
|
|
8286
|
-
*
|
|
9339
|
+
* // Custom logger
|
|
9340
|
+
* const runtime = createRuntime({
|
|
9341
|
+
* logger: createLogger({ level: 'debug' }),
|
|
9342
|
+
* })
|
|
8287
9343
|
*
|
|
8288
|
-
* //
|
|
8289
|
-
* const
|
|
9344
|
+
* // Custom metrics (e.g., Prometheus)
|
|
9345
|
+
* const runtime = createRuntime({
|
|
9346
|
+
* metrics: myPrometheusMetrics,
|
|
9347
|
+
* })
|
|
8290
9348
|
*
|
|
8291
|
-
* //
|
|
8292
|
-
*
|
|
8293
|
-
*
|
|
9349
|
+
* // Subscribe to events (don't replace the bus)
|
|
9350
|
+
* runtime.events.on('operation.*', (event) => {
|
|
9351
|
+
* console.log('Event:', event.name)
|
|
8294
9352
|
* })
|
|
8295
9353
|
* ```
|
|
8296
9354
|
*/
|
|
8297
|
-
|
|
9355
|
+
function createRuntime(options) {
|
|
9356
|
+
// Resolve logger first (events may need it)
|
|
9357
|
+
const logger = createLogger();
|
|
9358
|
+
// Internal services - not configurable
|
|
9359
|
+
const events = createEventBus({ logger });
|
|
9360
|
+
const clock = defaultClock;
|
|
9361
|
+
// Resolve metrics
|
|
9362
|
+
const metrics = noopMetrics;
|
|
9363
|
+
return Object.freeze({ logger, events, metrics, clock });
|
|
9364
|
+
}
|
|
8298
9365
|
|
|
8299
9366
|
/**
|
|
8300
|
-
*
|
|
9367
|
+
* Invocation context resolution - resolves the **WHO/HOW** of an operation.
|
|
8301
9368
|
*
|
|
8302
|
-
* @
|
|
8303
|
-
* @returns True if the selector is a raw token selector.
|
|
9369
|
+
* @packageDocumentation
|
|
8304
9370
|
*/
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
9371
|
+
// ============================================================================
|
|
9372
|
+
// Validation Schemas
|
|
9373
|
+
// ============================================================================
|
|
9374
|
+
/**
|
|
9375
|
+
* Schema for validating Caller.
|
|
9376
|
+
*/
|
|
9377
|
+
const callerSchema = zod.z.object({
|
|
9378
|
+
type: zod.z.string(),
|
|
9379
|
+
name: zod.z.string(),
|
|
9380
|
+
version: zod.z.string().optional(),
|
|
9381
|
+
});
|
|
9382
|
+
/**
|
|
9383
|
+
* Schema for validating InvocationMeta input.
|
|
9384
|
+
*/
|
|
9385
|
+
const invocationMetaSchema = zod.z
|
|
9386
|
+
.object({
|
|
9387
|
+
traceId: zod.z.string().optional(),
|
|
9388
|
+
runtime: zod.z.object({}).passthrough().optional(),
|
|
9389
|
+
tokens: zod.z.object({}).passthrough().optional(),
|
|
9390
|
+
callers: zod.z.array(callerSchema).optional(),
|
|
9391
|
+
})
|
|
9392
|
+
.strict();
|
|
9393
|
+
// ============================================================================
|
|
9394
|
+
// Invocation Context Resolution
|
|
9395
|
+
// ============================================================================
|
|
8308
9396
|
/**
|
|
8309
|
-
*
|
|
9397
|
+
* Resolve invocation metadata to invocation context.
|
|
8310
9398
|
*
|
|
8311
|
-
* @param
|
|
8312
|
-
* @
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
return symbol.toUpperCase();
|
|
8316
|
-
}
|
|
8317
|
-
/**
|
|
8318
|
-
* Create a token registry with built-in tokens and optional extensions.
|
|
9399
|
+
* @param meta - User-provided invocation metadata (**WHO/HOW**), optional.
|
|
9400
|
+
* @param defaults - Default runtime and tokens to use if not overridden.
|
|
9401
|
+
* @returns Frozen, immutable invocation context with guaranteed values.
|
|
9402
|
+
* @throws KitError when meta contains invalid properties.
|
|
8319
9403
|
*
|
|
8320
9404
|
* @remarks
|
|
8321
|
-
*
|
|
8322
|
-
*
|
|
8323
|
-
*
|
|
9405
|
+
* Resolves the **WHO** called and **HOW** to observe:
|
|
9406
|
+
* - TraceId: Uses provided value or generates new one
|
|
9407
|
+
* - Runtime: Uses meta.runtime if provided, otherwise defaults.runtime
|
|
9408
|
+
* - Tokens: Uses meta.tokens if provided, otherwise defaults.tokens
|
|
9409
|
+
* - Callers: Uses provided array or empty array
|
|
8324
9410
|
*
|
|
8325
|
-
*
|
|
8326
|
-
* @returns A token registry instance.
|
|
9411
|
+
* The returned context is frozen to enforce immutability.
|
|
8327
9412
|
*
|
|
8328
9413
|
* @example
|
|
8329
9414
|
* ```typescript
|
|
9415
|
+
* import { resolveInvocationContext, createRuntime } from '@core/runtime'
|
|
8330
9416
|
* import { createTokenRegistry } from '@core/tokens'
|
|
8331
9417
|
*
|
|
8332
|
-
*
|
|
8333
|
-
*
|
|
8334
|
-
*
|
|
8335
|
-
* // Resolve USDC on Ethereum
|
|
8336
|
-
* const usdc = registry.resolve('USDC', 'Ethereum')
|
|
8337
|
-
* console.log(usdc.locator) // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
8338
|
-
* console.log(usdc.decimals) // 6
|
|
8339
|
-
* ```
|
|
8340
|
-
*
|
|
8341
|
-
* @example
|
|
8342
|
-
* ```typescript
|
|
8343
|
-
* // Add custom tokens (built-ins are still included)
|
|
8344
|
-
* const myToken: TokenDefinition = {
|
|
8345
|
-
* symbol: 'MY',
|
|
8346
|
-
* decimals: 18,
|
|
8347
|
-
* locators: { Ethereum: '0x...' },
|
|
9418
|
+
* const defaults = {
|
|
9419
|
+
* runtime: createRuntime(),
|
|
9420
|
+
* tokens: createTokenRegistry(),
|
|
8348
9421
|
* }
|
|
8349
9422
|
*
|
|
8350
|
-
*
|
|
8351
|
-
*
|
|
8352
|
-
* registry.resolve('MY', 'Ethereum') // Also works
|
|
8353
|
-
* ```
|
|
8354
|
-
*
|
|
8355
|
-
* @example
|
|
8356
|
-
* ```typescript
|
|
8357
|
-
* // Override a built-in token
|
|
8358
|
-
* const customUsdc: TokenDefinition = {
|
|
8359
|
-
* symbol: 'USDC',
|
|
8360
|
-
* decimals: 6,
|
|
8361
|
-
* locators: { MyChain: '0xCustomAddress' },
|
|
8362
|
-
* }
|
|
9423
|
+
* // Minimal - just using defaults
|
|
9424
|
+
* const ctx = resolveInvocationContext(undefined, defaults)
|
|
8363
9425
|
*
|
|
8364
|
-
*
|
|
8365
|
-
*
|
|
8366
|
-
*
|
|
9426
|
+
* // With trace ID and caller info
|
|
9427
|
+
* const ctx = resolveInvocationContext(
|
|
9428
|
+
* {
|
|
9429
|
+
* traceId: 'abc-123',
|
|
9430
|
+
* callers: [{ type: 'kit', name: 'BridgeKit', version: '1.0.0' }],
|
|
9431
|
+
* },
|
|
9432
|
+
* defaults
|
|
9433
|
+
* )
|
|
8367
9434
|
*
|
|
8368
|
-
*
|
|
8369
|
-
*
|
|
8370
|
-
*
|
|
8371
|
-
*
|
|
8372
|
-
* const token = registry.resolve(
|
|
8373
|
-
* { locator: '0x1234...', decimals: 18 },
|
|
8374
|
-
* 'Ethereum'
|
|
9435
|
+
* // With runtime override (complete replacement)
|
|
9436
|
+
* const ctx = resolveInvocationContext(
|
|
9437
|
+
* { runtime: createRuntime({ logger: myLogger }) },
|
|
9438
|
+
* defaults
|
|
8375
9439
|
* )
|
|
8376
9440
|
* ```
|
|
8377
9441
|
*/
|
|
8378
|
-
function
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
8385
|
-
}
|
|
8386
|
-
// Custom tokens override built-ins
|
|
8387
|
-
for (const def of tokens) {
|
|
8388
|
-
tokenMap.set(normalizeSymbol(def.symbol), def);
|
|
8389
|
-
}
|
|
8390
|
-
/**
|
|
8391
|
-
* Resolve a symbol selector to token information.
|
|
8392
|
-
*/
|
|
8393
|
-
function resolveSymbol(symbol, chainId) {
|
|
8394
|
-
const normalizedSymbol = normalizeSymbol(symbol);
|
|
8395
|
-
const definition = tokenMap.get(normalizedSymbol);
|
|
8396
|
-
if (definition === undefined) {
|
|
8397
|
-
throw createTokenResolutionError(`Unknown token symbol: ${symbol}. Register it via createTokenRegistry({ tokens: [...] }) or use a raw selector.`, symbol, chainId);
|
|
8398
|
-
}
|
|
8399
|
-
const locator = definition.locators[chainId];
|
|
8400
|
-
if (locator === undefined || locator.trim() === '') {
|
|
8401
|
-
throw createTokenResolutionError(`Token ${symbol} has no locator for chain ${chainId}`, symbol, chainId);
|
|
8402
|
-
}
|
|
8403
|
-
return {
|
|
8404
|
-
symbol: definition.symbol,
|
|
8405
|
-
decimals: definition.decimals,
|
|
8406
|
-
locator,
|
|
8407
|
-
};
|
|
8408
|
-
}
|
|
8409
|
-
/**
|
|
8410
|
-
* Resolve a raw selector to token information.
|
|
8411
|
-
*/
|
|
8412
|
-
function resolveRaw(selector, chainId) {
|
|
8413
|
-
const { locator, decimals } = selector;
|
|
8414
|
-
// Validate locator
|
|
8415
|
-
if (!locator || typeof locator !== 'string') {
|
|
8416
|
-
throw createTokenResolutionError('Raw selector must have a valid locator string', selector, chainId);
|
|
8417
|
-
}
|
|
8418
|
-
// Decimals are always required for raw selectors
|
|
8419
|
-
if (decimals === undefined) {
|
|
8420
|
-
const message = requireDecimals
|
|
8421
|
-
? 'Decimals required for raw token selector (requireDecimals: true)'
|
|
8422
|
-
: 'Decimals required for raw token selector. Provide { locator, decimals }.';
|
|
8423
|
-
throw createTokenResolutionError(message, selector, chainId);
|
|
8424
|
-
}
|
|
8425
|
-
// Validate decimals
|
|
8426
|
-
if (typeof decimals !== 'number' ||
|
|
8427
|
-
decimals < 0 ||
|
|
8428
|
-
!Number.isInteger(decimals)) {
|
|
8429
|
-
throw createTokenResolutionError(`Invalid decimals: ${String(decimals)}. Must be a non-negative integer.`, selector, chainId);
|
|
9442
|
+
function resolveInvocationContext(meta, defaults) {
|
|
9443
|
+
// Validate meta input if provided
|
|
9444
|
+
if (meta !== undefined) {
|
|
9445
|
+
const result = invocationMetaSchema.safeParse(meta);
|
|
9446
|
+
if (!result.success) {
|
|
9447
|
+
throw createValidationFailedError('invocationMeta', meta, result.error.errors.map((e) => e.message).join(', '));
|
|
8430
9448
|
}
|
|
8431
|
-
return {
|
|
8432
|
-
decimals,
|
|
8433
|
-
locator,
|
|
8434
|
-
};
|
|
8435
9449
|
}
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
if (chainId === '' || typeof chainId !== 'string') {
|
|
8444
|
-
throw createTokenResolutionError('Chain ID is required for token resolution', selector, chainId);
|
|
8445
|
-
}
|
|
8446
|
-
// Dispatch based on selector type
|
|
8447
|
-
if (isRawSelector(selector)) {
|
|
8448
|
-
return resolveRaw(selector, chainId);
|
|
8449
|
-
}
|
|
8450
|
-
if (typeof selector === 'string') {
|
|
8451
|
-
return resolveSymbol(selector, chainId);
|
|
8452
|
-
}
|
|
8453
|
-
throw createTokenResolutionError(`Invalid selector type: ${typeof selector}. Expected string or object with locator.`, selector, chainId);
|
|
8454
|
-
},
|
|
8455
|
-
get(symbol) {
|
|
8456
|
-
if (!symbol || typeof symbol !== 'string') {
|
|
8457
|
-
return undefined;
|
|
8458
|
-
}
|
|
8459
|
-
return tokenMap.get(normalizeSymbol(symbol));
|
|
8460
|
-
},
|
|
8461
|
-
has(symbol) {
|
|
8462
|
-
if (!symbol || typeof symbol !== 'string') {
|
|
8463
|
-
return false;
|
|
8464
|
-
}
|
|
8465
|
-
return tokenMap.has(normalizeSymbol(symbol));
|
|
8466
|
-
},
|
|
8467
|
-
symbols() {
|
|
8468
|
-
return Array.from(tokenMap.values()).map((def) => def.symbol);
|
|
8469
|
-
},
|
|
8470
|
-
entries() {
|
|
8471
|
-
return Array.from(tokenMap.values());
|
|
8472
|
-
},
|
|
8473
|
-
};
|
|
9450
|
+
// Generate trace ID if not provided
|
|
9451
|
+
const traceId = meta?.traceId ?? createTraceId();
|
|
9452
|
+
// Use meta overrides or fall back to defaults
|
|
9453
|
+
const runtime = meta?.runtime ?? defaults.runtime;
|
|
9454
|
+
const tokens = meta?.tokens ?? defaults.tokens;
|
|
9455
|
+
const callers = meta?.callers ?? [];
|
|
9456
|
+
return Object.freeze({ traceId, runtime, tokens, callers });
|
|
8474
9457
|
}
|
|
8475
9458
|
|
|
8476
9459
|
/**
|
|
8477
|
-
*
|
|
9460
|
+
* Extend an invocation context by appending a caller to its call chain.
|
|
9461
|
+
*
|
|
9462
|
+
* @param context - The existing invocation context to extend.
|
|
9463
|
+
* @param caller - The caller to append to the call chain.
|
|
9464
|
+
* @returns A new frozen invocation context with the caller appended.
|
|
8478
9465
|
*
|
|
8479
9466
|
* @remarks
|
|
8480
|
-
*
|
|
9467
|
+
* This function creates a new immutable context with the caller appended
|
|
9468
|
+
* to the `callers` array while preserving all other context properties
|
|
9469
|
+
* (traceId, runtime, tokens).
|
|
9470
|
+
*
|
|
9471
|
+
* The returned context is frozen to enforce immutability.
|
|
8481
9472
|
*
|
|
8482
9473
|
* @example
|
|
8483
9474
|
* ```typescript
|
|
8484
|
-
* import {
|
|
8485
|
-
*
|
|
8486
|
-
* const registry = {
|
|
8487
|
-
* resolve: () => ({ locator: '0x0', decimals: 6 }),
|
|
8488
|
-
* }
|
|
9475
|
+
* import { extendInvocationContext } from '@core/runtime'
|
|
8489
9476
|
*
|
|
8490
|
-
*
|
|
9477
|
+
* const caller = { type: 'provider', name: 'CCTPV2', version: '1.0.0' }
|
|
9478
|
+
* const extended = extendInvocationContext(existingContext, caller)
|
|
9479
|
+
* // extended.callers === [...existingContext.callers, caller]
|
|
8491
9480
|
* ```
|
|
8492
9481
|
*/
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
9482
|
+
function extendInvocationContext(context, caller) {
|
|
9483
|
+
return Object.freeze({
|
|
9484
|
+
traceId: context.traceId,
|
|
9485
|
+
runtime: context.runtime,
|
|
9486
|
+
tokens: context.tokens,
|
|
9487
|
+
callers: [...context.callers, caller],
|
|
9488
|
+
});
|
|
9489
|
+
}
|
|
9490
|
+
|
|
9491
|
+
// Clock - expose defaultClock for backward compatibility
|
|
9492
|
+
/** Clock validation schema (backward compatibility). */
|
|
9493
|
+
zod.z.custom((val) => val !== null &&
|
|
9494
|
+
typeof val === 'object' &&
|
|
9495
|
+
'now' in val &&
|
|
9496
|
+
typeof val['now'] === 'function');
|
|
9497
|
+
/** EventBus validation schema (backward compatibility). */
|
|
9498
|
+
zod.z.custom((val) => val !== null &&
|
|
9499
|
+
typeof val === 'object' &&
|
|
9500
|
+
'emit' in val &&
|
|
9501
|
+
typeof val['emit'] === 'function');
|
|
9502
|
+
/** Runtime validation schema (backward compatibility). */
|
|
9503
|
+
zod.z
|
|
9504
|
+
.object({
|
|
9505
|
+
logger: zod.z.any().optional(),
|
|
9506
|
+
events: zod.z.any().optional(),
|
|
9507
|
+
metrics: zod.z.any().optional(),
|
|
9508
|
+
clock: zod.z.any().optional(),
|
|
9509
|
+
})
|
|
9510
|
+
.passthrough();
|
|
8506
9511
|
|
|
8507
|
-
var version = "1.
|
|
9512
|
+
var version = "1.5.0";
|
|
8508
9513
|
var pkg = {
|
|
8509
9514
|
version: version};
|
|
8510
9515
|
|
|
@@ -8987,6 +9992,24 @@ const validateNativeBalanceForTransaction = async (params) => {
|
|
|
8987
9992
|
}
|
|
8988
9993
|
};
|
|
8989
9994
|
|
|
9995
|
+
/**
|
|
9996
|
+
* Permit signature standards for gasless token approvals.
|
|
9997
|
+
*
|
|
9998
|
+
* Defines the permit types that can be used to approve token spending
|
|
9999
|
+
* without requiring a separate approval transaction.
|
|
10000
|
+
*
|
|
10001
|
+
* @remarks
|
|
10002
|
+
* - NONE: No permit, tokens must be pre-approved via separate transaction
|
|
10003
|
+
* - EIP2612: Standard ERC-20 permit (USDC, DAI v2, and most modern tokens)
|
|
10004
|
+
*/
|
|
10005
|
+
var PermitType;
|
|
10006
|
+
(function (PermitType) {
|
|
10007
|
+
/** No permit required - tokens must be pre-approved */
|
|
10008
|
+
PermitType[PermitType["NONE"] = 0] = "NONE";
|
|
10009
|
+
/** EIP-2612 standard permit */
|
|
10010
|
+
PermitType[PermitType["EIP2612"] = 1] = "EIP2612";
|
|
10011
|
+
})(PermitType || (PermitType = {}));
|
|
10012
|
+
|
|
8990
10013
|
/**
|
|
8991
10014
|
* CCTP bridge step names that can occur in the bridging flow.
|
|
8992
10015
|
*
|