@circle-fin/adapter-ethers-v6 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -1
- package/README.md +3 -3
- package/index.cjs +2481 -140
- package/index.d.ts +852 -34
- package/index.mjs +2481 -140
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -80,6 +80,10 @@ const ERROR_TYPES = {
|
|
|
80
80
|
RPC: 'RPC',
|
|
81
81
|
/** Internet connectivity, DNS resolution, connection issues */
|
|
82
82
|
NETWORK: 'NETWORK',
|
|
83
|
+
/** API throttling, request frequency limits errors */
|
|
84
|
+
RATE_LIMIT: 'RATE_LIMIT',
|
|
85
|
+
/** Service errors */
|
|
86
|
+
SERVICE: 'SERVICE',
|
|
83
87
|
/** Catch-all for unrecognized errors (code 0) */
|
|
84
88
|
UNKNOWN: 'UNKNOWN',
|
|
85
89
|
};
|
|
@@ -103,6 +107,8 @@ const ERROR_CODE_RANGES = [
|
|
|
103
107
|
{ min: 3000, max: 3999, type: 'NETWORK' },
|
|
104
108
|
{ min: 4000, max: 4999, type: 'RPC' },
|
|
105
109
|
{ min: 5000, max: 5999, type: 'ONCHAIN' },
|
|
110
|
+
{ min: 7000, max: 7999, type: 'RATE_LIMIT' },
|
|
111
|
+
{ min: 8000, max: 8999, type: 'SERVICE' },
|
|
106
112
|
{ min: 9000, max: 9999, type: 'BALANCE' },
|
|
107
113
|
];
|
|
108
114
|
/** Special code for UNKNOWN errors */
|
|
@@ -150,6 +156,8 @@ const errorDetailsSchema = z.object({
|
|
|
150
156
|
* - 3000-3999: NETWORK errors - Connectivity issues
|
|
151
157
|
* - 4000-4999: RPC errors - Provider issues, gas estimation
|
|
152
158
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures
|
|
159
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling
|
|
160
|
+
* - 8000-8999: SERVICE errors - Internal service errors
|
|
153
161
|
* - 9000-9999: BALANCE errors - Insufficient funds
|
|
154
162
|
*/
|
|
155
163
|
code: z
|
|
@@ -240,11 +248,11 @@ function validateErrorDetails(details) {
|
|
|
240
248
|
const MAX_MESSAGE_LENGTH = 950;
|
|
241
249
|
|
|
242
250
|
/**
|
|
243
|
-
* Structured error class for
|
|
251
|
+
* Structured error class for App Kit operations.
|
|
244
252
|
*
|
|
245
253
|
* This class extends the native Error class while implementing the ErrorDetails
|
|
246
254
|
* interface, providing a consistent error format for programmatic handling
|
|
247
|
-
* across the
|
|
255
|
+
* across the App Kits ecosystem. All properties are immutable to ensure
|
|
248
256
|
* error objects cannot be modified after creation.
|
|
249
257
|
*
|
|
250
258
|
* @example
|
|
@@ -254,6 +262,7 @@ const MAX_MESSAGE_LENGTH = 950;
|
|
|
254
262
|
* const error = new KitError({
|
|
255
263
|
* code: 1001,
|
|
256
264
|
* name: 'INPUT_NETWORK_MISMATCH',
|
|
265
|
+
* type: 'INPUT',
|
|
257
266
|
* recoverability: 'FATAL',
|
|
258
267
|
* message: 'Cannot bridge between mainnet and testnet'
|
|
259
268
|
* })
|
|
@@ -271,7 +280,8 @@ const MAX_MESSAGE_LENGTH = 950;
|
|
|
271
280
|
* // Error with cause information
|
|
272
281
|
* const error = new KitError({
|
|
273
282
|
* code: 1002,
|
|
274
|
-
* name: '
|
|
283
|
+
* name: 'INPUT_INVALID_AMOUNT',
|
|
284
|
+
* type: 'INPUT',
|
|
275
285
|
* recoverability: 'FATAL',
|
|
276
286
|
* message: 'Amount must be greater than zero',
|
|
277
287
|
* cause: {
|
|
@@ -355,6 +365,8 @@ class KitError extends Error {
|
|
|
355
365
|
* - 3000-3999: NETWORK errors - Internet connectivity, DNS, connection issues
|
|
356
366
|
* - 4000-4999: RPC errors - Blockchain provider issues, gas estimation, nonce errors
|
|
357
367
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures, gas exhaustion, reverts
|
|
368
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling, request frequency limits
|
|
369
|
+
* - 8000-8999: SERVICE errors - Internal service errors, server failures
|
|
358
370
|
* - 9000-9999: BALANCE errors - Insufficient funds, token balance, allowance
|
|
359
371
|
*/
|
|
360
372
|
/**
|
|
@@ -385,19 +397,30 @@ class KitError extends Error {
|
|
|
385
397
|
* ```
|
|
386
398
|
*/
|
|
387
399
|
const InputError = {
|
|
400
|
+
/** Invalid amount format or value (negative, zero, or malformed) */
|
|
401
|
+
INVALID_AMOUNT: {
|
|
402
|
+
code: 1002,
|
|
403
|
+
name: 'INPUT_INVALID_AMOUNT',
|
|
404
|
+
type: 'INPUT',
|
|
405
|
+
},
|
|
388
406
|
/** Invalid or unsupported chain identifier */
|
|
389
407
|
INVALID_CHAIN: {
|
|
390
408
|
code: 1005,
|
|
391
409
|
name: 'INPUT_INVALID_CHAIN',
|
|
392
410
|
type: 'INPUT',
|
|
393
411
|
},
|
|
412
|
+
/** Unsupported token for chain */
|
|
413
|
+
UNSUPPORTED_TOKEN: {
|
|
414
|
+
code: 1006,
|
|
415
|
+
name: 'INPUT_UNSUPPORTED_TOKEN',
|
|
416
|
+
type: 'INPUT',
|
|
417
|
+
},
|
|
394
418
|
/** General validation failure for complex validation rules */
|
|
395
419
|
VALIDATION_FAILED: {
|
|
396
420
|
code: 1098,
|
|
397
421
|
name: 'INPUT_VALIDATION_FAILED',
|
|
398
422
|
type: 'INPUT',
|
|
399
|
-
}
|
|
400
|
-
};
|
|
423
|
+
}};
|
|
401
424
|
/**
|
|
402
425
|
* Standardized error definitions for BALANCE type errors.
|
|
403
426
|
*
|
|
@@ -465,7 +488,20 @@ const OnchainError = {
|
|
|
465
488
|
code: 5003,
|
|
466
489
|
name: 'ONCHAIN_OUT_OF_GAS',
|
|
467
490
|
type: 'ONCHAIN',
|
|
468
|
-
}
|
|
491
|
+
},
|
|
492
|
+
/** Transaction size exceeds blockchain limit */
|
|
493
|
+
TRANSACTION_TOO_LARGE: {
|
|
494
|
+
code: 5005,
|
|
495
|
+
name: 'ONCHAIN_TRANSACTION_TOO_LARGE',
|
|
496
|
+
type: 'ONCHAIN',
|
|
497
|
+
},
|
|
498
|
+
/** Unknown blockchain error that cannot be categorized */
|
|
499
|
+
UNKNOWN_BLOCKCHAIN_ERROR: {
|
|
500
|
+
code: 5099,
|
|
501
|
+
name: 'ONCHAIN_UNKNOWN_BLOCKCHAIN_ERROR',
|
|
502
|
+
type: 'ONCHAIN',
|
|
503
|
+
},
|
|
504
|
+
};
|
|
469
505
|
/**
|
|
470
506
|
* Standardized error definitions for RPC type errors.
|
|
471
507
|
*
|
|
@@ -517,6 +553,66 @@ const NetworkError = {
|
|
|
517
553
|
type: 'NETWORK',
|
|
518
554
|
}};
|
|
519
555
|
|
|
556
|
+
/**
|
|
557
|
+
* Creates error for unsupported token on chain.
|
|
558
|
+
*
|
|
559
|
+
* This error is thrown when a token is not supported on the specified chain.
|
|
560
|
+
*
|
|
561
|
+
* @param token - The token symbol (e.g., 'USDC', 'USDT')
|
|
562
|
+
* @param chain - The chain name where the token is unsupported
|
|
563
|
+
* @returns KitError with specific token support details
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* ```typescript
|
|
567
|
+
* import { createUnsupportedTokenError } from '@core/errors'
|
|
568
|
+
*
|
|
569
|
+
* throw createUnsupportedTokenError('USDC', 'UnknownChain')
|
|
570
|
+
* // Message: "USDC is not supported on UnknownChain"
|
|
571
|
+
* ```
|
|
572
|
+
*/
|
|
573
|
+
function createUnsupportedTokenError(token, chain) {
|
|
574
|
+
const errorDetails = {
|
|
575
|
+
...InputError.UNSUPPORTED_TOKEN,
|
|
576
|
+
recoverability: 'FATAL',
|
|
577
|
+
message: `${token} is not supported on ${chain}.`,
|
|
578
|
+
cause: {
|
|
579
|
+
trace: { token, chain },
|
|
580
|
+
},
|
|
581
|
+
};
|
|
582
|
+
return new KitError(errorDetails);
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Creates error for invalid amount format or precision.
|
|
586
|
+
*
|
|
587
|
+
* This error is thrown when the provided amount doesn't meet validation
|
|
588
|
+
* requirements such as precision, range, or format.
|
|
589
|
+
*
|
|
590
|
+
* @param amount - The invalid amount string
|
|
591
|
+
* @param reason - Specific reason why amount is invalid
|
|
592
|
+
* @returns KitError with amount details and validation rule
|
|
593
|
+
*
|
|
594
|
+
* @example
|
|
595
|
+
* ```typescript
|
|
596
|
+
* import { createInvalidAmountError } from '@core/errors'
|
|
597
|
+
*
|
|
598
|
+
* throw createInvalidAmountError('0.000001', 'Amount must be at least 0.01 USDC')
|
|
599
|
+
* // Message: "Invalid amount '0.000001': Amount must be at least 0.01 USDC"
|
|
600
|
+
*
|
|
601
|
+
* throw createInvalidAmountError('1,000.50', 'Amount must be a numeric string with dot (.) as decimal separator, with no thousand separators or comma decimals')
|
|
602
|
+
* // Message: "Invalid amount '1,000.50': Amount must be a numeric string with dot (.) as decimal separator, with no thousand separators or comma decimals."
|
|
603
|
+
* ```
|
|
604
|
+
*/
|
|
605
|
+
function createInvalidAmountError(amount, reason) {
|
|
606
|
+
const errorDetails = {
|
|
607
|
+
...InputError.INVALID_AMOUNT,
|
|
608
|
+
recoverability: 'FATAL',
|
|
609
|
+
message: `Invalid amount '${amount}': ${reason}.`,
|
|
610
|
+
cause: {
|
|
611
|
+
trace: { amount, reason },
|
|
612
|
+
},
|
|
613
|
+
};
|
|
614
|
+
return new KitError(errorDetails);
|
|
615
|
+
}
|
|
520
616
|
/**
|
|
521
617
|
* Creates error for invalid chain configuration.
|
|
522
618
|
*
|
|
@@ -539,7 +635,7 @@ function createInvalidChainError(chain, reason) {
|
|
|
539
635
|
const errorDetails = {
|
|
540
636
|
...InputError.INVALID_CHAIN,
|
|
541
637
|
recoverability: 'FATAL',
|
|
542
|
-
message: `Invalid chain '${chain}': ${reason}
|
|
638
|
+
message: `Invalid chain '${chain}': ${reason}.`,
|
|
543
639
|
cause: {
|
|
544
640
|
trace: { chain, reason },
|
|
545
641
|
},
|
|
@@ -811,6 +907,8 @@ function createSimulationFailedError(chain, reason, trace) {
|
|
|
811
907
|
* @param chain - The blockchain network where the transaction reverted
|
|
812
908
|
* @param reason - The reason for the revert (e.g., revert message)
|
|
813
909
|
* @param trace - Optional trace context to include in error (can include rawError and additional debugging data)
|
|
910
|
+
* @param txHash - The transaction hash if the transaction was submitted (optional)
|
|
911
|
+
* @param explorerUrl - The block explorer URL for the transaction (optional)
|
|
814
912
|
* @returns KitError with transaction revert details
|
|
815
913
|
*
|
|
816
914
|
* @example
|
|
@@ -823,15 +921,17 @@ function createSimulationFailedError(chain, reason, trace) {
|
|
|
823
921
|
*
|
|
824
922
|
* @example
|
|
825
923
|
* ```typescript
|
|
826
|
-
* // With trace context for debugging
|
|
827
|
-
* throw createTransactionRevertedError(
|
|
828
|
-
*
|
|
829
|
-
*
|
|
830
|
-
*
|
|
831
|
-
*
|
|
924
|
+
* // With trace context and transaction details for debugging
|
|
925
|
+
* throw createTransactionRevertedError(
|
|
926
|
+
* 'Base',
|
|
927
|
+
* 'Slippage exceeded',
|
|
928
|
+
* { rawError: error },
|
|
929
|
+
* '0x123...',
|
|
930
|
+
* 'https://basescan.org/tx/0x123...'
|
|
931
|
+
* )
|
|
832
932
|
* ```
|
|
833
933
|
*/
|
|
834
|
-
function createTransactionRevertedError(chain, reason, trace) {
|
|
934
|
+
function createTransactionRevertedError(chain, reason, trace, txHash, explorerUrl) {
|
|
835
935
|
return new KitError({
|
|
836
936
|
...OnchainError.TRANSACTION_REVERTED,
|
|
837
937
|
recoverability: 'FATAL',
|
|
@@ -841,6 +941,8 @@ function createTransactionRevertedError(chain, reason, trace) {
|
|
|
841
941
|
...trace,
|
|
842
942
|
chain,
|
|
843
943
|
reason,
|
|
944
|
+
...(txHash !== undefined && txHash !== '' && { txHash }),
|
|
945
|
+
...(explorerUrl !== undefined && explorerUrl !== '' && { explorerUrl }),
|
|
844
946
|
},
|
|
845
947
|
},
|
|
846
948
|
});
|
|
@@ -853,6 +955,8 @@ function createTransactionRevertedError(chain, reason, trace) {
|
|
|
853
955
|
*
|
|
854
956
|
* @param chain - The blockchain network where the transaction ran out of gas
|
|
855
957
|
* @param trace - Optional trace context to include in error (can include rawError and additional debugging data)
|
|
958
|
+
* @param txHash - The transaction hash if the transaction was submitted (optional)
|
|
959
|
+
* @param explorerUrl - The block explorer URL for the transaction (optional)
|
|
856
960
|
* @returns KitError with out of gas details
|
|
857
961
|
*
|
|
858
962
|
* @example
|
|
@@ -867,13 +971,15 @@ function createTransactionRevertedError(chain, reason, trace) {
|
|
|
867
971
|
* ```typescript
|
|
868
972
|
* // With trace context for debugging
|
|
869
973
|
* throw createOutOfGasError('Polygon', {
|
|
870
|
-
* rawError: error,
|
|
871
974
|
* gasUsed: '50000',
|
|
872
975
|
* gasLimit: '45000',
|
|
873
|
-
* }
|
|
976
|
+
* },
|
|
977
|
+
* '0xabc...',
|
|
978
|
+
* 'https://polygonscan.com/tx/0xabc...'
|
|
979
|
+
* )
|
|
874
980
|
* ```
|
|
875
981
|
*/
|
|
876
|
-
function createOutOfGasError(chain, trace) {
|
|
982
|
+
function createOutOfGasError(chain, trace, txHash, explorerUrl) {
|
|
877
983
|
return new KitError({
|
|
878
984
|
...OnchainError.OUT_OF_GAS,
|
|
879
985
|
recoverability: 'FATAL',
|
|
@@ -882,20 +988,119 @@ function createOutOfGasError(chain, trace) {
|
|
|
882
988
|
trace: {
|
|
883
989
|
...trace,
|
|
884
990
|
chain,
|
|
991
|
+
...(txHash !== undefined && txHash !== '' && { txHash }),
|
|
992
|
+
...(explorerUrl !== undefined && explorerUrl !== '' && { explorerUrl }),
|
|
993
|
+
},
|
|
994
|
+
},
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Creates error for transaction size exceeding blockchain limits.
|
|
999
|
+
*
|
|
1000
|
+
* This error is thrown when a transaction's serialized size exceeds
|
|
1001
|
+
* the blockchain's maximum transaction size limit. The error is FATAL
|
|
1002
|
+
* as it requires reducing the transaction size (e.g., fewer instructions,
|
|
1003
|
+
* smaller data payloads, or splitting into multiple transactions).
|
|
1004
|
+
*
|
|
1005
|
+
* Common on Solana where transactions have strict size limits (e.g., max 1232 bytes).
|
|
1006
|
+
*
|
|
1007
|
+
* @param chain - The blockchain network where the size limit was exceeded
|
|
1008
|
+
* @param rawError - The original error from the underlying system (optional)
|
|
1009
|
+
* @returns KitError with transaction size exceeded details
|
|
1010
|
+
*
|
|
1011
|
+
* @example
|
|
1012
|
+
* ```typescript
|
|
1013
|
+
* import { createTransactionTooLargeError } from '@core/errors'
|
|
1014
|
+
*
|
|
1015
|
+
* throw createTransactionTooLargeError('Solana')
|
|
1016
|
+
* // Message: "Transaction size exceeds limit on Solana"
|
|
1017
|
+
* ```
|
|
1018
|
+
*
|
|
1019
|
+
* @example
|
|
1020
|
+
* ```typescript
|
|
1021
|
+
* import { createTransactionTooLargeError } from '@core/errors'
|
|
1022
|
+
*
|
|
1023
|
+
* // With raw error containing size details
|
|
1024
|
+
* throw createTransactionTooLargeError(
|
|
1025
|
+
* 'Solana',
|
|
1026
|
+
* new Error('transaction too large: max: encoded/raw 1644/1232')
|
|
1027
|
+
* )
|
|
1028
|
+
* // Error includes size information in cause.trace
|
|
1029
|
+
* ```
|
|
1030
|
+
*/
|
|
1031
|
+
function createTransactionTooLargeError(chain, rawError) {
|
|
1032
|
+
return new KitError({
|
|
1033
|
+
...OnchainError.TRANSACTION_TOO_LARGE,
|
|
1034
|
+
recoverability: 'FATAL',
|
|
1035
|
+
message: `Transaction size exceeds limit on ${chain}`,
|
|
1036
|
+
cause: {
|
|
1037
|
+
trace: {
|
|
1038
|
+
chain,
|
|
1039
|
+
rawError,
|
|
1040
|
+
},
|
|
1041
|
+
},
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* Creates error for unknown blockchain errors that cannot be categorized.
|
|
1046
|
+
*
|
|
1047
|
+
* This error is used as a fallback when a blockchain error doesn't match
|
|
1048
|
+
* any known patterns (balance, simulation, gas, network, RPC, etc.).
|
|
1049
|
+
* The error is FATAL as we cannot determine if it's retriable without
|
|
1050
|
+
* understanding the underlying cause.
|
|
1051
|
+
*
|
|
1052
|
+
* The original error message and context are preserved in the trace for
|
|
1053
|
+
* debugging purposes.
|
|
1054
|
+
*
|
|
1055
|
+
* @param chain - The blockchain network where the error occurred
|
|
1056
|
+
* @param originalMessage - The original error message from the blockchain
|
|
1057
|
+
* @param rawError - The original error object from the underlying system (optional)
|
|
1058
|
+
* @returns KitError with unknown blockchain error details
|
|
1059
|
+
*
|
|
1060
|
+
* @example
|
|
1061
|
+
* ```typescript
|
|
1062
|
+
* import { createUnknownBlockchainError } from '@core/errors'
|
|
1063
|
+
*
|
|
1064
|
+
* throw createUnknownBlockchainError('Ethereum', 'Unknown protocol error')
|
|
1065
|
+
* // Message: "Unknown blockchain error on Ethereum: Unknown protocol error"
|
|
1066
|
+
* ```
|
|
1067
|
+
*
|
|
1068
|
+
* @example
|
|
1069
|
+
* ```typescript
|
|
1070
|
+
* import { createUnknownBlockchainError } from '@core/errors'
|
|
1071
|
+
*
|
|
1072
|
+
* // With raw error for debugging
|
|
1073
|
+
* const rawError = new Error('Unexpected blockchain state')
|
|
1074
|
+
* throw createUnknownBlockchainError('Solana', rawError.message, rawError)
|
|
1075
|
+
* // Error preserves full context in cause.trace
|
|
1076
|
+
* ```
|
|
1077
|
+
*/
|
|
1078
|
+
function createUnknownBlockchainError(chain, originalMessage, rawError) {
|
|
1079
|
+
const errorMessage = originalMessage
|
|
1080
|
+
? 'Unknown blockchain error on ' + chain + ': ' + originalMessage
|
|
1081
|
+
: 'Unknown blockchain error on ' + chain;
|
|
1082
|
+
return new KitError({
|
|
1083
|
+
...OnchainError.UNKNOWN_BLOCKCHAIN_ERROR,
|
|
1084
|
+
recoverability: 'FATAL',
|
|
1085
|
+
message: errorMessage,
|
|
1086
|
+
cause: {
|
|
1087
|
+
trace: {
|
|
1088
|
+
chain,
|
|
1089
|
+
rawError,
|
|
885
1090
|
},
|
|
886
1091
|
},
|
|
887
1092
|
});
|
|
888
1093
|
}
|
|
889
1094
|
|
|
890
1095
|
/**
|
|
891
|
-
*
|
|
1096
|
+
* Create error for RPC endpoint failures.
|
|
892
1097
|
*
|
|
893
|
-
*
|
|
1098
|
+
* Throw when an RPC provider endpoint fails, returns an error,
|
|
894
1099
|
* or is unavailable. The error is RETRYABLE as RPC issues are often temporary.
|
|
895
1100
|
*
|
|
896
|
-
* @param chain - The blockchain network where the RPC error occurred
|
|
897
|
-
* @param trace - Optional trace context
|
|
898
|
-
* @returns KitError with RPC endpoint error details
|
|
1101
|
+
* @param chain - The blockchain network where the RPC error occurred.
|
|
1102
|
+
* @param trace - Optional trace context (can include rawError and debugging data).
|
|
1103
|
+
* @returns KitError with RPC endpoint error details.
|
|
899
1104
|
*
|
|
900
1105
|
* @example
|
|
901
1106
|
* ```typescript
|
|
@@ -907,7 +1112,6 @@ function createOutOfGasError(chain, trace) {
|
|
|
907
1112
|
*
|
|
908
1113
|
* @example
|
|
909
1114
|
* ```typescript
|
|
910
|
-
* // With trace context for debugging
|
|
911
1115
|
* throw createRpcEndpointError('Ethereum', {
|
|
912
1116
|
* rawError: error,
|
|
913
1117
|
* endpoint: 'https://mainnet.infura.io/v3/...',
|
|
@@ -930,15 +1134,15 @@ function createRpcEndpointError(chain, trace) {
|
|
|
930
1134
|
}
|
|
931
1135
|
|
|
932
1136
|
/**
|
|
933
|
-
*
|
|
1137
|
+
* Create error for network connection failures.
|
|
934
1138
|
*
|
|
935
|
-
*
|
|
1139
|
+
* Throw when network connectivity issues prevent reaching
|
|
936
1140
|
* the blockchain network. The error is RETRYABLE as network issues are
|
|
937
1141
|
* often temporary.
|
|
938
1142
|
*
|
|
939
|
-
* @param chain - The blockchain network where the connection failed
|
|
940
|
-
* @param trace - Optional trace context
|
|
941
|
-
* @returns KitError with network connection error details
|
|
1143
|
+
* @param chain - The blockchain network where the connection failed.
|
|
1144
|
+
* @param trace - Optional trace context (can include rawError and debugging data).
|
|
1145
|
+
* @returns KitError with network connection error details.
|
|
942
1146
|
*
|
|
943
1147
|
* @example
|
|
944
1148
|
* ```typescript
|
|
@@ -950,7 +1154,6 @@ function createRpcEndpointError(chain, trace) {
|
|
|
950
1154
|
*
|
|
951
1155
|
* @example
|
|
952
1156
|
* ```typescript
|
|
953
|
-
* // With trace context for debugging
|
|
954
1157
|
* throw createNetworkConnectionError('Ethereum', {
|
|
955
1158
|
* rawError: error,
|
|
956
1159
|
* endpoint: 'https://eth-mainnet.g.alchemy.com/v2/...',
|
|
@@ -972,6 +1175,25 @@ function createNetworkConnectionError(chain, trace) {
|
|
|
972
1175
|
});
|
|
973
1176
|
}
|
|
974
1177
|
|
|
1178
|
+
/**
|
|
1179
|
+
* Normalizes optional transaction details for error factories.
|
|
1180
|
+
*
|
|
1181
|
+
* Converts empty strings to undefined to ensure clean error traces.
|
|
1182
|
+
*
|
|
1183
|
+
* @param txHash - The transaction hash.
|
|
1184
|
+
* @param explorerUrl - The explorer URL.
|
|
1185
|
+
* @returns Normalized values or undefined.
|
|
1186
|
+
*/
|
|
1187
|
+
function normalizeTransactionDetails(txHash, explorerUrl) {
|
|
1188
|
+
const normalized = {};
|
|
1189
|
+
if (txHash !== undefined && txHash !== '') {
|
|
1190
|
+
normalized.txHash = txHash;
|
|
1191
|
+
}
|
|
1192
|
+
if (explorerUrl !== undefined && explorerUrl !== '') {
|
|
1193
|
+
normalized.explorerUrl = explorerUrl;
|
|
1194
|
+
}
|
|
1195
|
+
return normalized;
|
|
1196
|
+
}
|
|
975
1197
|
/**
|
|
976
1198
|
* Parses raw blockchain errors into structured KitError instances.
|
|
977
1199
|
*
|
|
@@ -979,12 +1201,17 @@ function createNetworkConnectionError(chain, trace) {
|
|
|
979
1201
|
* types and converts them into standardized KitError format. It handles
|
|
980
1202
|
* errors from viem, ethers, Solana web3.js, and other blockchain libraries.
|
|
981
1203
|
*
|
|
982
|
-
* The parser recognizes
|
|
1204
|
+
* The parser recognizes 6 main error patterns:
|
|
983
1205
|
* 1. Insufficient balance errors
|
|
984
1206
|
* 2. Simulation/execution reverted errors
|
|
985
1207
|
* 3. Gas-related errors
|
|
986
1208
|
* 4. Network connectivity errors
|
|
987
1209
|
* 5. RPC provider errors
|
|
1210
|
+
* 6. Transaction size limit errors
|
|
1211
|
+
*
|
|
1212
|
+
* When errors don't match known patterns, the parser uses operation context
|
|
1213
|
+
* (e.g., 'simulation', 'estimateGas') to categorize them appropriately.
|
|
1214
|
+
* Unrecognized errors without context are categorized as UNKNOWN_BLOCKCHAIN_ERROR.
|
|
988
1215
|
*
|
|
989
1216
|
* @param error - The raw error from the blockchain library
|
|
990
1217
|
* @param context - Context information including chain and optional token
|
|
@@ -1014,6 +1241,25 @@ function createNetworkConnectionError(chain, trace) {
|
|
|
1014
1241
|
* throw parseBlockchainError(error, { chain: 'Solana' })
|
|
1015
1242
|
* }
|
|
1016
1243
|
* ```
|
|
1244
|
+
*
|
|
1245
|
+
* @example
|
|
1246
|
+
* ```typescript
|
|
1247
|
+
* // With transaction hash and explorer URL
|
|
1248
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
1249
|
+
* import { Ethereum } from '@core/chains'
|
|
1250
|
+
*
|
|
1251
|
+
* try {
|
|
1252
|
+
* const txHash = await walletClient.sendTransaction(...)
|
|
1253
|
+
* await waitForTransaction(txHash)
|
|
1254
|
+
* } catch (error) {
|
|
1255
|
+
* const explorerUrl = buildExplorerUrl(Ethereum, txHash)
|
|
1256
|
+
* throw parseBlockchainError(error, {
|
|
1257
|
+
* chain: 'Ethereum',
|
|
1258
|
+
* txHash,
|
|
1259
|
+
* explorerUrl
|
|
1260
|
+
* })
|
|
1261
|
+
* }
|
|
1262
|
+
* ```
|
|
1017
1263
|
*/
|
|
1018
1264
|
function parseBlockchainError(error, context) {
|
|
1019
1265
|
const msg = extractMessage(error);
|
|
@@ -1028,7 +1274,7 @@ function parseBlockchainError(error, context) {
|
|
|
1028
1274
|
// Pattern 2: Simulation and execution reverts
|
|
1029
1275
|
// Matches contract revert errors and simulation failures
|
|
1030
1276
|
if (/execution reverted|simulation failed|transaction reverted|transaction failed/i.test(msg)) {
|
|
1031
|
-
const reason = extractRevertReason(msg) ?? 'Transaction reverted';
|
|
1277
|
+
const reason = extractRevertReason(msg, error) ?? 'Transaction reverted';
|
|
1032
1278
|
// Distinguish between simulation failures and transaction reverts
|
|
1033
1279
|
// "simulation failed" or "eth_call" indicates pre-flight simulation
|
|
1034
1280
|
// "transaction failed" or context.operation === 'transaction' indicates post-execution
|
|
@@ -1038,9 +1284,11 @@ function parseBlockchainError(error, context) {
|
|
|
1038
1284
|
});
|
|
1039
1285
|
}
|
|
1040
1286
|
// Transaction execution failures or reverts
|
|
1287
|
+
// Include txHash and explorerUrl if available (transaction was submitted)
|
|
1288
|
+
const { txHash, explorerUrl } = normalizeTransactionDetails(context.txHash, context.explorerUrl);
|
|
1041
1289
|
return createTransactionRevertedError(context.chain, reason, {
|
|
1042
1290
|
rawError: error,
|
|
1043
|
-
});
|
|
1291
|
+
}, txHash, explorerUrl);
|
|
1044
1292
|
}
|
|
1045
1293
|
// Pattern 3: Gas-related errors
|
|
1046
1294
|
// Matches gas estimation failures and gas exhaustion
|
|
@@ -1052,7 +1300,8 @@ function parseBlockchainError(error, context) {
|
|
|
1052
1300
|
// Gas exhaustion errors
|
|
1053
1301
|
// Use specific patterns without wildcards to avoid ReDoS
|
|
1054
1302
|
if (/out of gas|gas limit exceeded|exceeds block gas limit/i.test(msg)) {
|
|
1055
|
-
|
|
1303
|
+
const { txHash, explorerUrl } = normalizeTransactionDetails(context.txHash, context.explorerUrl);
|
|
1304
|
+
return createOutOfGasError(context.chain, { rawError: error }, txHash, explorerUrl);
|
|
1056
1305
|
}
|
|
1057
1306
|
// Insufficient funds for gas
|
|
1058
1307
|
if (/insufficient funds for gas/i.test(msg)) {
|
|
@@ -1068,15 +1317,38 @@ function parseBlockchainError(error, context) {
|
|
|
1068
1317
|
if (/rpc|invalid response|rate limit|too many requests/i.test(msg)) {
|
|
1069
1318
|
return createRpcEndpointError(context.chain, { rawError: error });
|
|
1070
1319
|
}
|
|
1320
|
+
// Pattern 6: Transaction size limit errors
|
|
1321
|
+
// Matches transaction size errors from various blockchains:
|
|
1322
|
+
// - Solana: "transaction too large: max: encoded/raw 1644/1232"
|
|
1323
|
+
// - Generic: "transaction exceeds size limit", "max transaction size"
|
|
1324
|
+
// Split into two checks to reduce regex complexity for SonarQube
|
|
1325
|
+
const isSizeError = /transaction (?:too large|exceeds size limit|size exceeds)|encoded\/raw\s+\d+\/\d+|max transaction size/i.test(msg) || /(?:tx|transaction) size is too big:\s*\d+,\s*max:\s*\d+/i.test(msg);
|
|
1326
|
+
if (isSizeError) {
|
|
1327
|
+
return createTransactionTooLargeError(context.chain, error);
|
|
1328
|
+
}
|
|
1071
1329
|
// Fallback based on operation context
|
|
1072
1330
|
// Gas-related operations are RPC calls
|
|
1073
1331
|
if (context.operation === 'estimateGas' ||
|
|
1074
1332
|
context.operation === 'getGasPrice') {
|
|
1075
1333
|
return createRpcEndpointError(context.chain, { rawError: error });
|
|
1076
1334
|
}
|
|
1077
|
-
//
|
|
1078
|
-
//
|
|
1079
|
-
|
|
1335
|
+
// Simulation operations that don't match standard patterns should still be
|
|
1336
|
+
// categorized as simulation failures. This handles cases where blockchain
|
|
1337
|
+
// libraries throw generic errors (e.g., "fail", "error") during staticCall
|
|
1338
|
+
// operations without descriptive messages. The operation context is authoritative
|
|
1339
|
+
// about what was being attempted, even when error messages are unclear.
|
|
1340
|
+
//
|
|
1341
|
+
// Example: ethers.js staticCall rejection with message "fail"
|
|
1342
|
+
// - Message doesn't match /execution reverted|simulation failed/
|
|
1343
|
+
// - But context.operation === 'simulation' tells us it was a simulation
|
|
1344
|
+
// - Result: SIMULATION_FAILED (accurate) vs UNKNOWN_BLOCKCHAIN_ERROR (misleading)
|
|
1345
|
+
if (context.operation === 'simulation') {
|
|
1346
|
+
return createSimulationFailedError(context.chain, msg.length > 0 ? msg : 'Simulation failed', { rawError: error });
|
|
1347
|
+
}
|
|
1348
|
+
// Final fallback for truly unrecognized errors
|
|
1349
|
+
// Only errors that don't match any pattern AND lack operation context
|
|
1350
|
+
// are categorized as unknown.
|
|
1351
|
+
return createUnknownBlockchainError(context.chain, msg.length > 0 ? msg : 'Unknown error', { rawError: error });
|
|
1080
1352
|
}
|
|
1081
1353
|
/**
|
|
1082
1354
|
* Type guard to check if error has Solana-Kit structure with logs.
|
|
@@ -1135,12 +1407,76 @@ function extractMessage(error) {
|
|
|
1135
1407
|
return String(error);
|
|
1136
1408
|
}
|
|
1137
1409
|
/**
|
|
1138
|
-
*
|
|
1410
|
+
* Mapping of custom error selectors to human-readable error names.
|
|
1411
|
+
*
|
|
1412
|
+
* These selectors correspond to custom errors from the contracts.
|
|
1413
|
+
* When a transaction reverts with a custom error, the 4-byte selector
|
|
1414
|
+
* (first 4 bytes of keccak256 of the error signature) is included in the error message.
|
|
1415
|
+
*
|
|
1416
|
+
*/
|
|
1417
|
+
const CUSTOM_ERROR_SELECTORS = {
|
|
1418
|
+
'0xd93c0665': 'This contract is currently paused', // EnforcedPause()
|
|
1419
|
+
'0x3ee5aeb5': 'Security check failed due to a reentrancy attempt', // ReentrancyGuardReentrantCall()
|
|
1420
|
+
'0x8baa579f': 'The provided signature is invalid or could not be verified', // InvalidSignature()
|
|
1421
|
+
'0x1ab7da6b': 'This request has expired', // DeadlineExpired()
|
|
1422
|
+
'0x64eee62e': 'No instructions provided', // EmptyInstructions()
|
|
1423
|
+
'0x3c46992e': 'Too many execution steps were provided', // TooManyInstructions()
|
|
1424
|
+
'0xe066e60e': 'Exceeds maximum token inputs limit', // TooManyTokenInputs()
|
|
1425
|
+
'0x5566df5c': 'The beneficiary address is invalid', // InvalidBeneficiary()
|
|
1426
|
+
'0xf41d7bc6': 'Execution ID already used', // ExecIdUsed()
|
|
1427
|
+
'0x948726e2': 'The account balance does not meet the required minimum', // InvalidBalanceState()
|
|
1428
|
+
'0x01aa0452': 'The permit type provided is not supported', // UnsupportedPermitType()
|
|
1429
|
+
'0x13be252b': 'Token approval failed and the allowance is insufficient', // InsufficientAllowance()
|
|
1430
|
+
'0x5274afe7': 'Token transfer or approval failed', // SafeERC20FailedOperation(address)
|
|
1431
|
+
'0x00bc1dcb': 'One of the execution targets is invalid', // InvalidInstruction(uint256)
|
|
1432
|
+
'0x5d693841': 'Cannot approve a zero address or a native token', // InvalidApprovalConfig(uint256)
|
|
1433
|
+
'0x3ec5cfe1': 'Cannot validate output for a zero address token', // InvalidOutputConfig(uint256)
|
|
1434
|
+
'0x492fd70e': 'Instruction call failed without revert data', // ExecutionFailed(uint256)
|
|
1435
|
+
'0xba235e1a': 'The received token amount is lower than the minimum required', // InsufficientOutput(uint256,address,uint256,uint256)
|
|
1436
|
+
'0x9147d463': 'Final balance is less than the initial balance', // InsufficientFinalBalance(address,uint256,uint256)
|
|
1437
|
+
'0xf4b3b1bc': 'Native token transfer to the beneficiary failed', // NativeTransferFailed()
|
|
1438
|
+
};
|
|
1439
|
+
/**
|
|
1440
|
+
* Attempts to extract an error selector from an error object or message.
|
|
1441
|
+
*
|
|
1442
|
+
* Checks multiple sources in priority order:
|
|
1443
|
+
* 1. `error.data` field
|
|
1444
|
+
* 2. Message pattern: "custom error 0x8baa579f"
|
|
1445
|
+
*
|
|
1446
|
+
* @param msg - The error message
|
|
1447
|
+
* @param error - The error object (optional)
|
|
1448
|
+
* @returns The 4 bytes selector , or undefined if not found
|
|
1449
|
+
*/
|
|
1450
|
+
function extractErrorSelector(msg, error) {
|
|
1451
|
+
// Check error.data field
|
|
1452
|
+
if (error !== null && typeof error === 'object' && 'data' in error) {
|
|
1453
|
+
if (typeof error.data === 'string' && /^0x[0-9a-f]{8}$/i.test(error.data)) {
|
|
1454
|
+
return error.data.toLowerCase();
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
// Check for "custom error 0x8baa579f" in the message
|
|
1458
|
+
const match = /custom error (0x[0-9a-f]{8})\b/i.exec(msg);
|
|
1459
|
+
const selector = match?.[1];
|
|
1460
|
+
if (selector !== undefined && selector.length > 0) {
|
|
1461
|
+
return selector.toLowerCase();
|
|
1462
|
+
}
|
|
1463
|
+
return undefined;
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Extracts the revert reason from an error message and error object.
|
|
1139
1467
|
*
|
|
1140
1468
|
* Attempts to parse out the meaningful reason from execution revert errors,
|
|
1141
1469
|
* removing common prefixes like "execution reverted:" or "reverted:".
|
|
1470
|
+
* If the error contains a custom error selector, it will be resolved to its
|
|
1471
|
+
* human-readable description with the selector included for developer reference.
|
|
1472
|
+
*
|
|
1473
|
+
* Supports multiple error formats:
|
|
1474
|
+
* - Custom error with selector in `error.data` field (e.g., `{ data: "0x8baa579f", ... }`)
|
|
1475
|
+
* - Message with selector pattern: `"Execution reverted with reason: custom error 0x8baa579f"`
|
|
1476
|
+
* - Standard revert: `"execution reverted: Insufficient funds"`
|
|
1142
1477
|
*
|
|
1143
1478
|
* @param msg - The error message to extract from
|
|
1479
|
+
* @param error - The full error object (optional, used to extract selector from `data` field)
|
|
1144
1480
|
* @returns The extracted revert reason, or null if not found
|
|
1145
1481
|
*
|
|
1146
1482
|
* @example
|
|
@@ -1158,10 +1494,48 @@ function extractMessage(error) {
|
|
|
1158
1494
|
* )
|
|
1159
1495
|
* // Returns: 'Insufficient allowance'
|
|
1160
1496
|
* ```
|
|
1497
|
+
*
|
|
1498
|
+
* @example
|
|
1499
|
+
* ```typescript
|
|
1500
|
+
* // Custom error with selector in message
|
|
1501
|
+
* const reason = extractRevertReason(
|
|
1502
|
+
* 'Execution reverted with reason: custom error 0x8baa579f'
|
|
1503
|
+
* )
|
|
1504
|
+
* // Returns: 'The provided signature is invalid or could not be verified (0x8baa579f)'
|
|
1505
|
+
* ```
|
|
1506
|
+
*
|
|
1507
|
+
* @example
|
|
1508
|
+
* ```typescript
|
|
1509
|
+
* // Error with data field
|
|
1510
|
+
* const reason = extractRevertReason(
|
|
1511
|
+
* 'execution reverted (unknown custom error)',
|
|
1512
|
+
* { data: '0x8baa579f' }
|
|
1513
|
+
* )
|
|
1514
|
+
* // Returns: 'The provided signature is invalid or could not be verified (0x8baa579f)'
|
|
1515
|
+
* ```
|
|
1516
|
+
*
|
|
1517
|
+
* @example
|
|
1518
|
+
* ```typescript
|
|
1519
|
+
* // Unrecognized selector preserved for debugging
|
|
1520
|
+
* const reason = extractRevertReason(
|
|
1521
|
+
* 'execution reverted (unknown custom error)',
|
|
1522
|
+
* { data: '0xdeadbeef' }
|
|
1523
|
+
* )
|
|
1524
|
+
* // Returns: 'Transaction reverted with error (0xdeadbeef)'
|
|
1525
|
+
* ```
|
|
1161
1526
|
*/
|
|
1162
|
-
function extractRevertReason(msg) {
|
|
1527
|
+
function extractRevertReason(msg, error) {
|
|
1528
|
+
// Try to extract and decode custom error selector
|
|
1529
|
+
const selector = extractErrorSelector(msg, error);
|
|
1530
|
+
if (selector !== undefined) {
|
|
1531
|
+
const errorMessage = CUSTOM_ERROR_SELECTORS[selector];
|
|
1532
|
+
if (errorMessage !== undefined) {
|
|
1533
|
+
return `${errorMessage} (${selector})`;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1163
1536
|
// Try to extract reason after "execution reverted:" or "reason:"
|
|
1164
1537
|
// Use [^\n.]+ instead of .+? to avoid ReDoS vulnerability
|
|
1538
|
+
// Fall back to standard revert reason extraction
|
|
1165
1539
|
const patterns = [
|
|
1166
1540
|
/(?:execution reverted|reverted):\s*([^\n.]+)/i,
|
|
1167
1541
|
/reason:\s*([^\n.]+)/i,
|
|
@@ -1174,9 +1548,49 @@ function extractRevertReason(msg) {
|
|
|
1174
1548
|
return extractedReason.trim();
|
|
1175
1549
|
}
|
|
1176
1550
|
}
|
|
1551
|
+
// Preserve unrecognized selector so it appears in error output for debugging
|
|
1552
|
+
if (selector !== undefined) {
|
|
1553
|
+
return `Transaction reverted with error (${selector})`;
|
|
1554
|
+
}
|
|
1177
1555
|
return null;
|
|
1178
1556
|
}
|
|
1179
1557
|
|
|
1558
|
+
/**
|
|
1559
|
+
* Safely extracts error message from any error type.
|
|
1560
|
+
*
|
|
1561
|
+
* This utility handles different error types gracefully, extracting
|
|
1562
|
+
* meaningful messages from Error instances, string errors, or providing
|
|
1563
|
+
* a fallback for unknown error types. Never throws.
|
|
1564
|
+
*
|
|
1565
|
+
* @param error - Unknown error to extract message from
|
|
1566
|
+
* @returns Error message string, or fallback message
|
|
1567
|
+
*
|
|
1568
|
+
* @example
|
|
1569
|
+
* ```typescript
|
|
1570
|
+
* import { getErrorMessage } from '@core/errors'
|
|
1571
|
+
*
|
|
1572
|
+
* try {
|
|
1573
|
+
* await riskyOperation()
|
|
1574
|
+
* } catch (error) {
|
|
1575
|
+
* const message = getErrorMessage(error)
|
|
1576
|
+
* console.log('Error occurred:', message)
|
|
1577
|
+
* // Works with Error, KitError, string, or any other type
|
|
1578
|
+
* }
|
|
1579
|
+
* ```
|
|
1580
|
+
*/
|
|
1581
|
+
function getErrorMessage(error) {
|
|
1582
|
+
if (error instanceof Error) {
|
|
1583
|
+
return error.message;
|
|
1584
|
+
}
|
|
1585
|
+
if (typeof error === 'string') {
|
|
1586
|
+
return error;
|
|
1587
|
+
}
|
|
1588
|
+
if (typeof error === 'object' && error !== null && 'message' in error) {
|
|
1589
|
+
return String(error.message);
|
|
1590
|
+
}
|
|
1591
|
+
return 'An unknown error occurred';
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1180
1594
|
// -----------------------------------------------------------------------------
|
|
1181
1595
|
// Blockchain Enum
|
|
1182
1596
|
// -----------------------------------------------------------------------------
|
|
@@ -1209,6 +1623,8 @@ var Blockchain;
|
|
|
1209
1623
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
1210
1624
|
Blockchain["Codex"] = "Codex";
|
|
1211
1625
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
1626
|
+
Blockchain["Edge"] = "Edge";
|
|
1627
|
+
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
1212
1628
|
Blockchain["Ethereum"] = "Ethereum";
|
|
1213
1629
|
Blockchain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
1214
1630
|
Blockchain["Hedera"] = "Hedera";
|
|
@@ -1221,6 +1637,8 @@ var Blockchain;
|
|
|
1221
1637
|
Blockchain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
1222
1638
|
Blockchain["Monad"] = "Monad";
|
|
1223
1639
|
Blockchain["Monad_Testnet"] = "Monad_Testnet";
|
|
1640
|
+
Blockchain["Morph"] = "Morph";
|
|
1641
|
+
Blockchain["Morph_Testnet"] = "Morph_Testnet";
|
|
1224
1642
|
Blockchain["NEAR"] = "NEAR";
|
|
1225
1643
|
Blockchain["NEAR_Testnet"] = "NEAR_Testnet";
|
|
1226
1644
|
Blockchain["Noble"] = "Noble";
|
|
@@ -1252,6 +1670,122 @@ var Blockchain;
|
|
|
1252
1670
|
Blockchain["ZKSync_Era"] = "ZKSync_Era";
|
|
1253
1671
|
Blockchain["ZKSync_Sepolia"] = "ZKSync_Sepolia";
|
|
1254
1672
|
})(Blockchain || (Blockchain = {}));
|
|
1673
|
+
/**
|
|
1674
|
+
* Enum representing the subset of {@link Blockchain} that supports swap operations.
|
|
1675
|
+
*
|
|
1676
|
+
* This enum provides compile-time type safety for swap chain selection,
|
|
1677
|
+
* ensuring only supported chains are available in IDE autocomplete
|
|
1678
|
+
* when building swap parameters.
|
|
1679
|
+
*
|
|
1680
|
+
* @remarks
|
|
1681
|
+
* Unlike the full {@link Blockchain} enum, SwapChain only includes networks
|
|
1682
|
+
* where the swap functionality is actively supported by the library.
|
|
1683
|
+
* Using this enum prevents runtime errors from attempting unsupported
|
|
1684
|
+
* cross-chain swaps.
|
|
1685
|
+
*
|
|
1686
|
+
* Currently supports:
|
|
1687
|
+
* - Ethereum mainnet
|
|
1688
|
+
* - Base mainnet
|
|
1689
|
+
* - Polygon mainnet
|
|
1690
|
+
* - Solana mainnet
|
|
1691
|
+
*
|
|
1692
|
+
* @example
|
|
1693
|
+
* ```typescript
|
|
1694
|
+
* import { SwapChain, swap, createSwapKitContext } from '@circle-fin/swap-kit'
|
|
1695
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
1696
|
+
*
|
|
1697
|
+
* const context = createSwapKitContext()
|
|
1698
|
+
* const adapter = createViemAdapterFromPrivateKey({
|
|
1699
|
+
* privateKey: process.env.PRIVATE_KEY
|
|
1700
|
+
* })
|
|
1701
|
+
*
|
|
1702
|
+
* // ✅ Autocomplete shows only swap-supported chains
|
|
1703
|
+
* const result = await swap(context, {
|
|
1704
|
+
* from: {
|
|
1705
|
+
* adapter,
|
|
1706
|
+
* chain: SwapChain.Ethereum // Autocomplete: Ethereum, Base, Polygon, Solana
|
|
1707
|
+
* },
|
|
1708
|
+
* tokenIn: 'USDC',
|
|
1709
|
+
* tokenOut: 'USDT',
|
|
1710
|
+
* amount: '100.0'
|
|
1711
|
+
* })
|
|
1712
|
+
* ```
|
|
1713
|
+
*
|
|
1714
|
+
* @example
|
|
1715
|
+
* ```typescript
|
|
1716
|
+
* // String literals also work (constrained to SwapChain values)
|
|
1717
|
+
* const result = await swap(context, {
|
|
1718
|
+
* from: {
|
|
1719
|
+
* adapter,
|
|
1720
|
+
* chain: 'Ethereum' // ✅ Only SwapChain strings allowed
|
|
1721
|
+
* },
|
|
1722
|
+
* tokenIn: 'USDC',
|
|
1723
|
+
* tokenOut: 'NATIVE',
|
|
1724
|
+
* amount: '50.0'
|
|
1725
|
+
* })
|
|
1726
|
+
*
|
|
1727
|
+
* // ❌ TypeScript error - Sui not in SwapChain enum
|
|
1728
|
+
* const invalidResult = await swap(context, {
|
|
1729
|
+
* from: {
|
|
1730
|
+
* adapter,
|
|
1731
|
+
* chain: 'Sui' // Compile-time error!
|
|
1732
|
+
* },
|
|
1733
|
+
* tokenIn: 'USDC',
|
|
1734
|
+
* tokenOut: 'USDT',
|
|
1735
|
+
* amount: '100.0'
|
|
1736
|
+
* })
|
|
1737
|
+
* ```
|
|
1738
|
+
*/
|
|
1739
|
+
/**
|
|
1740
|
+
* Enum representing chains that support same-chain swaps through the Swap Kit.
|
|
1741
|
+
*
|
|
1742
|
+
* Unlike the full {@link Blockchain} enum, SwapChain includes only mainnet
|
|
1743
|
+
* networks where adapter contracts are deployed (CCTPv2 support).
|
|
1744
|
+
*
|
|
1745
|
+
* Dynamic validation via {@link isSwapSupportedChain} ensures chains
|
|
1746
|
+
* automatically work when adapter contracts and supported tokens are deployed.
|
|
1747
|
+
*
|
|
1748
|
+
* @example
|
|
1749
|
+
* ```typescript
|
|
1750
|
+
* import { SwapChain } from '@core/chains'
|
|
1751
|
+
* import { swap } from '@circle-fin/swap-kit'
|
|
1752
|
+
*
|
|
1753
|
+
* const result = await swap(context, {
|
|
1754
|
+
* from: {
|
|
1755
|
+
* adapter,
|
|
1756
|
+
* chain: SwapChain.Arbitrum // Now supported!
|
|
1757
|
+
* },
|
|
1758
|
+
* tokenIn: 'USDC',
|
|
1759
|
+
* tokenOut: 'WETH',
|
|
1760
|
+
* amount: '100.0'
|
|
1761
|
+
* })
|
|
1762
|
+
* ```
|
|
1763
|
+
*
|
|
1764
|
+
* @see {@link isSwapSupportedChain} for runtime validation
|
|
1765
|
+
* @see {@link getSwapSupportedChains} for all supported chains
|
|
1766
|
+
*/
|
|
1767
|
+
var SwapChain;
|
|
1768
|
+
(function (SwapChain) {
|
|
1769
|
+
// Original 4 chains
|
|
1770
|
+
SwapChain["Ethereum"] = "Ethereum";
|
|
1771
|
+
SwapChain["Base"] = "Base";
|
|
1772
|
+
SwapChain["Polygon"] = "Polygon";
|
|
1773
|
+
SwapChain["Solana"] = "Solana";
|
|
1774
|
+
// Additional supported chains
|
|
1775
|
+
SwapChain["Arbitrum"] = "Arbitrum";
|
|
1776
|
+
SwapChain["Optimism"] = "Optimism";
|
|
1777
|
+
SwapChain["Avalanche"] = "Avalanche";
|
|
1778
|
+
SwapChain["Linea"] = "Linea";
|
|
1779
|
+
SwapChain["Ink"] = "Ink";
|
|
1780
|
+
SwapChain["World_Chain"] = "World_Chain";
|
|
1781
|
+
SwapChain["Unichain"] = "Unichain";
|
|
1782
|
+
SwapChain["Plume"] = "Plume";
|
|
1783
|
+
SwapChain["Sei"] = "Sei";
|
|
1784
|
+
SwapChain["Sonic"] = "Sonic";
|
|
1785
|
+
SwapChain["XDC"] = "XDC";
|
|
1786
|
+
SwapChain["HyperEVM"] = "HyperEVM";
|
|
1787
|
+
SwapChain["Monad"] = "Monad";
|
|
1788
|
+
})(SwapChain || (SwapChain = {}));
|
|
1255
1789
|
// -----------------------------------------------------------------------------
|
|
1256
1790
|
// Bridge Chain Enum (CCTPv2 Supported Chains)
|
|
1257
1791
|
// -----------------------------------------------------------------------------
|
|
@@ -1308,11 +1842,13 @@ var BridgeChain;
|
|
|
1308
1842
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
1309
1843
|
BridgeChain["Base"] = "Base";
|
|
1310
1844
|
BridgeChain["Codex"] = "Codex";
|
|
1845
|
+
BridgeChain["Edge"] = "Edge";
|
|
1311
1846
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
1312
1847
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
1313
1848
|
BridgeChain["Ink"] = "Ink";
|
|
1314
1849
|
BridgeChain["Linea"] = "Linea";
|
|
1315
1850
|
BridgeChain["Monad"] = "Monad";
|
|
1851
|
+
BridgeChain["Morph"] = "Morph";
|
|
1316
1852
|
BridgeChain["Optimism"] = "Optimism";
|
|
1317
1853
|
BridgeChain["Plume"] = "Plume";
|
|
1318
1854
|
BridgeChain["Polygon"] = "Polygon";
|
|
@@ -1328,11 +1864,13 @@ var BridgeChain;
|
|
|
1328
1864
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
1329
1865
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
1330
1866
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
1867
|
+
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
1331
1868
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
1332
1869
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
1333
1870
|
BridgeChain["Ink_Testnet"] = "Ink_Testnet";
|
|
1334
1871
|
BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
1335
1872
|
BridgeChain["Monad_Testnet"] = "Monad_Testnet";
|
|
1873
|
+
BridgeChain["Morph_Testnet"] = "Morph_Testnet";
|
|
1336
1874
|
BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
|
|
1337
1875
|
BridgeChain["Plume_Testnet"] = "Plume_Testnet";
|
|
1338
1876
|
BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
|
|
@@ -1403,6 +1941,7 @@ const Algorand = defineChain({
|
|
|
1403
1941
|
rpcEndpoints: ['https://mainnet-api.algonode.cloud'],
|
|
1404
1942
|
eurcAddress: null,
|
|
1405
1943
|
usdcAddress: '31566704',
|
|
1944
|
+
usdtAddress: null,
|
|
1406
1945
|
cctp: null,
|
|
1407
1946
|
});
|
|
1408
1947
|
|
|
@@ -1426,6 +1965,7 @@ const AlgorandTestnet = defineChain({
|
|
|
1426
1965
|
rpcEndpoints: ['https://testnet-api.algonode.cloud'],
|
|
1427
1966
|
eurcAddress: null,
|
|
1428
1967
|
usdcAddress: '10458941',
|
|
1968
|
+
usdtAddress: null,
|
|
1429
1969
|
cctp: null,
|
|
1430
1970
|
});
|
|
1431
1971
|
|
|
@@ -1449,6 +1989,7 @@ const Aptos = defineChain({
|
|
|
1449
1989
|
rpcEndpoints: ['https://fullnode.mainnet.aptoslabs.com/v1'],
|
|
1450
1990
|
eurcAddress: null,
|
|
1451
1991
|
usdcAddress: '0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b',
|
|
1992
|
+
usdtAddress: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
1452
1993
|
cctp: {
|
|
1453
1994
|
domain: 9,
|
|
1454
1995
|
contracts: {
|
|
@@ -1486,6 +2027,7 @@ const AptosTestnet = defineChain({
|
|
|
1486
2027
|
rpcEndpoints: ['https://fullnode.testnet.aptoslabs.com/v1'],
|
|
1487
2028
|
eurcAddress: null,
|
|
1488
2029
|
usdcAddress: '0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832',
|
|
2030
|
+
usdtAddress: null,
|
|
1489
2031
|
cctp: {
|
|
1490
2032
|
domain: 9,
|
|
1491
2033
|
contracts: {
|
|
@@ -1503,6 +2045,121 @@ const AptosTestnet = defineChain({
|
|
|
1503
2045
|
},
|
|
1504
2046
|
});
|
|
1505
2047
|
|
|
2048
|
+
/**
|
|
2049
|
+
* Complete swap token registry - single source of truth for all swap-supported tokens.
|
|
2050
|
+
*
|
|
2051
|
+
* @remarks
|
|
2052
|
+
* All packages should import from this registry for swap operations.
|
|
2053
|
+
* Adding a new swap token requires updating only this registry.
|
|
2054
|
+
*
|
|
2055
|
+
* The NATIVE token is handled separately as it resolves dynamically based on chain.
|
|
2056
|
+
*
|
|
2057
|
+
* @example
|
|
2058
|
+
* ```typescript
|
|
2059
|
+
* import { SWAP_TOKEN_REGISTRY } from '@core/chains'
|
|
2060
|
+
*
|
|
2061
|
+
* // Get token decimals
|
|
2062
|
+
* const decimals = SWAP_TOKEN_REGISTRY.USDC.decimals // 6
|
|
2063
|
+
*
|
|
2064
|
+
* // Check if token is stablecoin
|
|
2065
|
+
* const isStable = SWAP_TOKEN_REGISTRY.DAI.category === 'stablecoin' // true
|
|
2066
|
+
* ```
|
|
2067
|
+
*/
|
|
2068
|
+
const SWAP_TOKEN_REGISTRY = {
|
|
2069
|
+
// ============================================================================
|
|
2070
|
+
// Stablecoins (6 decimals)
|
|
2071
|
+
// ============================================================================
|
|
2072
|
+
USDC: {
|
|
2073
|
+
symbol: 'USDC',
|
|
2074
|
+
decimals: 6,
|
|
2075
|
+
category: 'stablecoin',
|
|
2076
|
+
description: 'USD Coin',
|
|
2077
|
+
},
|
|
2078
|
+
EURC: {
|
|
2079
|
+
symbol: 'EURC',
|
|
2080
|
+
decimals: 6,
|
|
2081
|
+
category: 'stablecoin',
|
|
2082
|
+
description: 'Euro Coin',
|
|
2083
|
+
},
|
|
2084
|
+
USDT: {
|
|
2085
|
+
symbol: 'USDT',
|
|
2086
|
+
decimals: 6,
|
|
2087
|
+
category: 'stablecoin',
|
|
2088
|
+
description: 'Tether USD',
|
|
2089
|
+
},
|
|
2090
|
+
PYUSD: {
|
|
2091
|
+
symbol: 'PYUSD',
|
|
2092
|
+
decimals: 6,
|
|
2093
|
+
category: 'stablecoin',
|
|
2094
|
+
description: 'PayPal USD',
|
|
2095
|
+
},
|
|
2096
|
+
// ============================================================================
|
|
2097
|
+
// Stablecoins (18 decimals)
|
|
2098
|
+
// ============================================================================
|
|
2099
|
+
DAI: {
|
|
2100
|
+
symbol: 'DAI',
|
|
2101
|
+
decimals: 18,
|
|
2102
|
+
category: 'stablecoin',
|
|
2103
|
+
description: 'MakerDAO stablecoin',
|
|
2104
|
+
},
|
|
2105
|
+
USDE: {
|
|
2106
|
+
symbol: 'USDE',
|
|
2107
|
+
decimals: 18,
|
|
2108
|
+
category: 'stablecoin',
|
|
2109
|
+
description: 'Ethena USD (synthetic dollar)',
|
|
2110
|
+
},
|
|
2111
|
+
// ============================================================================
|
|
2112
|
+
// Wrapped Tokens
|
|
2113
|
+
// ============================================================================
|
|
2114
|
+
WBTC: {
|
|
2115
|
+
symbol: 'WBTC',
|
|
2116
|
+
decimals: 8,
|
|
2117
|
+
category: 'wrapped',
|
|
2118
|
+
description: 'Wrapped Bitcoin',
|
|
2119
|
+
},
|
|
2120
|
+
WETH: {
|
|
2121
|
+
symbol: 'WETH',
|
|
2122
|
+
decimals: 18,
|
|
2123
|
+
category: 'wrapped',
|
|
2124
|
+
description: 'Wrapped Ethereum',
|
|
2125
|
+
},
|
|
2126
|
+
WSOL: {
|
|
2127
|
+
symbol: 'WSOL',
|
|
2128
|
+
decimals: 9,
|
|
2129
|
+
category: 'wrapped',
|
|
2130
|
+
description: 'Wrapped Solana',
|
|
2131
|
+
},
|
|
2132
|
+
WAVAX: {
|
|
2133
|
+
symbol: 'WAVAX',
|
|
2134
|
+
decimals: 18,
|
|
2135
|
+
category: 'wrapped',
|
|
2136
|
+
description: 'Wrapped Avalanche',
|
|
2137
|
+
},
|
|
2138
|
+
WPOL: {
|
|
2139
|
+
symbol: 'WPOL',
|
|
2140
|
+
decimals: 18,
|
|
2141
|
+
category: 'wrapped',
|
|
2142
|
+
description: 'Wrapped Polygon',
|
|
2143
|
+
},
|
|
2144
|
+
};
|
|
2145
|
+
/**
|
|
2146
|
+
* Special NATIVE token constant for swap operations.
|
|
2147
|
+
*
|
|
2148
|
+
* @remarks
|
|
2149
|
+
* NATIVE is handled separately from SWAP_TOKEN_REGISTRY because it resolves
|
|
2150
|
+
* dynamically based on the chain (ETH on Ethereum, SOL on Solana, etc.).
|
|
2151
|
+
* Its decimals are chain-specific.
|
|
2152
|
+
*/
|
|
2153
|
+
const NATIVE_TOKEN = 'NATIVE';
|
|
2154
|
+
/**
|
|
2155
|
+
* Array of all supported swap token symbols including NATIVE.
|
|
2156
|
+
* Useful for iteration, validation, and filtering.
|
|
2157
|
+
*/
|
|
2158
|
+
[
|
|
2159
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
2160
|
+
NATIVE_TOKEN,
|
|
2161
|
+
];
|
|
2162
|
+
|
|
1506
2163
|
/**
|
|
1507
2164
|
* The bridge contract address for EVM testnet networks.
|
|
1508
2165
|
*
|
|
@@ -1519,6 +2176,13 @@ const BRIDGE_CONTRACT_EVM_TESTNET = '0xC5567a5E3370d4DBfB0540025078e283e36A363d'
|
|
|
1519
2176
|
* USDC transfers on live networks.
|
|
1520
2177
|
*/
|
|
1521
2178
|
const BRIDGE_CONTRACT_EVM_MAINNET = '0xB3FA262d0fB521cc93bE83d87b322b8A23DAf3F0';
|
|
2179
|
+
/**
|
|
2180
|
+
* The adapter contract address for EVM mainnet networks.
|
|
2181
|
+
*
|
|
2182
|
+
* This contract serves as an adapter for integrating with various protocols
|
|
2183
|
+
* on EVM-compatible chains. Use this address for mainnet adapter integrations.
|
|
2184
|
+
*/
|
|
2185
|
+
const ADAPTER_CONTRACT_EVM_MAINNET = '0x7FB8c7260b63934d8da38aF902f87ae6e284a845';
|
|
1522
2186
|
|
|
1523
2187
|
/**
|
|
1524
2188
|
* Arc Testnet chain definition
|
|
@@ -1548,6 +2212,7 @@ const ArcTestnet = defineChain({
|
|
|
1548
2212
|
rpcEndpoints: ['https://rpc.testnet.arc.network/'],
|
|
1549
2213
|
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
1550
2214
|
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
2215
|
+
usdtAddress: null,
|
|
1551
2216
|
cctp: {
|
|
1552
2217
|
domain: 26,
|
|
1553
2218
|
contracts: {
|
|
@@ -1590,6 +2255,7 @@ const Arbitrum = defineChain({
|
|
|
1590
2255
|
rpcEndpoints: ['https://arb1.arbitrum.io/rpc'],
|
|
1591
2256
|
eurcAddress: null,
|
|
1592
2257
|
usdcAddress: '0xaf88d065e77c8cc2239327c5edb3a432268e5831',
|
|
2258
|
+
usdtAddress: null,
|
|
1593
2259
|
cctp: {
|
|
1594
2260
|
domain: 3,
|
|
1595
2261
|
contracts: {
|
|
@@ -1614,6 +2280,7 @@ const Arbitrum = defineChain({
|
|
|
1614
2280
|
},
|
|
1615
2281
|
kitContracts: {
|
|
1616
2282
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2283
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1617
2284
|
},
|
|
1618
2285
|
});
|
|
1619
2286
|
|
|
@@ -1638,6 +2305,7 @@ const ArbitrumSepolia = defineChain({
|
|
|
1638
2305
|
rpcEndpoints: ['https://sepolia-rollup.arbitrum.io/rpc'],
|
|
1639
2306
|
eurcAddress: null,
|
|
1640
2307
|
usdcAddress: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
2308
|
+
usdtAddress: null,
|
|
1641
2309
|
cctp: {
|
|
1642
2310
|
domain: 3,
|
|
1643
2311
|
contracts: {
|
|
@@ -1686,6 +2354,7 @@ const Avalanche = defineChain({
|
|
|
1686
2354
|
rpcEndpoints: ['https://api.avax.network/ext/bc/C/rpc'],
|
|
1687
2355
|
eurcAddress: '0xc891eb4cbdeff6e073e859e987815ed1505c2acd',
|
|
1688
2356
|
usdcAddress: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
2357
|
+
usdtAddress: '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7',
|
|
1689
2358
|
cctp: {
|
|
1690
2359
|
domain: 1,
|
|
1691
2360
|
contracts: {
|
|
@@ -1710,6 +2379,7 @@ const Avalanche = defineChain({
|
|
|
1710
2379
|
},
|
|
1711
2380
|
kitContracts: {
|
|
1712
2381
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2382
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1713
2383
|
},
|
|
1714
2384
|
});
|
|
1715
2385
|
|
|
@@ -1733,6 +2403,7 @@ const AvalancheFuji = defineChain({
|
|
|
1733
2403
|
explorerUrl: 'https://subnets-test.avax.network/c-chain/tx/{hash}',
|
|
1734
2404
|
eurcAddress: '0x5e44db7996c682e92a960b65ac713a54ad815c6b',
|
|
1735
2405
|
usdcAddress: '0x5425890298aed601595a70ab815c96711a31bc65',
|
|
2406
|
+
usdtAddress: null,
|
|
1736
2407
|
cctp: {
|
|
1737
2408
|
domain: 1,
|
|
1738
2409
|
contracts: {
|
|
@@ -1782,6 +2453,7 @@ const Base = defineChain({
|
|
|
1782
2453
|
rpcEndpoints: ['https://mainnet.base.org', 'https://base.publicnode.com'],
|
|
1783
2454
|
eurcAddress: '0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42',
|
|
1784
2455
|
usdcAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
2456
|
+
usdtAddress: null,
|
|
1785
2457
|
cctp: {
|
|
1786
2458
|
domain: 6,
|
|
1787
2459
|
contracts: {
|
|
@@ -1806,6 +2478,7 @@ const Base = defineChain({
|
|
|
1806
2478
|
},
|
|
1807
2479
|
kitContracts: {
|
|
1808
2480
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2481
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1809
2482
|
},
|
|
1810
2483
|
});
|
|
1811
2484
|
|
|
@@ -1830,6 +2503,7 @@ const BaseSepolia = defineChain({
|
|
|
1830
2503
|
rpcEndpoints: ['https://sepolia.base.org'],
|
|
1831
2504
|
eurcAddress: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
1832
2505
|
usdcAddress: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
2506
|
+
usdtAddress: null,
|
|
1833
2507
|
cctp: {
|
|
1834
2508
|
domain: 6,
|
|
1835
2509
|
contracts: {
|
|
@@ -1878,6 +2552,7 @@ const Celo = defineChain({
|
|
|
1878
2552
|
rpcEndpoints: ['https://forno.celo.org'],
|
|
1879
2553
|
eurcAddress: null,
|
|
1880
2554
|
usdcAddress: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
2555
|
+
usdtAddress: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
1881
2556
|
cctp: null,
|
|
1882
2557
|
});
|
|
1883
2558
|
|
|
@@ -1902,6 +2577,7 @@ const CeloAlfajoresTestnet = defineChain({
|
|
|
1902
2577
|
rpcEndpoints: ['https://alfajores-forno.celo-testnet.org'],
|
|
1903
2578
|
eurcAddress: null,
|
|
1904
2579
|
usdcAddress: '0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B',
|
|
2580
|
+
usdtAddress: null,
|
|
1905
2581
|
cctp: null,
|
|
1906
2582
|
});
|
|
1907
2583
|
|
|
@@ -1926,62 +2602,152 @@ const Codex = defineChain({
|
|
|
1926
2602
|
rpcEndpoints: ['https://rpc.codex.xyz'],
|
|
1927
2603
|
eurcAddress: null,
|
|
1928
2604
|
usdcAddress: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
2605
|
+
usdtAddress: null,
|
|
2606
|
+
cctp: {
|
|
2607
|
+
domain: 12,
|
|
2608
|
+
contracts: {
|
|
2609
|
+
v2: {
|
|
2610
|
+
type: 'split',
|
|
2611
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
2612
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
2613
|
+
confirmations: 65,
|
|
2614
|
+
fastConfirmations: 1,
|
|
2615
|
+
},
|
|
2616
|
+
},
|
|
2617
|
+
forwarderSupported: {
|
|
2618
|
+
source: true,
|
|
2619
|
+
destination: false,
|
|
2620
|
+
},
|
|
2621
|
+
},
|
|
2622
|
+
kitContracts: {
|
|
2623
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2624
|
+
},
|
|
2625
|
+
});
|
|
2626
|
+
|
|
2627
|
+
/**
|
|
2628
|
+
* Codex Testnet chain definition
|
|
2629
|
+
* @remarks
|
|
2630
|
+
* This represents the test network for the Codex blockchain.
|
|
2631
|
+
*/
|
|
2632
|
+
const CodexTestnet = defineChain({
|
|
2633
|
+
type: 'evm',
|
|
2634
|
+
chain: Blockchain.Codex_Testnet,
|
|
2635
|
+
name: 'Codex Testnet',
|
|
2636
|
+
title: 'Codex Testnet',
|
|
2637
|
+
nativeCurrency: {
|
|
2638
|
+
name: 'ETH',
|
|
2639
|
+
symbol: 'ETH',
|
|
2640
|
+
decimals: 18,
|
|
2641
|
+
},
|
|
2642
|
+
chainId: 812242,
|
|
2643
|
+
isTestnet: true,
|
|
2644
|
+
explorerUrl: 'https://explorer.codex-stg.xyz/tx/{hash}',
|
|
2645
|
+
rpcEndpoints: ['https://rpc.codex-stg.xyz'],
|
|
2646
|
+
eurcAddress: null,
|
|
2647
|
+
usdcAddress: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
2648
|
+
usdtAddress: null,
|
|
1929
2649
|
cctp: {
|
|
1930
2650
|
domain: 12,
|
|
1931
2651
|
contracts: {
|
|
1932
2652
|
v2: {
|
|
1933
2653
|
type: 'split',
|
|
1934
|
-
tokenMessenger: '
|
|
1935
|
-
messageTransmitter: '
|
|
2654
|
+
tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
|
|
2655
|
+
messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
|
|
2656
|
+
confirmations: 65,
|
|
2657
|
+
fastConfirmations: 1,
|
|
2658
|
+
},
|
|
2659
|
+
},
|
|
2660
|
+
forwarderSupported: {
|
|
2661
|
+
source: true,
|
|
2662
|
+
destination: false,
|
|
2663
|
+
},
|
|
2664
|
+
},
|
|
2665
|
+
kitContracts: {
|
|
2666
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
2667
|
+
},
|
|
2668
|
+
});
|
|
2669
|
+
|
|
2670
|
+
/**
|
|
2671
|
+
* Edge Mainnet chain definition
|
|
2672
|
+
* @remarks
|
|
2673
|
+
* This represents the official production network for the Edge blockchain.
|
|
2674
|
+
* Edge is an EVM-compatible blockchain.
|
|
2675
|
+
*/
|
|
2676
|
+
const Edge = defineChain({
|
|
2677
|
+
type: 'evm',
|
|
2678
|
+
chain: Blockchain.Edge,
|
|
2679
|
+
name: 'Edge',
|
|
2680
|
+
title: 'Edge Mainnet',
|
|
2681
|
+
nativeCurrency: {
|
|
2682
|
+
name: 'Ether',
|
|
2683
|
+
symbol: 'ETH',
|
|
2684
|
+
decimals: 18,
|
|
2685
|
+
},
|
|
2686
|
+
chainId: 3343,
|
|
2687
|
+
isTestnet: false,
|
|
2688
|
+
explorerUrl: 'https://pro.edgex.exchange/en-US/explorer/tx/{hash}',
|
|
2689
|
+
rpcEndpoints: ['https://edge-mainnet.g.alchemy.com/public'],
|
|
2690
|
+
eurcAddress: null,
|
|
2691
|
+
usdcAddress: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
2692
|
+
usdtAddress: null,
|
|
2693
|
+
cctp: {
|
|
2694
|
+
domain: 28,
|
|
2695
|
+
contracts: {
|
|
2696
|
+
v2: {
|
|
2697
|
+
type: 'split',
|
|
2698
|
+
tokenMessenger: '0x98706A006bc632Df31CAdFCBD43F38887ce2ca5c',
|
|
2699
|
+
messageTransmitter: '0x5b61381Fc9e58E70EfC13a4A97516997019198ee',
|
|
1936
2700
|
confirmations: 65,
|
|
1937
2701
|
fastConfirmations: 1,
|
|
1938
2702
|
},
|
|
1939
2703
|
},
|
|
1940
2704
|
forwarderSupported: {
|
|
1941
2705
|
source: true,
|
|
1942
|
-
destination:
|
|
2706
|
+
destination: true,
|
|
1943
2707
|
},
|
|
1944
2708
|
},
|
|
1945
2709
|
kitContracts: {
|
|
1946
|
-
bridge:
|
|
2710
|
+
bridge: '0x6D1AaE1c34Aeb582022916a67f2A655C6f4eDFF2', //Unique bridge address as CCTP address for Edge is also unique
|
|
1947
2711
|
},
|
|
1948
2712
|
});
|
|
1949
2713
|
|
|
1950
2714
|
/**
|
|
1951
|
-
*
|
|
2715
|
+
* Edge Testnet chain definition
|
|
1952
2716
|
* @remarks
|
|
1953
|
-
* This represents the test network for the
|
|
2717
|
+
* This represents the official test network for the Edge blockchain.
|
|
2718
|
+
* Edge is an EVM-compatible blockchain.
|
|
1954
2719
|
*/
|
|
1955
|
-
const
|
|
2720
|
+
const EdgeTestnet = defineChain({
|
|
1956
2721
|
type: 'evm',
|
|
1957
|
-
chain: Blockchain.
|
|
1958
|
-
name: '
|
|
1959
|
-
title: '
|
|
2722
|
+
chain: Blockchain.Edge_Testnet,
|
|
2723
|
+
name: 'Edge Testnet',
|
|
2724
|
+
title: 'Edge Testnet',
|
|
1960
2725
|
nativeCurrency: {
|
|
1961
|
-
name: '
|
|
2726
|
+
name: 'Ether',
|
|
1962
2727
|
symbol: 'ETH',
|
|
1963
2728
|
decimals: 18,
|
|
1964
2729
|
},
|
|
1965
|
-
chainId:
|
|
2730
|
+
chainId: 33431,
|
|
1966
2731
|
isTestnet: true,
|
|
1967
|
-
explorerUrl: 'https://explorer.
|
|
1968
|
-
rpcEndpoints: ['https://
|
|
2732
|
+
explorerUrl: 'https://edge-testnet.explorer.alchemy.com/tx/{hash}',
|
|
2733
|
+
rpcEndpoints: ['https://edge-testnet.g.alchemy.com/public'],
|
|
1969
2734
|
eurcAddress: null,
|
|
1970
|
-
usdcAddress: '
|
|
2735
|
+
usdcAddress: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
2736
|
+
usdtAddress: null,
|
|
1971
2737
|
cctp: {
|
|
1972
|
-
domain:
|
|
2738
|
+
domain: 28,
|
|
1973
2739
|
contracts: {
|
|
1974
2740
|
v2: {
|
|
1975
2741
|
type: 'split',
|
|
1976
|
-
tokenMessenger: '
|
|
1977
|
-
messageTransmitter: '
|
|
2742
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
2743
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
1978
2744
|
confirmations: 65,
|
|
1979
2745
|
fastConfirmations: 1,
|
|
1980
2746
|
},
|
|
1981
2747
|
},
|
|
1982
2748
|
forwarderSupported: {
|
|
1983
2749
|
source: true,
|
|
1984
|
-
destination:
|
|
2750
|
+
destination: true,
|
|
1985
2751
|
},
|
|
1986
2752
|
},
|
|
1987
2753
|
kitContracts: {
|
|
@@ -2010,6 +2776,7 @@ const Ethereum = defineChain({
|
|
|
2010
2776
|
rpcEndpoints: ['https://eth.merkle.io', 'https://ethereum.publicnode.com'],
|
|
2011
2777
|
eurcAddress: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
2012
2778
|
usdcAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
2779
|
+
usdtAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7',
|
|
2013
2780
|
cctp: {
|
|
2014
2781
|
domain: 0,
|
|
2015
2782
|
contracts: {
|
|
@@ -2034,6 +2801,7 @@ const Ethereum = defineChain({
|
|
|
2034
2801
|
},
|
|
2035
2802
|
kitContracts: {
|
|
2036
2803
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2804
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2037
2805
|
},
|
|
2038
2806
|
});
|
|
2039
2807
|
|
|
@@ -2058,6 +2826,7 @@ const EthereumSepolia = defineChain({
|
|
|
2058
2826
|
rpcEndpoints: ['https://sepolia.drpc.org'],
|
|
2059
2827
|
eurcAddress: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4',
|
|
2060
2828
|
usdcAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
2829
|
+
usdtAddress: null,
|
|
2061
2830
|
cctp: {
|
|
2062
2831
|
domain: 0,
|
|
2063
2832
|
contracts: {
|
|
@@ -2105,6 +2874,7 @@ const Hedera = defineChain({
|
|
|
2105
2874
|
rpcEndpoints: ['https://mainnet.hashio.io/api'],
|
|
2106
2875
|
eurcAddress: null,
|
|
2107
2876
|
usdcAddress: '0.0.456858',
|
|
2877
|
+
usdtAddress: null,
|
|
2108
2878
|
cctp: null,
|
|
2109
2879
|
});
|
|
2110
2880
|
|
|
@@ -2128,6 +2898,7 @@ const HederaTestnet = defineChain({
|
|
|
2128
2898
|
rpcEndpoints: ['https://testnet.hashio.io/api'],
|
|
2129
2899
|
eurcAddress: null,
|
|
2130
2900
|
usdcAddress: '0.0.429274',
|
|
2901
|
+
usdtAddress: null,
|
|
2131
2902
|
cctp: null,
|
|
2132
2903
|
});
|
|
2133
2904
|
|
|
@@ -2154,6 +2925,7 @@ const HyperEVM = defineChain({
|
|
|
2154
2925
|
rpcEndpoints: ['https://rpc.hyperliquid.xyz/evm'],
|
|
2155
2926
|
eurcAddress: null,
|
|
2156
2927
|
usdcAddress: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
2928
|
+
usdtAddress: null,
|
|
2157
2929
|
cctp: {
|
|
2158
2930
|
domain: 19,
|
|
2159
2931
|
contracts: {
|
|
@@ -2172,6 +2944,7 @@ const HyperEVM = defineChain({
|
|
|
2172
2944
|
},
|
|
2173
2945
|
kitContracts: {
|
|
2174
2946
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2947
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2175
2948
|
},
|
|
2176
2949
|
});
|
|
2177
2950
|
|
|
@@ -2197,6 +2970,7 @@ const HyperEVMTestnet = defineChain({
|
|
|
2197
2970
|
rpcEndpoints: ['https://rpc.hyperliquid-testnet.xyz/evm'],
|
|
2198
2971
|
eurcAddress: null,
|
|
2199
2972
|
usdcAddress: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
2973
|
+
usdtAddress: null,
|
|
2200
2974
|
cctp: {
|
|
2201
2975
|
domain: 19,
|
|
2202
2976
|
contracts: {
|
|
@@ -2244,6 +3018,7 @@ const Ink = defineChain({
|
|
|
2244
3018
|
],
|
|
2245
3019
|
eurcAddress: null,
|
|
2246
3020
|
usdcAddress: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
3021
|
+
usdtAddress: null,
|
|
2247
3022
|
cctp: {
|
|
2248
3023
|
domain: 21,
|
|
2249
3024
|
contracts: {
|
|
@@ -2262,6 +3037,7 @@ const Ink = defineChain({
|
|
|
2262
3037
|
},
|
|
2263
3038
|
kitContracts: {
|
|
2264
3039
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3040
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2265
3041
|
},
|
|
2266
3042
|
});
|
|
2267
3043
|
|
|
@@ -2290,6 +3066,7 @@ const InkTestnet = defineChain({
|
|
|
2290
3066
|
],
|
|
2291
3067
|
eurcAddress: null,
|
|
2292
3068
|
usdcAddress: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
3069
|
+
usdtAddress: null,
|
|
2293
3070
|
cctp: {
|
|
2294
3071
|
domain: 21,
|
|
2295
3072
|
contracts: {
|
|
@@ -2332,6 +3109,7 @@ const Linea = defineChain({
|
|
|
2332
3109
|
rpcEndpoints: ['https://rpc.linea.build'],
|
|
2333
3110
|
eurcAddress: null,
|
|
2334
3111
|
usdcAddress: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
3112
|
+
usdtAddress: null,
|
|
2335
3113
|
cctp: {
|
|
2336
3114
|
domain: 11,
|
|
2337
3115
|
contracts: {
|
|
@@ -2350,6 +3128,7 @@ const Linea = defineChain({
|
|
|
2350
3128
|
},
|
|
2351
3129
|
kitContracts: {
|
|
2352
3130
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3131
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2353
3132
|
},
|
|
2354
3133
|
});
|
|
2355
3134
|
|
|
@@ -2374,6 +3153,7 @@ const LineaSepolia = defineChain({
|
|
|
2374
3153
|
rpcEndpoints: ['https://rpc.sepolia.linea.build'],
|
|
2375
3154
|
eurcAddress: null,
|
|
2376
3155
|
usdcAddress: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
3156
|
+
usdtAddress: null,
|
|
2377
3157
|
cctp: {
|
|
2378
3158
|
domain: 11,
|
|
2379
3159
|
contracts: {
|
|
@@ -2418,6 +3198,7 @@ const Monad = defineChain({
|
|
|
2418
3198
|
rpcEndpoints: ['https://rpc.monad.xyz'],
|
|
2419
3199
|
eurcAddress: null,
|
|
2420
3200
|
usdcAddress: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
3201
|
+
usdtAddress: null,
|
|
2421
3202
|
cctp: {
|
|
2422
3203
|
domain: 15,
|
|
2423
3204
|
contracts: {
|
|
@@ -2436,6 +3217,7 @@ const Monad = defineChain({
|
|
|
2436
3217
|
},
|
|
2437
3218
|
kitContracts: {
|
|
2438
3219
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3220
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2439
3221
|
},
|
|
2440
3222
|
});
|
|
2441
3223
|
|
|
@@ -2462,6 +3244,7 @@ const MonadTestnet = defineChain({
|
|
|
2462
3244
|
rpcEndpoints: ['https://testnet-rpc.monad.xyz'],
|
|
2463
3245
|
eurcAddress: null,
|
|
2464
3246
|
usdcAddress: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
3247
|
+
usdtAddress: null,
|
|
2465
3248
|
cctp: {
|
|
2466
3249
|
domain: 15,
|
|
2467
3250
|
contracts: {
|
|
@@ -2483,6 +3266,94 @@ const MonadTestnet = defineChain({
|
|
|
2483
3266
|
},
|
|
2484
3267
|
});
|
|
2485
3268
|
|
|
3269
|
+
/**
|
|
3270
|
+
* Morph Mainnet chain definition
|
|
3271
|
+
* @remarks
|
|
3272
|
+
* This represents the official production network for the Morph blockchain.
|
|
3273
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
3274
|
+
*/
|
|
3275
|
+
const Morph = defineChain({
|
|
3276
|
+
type: 'evm',
|
|
3277
|
+
chain: Blockchain.Morph,
|
|
3278
|
+
name: 'Morph',
|
|
3279
|
+
title: 'Morph Mainnet',
|
|
3280
|
+
nativeCurrency: {
|
|
3281
|
+
name: 'Ether',
|
|
3282
|
+
symbol: 'ETH',
|
|
3283
|
+
decimals: 18,
|
|
3284
|
+
},
|
|
3285
|
+
chainId: 2818,
|
|
3286
|
+
isTestnet: false,
|
|
3287
|
+
explorerUrl: 'https://explorer.morph.network/tx/{hash}',
|
|
3288
|
+
rpcEndpoints: ['https://rpc.morphl2.io'],
|
|
3289
|
+
eurcAddress: null,
|
|
3290
|
+
usdcAddress: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
3291
|
+
usdtAddress: null,
|
|
3292
|
+
cctp: {
|
|
3293
|
+
domain: 30,
|
|
3294
|
+
contracts: {
|
|
3295
|
+
v2: {
|
|
3296
|
+
type: 'split',
|
|
3297
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
3298
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
3299
|
+
confirmations: 64,
|
|
3300
|
+
fastConfirmations: 1,
|
|
3301
|
+
},
|
|
3302
|
+
},
|
|
3303
|
+
forwarderSupported: {
|
|
3304
|
+
source: false,
|
|
3305
|
+
destination: false,
|
|
3306
|
+
},
|
|
3307
|
+
},
|
|
3308
|
+
kitContracts: {
|
|
3309
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3310
|
+
},
|
|
3311
|
+
});
|
|
3312
|
+
|
|
3313
|
+
/**
|
|
3314
|
+
* Morph Hoodi Testnet chain definition
|
|
3315
|
+
* @remarks
|
|
3316
|
+
* This represents the official test network for the Morph blockchain.
|
|
3317
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
3318
|
+
*/
|
|
3319
|
+
const MorphTestnet = defineChain({
|
|
3320
|
+
type: 'evm',
|
|
3321
|
+
chain: Blockchain.Morph_Testnet,
|
|
3322
|
+
name: 'Morph Hoodi',
|
|
3323
|
+
title: 'Morph Hoodi Testnet',
|
|
3324
|
+
nativeCurrency: {
|
|
3325
|
+
name: 'Ether',
|
|
3326
|
+
symbol: 'ETH',
|
|
3327
|
+
decimals: 18,
|
|
3328
|
+
},
|
|
3329
|
+
chainId: 2910,
|
|
3330
|
+
isTestnet: true,
|
|
3331
|
+
explorerUrl: 'https://explorer-hoodi.morphl2.io/tx/{hash}',
|
|
3332
|
+
rpcEndpoints: ['https://rpc-hoodi.morphl2.io'],
|
|
3333
|
+
eurcAddress: null,
|
|
3334
|
+
usdcAddress: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
3335
|
+
usdtAddress: null,
|
|
3336
|
+
cctp: {
|
|
3337
|
+
domain: 30,
|
|
3338
|
+
contracts: {
|
|
3339
|
+
v2: {
|
|
3340
|
+
type: 'split',
|
|
3341
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
3342
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
3343
|
+
confirmations: 64,
|
|
3344
|
+
fastConfirmations: 1,
|
|
3345
|
+
},
|
|
3346
|
+
},
|
|
3347
|
+
forwarderSupported: {
|
|
3348
|
+
source: false,
|
|
3349
|
+
destination: false,
|
|
3350
|
+
},
|
|
3351
|
+
},
|
|
3352
|
+
kitContracts: {
|
|
3353
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
3354
|
+
},
|
|
3355
|
+
});
|
|
3356
|
+
|
|
2486
3357
|
/**
|
|
2487
3358
|
* NEAR Protocol Mainnet chain definition
|
|
2488
3359
|
* @remarks
|
|
@@ -2503,6 +3374,7 @@ const NEAR = defineChain({
|
|
|
2503
3374
|
rpcEndpoints: ['https://eth-rpc.mainnet.near.org'],
|
|
2504
3375
|
eurcAddress: null,
|
|
2505
3376
|
usdcAddress: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
3377
|
+
usdtAddress: 'usdt.tether-token.near',
|
|
2506
3378
|
cctp: null,
|
|
2507
3379
|
});
|
|
2508
3380
|
|
|
@@ -2526,6 +3398,7 @@ const NEARTestnet = defineChain({
|
|
|
2526
3398
|
rpcEndpoints: ['https://eth-rpc.testnet.near.org'],
|
|
2527
3399
|
eurcAddress: null,
|
|
2528
3400
|
usdcAddress: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
3401
|
+
usdtAddress: null,
|
|
2529
3402
|
cctp: null,
|
|
2530
3403
|
});
|
|
2531
3404
|
|
|
@@ -2549,6 +3422,7 @@ const Noble = defineChain({
|
|
|
2549
3422
|
rpcEndpoints: ['https://noble-rpc.polkachu.com'],
|
|
2550
3423
|
eurcAddress: null,
|
|
2551
3424
|
usdcAddress: 'uusdc',
|
|
3425
|
+
usdtAddress: null,
|
|
2552
3426
|
cctp: {
|
|
2553
3427
|
domain: 4,
|
|
2554
3428
|
contracts: {
|
|
@@ -2585,6 +3459,7 @@ const NobleTestnet = defineChain({
|
|
|
2585
3459
|
rpcEndpoints: ['https://noble-testnet-rpc.polkachu.com'],
|
|
2586
3460
|
eurcAddress: null,
|
|
2587
3461
|
usdcAddress: 'uusdc',
|
|
3462
|
+
usdtAddress: null,
|
|
2588
3463
|
cctp: {
|
|
2589
3464
|
domain: 4,
|
|
2590
3465
|
contracts: {
|
|
@@ -2622,6 +3497,7 @@ const Optimism = defineChain({
|
|
|
2622
3497
|
rpcEndpoints: ['https://mainnet.optimism.io'],
|
|
2623
3498
|
eurcAddress: null,
|
|
2624
3499
|
usdcAddress: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
3500
|
+
usdtAddress: null,
|
|
2625
3501
|
cctp: {
|
|
2626
3502
|
domain: 2,
|
|
2627
3503
|
contracts: {
|
|
@@ -2646,6 +3522,7 @@ const Optimism = defineChain({
|
|
|
2646
3522
|
},
|
|
2647
3523
|
kitContracts: {
|
|
2648
3524
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3525
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2649
3526
|
},
|
|
2650
3527
|
});
|
|
2651
3528
|
|
|
@@ -2670,6 +3547,7 @@ const OptimismSepolia = defineChain({
|
|
|
2670
3547
|
rpcEndpoints: ['https://sepolia.optimism.io'],
|
|
2671
3548
|
eurcAddress: null,
|
|
2672
3549
|
usdcAddress: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
3550
|
+
usdtAddress: null,
|
|
2673
3551
|
cctp: {
|
|
2674
3552
|
domain: 2,
|
|
2675
3553
|
contracts: {
|
|
@@ -2720,6 +3598,7 @@ const Plume = defineChain({
|
|
|
2720
3598
|
rpcEndpoints: ['https://rpc.plume.org'],
|
|
2721
3599
|
eurcAddress: null,
|
|
2722
3600
|
usdcAddress: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
3601
|
+
usdtAddress: null,
|
|
2723
3602
|
cctp: {
|
|
2724
3603
|
domain: 22,
|
|
2725
3604
|
contracts: {
|
|
@@ -2738,6 +3617,7 @@ const Plume = defineChain({
|
|
|
2738
3617
|
},
|
|
2739
3618
|
kitContracts: {
|
|
2740
3619
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3620
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2741
3621
|
},
|
|
2742
3622
|
});
|
|
2743
3623
|
|
|
@@ -2763,6 +3643,7 @@ const PlumeTestnet = defineChain({
|
|
|
2763
3643
|
rpcEndpoints: ['https://testnet-rpc.plume.org'],
|
|
2764
3644
|
eurcAddress: null,
|
|
2765
3645
|
usdcAddress: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
3646
|
+
usdtAddress: null,
|
|
2766
3647
|
cctp: {
|
|
2767
3648
|
domain: 22,
|
|
2768
3649
|
contracts: {
|
|
@@ -2804,6 +3685,7 @@ const PolkadotAssetHub = defineChain({
|
|
|
2804
3685
|
rpcEndpoints: ['https://asset-hub-polkadot-rpc.n.dwellir.com'],
|
|
2805
3686
|
eurcAddress: null,
|
|
2806
3687
|
usdcAddress: '1337',
|
|
3688
|
+
usdtAddress: '1984',
|
|
2807
3689
|
cctp: null,
|
|
2808
3690
|
});
|
|
2809
3691
|
|
|
@@ -2827,6 +3709,7 @@ const PolkadotWestmint = defineChain({
|
|
|
2827
3709
|
rpcEndpoints: ['https://westmint-rpc.polkadot.io'],
|
|
2828
3710
|
eurcAddress: null,
|
|
2829
3711
|
usdcAddress: 'Asset ID 31337',
|
|
3712
|
+
usdtAddress: null,
|
|
2830
3713
|
cctp: null,
|
|
2831
3714
|
});
|
|
2832
3715
|
|
|
@@ -2848,9 +3731,10 @@ const Polygon = defineChain({
|
|
|
2848
3731
|
chainId: 137,
|
|
2849
3732
|
isTestnet: false,
|
|
2850
3733
|
explorerUrl: 'https://polygonscan.com/tx/{hash}',
|
|
2851
|
-
rpcEndpoints: ['https://polygon
|
|
3734
|
+
rpcEndpoints: ['https://polygon.publicnode.com', 'https://polygon.drpc.org'],
|
|
2852
3735
|
eurcAddress: null,
|
|
2853
3736
|
usdcAddress: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
3737
|
+
usdtAddress: null,
|
|
2854
3738
|
cctp: {
|
|
2855
3739
|
domain: 7,
|
|
2856
3740
|
contracts: {
|
|
@@ -2875,6 +3759,7 @@ const Polygon = defineChain({
|
|
|
2875
3759
|
},
|
|
2876
3760
|
kitContracts: {
|
|
2877
3761
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3762
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2878
3763
|
},
|
|
2879
3764
|
});
|
|
2880
3765
|
|
|
@@ -2899,6 +3784,7 @@ const PolygonAmoy = defineChain({
|
|
|
2899
3784
|
rpcEndpoints: ['https://rpc-amoy.polygon.technology'],
|
|
2900
3785
|
eurcAddress: null,
|
|
2901
3786
|
usdcAddress: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
3787
|
+
usdtAddress: null,
|
|
2902
3788
|
cctp: {
|
|
2903
3789
|
domain: 7,
|
|
2904
3790
|
contracts: {
|
|
@@ -2949,6 +3835,7 @@ const Sei = defineChain({
|
|
|
2949
3835
|
rpcEndpoints: ['https://evm-rpc.sei-apis.com'],
|
|
2950
3836
|
eurcAddress: null,
|
|
2951
3837
|
usdcAddress: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
3838
|
+
usdtAddress: null,
|
|
2952
3839
|
cctp: {
|
|
2953
3840
|
domain: 16,
|
|
2954
3841
|
contracts: {
|
|
@@ -2967,6 +3854,7 @@ const Sei = defineChain({
|
|
|
2967
3854
|
},
|
|
2968
3855
|
kitContracts: {
|
|
2969
3856
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3857
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2970
3858
|
},
|
|
2971
3859
|
});
|
|
2972
3860
|
|
|
@@ -2992,6 +3880,7 @@ const SeiTestnet = defineChain({
|
|
|
2992
3880
|
rpcEndpoints: ['https://evm-rpc-testnet.sei-apis.com'],
|
|
2993
3881
|
eurcAddress: null,
|
|
2994
3882
|
usdcAddress: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
3883
|
+
usdtAddress: null,
|
|
2995
3884
|
cctp: {
|
|
2996
3885
|
domain: 16,
|
|
2997
3886
|
contracts: {
|
|
@@ -3034,6 +3923,7 @@ const Sonic = defineChain({
|
|
|
3034
3923
|
rpcEndpoints: ['https://rpc.soniclabs.com'],
|
|
3035
3924
|
eurcAddress: null,
|
|
3036
3925
|
usdcAddress: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
3926
|
+
usdtAddress: null,
|
|
3037
3927
|
cctp: {
|
|
3038
3928
|
domain: 13,
|
|
3039
3929
|
contracts: {
|
|
@@ -3052,6 +3942,7 @@ const Sonic = defineChain({
|
|
|
3052
3942
|
},
|
|
3053
3943
|
kitContracts: {
|
|
3054
3944
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3945
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
3055
3946
|
},
|
|
3056
3947
|
});
|
|
3057
3948
|
|
|
@@ -3076,6 +3967,7 @@ const SonicTestnet = defineChain({
|
|
|
3076
3967
|
rpcEndpoints: ['https://rpc.testnet.soniclabs.com'],
|
|
3077
3968
|
eurcAddress: null,
|
|
3078
3969
|
usdcAddress: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
3970
|
+
usdtAddress: null,
|
|
3079
3971
|
cctp: {
|
|
3080
3972
|
domain: 13,
|
|
3081
3973
|
contracts: {
|
|
@@ -3117,6 +4009,7 @@ const Solana = defineChain({
|
|
|
3117
4009
|
rpcEndpoints: ['https://api.mainnet-beta.solana.com'],
|
|
3118
4010
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
3119
4011
|
usdcAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
4012
|
+
usdtAddress: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
3120
4013
|
cctp: {
|
|
3121
4014
|
domain: 5,
|
|
3122
4015
|
contracts: {
|
|
@@ -3163,6 +4056,7 @@ const SolanaDevnet = defineChain({
|
|
|
3163
4056
|
explorerUrl: 'https://solscan.io/tx/{hash}?cluster=devnet',
|
|
3164
4057
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
3165
4058
|
usdcAddress: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
4059
|
+
usdtAddress: null,
|
|
3166
4060
|
cctp: {
|
|
3167
4061
|
domain: 5,
|
|
3168
4062
|
contracts: {
|
|
@@ -3211,6 +4105,7 @@ const Stellar = defineChain({
|
|
|
3211
4105
|
rpcEndpoints: ['https://horizon.stellar.org'],
|
|
3212
4106
|
eurcAddress: 'EURC-GDHU6WRG4IEQXM5NZ4BMPKOXHW76MZM4Y2IEMFDVXBSDP6SJY4ITNPP2',
|
|
3213
4107
|
usdcAddress: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
4108
|
+
usdtAddress: null,
|
|
3214
4109
|
cctp: null,
|
|
3215
4110
|
});
|
|
3216
4111
|
|
|
@@ -3234,6 +4129,7 @@ const StellarTestnet = defineChain({
|
|
|
3234
4129
|
rpcEndpoints: ['https://horizon-testnet.stellar.org'],
|
|
3235
4130
|
eurcAddress: 'EURC-GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO',
|
|
3236
4131
|
usdcAddress: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
4132
|
+
usdtAddress: null,
|
|
3237
4133
|
cctp: null,
|
|
3238
4134
|
});
|
|
3239
4135
|
|
|
@@ -3257,6 +4153,7 @@ const Sui = defineChain({
|
|
|
3257
4153
|
rpcEndpoints: ['https://fullnode.mainnet.sui.io'],
|
|
3258
4154
|
eurcAddress: null,
|
|
3259
4155
|
usdcAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
4156
|
+
usdtAddress: null,
|
|
3260
4157
|
cctp: {
|
|
3261
4158
|
domain: 8,
|
|
3262
4159
|
contracts: {
|
|
@@ -3294,6 +4191,7 @@ const SuiTestnet = defineChain({
|
|
|
3294
4191
|
rpcEndpoints: ['https://fullnode.testnet.sui.io'],
|
|
3295
4192
|
eurcAddress: null,
|
|
3296
4193
|
usdcAddress: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
4194
|
+
usdtAddress: null,
|
|
3297
4195
|
cctp: {
|
|
3298
4196
|
domain: 8,
|
|
3299
4197
|
contracts: {
|
|
@@ -3332,6 +4230,7 @@ const Unichain = defineChain({
|
|
|
3332
4230
|
rpcEndpoints: ['https://mainnet.unichain.org'],
|
|
3333
4231
|
eurcAddress: null,
|
|
3334
4232
|
usdcAddress: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
4233
|
+
usdtAddress: null,
|
|
3335
4234
|
cctp: {
|
|
3336
4235
|
domain: 10,
|
|
3337
4236
|
contracts: {
|
|
@@ -3356,6 +4255,7 @@ const Unichain = defineChain({
|
|
|
3356
4255
|
},
|
|
3357
4256
|
kitContracts: {
|
|
3358
4257
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
4258
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
3359
4259
|
},
|
|
3360
4260
|
});
|
|
3361
4261
|
|
|
@@ -3380,6 +4280,7 @@ const UnichainSepolia = defineChain({
|
|
|
3380
4280
|
rpcEndpoints: ['https://sepolia.unichain.org'],
|
|
3381
4281
|
eurcAddress: null,
|
|
3382
4282
|
usdcAddress: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
4283
|
+
usdtAddress: null,
|
|
3383
4284
|
cctp: {
|
|
3384
4285
|
domain: 10,
|
|
3385
4286
|
contracts: {
|
|
@@ -3428,6 +4329,7 @@ const WorldChain = defineChain({
|
|
|
3428
4329
|
rpcEndpoints: ['https://worldchain-mainnet.g.alchemy.com/public'],
|
|
3429
4330
|
eurcAddress: null,
|
|
3430
4331
|
usdcAddress: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
4332
|
+
usdtAddress: null,
|
|
3431
4333
|
cctp: {
|
|
3432
4334
|
domain: 14,
|
|
3433
4335
|
contracts: {
|
|
@@ -3446,6 +4348,7 @@ const WorldChain = defineChain({
|
|
|
3446
4348
|
},
|
|
3447
4349
|
kitContracts: {
|
|
3448
4350
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
4351
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
3449
4352
|
},
|
|
3450
4353
|
});
|
|
3451
4354
|
|
|
@@ -3473,6 +4376,7 @@ const WorldChainSepolia = defineChain({
|
|
|
3473
4376
|
],
|
|
3474
4377
|
eurcAddress: null,
|
|
3475
4378
|
usdcAddress: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
4379
|
+
usdtAddress: null,
|
|
3476
4380
|
cctp: {
|
|
3477
4381
|
domain: 14,
|
|
3478
4382
|
contracts: {
|
|
@@ -3517,6 +4421,7 @@ const XDC = defineChain({
|
|
|
3517
4421
|
rpcEndpoints: ['https://erpc.xdcrpc.com', 'https://erpc.xinfin.network'],
|
|
3518
4422
|
eurcAddress: null,
|
|
3519
4423
|
usdcAddress: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
4424
|
+
usdtAddress: null,
|
|
3520
4425
|
cctp: {
|
|
3521
4426
|
domain: 18,
|
|
3522
4427
|
contracts: {
|
|
@@ -3535,6 +4440,7 @@ const XDC = defineChain({
|
|
|
3535
4440
|
},
|
|
3536
4441
|
kitContracts: {
|
|
3537
4442
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
4443
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
3538
4444
|
},
|
|
3539
4445
|
});
|
|
3540
4446
|
|
|
@@ -3559,6 +4465,7 @@ const XDCApothem = defineChain({
|
|
|
3559
4465
|
rpcEndpoints: ['https://erpc.apothem.network'],
|
|
3560
4466
|
eurcAddress: null,
|
|
3561
4467
|
usdcAddress: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
4468
|
+
usdtAddress: null,
|
|
3562
4469
|
cctp: {
|
|
3563
4470
|
domain: 18,
|
|
3564
4471
|
contracts: {
|
|
@@ -3601,6 +4508,7 @@ const ZKSyncEra = defineChain({
|
|
|
3601
4508
|
rpcEndpoints: ['https://mainnet.era.zksync.io'],
|
|
3602
4509
|
eurcAddress: null,
|
|
3603
4510
|
usdcAddress: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
4511
|
+
usdtAddress: null,
|
|
3604
4512
|
cctp: null,
|
|
3605
4513
|
});
|
|
3606
4514
|
|
|
@@ -3625,6 +4533,7 @@ const ZKSyncEraSepolia = defineChain({
|
|
|
3625
4533
|
rpcEndpoints: ['https://sepolia.era.zksync.dev'],
|
|
3626
4534
|
eurcAddress: null,
|
|
3627
4535
|
usdcAddress: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
4536
|
+
usdtAddress: null,
|
|
3628
4537
|
cctp: null,
|
|
3629
4538
|
});
|
|
3630
4539
|
|
|
@@ -3645,6 +4554,8 @@ var Blockchains = /*#__PURE__*/Object.freeze({
|
|
|
3645
4554
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
3646
4555
|
Codex: Codex,
|
|
3647
4556
|
CodexTestnet: CodexTestnet,
|
|
4557
|
+
Edge: Edge,
|
|
4558
|
+
EdgeTestnet: EdgeTestnet,
|
|
3648
4559
|
Ethereum: Ethereum,
|
|
3649
4560
|
EthereumSepolia: EthereumSepolia,
|
|
3650
4561
|
Hedera: Hedera,
|
|
@@ -3657,6 +4568,8 @@ var Blockchains = /*#__PURE__*/Object.freeze({
|
|
|
3657
4568
|
LineaSepolia: LineaSepolia,
|
|
3658
4569
|
Monad: Monad,
|
|
3659
4570
|
MonadTestnet: MonadTestnet,
|
|
4571
|
+
Morph: Morph,
|
|
4572
|
+
MorphTestnet: MorphTestnet,
|
|
3660
4573
|
NEAR: NEAR,
|
|
3661
4574
|
NEARTestnet: NEARTestnet,
|
|
3662
4575
|
Noble: Noble,
|
|
@@ -3770,10 +4683,12 @@ const baseChainDefinitionSchema = z.object({
|
|
|
3770
4683
|
rpcEndpoints: z.array(z.string()),
|
|
3771
4684
|
eurcAddress: z.string().nullable(),
|
|
3772
4685
|
usdcAddress: z.string().nullable(),
|
|
4686
|
+
usdtAddress: z.string().nullable(),
|
|
3773
4687
|
cctp: z.any().nullable(), // We'll accept any CCTP config structure
|
|
3774
4688
|
kitContracts: z
|
|
3775
4689
|
.object({
|
|
3776
4690
|
bridge: z.string().optional(),
|
|
4691
|
+
adapter: z.string().optional(),
|
|
3777
4692
|
})
|
|
3778
4693
|
.optional(),
|
|
3779
4694
|
});
|
|
@@ -3888,6 +4803,29 @@ z.union([
|
|
|
3888
4803
|
z.nativeEnum(Blockchain),
|
|
3889
4804
|
chainDefinitionSchema$1,
|
|
3890
4805
|
]);
|
|
4806
|
+
/**
|
|
4807
|
+
* Zod schema for validating swap-specific chain identifiers.
|
|
4808
|
+
*
|
|
4809
|
+
* Validates chains based on:
|
|
4810
|
+
* - CCTPv2 support (adapter contract deployed)
|
|
4811
|
+
* - Mainnet only (no testnets)
|
|
4812
|
+
* - At least one supported token available
|
|
4813
|
+
*
|
|
4814
|
+
*/
|
|
4815
|
+
z.union([
|
|
4816
|
+
// String blockchain identifier (accepts SwapChain enum values)
|
|
4817
|
+
z.string().refine((val) => val in SwapChain, (val) => ({
|
|
4818
|
+
message: `"${val}" is not a supported swap chain. ` +
|
|
4819
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
4820
|
+
})),
|
|
4821
|
+
// SwapChain enum
|
|
4822
|
+
z.nativeEnum(SwapChain),
|
|
4823
|
+
// ChainDefinition object (checks if chain.chain is in SwapChain)
|
|
4824
|
+
chainDefinitionSchema$1.refine((chain) => chain.chain in SwapChain, (chain) => ({
|
|
4825
|
+
message: `"${chain.chain}" is not a supported swap chain. ` +
|
|
4826
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
4827
|
+
})),
|
|
4828
|
+
]);
|
|
3891
4829
|
/**
|
|
3892
4830
|
* Zod schema for validating bridge chain identifiers.
|
|
3893
4831
|
*
|
|
@@ -3927,12 +4865,44 @@ z.union([
|
|
|
3927
4865
|
})),
|
|
3928
4866
|
]);
|
|
3929
4867
|
|
|
4868
|
+
/**
|
|
4869
|
+
* @packageDocumentation
|
|
4870
|
+
* @module SwapTokenSchemas
|
|
4871
|
+
*
|
|
4872
|
+
* Zod validation schemas for supported swap tokens.
|
|
4873
|
+
*/
|
|
4874
|
+
// Internal enum used after input normalization.
|
|
4875
|
+
const swapTokenEnumSchema = z.enum([
|
|
4876
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
4877
|
+
NATIVE_TOKEN,
|
|
4878
|
+
]);
|
|
4879
|
+
/**
|
|
4880
|
+
* Zod schema for validating supported swap token symbols.
|
|
4881
|
+
*
|
|
4882
|
+
* Accepts any token symbol from the SWAP_TOKEN_REGISTRY plus NATIVE.
|
|
4883
|
+
* Input matching is case-insensitive and normalized to uppercase.
|
|
4884
|
+
*
|
|
4885
|
+
* @example
|
|
4886
|
+
* ```typescript
|
|
4887
|
+
* import { supportedSwapTokenSchema } from '@core/chains'
|
|
4888
|
+
*
|
|
4889
|
+
* const result = supportedSwapTokenSchema.safeParse('USDC')
|
|
4890
|
+
* if (result.success) {
|
|
4891
|
+
* console.log('Valid swap token:', result.data)
|
|
4892
|
+
* }
|
|
4893
|
+
* ```
|
|
4894
|
+
*/
|
|
4895
|
+
z
|
|
4896
|
+
.string()
|
|
4897
|
+
.transform((value) => value.toUpperCase())
|
|
4898
|
+
.pipe(swapTokenEnumSchema);
|
|
4899
|
+
|
|
3930
4900
|
/**
|
|
3931
4901
|
* Get all supported EVM chain definitions.
|
|
3932
4902
|
*
|
|
3933
4903
|
* This function searches through all available blockchain definitions and returns
|
|
3934
4904
|
* only those that are EVM-compatible. It provides a comprehensive list of all
|
|
3935
|
-
* EVM chains supported by the
|
|
4905
|
+
* EVM chains supported by the App Kits ecosystem.
|
|
3936
4906
|
*
|
|
3937
4907
|
* @returns Array of all EVM chain definitions supported by the library
|
|
3938
4908
|
*
|
|
@@ -4026,6 +4996,11 @@ const getChainByEnum = (blockchain) => {
|
|
|
4026
4996
|
* ```
|
|
4027
4997
|
*/
|
|
4028
4998
|
function resolveChainIdentifier(chainIdentifier) {
|
|
4999
|
+
// Handle null explicitly (typeof null === 'object' in JavaScript)
|
|
5000
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
5001
|
+
if (chainIdentifier === null) {
|
|
5002
|
+
throw new Error(`Invalid chain identifier type: null. Expected ChainDefinition object, Blockchain enum, or string literal.`);
|
|
5003
|
+
}
|
|
4029
5004
|
// If it's already a ChainDefinition object, return it unchanged
|
|
4030
5005
|
if (typeof chainIdentifier === 'object') {
|
|
4031
5006
|
return chainIdentifier;
|
|
@@ -4388,11 +5363,11 @@ async function resolveOperationContext(adapter, ctx) {
|
|
|
4388
5363
|
/**
|
|
4389
5364
|
* Abstract class defining the standard interface for an adapter that interacts with a specific blockchain.
|
|
4390
5365
|
*
|
|
4391
|
-
*
|
|
5366
|
+
* An `Adapter` is responsible for encapsulating chain-specific logic necessary to
|
|
4392
5367
|
* perform operations like sending transactions, querying balances, or interacting with smart contracts.
|
|
4393
5368
|
* Implementations of this class will provide concrete logic for a particular blockchain protocol.
|
|
4394
5369
|
*
|
|
4395
|
-
* This abstraction allows the
|
|
5370
|
+
* This abstraction allows the App Kit to work with multiple blockchains in a uniform way.
|
|
4396
5371
|
*
|
|
4397
5372
|
* @typeParam TAdapterCapabilities - The adapter capabilities type for compile-time address validation.
|
|
4398
5373
|
* When provided, enables strict typing of operation context based on the adapter's address control model.
|
|
@@ -4916,6 +5891,439 @@ const convertAddress = (address, targetFormat) => {
|
|
|
4916
5891
|
throw new Error(`Unsupported address format: ${address}`);
|
|
4917
5892
|
};
|
|
4918
5893
|
|
|
5894
|
+
/**
|
|
5895
|
+
* USDC token definition with addresses and metadata.
|
|
5896
|
+
*
|
|
5897
|
+
* @remarks
|
|
5898
|
+
* This is the built-in USDC definition used by the TokenRegistry.
|
|
5899
|
+
* Includes all known USDC addresses across supported chains.
|
|
5900
|
+
*
|
|
5901
|
+
* Keys use the `Blockchain` enum for type safety. Both enum values
|
|
5902
|
+
* and string literals are supported:
|
|
5903
|
+
* - `Blockchain.Ethereum` or `'Ethereum'`
|
|
5904
|
+
*
|
|
5905
|
+
* @example
|
|
5906
|
+
* ```typescript
|
|
5907
|
+
* import { USDC } from '@core/tokens'
|
|
5908
|
+
* import { Blockchain } from '@core/chains'
|
|
5909
|
+
*
|
|
5910
|
+
* console.log(USDC.symbol) // 'USDC'
|
|
5911
|
+
* console.log(USDC.decimals) // 6
|
|
5912
|
+
* console.log(USDC.locators[Blockchain.Ethereum])
|
|
5913
|
+
* // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
5914
|
+
* ```
|
|
5915
|
+
*/
|
|
5916
|
+
const USDC = {
|
|
5917
|
+
symbol: 'USDC',
|
|
5918
|
+
decimals: 6,
|
|
5919
|
+
locators: {
|
|
5920
|
+
// =========================================================================
|
|
5921
|
+
// Mainnets (alphabetically sorted)
|
|
5922
|
+
// =========================================================================
|
|
5923
|
+
[Blockchain.Arbitrum]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
5924
|
+
[Blockchain.Avalanche]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
5925
|
+
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
5926
|
+
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
5927
|
+
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
5928
|
+
[Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
5929
|
+
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
5930
|
+
[Blockchain.Hedera]: '0.0.456858',
|
|
5931
|
+
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
5932
|
+
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
5933
|
+
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
5934
|
+
[Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
5935
|
+
[Blockchain.Morph]: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
5936
|
+
[Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
5937
|
+
[Blockchain.Noble]: 'uusdc',
|
|
5938
|
+
[Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
5939
|
+
[Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
5940
|
+
[Blockchain.Polkadot_Asset_Hub]: '1337',
|
|
5941
|
+
[Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
5942
|
+
[Blockchain.Sei]: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
5943
|
+
[Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
5944
|
+
[Blockchain.Sonic]: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
5945
|
+
[Blockchain.Stellar]: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
5946
|
+
[Blockchain.Sui]: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
5947
|
+
[Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
5948
|
+
[Blockchain.World_Chain]: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
5949
|
+
[Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
5950
|
+
[Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
5951
|
+
// =========================================================================
|
|
5952
|
+
// Testnets (alphabetically sorted)
|
|
5953
|
+
// =========================================================================
|
|
5954
|
+
[Blockchain.Arbitrum_Sepolia]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
5955
|
+
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
5956
|
+
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
5957
|
+
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
5958
|
+
[Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
5959
|
+
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
5960
|
+
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
5961
|
+
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
5962
|
+
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
5963
|
+
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
5964
|
+
[Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
5965
|
+
[Blockchain.Morph_Testnet]: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
5966
|
+
[Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
5967
|
+
[Blockchain.Noble_Testnet]: 'uusdc',
|
|
5968
|
+
[Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
5969
|
+
[Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
5970
|
+
[Blockchain.Polkadot_Westmint]: '31337',
|
|
5971
|
+
[Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
5972
|
+
[Blockchain.Sei_Testnet]: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
5973
|
+
[Blockchain.Solana_Devnet]: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
5974
|
+
[Blockchain.Sonic_Testnet]: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
5975
|
+
[Blockchain.Stellar_Testnet]: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
5976
|
+
[Blockchain.Sui_Testnet]: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
5977
|
+
[Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
5978
|
+
[Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
5979
|
+
[Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
5980
|
+
[Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
5981
|
+
},
|
|
5982
|
+
};
|
|
5983
|
+
|
|
5984
|
+
/**
|
|
5985
|
+
* USDT (Tether) token definition with addresses and metadata.
|
|
5986
|
+
*
|
|
5987
|
+
* @remarks
|
|
5988
|
+
* Built-in USDT definition for the TokenRegistry. Includes chain locators
|
|
5989
|
+
* for swap-supported chains.
|
|
5990
|
+
*/
|
|
5991
|
+
const USDT = {
|
|
5992
|
+
symbol: 'USDT',
|
|
5993
|
+
decimals: 6,
|
|
5994
|
+
locators: {
|
|
5995
|
+
[Blockchain.Aptos]: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
5996
|
+
[Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
|
|
5997
|
+
[Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
|
|
5998
|
+
[Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
5999
|
+
[Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
|
6000
|
+
[Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
|
|
6001
|
+
[Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
|
|
6002
|
+
[Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
|
|
6003
|
+
[Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
|
|
6004
|
+
[Blockchain.NEAR]: 'usdt.tether-token.near',
|
|
6005
|
+
[Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
|
|
6006
|
+
[Blockchain.Polkadot_Asset_Hub]: '1984',
|
|
6007
|
+
[Blockchain.Polygon]: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
|
6008
|
+
[Blockchain.Sei]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
6009
|
+
[Blockchain.Solana]: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
6010
|
+
[Blockchain.Unichain]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
6011
|
+
},
|
|
6012
|
+
};
|
|
6013
|
+
|
|
6014
|
+
/**
|
|
6015
|
+
* EURC (Euro Coin) token definition with addresses and metadata.
|
|
6016
|
+
*
|
|
6017
|
+
* @remarks
|
|
6018
|
+
* Built-in EURC definition for the TokenRegistry. Includes chain locators
|
|
6019
|
+
* for swap-supported chains.
|
|
6020
|
+
*/
|
|
6021
|
+
const EURC = {
|
|
6022
|
+
symbol: 'EURC',
|
|
6023
|
+
decimals: 6,
|
|
6024
|
+
locators: {
|
|
6025
|
+
[Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
6026
|
+
[Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
6027
|
+
[Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
6028
|
+
[Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
6029
|
+
[Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
6030
|
+
},
|
|
6031
|
+
};
|
|
6032
|
+
|
|
6033
|
+
/**
|
|
6034
|
+
* DAI (Maker DAO) stablecoin token definition with addresses and metadata.
|
|
6035
|
+
*
|
|
6036
|
+
* @remarks
|
|
6037
|
+
* Built-in DAI definition for the TokenRegistry. Includes chain locators
|
|
6038
|
+
* for swap-supported chains.
|
|
6039
|
+
*/
|
|
6040
|
+
const DAI = {
|
|
6041
|
+
symbol: 'DAI',
|
|
6042
|
+
decimals: 18,
|
|
6043
|
+
chainDecimals: {
|
|
6044
|
+
[Blockchain.Solana]: 8,
|
|
6045
|
+
},
|
|
6046
|
+
locators: {
|
|
6047
|
+
[Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
6048
|
+
[Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
|
|
6049
|
+
[Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
|
|
6050
|
+
[Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
6051
|
+
[Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
|
|
6052
|
+
[Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
6053
|
+
[Blockchain.Polygon]: '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063',
|
|
6054
|
+
[Blockchain.Solana]: 'EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o',
|
|
6055
|
+
},
|
|
6056
|
+
};
|
|
6057
|
+
|
|
6058
|
+
/**
|
|
6059
|
+
* USDe (Ethena) synthetic dollar token definition with addresses and metadata.
|
|
6060
|
+
*
|
|
6061
|
+
* @remarks
|
|
6062
|
+
* Built-in USDE definition for the TokenRegistry. Includes chain locators
|
|
6063
|
+
* for swap-supported chains.
|
|
6064
|
+
*/
|
|
6065
|
+
const USDE = {
|
|
6066
|
+
symbol: 'USDe',
|
|
6067
|
+
decimals: 18,
|
|
6068
|
+
chainDecimals: {
|
|
6069
|
+
[Blockchain.Solana]: 9,
|
|
6070
|
+
},
|
|
6071
|
+
locators: {
|
|
6072
|
+
[Blockchain.Arbitrum]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
6073
|
+
[Blockchain.Base]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
6074
|
+
[Blockchain.Ethereum]: '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3',
|
|
6075
|
+
[Blockchain.Linea]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
6076
|
+
[Blockchain.Optimism]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
6077
|
+
[Blockchain.Solana]: 'DEkqHyPN7GMRJ5cArtQFAWefqbZb33Hyf6s5iCwjEonT',
|
|
6078
|
+
},
|
|
6079
|
+
};
|
|
6080
|
+
|
|
6081
|
+
/**
|
|
6082
|
+
* PYUSD (PayPal USD) stablecoin token definition with addresses and metadata.
|
|
6083
|
+
*
|
|
6084
|
+
* @remarks
|
|
6085
|
+
* Built-in PYUSD definition for the TokenRegistry. Includes chain locators
|
|
6086
|
+
* for swap-supported chains.
|
|
6087
|
+
*/
|
|
6088
|
+
const PYUSD = {
|
|
6089
|
+
symbol: 'PYUSD',
|
|
6090
|
+
decimals: 6,
|
|
6091
|
+
locators: {
|
|
6092
|
+
[Blockchain.Arbitrum]: '0x46850aD61C2B7d64d08c9C754F45254596696984',
|
|
6093
|
+
[Blockchain.Ethereum]: '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8',
|
|
6094
|
+
[Blockchain.Solana]: '2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo',
|
|
6095
|
+
},
|
|
6096
|
+
};
|
|
6097
|
+
|
|
6098
|
+
/**
|
|
6099
|
+
* WETH (Wrapped Ether) token definition with addresses and metadata.
|
|
6100
|
+
*
|
|
6101
|
+
* @remarks
|
|
6102
|
+
* Built-in WETH definition for the TokenRegistry. Includes chain locators
|
|
6103
|
+
* for swap-supported chains where WETH is available.
|
|
6104
|
+
*/
|
|
6105
|
+
const WETH = {
|
|
6106
|
+
symbol: 'WETH',
|
|
6107
|
+
decimals: 18,
|
|
6108
|
+
chainDecimals: {
|
|
6109
|
+
[Blockchain.Solana]: 9,
|
|
6110
|
+
},
|
|
6111
|
+
locators: {
|
|
6112
|
+
[Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
|
|
6113
|
+
[Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
|
|
6114
|
+
[Blockchain.Base]: '0x4200000000000000000000000000000000000006',
|
|
6115
|
+
[Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
6116
|
+
[Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
|
|
6117
|
+
[Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
|
|
6118
|
+
[Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs',
|
|
6119
|
+
},
|
|
6120
|
+
};
|
|
6121
|
+
|
|
6122
|
+
/**
|
|
6123
|
+
* WBTC (Wrapped Bitcoin) token definition with addresses and metadata.
|
|
6124
|
+
*
|
|
6125
|
+
* @remarks
|
|
6126
|
+
* Built-in WBTC definition for the TokenRegistry. Includes chain locators
|
|
6127
|
+
* for swap-supported chains where WBTC is available.
|
|
6128
|
+
*/
|
|
6129
|
+
const WBTC = {
|
|
6130
|
+
symbol: 'WBTC',
|
|
6131
|
+
decimals: 8,
|
|
6132
|
+
locators: {
|
|
6133
|
+
[Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
|
|
6134
|
+
[Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
|
|
6135
|
+
[Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218',
|
|
6136
|
+
},
|
|
6137
|
+
};
|
|
6138
|
+
|
|
6139
|
+
/**
|
|
6140
|
+
* WSOL (Wrapped SOL) token definition with addresses and metadata.
|
|
6141
|
+
*
|
|
6142
|
+
* @remarks
|
|
6143
|
+
* Built-in WSOL definition for the TokenRegistry. Includes chain locators
|
|
6144
|
+
* for swap-supported chains where WSOL is available.
|
|
6145
|
+
*/
|
|
6146
|
+
const WSOL = {
|
|
6147
|
+
symbol: 'WSOL',
|
|
6148
|
+
decimals: 9,
|
|
6149
|
+
locators: {
|
|
6150
|
+
[Blockchain.Solana]: 'So11111111111111111111111111111111111111112',
|
|
6151
|
+
},
|
|
6152
|
+
};
|
|
6153
|
+
|
|
6154
|
+
/**
|
|
6155
|
+
* WAVAX (Wrapped AVAX) token definition with addresses and metadata.
|
|
6156
|
+
*
|
|
6157
|
+
* @remarks
|
|
6158
|
+
* Built-in WAVAX definition for the TokenRegistry. Includes chain locators
|
|
6159
|
+
* for swap-supported chains where WAVAX is available.
|
|
6160
|
+
*/
|
|
6161
|
+
const WAVAX = {
|
|
6162
|
+
symbol: 'WAVAX',
|
|
6163
|
+
decimals: 18,
|
|
6164
|
+
locators: {
|
|
6165
|
+
[Blockchain.Avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7',
|
|
6166
|
+
},
|
|
6167
|
+
};
|
|
6168
|
+
|
|
6169
|
+
/**
|
|
6170
|
+
* WPOL (Wrapped POL) token definition with addresses and metadata.
|
|
6171
|
+
*
|
|
6172
|
+
* @remarks
|
|
6173
|
+
* Built-in WPOL definition for the TokenRegistry. Includes chain locators
|
|
6174
|
+
* for swap-supported chains where WPOL is available.
|
|
6175
|
+
*/
|
|
6176
|
+
const WPOL = {
|
|
6177
|
+
symbol: 'WPOL',
|
|
6178
|
+
decimals: 18,
|
|
6179
|
+
locators: {
|
|
6180
|
+
[Blockchain.Polygon]: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
|
|
6181
|
+
},
|
|
6182
|
+
};
|
|
6183
|
+
|
|
6184
|
+
/**
|
|
6185
|
+
* ETH (native Ether alias) token definition with metadata.
|
|
6186
|
+
*
|
|
6187
|
+
* @remarks
|
|
6188
|
+
* Built-in ETH definition for the TokenRegistry. Used as a symbol alias
|
|
6189
|
+
* for native ETH (e.g. in swap flows). Chain locators are TBD and will
|
|
6190
|
+
* be added when addresses are available. Use raw selector with
|
|
6191
|
+
* locator + decimals where native gas token is represented as a contract.
|
|
6192
|
+
*/
|
|
6193
|
+
const ETH = {
|
|
6194
|
+
symbol: 'ETH',
|
|
6195
|
+
decimals: 18,
|
|
6196
|
+
locators: {},
|
|
6197
|
+
};
|
|
6198
|
+
|
|
6199
|
+
/**
|
|
6200
|
+
* POL (Polygon native token) token definition with addresses and metadata.
|
|
6201
|
+
*
|
|
6202
|
+
* @remarks
|
|
6203
|
+
* Built-in POL definition for the TokenRegistry. Includes chain locators
|
|
6204
|
+
* where POL is available as a bridged/wrapped asset.
|
|
6205
|
+
*/
|
|
6206
|
+
const POL = {
|
|
6207
|
+
symbol: 'POL',
|
|
6208
|
+
decimals: 18,
|
|
6209
|
+
locators: {
|
|
6210
|
+
[Blockchain.Ethereum]: '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6',
|
|
6211
|
+
},
|
|
6212
|
+
};
|
|
6213
|
+
|
|
6214
|
+
/**
|
|
6215
|
+
* PLUME (Plume network token) token definition with addresses and metadata.
|
|
6216
|
+
*
|
|
6217
|
+
* @remarks
|
|
6218
|
+
* Built-in PLUME definition for the TokenRegistry. Includes chain locators
|
|
6219
|
+
* where PLUME is available.
|
|
6220
|
+
*/
|
|
6221
|
+
const PLUME = {
|
|
6222
|
+
symbol: 'PLUME',
|
|
6223
|
+
decimals: 18,
|
|
6224
|
+
locators: {
|
|
6225
|
+
[Blockchain.Ethereum]: '0x4C1746A800D224393fE2470C70A35717eD4eA5F1',
|
|
6226
|
+
},
|
|
6227
|
+
};
|
|
6228
|
+
|
|
6229
|
+
/**
|
|
6230
|
+
* MON token definition with Solana mint metadata.
|
|
6231
|
+
*
|
|
6232
|
+
* @remarks
|
|
6233
|
+
* Built-in MON definition for the TokenRegistry. Includes chain locators
|
|
6234
|
+
* for swap-supported chains.
|
|
6235
|
+
*/
|
|
6236
|
+
const MON = {
|
|
6237
|
+
symbol: 'MON',
|
|
6238
|
+
decimals: 18,
|
|
6239
|
+
chainDecimals: {
|
|
6240
|
+
[Blockchain.Solana]: 8,
|
|
6241
|
+
},
|
|
6242
|
+
locators: {
|
|
6243
|
+
[Blockchain.Solana]: 'CrAr4RRJMBVwRsZtT62pEhfA9H5utymC2mVx8e7FreP2',
|
|
6244
|
+
},
|
|
6245
|
+
};
|
|
6246
|
+
|
|
6247
|
+
// Re-export for consumers
|
|
6248
|
+
/**
|
|
6249
|
+
* All default token definitions.
|
|
6250
|
+
*
|
|
6251
|
+
* @remarks
|
|
6252
|
+
* These tokens are automatically included in the TokenRegistry when created
|
|
6253
|
+
* without explicit defaults. Extensions can override these definitions.
|
|
6254
|
+
* Includes USDC, USDT, EURC, DAI, USDE, PYUSD, WETH, WBTC, WSOL, WAVAX,
|
|
6255
|
+
* WPOL, ETH, POL, PLUME, and MON.
|
|
6256
|
+
*
|
|
6257
|
+
* @example
|
|
6258
|
+
* ```typescript
|
|
6259
|
+
* import { createTokenRegistry } from '@core/tokens'
|
|
6260
|
+
*
|
|
6261
|
+
* // Registry uses these by default
|
|
6262
|
+
* const registry = createTokenRegistry()
|
|
6263
|
+
*
|
|
6264
|
+
* // Add custom tokens (built-ins are still included)
|
|
6265
|
+
* const customRegistry = createTokenRegistry({
|
|
6266
|
+
* tokens: [myCustomToken],
|
|
6267
|
+
* })
|
|
6268
|
+
* ```
|
|
6269
|
+
*/
|
|
6270
|
+
const DEFAULT_TOKENS = [
|
|
6271
|
+
USDC,
|
|
6272
|
+
USDT,
|
|
6273
|
+
EURC,
|
|
6274
|
+
DAI,
|
|
6275
|
+
USDE,
|
|
6276
|
+
PYUSD,
|
|
6277
|
+
WETH,
|
|
6278
|
+
WBTC,
|
|
6279
|
+
WSOL,
|
|
6280
|
+
WAVAX,
|
|
6281
|
+
WPOL,
|
|
6282
|
+
ETH,
|
|
6283
|
+
POL,
|
|
6284
|
+
PLUME,
|
|
6285
|
+
MON,
|
|
6286
|
+
];
|
|
6287
|
+
/**
|
|
6288
|
+
* Uppercased token symbols approved for swap fee collection.
|
|
6289
|
+
*
|
|
6290
|
+
* @remarks
|
|
6291
|
+
* Derived from {@link DEFAULT_TOKENS} so all consumers share a single
|
|
6292
|
+
* allowlist source and stay in sync when defaults change.
|
|
6293
|
+
*/
|
|
6294
|
+
new Set(DEFAULT_TOKENS.map((t) => t.symbol.toUpperCase()));
|
|
6295
|
+
|
|
6296
|
+
/**
|
|
6297
|
+
* Define a schema for token registry interfaces.
|
|
6298
|
+
*
|
|
6299
|
+
* @remarks
|
|
6300
|
+
* Validate that a registry exposes the `resolve()` API used by adapters.
|
|
6301
|
+
*
|
|
6302
|
+
* @example
|
|
6303
|
+
* ```typescript
|
|
6304
|
+
* import { tokenRegistrySchema } from '@core/tokens'
|
|
6305
|
+
*
|
|
6306
|
+
* const registry = {
|
|
6307
|
+
* resolve: () => ({ locator: '0x0', decimals: 6 }),
|
|
6308
|
+
* }
|
|
6309
|
+
*
|
|
6310
|
+
* tokenRegistrySchema.parse(registry)
|
|
6311
|
+
* ```
|
|
6312
|
+
*/
|
|
6313
|
+
z.custom((value) => {
|
|
6314
|
+
if (value === null || typeof value !== 'object') {
|
|
6315
|
+
return false;
|
|
6316
|
+
}
|
|
6317
|
+
const record = value;
|
|
6318
|
+
return (typeof record['resolve'] === 'function' &&
|
|
6319
|
+
typeof record['get'] === 'function' &&
|
|
6320
|
+
typeof record['has'] === 'function' &&
|
|
6321
|
+
typeof record['symbols'] === 'function' &&
|
|
6322
|
+
typeof record['entries'] === 'function');
|
|
6323
|
+
}, {
|
|
6324
|
+
message: 'Invalid token registry',
|
|
6325
|
+
});
|
|
6326
|
+
|
|
4919
6327
|
/**
|
|
4920
6328
|
* Schema for validating hexadecimal strings with '0x' prefix.
|
|
4921
6329
|
*
|
|
@@ -5103,9 +6511,27 @@ const adapterSchema = z.object({
|
|
|
5103
6511
|
* console.log('EVM address is valid')
|
|
5104
6512
|
* ```
|
|
5105
6513
|
*/
|
|
5106
|
-
function assertEvmAddress(address) {
|
|
5107
|
-
validateOrThrow(address, evmAddressSchema, 'Invalid EVM address');
|
|
5108
|
-
}
|
|
6514
|
+
function assertEvmAddress(address) {
|
|
6515
|
+
validateOrThrow(address, evmAddressSchema, 'Invalid EVM address');
|
|
6516
|
+
}
|
|
6517
|
+
|
|
6518
|
+
/**
|
|
6519
|
+
* Permit signature standards for gasless token approvals.
|
|
6520
|
+
*
|
|
6521
|
+
* Defines the permit types that can be used to approve token spending
|
|
6522
|
+
* without requiring a separate approval transaction.
|
|
6523
|
+
*
|
|
6524
|
+
* @remarks
|
|
6525
|
+
* - NONE: No permit, tokens must be pre-approved via separate transaction
|
|
6526
|
+
* - EIP2612: Standard ERC-20 permit (USDC, DAI v2, and most modern tokens)
|
|
6527
|
+
*/
|
|
6528
|
+
var PermitType;
|
|
6529
|
+
(function (PermitType) {
|
|
6530
|
+
/** No permit required - tokens must be pre-approved */
|
|
6531
|
+
PermitType[PermitType["NONE"] = 0] = "NONE";
|
|
6532
|
+
/** EIP-2612 standard permit */
|
|
6533
|
+
PermitType[PermitType["EIP2612"] = 1] = "EIP2612";
|
|
6534
|
+
})(PermitType || (PermitType = {}));
|
|
5109
6535
|
|
|
5110
6536
|
/**
|
|
5111
6537
|
* Creates a no-op prepared chain request.
|
|
@@ -5214,6 +6640,12 @@ function getSupportedChains(ecosystem) {
|
|
|
5214
6640
|
*
|
|
5215
6641
|
* This ABI is used to interact with generic ERC20 tokens on EVM networks.
|
|
5216
6642
|
*
|
|
6643
|
+
* @remarks
|
|
6644
|
+
* The `approve`, `transfer` and `transferFrom` functions have been modified to not expect a return value
|
|
6645
|
+
* (empty `outputs` array) to support non-standard implementations like USDT
|
|
6646
|
+
* that return `void` instead of `bool`. This is safe because the SDK never
|
|
6647
|
+
* uses the return value from these functions - only the transaction hash matters.
|
|
6648
|
+
*
|
|
5217
6649
|
* @see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
|
|
5218
6650
|
*/
|
|
5219
6651
|
const erc20Abi = [
|
|
@@ -5244,12 +6676,7 @@ const erc20Abi = [
|
|
|
5244
6676
|
},
|
|
5245
6677
|
],
|
|
5246
6678
|
name: 'approve',
|
|
5247
|
-
outputs: [
|
|
5248
|
-
{
|
|
5249
|
-
name: '',
|
|
5250
|
-
type: 'bool',
|
|
5251
|
-
},
|
|
5252
|
-
],
|
|
6679
|
+
outputs: [],
|
|
5253
6680
|
payable: false,
|
|
5254
6681
|
stateMutability: 'nonpayable',
|
|
5255
6682
|
type: 'function',
|
|
@@ -5285,12 +6712,7 @@ const erc20Abi = [
|
|
|
5285
6712
|
},
|
|
5286
6713
|
],
|
|
5287
6714
|
name: 'transferFrom',
|
|
5288
|
-
outputs: [
|
|
5289
|
-
{
|
|
5290
|
-
name: '',
|
|
5291
|
-
type: 'bool',
|
|
5292
|
-
},
|
|
5293
|
-
],
|
|
6715
|
+
outputs: [],
|
|
5294
6716
|
payable: false,
|
|
5295
6717
|
stateMutability: 'nonpayable',
|
|
5296
6718
|
type: 'function',
|
|
@@ -5355,12 +6777,7 @@ const erc20Abi = [
|
|
|
5355
6777
|
},
|
|
5356
6778
|
],
|
|
5357
6779
|
name: 'transfer',
|
|
5358
|
-
outputs: [
|
|
5359
|
-
{
|
|
5360
|
-
name: '',
|
|
5361
|
-
type: 'bool',
|
|
5362
|
-
},
|
|
5363
|
-
],
|
|
6780
|
+
outputs: [],
|
|
5364
6781
|
payable: false,
|
|
5365
6782
|
stateMutability: 'nonpayable',
|
|
5366
6783
|
type: 'function',
|
|
@@ -8583,6 +10000,78 @@ const bridgeContractAbi = [
|
|
|
8583
10000
|
},
|
|
8584
10001
|
];
|
|
8585
10002
|
|
|
10003
|
+
/**
|
|
10004
|
+
* Adapter Contract ABI
|
|
10005
|
+
*
|
|
10006
|
+
* This ABI is used to interact with the Adapter smart contract that handles
|
|
10007
|
+
* gasless token approvals via permits and atomic swap execution.
|
|
10008
|
+
*
|
|
10009
|
+
* The execute() function is the primary entry point for swap operations.
|
|
10010
|
+
*/
|
|
10011
|
+
const adapterContractAbi = [
|
|
10012
|
+
{
|
|
10013
|
+
type: 'function',
|
|
10014
|
+
name: 'execute',
|
|
10015
|
+
inputs: [
|
|
10016
|
+
{
|
|
10017
|
+
name: 'params',
|
|
10018
|
+
type: 'tuple',
|
|
10019
|
+
internalType: 'struct IAdapter.ExecutionParams',
|
|
10020
|
+
components: [
|
|
10021
|
+
{
|
|
10022
|
+
name: 'instructions',
|
|
10023
|
+
type: 'tuple[]',
|
|
10024
|
+
internalType: 'struct IAdapter.Instruction[]',
|
|
10025
|
+
components: [
|
|
10026
|
+
{ name: 'target', type: 'address', internalType: 'address' },
|
|
10027
|
+
{ name: 'data', type: 'bytes', internalType: 'bytes' },
|
|
10028
|
+
{ name: 'value', type: 'uint256', internalType: 'uint256' },
|
|
10029
|
+
{ name: 'tokenIn', type: 'address', internalType: 'address' },
|
|
10030
|
+
{
|
|
10031
|
+
name: 'amountToApprove',
|
|
10032
|
+
type: 'uint256',
|
|
10033
|
+
internalType: 'uint256',
|
|
10034
|
+
},
|
|
10035
|
+
{ name: 'tokenOut', type: 'address', internalType: 'address' },
|
|
10036
|
+
{ name: 'minTokenOut', type: 'uint256', internalType: 'uint256' },
|
|
10037
|
+
],
|
|
10038
|
+
},
|
|
10039
|
+
{
|
|
10040
|
+
name: 'tokens',
|
|
10041
|
+
type: 'tuple[]',
|
|
10042
|
+
internalType: 'struct IAdapter.TokenRecipient[]',
|
|
10043
|
+
components: [
|
|
10044
|
+
{ name: 'token', type: 'address', internalType: 'address' },
|
|
10045
|
+
{ name: 'beneficiary', type: 'address', internalType: 'address' },
|
|
10046
|
+
],
|
|
10047
|
+
},
|
|
10048
|
+
{ name: 'execId', type: 'uint256', internalType: 'uint256' },
|
|
10049
|
+
{ name: 'deadline', type: 'uint256', internalType: 'uint256' },
|
|
10050
|
+
{ name: 'metadata', type: 'bytes', internalType: 'bytes' },
|
|
10051
|
+
],
|
|
10052
|
+
},
|
|
10053
|
+
{
|
|
10054
|
+
name: 'tokenInputs',
|
|
10055
|
+
type: 'tuple[]',
|
|
10056
|
+
internalType: 'struct IAdapter.TokenInput[]',
|
|
10057
|
+
components: [
|
|
10058
|
+
{
|
|
10059
|
+
name: 'permitType',
|
|
10060
|
+
type: 'uint8',
|
|
10061
|
+
internalType: 'enum IAdapter.PermitType',
|
|
10062
|
+
},
|
|
10063
|
+
{ name: 'token', type: 'address', internalType: 'address' },
|
|
10064
|
+
{ name: 'amount', type: 'uint256', internalType: 'uint256' },
|
|
10065
|
+
{ name: 'permitCalldata', type: 'bytes', internalType: 'bytes' },
|
|
10066
|
+
],
|
|
10067
|
+
},
|
|
10068
|
+
{ name: 'signature', type: 'bytes', internalType: 'bytes' },
|
|
10069
|
+
],
|
|
10070
|
+
outputs: [],
|
|
10071
|
+
stateMutability: 'payable',
|
|
10072
|
+
},
|
|
10073
|
+
];
|
|
10074
|
+
|
|
8586
10075
|
/**
|
|
8587
10076
|
* Core type definitions for EVM-compatible blockchain transaction execution
|
|
8588
10077
|
* and gas estimation.
|
|
@@ -8592,6 +10081,66 @@ const bridgeContractAbi = [
|
|
|
8592
10081
|
*
|
|
8593
10082
|
* @module constants
|
|
8594
10083
|
*/
|
|
10084
|
+
/**
|
|
10085
|
+
* The zero address constant for EVM chains.
|
|
10086
|
+
*
|
|
10087
|
+
* @remarks
|
|
10088
|
+
* This 20-byte address (`0x00...00`) is commonly used to represent:
|
|
10089
|
+
* - Disabled token approvals in instructions (tokenIn = ZERO_ADDRESS)
|
|
10090
|
+
* - Disabled balance validations (tokenOut = ZERO_ADDRESS)
|
|
10091
|
+
* - Null/unset address values
|
|
10092
|
+
*
|
|
10093
|
+
* **Note**: For native currency representation in adapter contract instructions,
|
|
10094
|
+
* use {@link NATIVE_TOKEN_ADDRESS} (`0xEeee...`) instead.
|
|
10095
|
+
*
|
|
10096
|
+
* @example
|
|
10097
|
+
* ```typescript
|
|
10098
|
+
* import { ZERO_ADDRESS } from '@core/adapter-evm'
|
|
10099
|
+
*
|
|
10100
|
+
* // Check if instruction has no token output (validation disabled)
|
|
10101
|
+
* if (instruction.tokenOut === ZERO_ADDRESS) {
|
|
10102
|
+
* // No output validation needed
|
|
10103
|
+
* }
|
|
10104
|
+
* ```
|
|
10105
|
+
*/
|
|
10106
|
+
/**
|
|
10107
|
+
* The native token address constant used by the Adapter Contract.
|
|
10108
|
+
*
|
|
10109
|
+
* @remarks
|
|
10110
|
+
* This address (`0xEeee...`) is the standard convention used by DEX aggregators
|
|
10111
|
+
* and the Adapter Contract to represent native currency (ETH, MATIC, AVAX, etc.)
|
|
10112
|
+
* in swap instructions.
|
|
10113
|
+
*
|
|
10114
|
+
* **Address Conventions in Adapter Contract:**
|
|
10115
|
+
* - Native Token: `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`
|
|
10116
|
+
* - No Token: `0x0000000000000000000000000000000000000000` (ZERO_ADDRESS)
|
|
10117
|
+
* - ERC20: Any other valid address
|
|
10118
|
+
*
|
|
10119
|
+
* **Native currency swaps:**
|
|
10120
|
+
* - When `tokenIn === NATIVE_TOKEN_ADDRESS`, value is sent via tx.value
|
|
10121
|
+
* - No approval or permit is required for native currency
|
|
10122
|
+
* - Used in instructions from stablecoin-service for ETH/MATIC/AVAX swaps
|
|
10123
|
+
*
|
|
10124
|
+
* @example
|
|
10125
|
+
* ```typescript
|
|
10126
|
+
* import { NATIVE_TOKEN_ADDRESS, ZERO_ADDRESS } from '@core/adapter-evm'
|
|
10127
|
+
*
|
|
10128
|
+
* // Check if token requires approval (exclude native and zero)
|
|
10129
|
+
* function requiresApproval(tokenAddress: string): boolean {
|
|
10130
|
+
* const normalized = tokenAddress.toLowerCase()
|
|
10131
|
+
* return normalized !== NATIVE_TOKEN_ADDRESS.toLowerCase() &&
|
|
10132
|
+
* normalized !== ZERO_ADDRESS.toLowerCase()
|
|
10133
|
+
* }
|
|
10134
|
+
*
|
|
10135
|
+
* // Example: ETH → USDC swap
|
|
10136
|
+
* const instruction = {
|
|
10137
|
+
* tokenIn: NATIVE_TOKEN_ADDRESS, // No approval needed
|
|
10138
|
+
* amount: 1000000000000000000n, // 1 ETH
|
|
10139
|
+
* value: 1000000000000000000n, // Sent via tx.value
|
|
10140
|
+
* }
|
|
10141
|
+
* ```
|
|
10142
|
+
*/
|
|
10143
|
+
const NATIVE_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
|
8595
10144
|
/**
|
|
8596
10145
|
* A constant representing the zero hash value.
|
|
8597
10146
|
*
|
|
@@ -9212,6 +10761,58 @@ const customBurnWithHook = async (params, adapter, context) => {
|
|
|
9212
10761
|
return prepareCustomBurn(params, adapter, context);
|
|
9213
10762
|
};
|
|
9214
10763
|
|
|
10764
|
+
/**
|
|
10765
|
+
* Prepare an EVM-compatible native token transfer transaction.
|
|
10766
|
+
*
|
|
10767
|
+
* Create a prepared chain request to move native tokens from the caller's wallet to a
|
|
10768
|
+
* recipient address on EVM chains.
|
|
10769
|
+
*
|
|
10770
|
+
* The function validates that the current chain is EVM-compatible, then builds a
|
|
10771
|
+
* transaction targeting the provided recipient address. The resulting prepared
|
|
10772
|
+
* request can be simulated or executed by the caller.
|
|
10773
|
+
*
|
|
10774
|
+
* @param params - The action payload for `native.transfer` containing:
|
|
10775
|
+
* - `to`: The recipient wallet address.
|
|
10776
|
+
* - `amount`: The native token amount (as a `bigint`).
|
|
10777
|
+
* - `chain`: The chain to transfer the native tokens on.
|
|
10778
|
+
* @param adapter - The EVM adapter responsible for chain context and transaction preparation.
|
|
10779
|
+
* @returns A promise that resolves to a prepared chain request for the `transfer` call.
|
|
10780
|
+
* @throws {KitError} If chain is not EVM (INPUT_INVALID_CHAIN) or amount is invalid (INPUT_INVALID_AMOUNT).
|
|
10781
|
+
*
|
|
10782
|
+
* @example
|
|
10783
|
+
* ```typescript
|
|
10784
|
+
* const prepared = await transfer(
|
|
10785
|
+
* {
|
|
10786
|
+
* to: '0x1111111111111111111111111111111111111111',
|
|
10787
|
+
* amount: 1_000_000n,
|
|
10788
|
+
* chain: 'Ethereum_Sepolia',
|
|
10789
|
+
* },
|
|
10790
|
+
* adapter
|
|
10791
|
+
* );
|
|
10792
|
+
* await prepared.execute();
|
|
10793
|
+
* ```
|
|
10794
|
+
*/
|
|
10795
|
+
const transfer$3 = async (params, adapter, context) => {
|
|
10796
|
+
const chain = context.chain;
|
|
10797
|
+
if (chain.type !== 'evm') {
|
|
10798
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain definition, but received chain type: ${chain.type}`);
|
|
10799
|
+
}
|
|
10800
|
+
const { to, amount } = params;
|
|
10801
|
+
// Validate the amount
|
|
10802
|
+
if (typeof amount !== 'bigint' || amount <= 0n) {
|
|
10803
|
+
throw createInvalidAmountError(String(amount), 'Transfer amount must be a positive bigint');
|
|
10804
|
+
}
|
|
10805
|
+
// Validate the to address
|
|
10806
|
+
assertEvmAddress(to);
|
|
10807
|
+
// Prepare the transfer transaction
|
|
10808
|
+
// Note: Type assertion needed - native transfers don't use contract ABI
|
|
10809
|
+
return adapter.prepare({
|
|
10810
|
+
type: 'evm',
|
|
10811
|
+
address: to,
|
|
10812
|
+
value: amount,
|
|
10813
|
+
}, context);
|
|
10814
|
+
};
|
|
10815
|
+
|
|
9215
10816
|
/**
|
|
9216
10817
|
* Prepares an EVM-compatible native token balance read (ETH, MATIC, etc.).
|
|
9217
10818
|
*
|
|
@@ -9266,6 +10867,159 @@ const balanceOf$2 = async (params, adapter, context) => {
|
|
|
9266
10867
|
};
|
|
9267
10868
|
};
|
|
9268
10869
|
|
|
10870
|
+
/**
|
|
10871
|
+
* Type guard to check if params is ExecuteSwapEVMParams.
|
|
10872
|
+
*
|
|
10873
|
+
* Uses property-based narrowing: EVM swap params have `executeParams`, `tokenInputs`,
|
|
10874
|
+
* `inputAmount`, and `tokenInAddress`, while Solana swap params have `serializedTransaction`.
|
|
10875
|
+
*
|
|
10876
|
+
* @remarks
|
|
10877
|
+
* Checks both property existence and that values are not undefined to provide
|
|
10878
|
+
* robust runtime validation against malformed inputs.
|
|
10879
|
+
*/
|
|
10880
|
+
const isEVMSwapParams = (params) => {
|
|
10881
|
+
return ('executeParams' in params &&
|
|
10882
|
+
params.executeParams !== undefined &&
|
|
10883
|
+
'tokenInputs' in params &&
|
|
10884
|
+
params.tokenInputs !== undefined &&
|
|
10885
|
+
'inputAmount' in params &&
|
|
10886
|
+
params.inputAmount !== undefined &&
|
|
10887
|
+
'tokenInAddress' in params &&
|
|
10888
|
+
params.tokenInAddress !== undefined);
|
|
10889
|
+
};
|
|
10890
|
+
/**
|
|
10891
|
+
* Executes a swap transaction via the Adapter smart contract.
|
|
10892
|
+
*
|
|
10893
|
+
* This action prepares swap transactions that execute through the Adapter
|
|
10894
|
+
* Contract, which handles gasless token approvals via permits (EIP-2612,
|
|
10895
|
+
* Permit2, etc.) and executes multi-step swap instructions atomically.
|
|
10896
|
+
*
|
|
10897
|
+
* @remarks
|
|
10898
|
+
* **Adapter Contract Pattern**
|
|
10899
|
+
*
|
|
10900
|
+
* The Adapter Contract pattern enables single-transaction swaps with gasless
|
|
10901
|
+
* approvals. The flow is:
|
|
10902
|
+
* 1. Service provides `executeParams` (swap instructions) and `signature` (proxy authorization)
|
|
10903
|
+
* 2. SDK builds `tokenInputs` with permit signatures for token approvals
|
|
10904
|
+
* 3. SDK calls AdapterContract.execute(executeParams, tokenInputs, signature)
|
|
10905
|
+
* 4. Adapter pulls tokens via permits, executes swaps, validates outputs, sweeps residuals
|
|
10906
|
+
*
|
|
10907
|
+
* **Permit Support**
|
|
10908
|
+
*
|
|
10909
|
+
* Token approvals are handled via permits encoded in `tokenInputs`. The SDK
|
|
10910
|
+
* constructs `TokenInput` objects with `permitCalldata` containing the encoded
|
|
10911
|
+
* permit signature. The Adapter Contract executes these permits on-chain before
|
|
10912
|
+
* executing swap instructions, enabling gasless approvals in a single atomic transaction.
|
|
10913
|
+
*
|
|
10914
|
+
* Supported permit types: EIP-2612, Permit2, DAI-like, EIP-3009
|
|
10915
|
+
*
|
|
10916
|
+
* **Service Integration**
|
|
10917
|
+
*
|
|
10918
|
+
* The `executeParams` and `signature` come from the stablecoin-service `createSwap`
|
|
10919
|
+
* endpoint. These are EIP-712 signed by Circle's proxy service and must be passed
|
|
10920
|
+
* to the Adapter Contract exactly as received (no modification).
|
|
10921
|
+
*
|
|
10922
|
+
* @param params - Swap execution parameters:
|
|
10923
|
+
* - `executeParams`: Execution parameters from service (instructions, tokens, execId, deadline)
|
|
10924
|
+
* - `tokenInputs`: Token inputs with permit signatures (built by provider)
|
|
10925
|
+
* - `signature`: EIP-712 signature from service (proxy authorization)
|
|
10926
|
+
* - `inputAmount`: User's swap input amount from service response (source of truth)
|
|
10927
|
+
* @param adapter - EVM adapter for transaction preparation
|
|
10928
|
+
* @param context - Resolved operation context with chain and address information
|
|
10929
|
+
* @returns Prepared chain request ready for estimation or execution
|
|
10930
|
+
*
|
|
10931
|
+
* @throws KitError If chain is not EVM-compatible (INPUT_INVALID_CHAIN)
|
|
10932
|
+
* @throws KitError If executeParams is missing or invalid (INPUT_VALIDATION_FAILED)
|
|
10933
|
+
* @throws KitError If signature is invalid (INPUT_VALIDATION_FAILED)
|
|
10934
|
+
* @throws KitError If tokenInputs is not an array (INPUT_VALIDATION_FAILED)
|
|
10935
|
+
*
|
|
10936
|
+
* @example
|
|
10937
|
+
* ```typescript
|
|
10938
|
+
* import { createSwap } from '@core/service-client'
|
|
10939
|
+
* import { PermitType } from '@core/adapter'
|
|
10940
|
+
* import type { EvmAdapter } from '@core/adapter-evm'
|
|
10941
|
+
*
|
|
10942
|
+
* // 1. Get swap transaction from stablecoin-service
|
|
10943
|
+
* const swapResponse = await createSwap({
|
|
10944
|
+
* tokenInAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
|
|
10945
|
+
* tokenOutAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec8', // USDT
|
|
10946
|
+
* tokenInChain: 'Ethereum',
|
|
10947
|
+
* fromAddress: await adapter.getAddress(),
|
|
10948
|
+
* toAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
|
|
10949
|
+
* amount: '1000000', // 1 USDC in base units
|
|
10950
|
+
* apiKey: process.env.API_KEY,
|
|
10951
|
+
* })
|
|
10952
|
+
*
|
|
10953
|
+
* // 2. Build token inputs with permit signature (provider responsibility)
|
|
10954
|
+
* const tokenInputs: TokenInput[] = [{
|
|
10955
|
+
* permitType: PermitType.EIP2612,
|
|
10956
|
+
* token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
10957
|
+
* from: await adapter.getAddress(Ethereum),
|
|
10958
|
+
* amount: 1000000n,
|
|
10959
|
+
* permitCalldata: '0x...' // Encoded permit signature from provider
|
|
10960
|
+
* }]
|
|
10961
|
+
*
|
|
10962
|
+
* // 3. Execute swap via adapter action
|
|
10963
|
+
* const swapRequest = await adapter.prepareAction(
|
|
10964
|
+
* 'swap.execute',
|
|
10965
|
+
* {
|
|
10966
|
+
* executeParams: swapResponse.transaction.executeParams,
|
|
10967
|
+
* tokenInputs,
|
|
10968
|
+
* signature: swapResponse.transaction.signature,
|
|
10969
|
+
* inputAmount: BigInt(swapResponse.amount) // From service response
|
|
10970
|
+
* },
|
|
10971
|
+
* context
|
|
10972
|
+
* )
|
|
10973
|
+
*
|
|
10974
|
+
* // 4. Estimate gas
|
|
10975
|
+
* const gasEstimate = await swapRequest.estimate()
|
|
10976
|
+
* console.log('Gas required:', gasEstimate.gas)
|
|
10977
|
+
*
|
|
10978
|
+
* // 5. Execute transaction
|
|
10979
|
+
* const txHash = await swapRequest.execute()
|
|
10980
|
+
* console.log('Swap transaction:', txHash)
|
|
10981
|
+
* ```
|
|
10982
|
+
*/
|
|
10983
|
+
const executeSwap = async (params, adapter, context) => {
|
|
10984
|
+
const { chain } = context;
|
|
10985
|
+
// Validate EVM chain first (this is an EVM-specific action)
|
|
10986
|
+
if (chain.type !== 'evm') {
|
|
10987
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain, but received chain type: ${String(chain.type)}`);
|
|
10988
|
+
}
|
|
10989
|
+
const adapterContractAddress = chain.kitContracts?.adapter;
|
|
10990
|
+
if (adapterContractAddress === undefined) {
|
|
10991
|
+
throw createInvalidChainError(chain.name, `Swap action is not supported on this chain: ${chain.name}`);
|
|
10992
|
+
}
|
|
10993
|
+
// Narrow type using property-based guard - this function only handles EVM swaps
|
|
10994
|
+
if (!isEVMSwapParams(params)) {
|
|
10995
|
+
throw createValidationFailedError('params', 'Invalid or incomplete EVM swap parameters', 'This action handler only supports EVM swap parameters (must have executeParams and tokenInputs)');
|
|
10996
|
+
}
|
|
10997
|
+
// Validate executeParams exists
|
|
10998
|
+
if (typeof params.executeParams !== 'object') {
|
|
10999
|
+
throw createValidationFailedError('executeParams', params.executeParams, 'ExecuteParams is required from service response');
|
|
11000
|
+
}
|
|
11001
|
+
// Validate signature
|
|
11002
|
+
if (params.signature === '0x') {
|
|
11003
|
+
throw createValidationFailedError('signature', params.signature, 'Signature is required from service response');
|
|
11004
|
+
}
|
|
11005
|
+
// Validate tokenInputs array (can be empty if no permits needed)
|
|
11006
|
+
if (!Array.isArray(params.tokenInputs)) {
|
|
11007
|
+
throw createValidationFailedError('tokenInputs', params.tokenInputs, 'TokenInputs must be an array');
|
|
11008
|
+
}
|
|
11009
|
+
// Check if swapping native currency (ETH, MATIC, etc.) vs ERC20 tokens
|
|
11010
|
+
const isNativeSwap = params.tokenInAddress.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase();
|
|
11011
|
+
// Prepare transaction to Adapter Contract
|
|
11012
|
+
return adapter.prepare({
|
|
11013
|
+
type: 'evm',
|
|
11014
|
+
abi: adapterContractAbi,
|
|
11015
|
+
address: adapterContractAddress,
|
|
11016
|
+
functionName: 'execute',
|
|
11017
|
+
args: [params.executeParams, params.tokenInputs, params.signature],
|
|
11018
|
+
// Include value only for native currency swaps (ETH → USDC, etc.)
|
|
11019
|
+
...(isNativeSwap && { value: params.inputAmount }),
|
|
11020
|
+
}, context);
|
|
11021
|
+
};
|
|
11022
|
+
|
|
9269
11023
|
/**
|
|
9270
11024
|
* Prepares an EVM-compatible `balanceOf` read for any ERC-20 token.
|
|
9271
11025
|
*
|
|
@@ -9314,66 +11068,228 @@ const balanceOf$1 = async (params, adapter, context) => {
|
|
|
9314
11068
|
args: [walletAddress],
|
|
9315
11069
|
}, context);
|
|
9316
11070
|
}
|
|
9317
|
-
catch (error) {
|
|
9318
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
9319
|
-
throw new Error(`Failed to get token balance for ${walletAddress} from ${tokenAddress}: ${errorMessage}`);
|
|
11071
|
+
catch (error) {
|
|
11072
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
11073
|
+
throw new Error(`Failed to get token balance for ${walletAddress} from ${tokenAddress}: ${errorMessage}`);
|
|
11074
|
+
}
|
|
11075
|
+
};
|
|
11076
|
+
|
|
11077
|
+
/**
|
|
11078
|
+
* Prepares an EVM-compatible `allowance` read for any ERC-20 token.
|
|
11079
|
+
*
|
|
11080
|
+
* This function creates a prepared chain request for reading the allowance of a given wallet (owner)
|
|
11081
|
+
* and delegate (spender) address for a specified ERC-20 token on an EVM-based chain. It validates the chain type
|
|
11082
|
+
* and all addresses, then constructs a read-only contract call using the canonical ERC-20 ABI and the provided token address.
|
|
11083
|
+
* The resulting prepared request can be executed or simulated by the caller.
|
|
11084
|
+
*
|
|
11085
|
+
* @param params - The action payload containing:
|
|
11086
|
+
* - `tokenAddress`: The contract address of the ERC-20 token.
|
|
11087
|
+
* - `walletAddress`: The address of the token owner (if not provided, will use the adapter's address).
|
|
11088
|
+
* - `delegate`: The address to check the allowance for (spender).
|
|
11089
|
+
* @param adapter - The EVM adapter responsible for chain context and contract interaction.
|
|
11090
|
+
* @param context - The resolved operation context providing chain and address information.
|
|
11091
|
+
* @returns A promise that resolves to a prepared chain request for the `allowance` call.
|
|
11092
|
+
* The `execute` method returns the allowance as a string (in the token's smallest unit).
|
|
11093
|
+
* @throws Error if the current chain is not EVM-compatible, if address validation fails, or if the contract call fails.
|
|
11094
|
+
*
|
|
11095
|
+
* @example
|
|
11096
|
+
* ```typescript
|
|
11097
|
+
* const prepared = await allowance(
|
|
11098
|
+
* { tokenAddress: '0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', walletAddress: '0xabc...', delegate: '0xdef...' },
|
|
11099
|
+
* adapter,
|
|
11100
|
+
* context
|
|
11101
|
+
* );
|
|
11102
|
+
* const allowance = await prepared.execute();
|
|
11103
|
+
* console.log(allowance); // e.g., "1000000" (for 1 USDC allowance with 6 decimals)
|
|
11104
|
+
* ```
|
|
11105
|
+
*/
|
|
11106
|
+
const allowance$1 = async (params, adapter, context) => {
|
|
11107
|
+
const chain = context.chain;
|
|
11108
|
+
if (chain.type !== 'evm') {
|
|
11109
|
+
throw new Error(`Expected EVM chain definition, but received chain type: ${chain.type}`);
|
|
11110
|
+
}
|
|
11111
|
+
const { tokenAddress, walletAddress: walletAddressParam, delegate } = params;
|
|
11112
|
+
// Use provided wallet address or fall back to context address
|
|
11113
|
+
const walletAddress = walletAddressParam ?? context.address;
|
|
11114
|
+
// validate the address
|
|
11115
|
+
assertEvmAddress(walletAddress);
|
|
11116
|
+
assertEvmAddress(tokenAddress);
|
|
11117
|
+
assertEvmAddress(delegate);
|
|
11118
|
+
try {
|
|
11119
|
+
return await adapter.prepare({
|
|
11120
|
+
type: 'evm',
|
|
11121
|
+
address: tokenAddress,
|
|
11122
|
+
abi: erc20Abi,
|
|
11123
|
+
functionName: 'allowance',
|
|
11124
|
+
args: [walletAddress, delegate],
|
|
11125
|
+
}, context);
|
|
11126
|
+
}
|
|
11127
|
+
catch (error) {
|
|
11128
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
11129
|
+
throw new Error(`Failed to get token allowance for ${walletAddress} from ${tokenAddress}: ${errorMessage}`);
|
|
11130
|
+
}
|
|
11131
|
+
};
|
|
11132
|
+
|
|
11133
|
+
/**
|
|
11134
|
+
* Prepares an EVM-compatible `approve` transaction for any ERC-20 token.
|
|
11135
|
+
*
|
|
11136
|
+
* This function creates a prepared chain request for approving a delegate (spender)
|
|
11137
|
+
* to spend a specified amount of tokens on behalf of the caller. It validates the
|
|
11138
|
+
* chain type and all addresses, then constructs a transaction using the standard
|
|
11139
|
+
* ERC-20 ABI and the provided token address. The resulting prepared request can be
|
|
11140
|
+
* executed or simulated by the caller.
|
|
11141
|
+
*
|
|
11142
|
+
* @remarks
|
|
11143
|
+
* **Race Condition Consideration**
|
|
11144
|
+
*
|
|
11145
|
+
* The standard ERC-20 `approve()` function has a known theoretical race condition
|
|
11146
|
+
* where a malicious spender could front-run an approval change to spend both the
|
|
11147
|
+
* old and new allowance amounts. However, this is rare in practice and is the
|
|
11148
|
+
* accepted industry standard used by major protocols (Uniswap, 1inch, etc.).
|
|
11149
|
+
*
|
|
11150
|
+
* @param params - The action payload containing:
|
|
11151
|
+
* - `tokenAddress`: The contract address of the ERC-20 token.
|
|
11152
|
+
* - `delegate`: The address to grant the allowance to (spender).
|
|
11153
|
+
* - `amount`: The amount of tokens to approve (as a bigint, in the token's smallest unit).
|
|
11154
|
+
* @param adapter - The EVM adapter responsible for chain context and transaction preparation.
|
|
11155
|
+
* @param context - The resolved operation context providing chain and address information.
|
|
11156
|
+
* @returns A promise that resolves to a prepared chain request for the `approve` call.
|
|
11157
|
+
* The `execute` method returns the transaction hash.
|
|
11158
|
+
* @throws {KitError} If the current chain is not EVM-compatible (INPUT_INVALID_CHAIN).
|
|
11159
|
+
* @throws {KitError} if the amount is not a postive or zero bigint (INPUT_INVALID_AMOUNT).
|
|
11160
|
+
* @throws {ValidationError} If address validation fails for tokenAddress or delegate.
|
|
11161
|
+
*
|
|
11162
|
+
* @example Approve USDT for a swap contract
|
|
11163
|
+
* ```typescript
|
|
11164
|
+
* import { approve } from '@core/adapter-evm/actions/token'
|
|
11165
|
+
* import { createAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
11166
|
+
* import { Ethereum } from '@core/chains'
|
|
11167
|
+
*
|
|
11168
|
+
* const adapter = createAdapterFromPrivateKey({ privateKey: '0x...' })
|
|
11169
|
+
* const context = {
|
|
11170
|
+
* chain: Ethereum,
|
|
11171
|
+
* address: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
|
|
11172
|
+
* }
|
|
11173
|
+
*
|
|
11174
|
+
* // Approve 100 USDT (6 decimals) for a swap contract
|
|
11175
|
+
* const prepared = await approve(
|
|
11176
|
+
* {
|
|
11177
|
+
* tokenAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
|
|
11178
|
+
* delegate: '0x1234567890123456789012345678901234567890', // Swap contract
|
|
11179
|
+
* amount: 100_000000n // 100 USDT
|
|
11180
|
+
* },
|
|
11181
|
+
* adapter,
|
|
11182
|
+
* context
|
|
11183
|
+
* )
|
|
11184
|
+
*
|
|
11185
|
+
* // Execute the approval
|
|
11186
|
+
* const txHash = await prepared.execute()
|
|
11187
|
+
* console.log('Approval transaction:', txHash)
|
|
11188
|
+
* ```
|
|
11189
|
+
*
|
|
11190
|
+
* @example Approve DAI for a lending protocol
|
|
11191
|
+
* ```typescript
|
|
11192
|
+
* // Approve 1000 DAI (18 decimals) for a lending protocol
|
|
11193
|
+
* const prepared = await approve(
|
|
11194
|
+
* {
|
|
11195
|
+
* tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
|
|
11196
|
+
* delegate: '0xLendingProtocolAddress',
|
|
11197
|
+
* amount: 1000_000000000000000000n // 1000 DAI
|
|
11198
|
+
* },
|
|
11199
|
+
* adapter,
|
|
11200
|
+
* context
|
|
11201
|
+
* )
|
|
11202
|
+
*
|
|
11203
|
+
* await prepared.execute()
|
|
11204
|
+
* ```
|
|
11205
|
+
*
|
|
11206
|
+
* @example Revoke approval by setting to zero
|
|
11207
|
+
* ```typescript
|
|
11208
|
+
* // Revoke approval by setting allowance to 0
|
|
11209
|
+
* const prepared = await approve(
|
|
11210
|
+
* {
|
|
11211
|
+
* tokenAddress: '0xTokenAddress',
|
|
11212
|
+
* delegate: '0xSpenderAddress',
|
|
11213
|
+
* amount: 0n // Revoke approval
|
|
11214
|
+
* },
|
|
11215
|
+
* adapter,
|
|
11216
|
+
* context
|
|
11217
|
+
* )
|
|
11218
|
+
*
|
|
11219
|
+
* await prepared.execute()
|
|
11220
|
+
* ```
|
|
11221
|
+
*/
|
|
11222
|
+
const approve = async (params, adapter, context) => {
|
|
11223
|
+
const chain = context.chain;
|
|
11224
|
+
if (chain.type !== 'evm') {
|
|
11225
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain definition, but received chain type: ${chain.type}`);
|
|
11226
|
+
}
|
|
11227
|
+
const { tokenAddress, delegate, amount } = params;
|
|
11228
|
+
// Validate addresses
|
|
11229
|
+
assertEvmAddress(tokenAddress);
|
|
11230
|
+
assertEvmAddress(delegate);
|
|
11231
|
+
// Validate amount (must be bigint and >= 0)
|
|
11232
|
+
if (typeof amount !== 'bigint' || amount < 0n) {
|
|
11233
|
+
throw createInvalidAmountError(String(amount), 'Approval amount must be a non-negative bigint');
|
|
9320
11234
|
}
|
|
11235
|
+
// Prepare the approve transaction
|
|
11236
|
+
return adapter.prepare({
|
|
11237
|
+
type: 'evm',
|
|
11238
|
+
abi: erc20Abi,
|
|
11239
|
+
address: tokenAddress,
|
|
11240
|
+
functionName: 'approve',
|
|
11241
|
+
args: [delegate, amount],
|
|
11242
|
+
}, context);
|
|
9321
11243
|
};
|
|
9322
11244
|
|
|
9323
11245
|
/**
|
|
9324
|
-
*
|
|
11246
|
+
* Prepare an EVM-compatible ERC-20 `transfer` transaction.
|
|
9325
11247
|
*
|
|
9326
|
-
*
|
|
9327
|
-
*
|
|
9328
|
-
* and all addresses, then constructs a read-only contract call using the canonical ERC-20 ABI and the provided token address.
|
|
9329
|
-
* The resulting prepared request can be executed or simulated by the caller.
|
|
11248
|
+
* Create a prepared chain request to move tokens from the caller's wallet to a
|
|
11249
|
+
* recipient address on EVM chains using the standard ERC-20 ABI.
|
|
9330
11250
|
*
|
|
9331
|
-
*
|
|
9332
|
-
*
|
|
9333
|
-
*
|
|
9334
|
-
*
|
|
9335
|
-
* @param
|
|
9336
|
-
*
|
|
9337
|
-
*
|
|
9338
|
-
*
|
|
9339
|
-
* @
|
|
11251
|
+
* The function validates that the current chain is EVM-compatible, then builds a
|
|
11252
|
+
* transaction targeting the provided token contract address. The resulting prepared
|
|
11253
|
+
* request can be simulated or executed by the caller.
|
|
11254
|
+
*
|
|
11255
|
+
* @param params - The action payload for `token.transfer` containing:
|
|
11256
|
+
* - `tokenAddress`: The ERC-20 token contract address.
|
|
11257
|
+
* - `to`: The recipient wallet address.
|
|
11258
|
+
* - `amount`: The token amount in the smallest unit (as a `bigint`).
|
|
11259
|
+
* @param adapter - The EVM adapter responsible for chain context and transaction preparation.
|
|
11260
|
+
* @returns A promise that resolves to a prepared chain request for the `transfer` call.
|
|
11261
|
+
* @throws {KitError} If chain is not EVM (INPUT_INVALID_CHAIN) or amount is invalid (INPUT_INVALID_AMOUNT).
|
|
9340
11262
|
*
|
|
9341
11263
|
* @example
|
|
9342
11264
|
* ```typescript
|
|
9343
|
-
* const prepared = await
|
|
9344
|
-
* {
|
|
9345
|
-
*
|
|
9346
|
-
*
|
|
11265
|
+
* const prepared = await transfer(
|
|
11266
|
+
* {
|
|
11267
|
+
* tokenAddress: '0x0000000000000000000000000000000000000000',
|
|
11268
|
+
* to: '0x1111111111111111111111111111111111111111',
|
|
11269
|
+
* amount: 1_000_000n,
|
|
11270
|
+
* },
|
|
11271
|
+
* adapter
|
|
9347
11272
|
* );
|
|
9348
|
-
*
|
|
9349
|
-
* console.log(allowance); // e.g., "1000000" (for 1 USDC allowance with 6 decimals)
|
|
11273
|
+
* await prepared.execute();
|
|
9350
11274
|
* ```
|
|
9351
11275
|
*/
|
|
9352
|
-
const
|
|
11276
|
+
const transfer$2 = async (params, adapter, context) => {
|
|
9353
11277
|
const chain = context.chain;
|
|
9354
11278
|
if (chain.type !== 'evm') {
|
|
9355
|
-
throw
|
|
9356
|
-
}
|
|
9357
|
-
const { tokenAddress, walletAddress: walletAddressParam, delegate } = params;
|
|
9358
|
-
// Use provided wallet address or fall back to context address
|
|
9359
|
-
const walletAddress = walletAddressParam ?? context.address;
|
|
9360
|
-
// validate the address
|
|
9361
|
-
assertEvmAddress(walletAddress);
|
|
9362
|
-
assertEvmAddress(tokenAddress);
|
|
9363
|
-
assertEvmAddress(delegate);
|
|
9364
|
-
try {
|
|
9365
|
-
return await adapter.prepare({
|
|
9366
|
-
type: 'evm',
|
|
9367
|
-
address: tokenAddress,
|
|
9368
|
-
abi: erc20Abi,
|
|
9369
|
-
functionName: 'allowance',
|
|
9370
|
-
args: [walletAddress, delegate],
|
|
9371
|
-
}, context);
|
|
11279
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain definition, but received chain type: ${chain.type}`);
|
|
9372
11280
|
}
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
throw
|
|
11281
|
+
// Validate the amount
|
|
11282
|
+
if (typeof params.amount !== 'bigint' || params.amount <= 0n) {
|
|
11283
|
+
throw createInvalidAmountError(String(params.amount), 'Transfer amount must be a positive bigint');
|
|
9376
11284
|
}
|
|
11285
|
+
// Prepare the transfer transaction
|
|
11286
|
+
return adapter.prepare({
|
|
11287
|
+
type: 'evm',
|
|
11288
|
+
abi: erc20Abi,
|
|
11289
|
+
address: params.tokenAddress,
|
|
11290
|
+
functionName: 'transfer',
|
|
11291
|
+
args: [params.to, params.amount],
|
|
11292
|
+
}, context);
|
|
9377
11293
|
};
|
|
9378
11294
|
|
|
9379
11295
|
/**
|
|
@@ -9503,6 +11419,106 @@ const allowance = async (params, adapter, context) => {
|
|
|
9503
11419
|
}, adapter, context);
|
|
9504
11420
|
};
|
|
9505
11421
|
|
|
11422
|
+
/**
|
|
11423
|
+
* Prepares a USDC `transfer` transaction for EVM-compatible chains.
|
|
11424
|
+
*
|
|
11425
|
+
* This function validates that the current chain is EVM-compatible and that a canonical
|
|
11426
|
+
* USDC contract address is available for the chain. It then constructs a prepared chain
|
|
11427
|
+
* request to transfer USDC from the caller's wallet to a specified recipient address,
|
|
11428
|
+
* using the standard ERC-20 ABI and the chain's USDC contract address.
|
|
11429
|
+
*
|
|
11430
|
+
* The resulting prepared request can be simulated, estimated, or executed by the caller.
|
|
11431
|
+
*
|
|
11432
|
+
* @param params - The action payload for `usdc.transfer`:
|
|
11433
|
+
* - `to`: The recipient wallet address.
|
|
11434
|
+
* - `amount`: The USDC amount to transfer (in the smallest unit, as a `bigint`).
|
|
11435
|
+
* @param adapter - The EVM adapter providing chain context and contract interaction.
|
|
11436
|
+
* @returns A promise resolving to a prepared chain request for the USDC `transfer` call.
|
|
11437
|
+
* The returned request's `execute` method sends the transaction.
|
|
11438
|
+
* @throws {KitError} If chain is not EVM (INPUT_INVALID_CHAIN) or USDC is not supported (INPUT_UNSUPPORTED_TOKEN).
|
|
11439
|
+
*
|
|
11440
|
+
* @example
|
|
11441
|
+
* ```typescript
|
|
11442
|
+
* const prepared = await transfer(
|
|
11443
|
+
* {
|
|
11444
|
+
* to: '0x1111111111111111111111111111111111111111',
|
|
11445
|
+
* amount: 1_000_000n,
|
|
11446
|
+
* },
|
|
11447
|
+
* adapter
|
|
11448
|
+
* );
|
|
11449
|
+
* await prepared.execute();
|
|
11450
|
+
* ```
|
|
11451
|
+
*/
|
|
11452
|
+
const transfer$1 = async (params, adapter, context) => {
|
|
11453
|
+
const chain = context.chain;
|
|
11454
|
+
if (chain.type !== 'evm') {
|
|
11455
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain definition, but received chain type: ${chain.type}`);
|
|
11456
|
+
}
|
|
11457
|
+
const tokenAddress = chain.usdcAddress;
|
|
11458
|
+
// Check if USDC address exists before validating
|
|
11459
|
+
if (tokenAddress == null) {
|
|
11460
|
+
throw createUnsupportedTokenError('USDC', chain.name);
|
|
11461
|
+
}
|
|
11462
|
+
assertEvmAddress(tokenAddress);
|
|
11463
|
+
// Prepare the usdc transfer transaction using the base token transfer function
|
|
11464
|
+
return transfer$2({
|
|
11465
|
+
tokenAddress,
|
|
11466
|
+
to: params.to,
|
|
11467
|
+
amount: params.amount,
|
|
11468
|
+
}, adapter, context);
|
|
11469
|
+
};
|
|
11470
|
+
|
|
11471
|
+
/**
|
|
11472
|
+
* Prepares a USDT `transfer` transaction for EVM-compatible chains.
|
|
11473
|
+
*
|
|
11474
|
+
* This function validates that the current chain is EVM-compatible and that a canonical
|
|
11475
|
+
* USDT contract address is available for the chain. It then constructs a prepared chain
|
|
11476
|
+
* request to transfer USDT from the caller's wallet to a specified recipient address,
|
|
11477
|
+
* using the standard ERC-20 ABI and the chain's USDT contract address.
|
|
11478
|
+
*
|
|
11479
|
+
* The resulting prepared request can be simulated, estimated, or executed by the caller.
|
|
11480
|
+
*
|
|
11481
|
+
* @param params - The action payload for `usdt.transfer`:
|
|
11482
|
+
* - `to`: The recipient wallet address.
|
|
11483
|
+
* - `amount`: The USDT amount to transfer (in the smallest unit, as a `bigint`).
|
|
11484
|
+
* @param adapter - The EVM adapter providing chain context and contract interaction.
|
|
11485
|
+
* @param context - The resolved operation context containing chain definition.
|
|
11486
|
+
* @returns A promise resolving to a prepared chain request for the USDT `transfer` call.
|
|
11487
|
+
* The returned request's `execute` method sends the transaction.
|
|
11488
|
+
* @throws {KitError} If chain is not EVM (INPUT_INVALID_CHAIN) or USDT is not supported (INPUT_UNSUPPORTED_TOKEN).
|
|
11489
|
+
*
|
|
11490
|
+
* @example
|
|
11491
|
+
* ```typescript
|
|
11492
|
+
* const prepared = await transfer(
|
|
11493
|
+
* {
|
|
11494
|
+
* to: '0x1111111111111111111111111111111111111111',
|
|
11495
|
+
* amount: 1_000_000n,
|
|
11496
|
+
* },
|
|
11497
|
+
* adapter,
|
|
11498
|
+
* context
|
|
11499
|
+
* );
|
|
11500
|
+
* await prepared.execute();
|
|
11501
|
+
* ```
|
|
11502
|
+
*/
|
|
11503
|
+
const transfer = async (params, adapter, context) => {
|
|
11504
|
+
const chain = context.chain;
|
|
11505
|
+
if (chain.type !== 'evm') {
|
|
11506
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain, but received chain type: ${chain.type}`);
|
|
11507
|
+
}
|
|
11508
|
+
const tokenAddress = chain.usdtAddress;
|
|
11509
|
+
// Check if USDT address exists before validating
|
|
11510
|
+
if (tokenAddress == null) {
|
|
11511
|
+
throw createUnsupportedTokenError('USDT', chain.name);
|
|
11512
|
+
}
|
|
11513
|
+
assertEvmAddress(tokenAddress);
|
|
11514
|
+
// Prepare the usdt transfer transaction using the base token transfer function
|
|
11515
|
+
return transfer$2({
|
|
11516
|
+
tokenAddress,
|
|
11517
|
+
to: params.to,
|
|
11518
|
+
amount: params.amount,
|
|
11519
|
+
}, adapter, context);
|
|
11520
|
+
};
|
|
11521
|
+
|
|
9506
11522
|
/**
|
|
9507
11523
|
* Creates a collection of action handlers for EVM blockchain operations.
|
|
9508
11524
|
*
|
|
@@ -9539,6 +11555,15 @@ const getHandlers = (adapter) => {
|
|
|
9539
11555
|
'token.balanceOf': async (params, context) => {
|
|
9540
11556
|
return balanceOf$1(params, adapter, context);
|
|
9541
11557
|
},
|
|
11558
|
+
/**
|
|
11559
|
+
* Handler for token approve operations on EVM chains.
|
|
11560
|
+
*
|
|
11561
|
+
* Approves a delegate to spend tokens on behalf of the caller.
|
|
11562
|
+
* Uses the standard ERC-20 approve function.
|
|
11563
|
+
*/
|
|
11564
|
+
'token.approve': async (params, context) => {
|
|
11565
|
+
return approve(params, adapter, context);
|
|
11566
|
+
},
|
|
9542
11567
|
/**
|
|
9543
11568
|
* Handler for USDC allowance operations on EVM chains.
|
|
9544
11569
|
*
|
|
@@ -9602,6 +11627,49 @@ const getHandlers = (adapter) => {
|
|
|
9602
11627
|
'cctp.v2.customBurn': async (params, context) => {
|
|
9603
11628
|
return customBurn(params, adapter, context);
|
|
9604
11629
|
},
|
|
11630
|
+
/**
|
|
11631
|
+
* Handler for token transfer operations on EVM chains.
|
|
11632
|
+
*
|
|
11633
|
+
* Transfers the specified amount of the token from the caller's wallet to the specified recipient address.
|
|
11634
|
+
*/
|
|
11635
|
+
'token.transfer': async (params, context) => {
|
|
11636
|
+
return transfer$2(params, adapter, context);
|
|
11637
|
+
},
|
|
11638
|
+
/**
|
|
11639
|
+
* Handler for native token transfer operations on EVM chains.
|
|
11640
|
+
*
|
|
11641
|
+
* Transfers the specified amount of native tokens from the caller's wallet to the specified recipient address.
|
|
11642
|
+
*/
|
|
11643
|
+
'native.transfer': async (params, context) => {
|
|
11644
|
+
return transfer$3(params, adapter, context);
|
|
11645
|
+
},
|
|
11646
|
+
/**
|
|
11647
|
+
* Handler for USDC transfer operations on EVM chains.
|
|
11648
|
+
*
|
|
11649
|
+
* Transfers the specified amount of USDC from the caller's wallet to the specified recipient address.
|
|
11650
|
+
*/
|
|
11651
|
+
'usdc.transfer': async (params, context) => {
|
|
11652
|
+
return transfer$1(params, adapter, context);
|
|
11653
|
+
},
|
|
11654
|
+
/**
|
|
11655
|
+
* Handler for USDT transfer operations on EVM chains.
|
|
11656
|
+
*
|
|
11657
|
+
* Transfers the specified amount of USDT from the caller's wallet to the specified recipient address.
|
|
11658
|
+
*/
|
|
11659
|
+
'usdt.transfer': async (params, context) => {
|
|
11660
|
+
return transfer(params, adapter, context);
|
|
11661
|
+
},
|
|
11662
|
+
/**
|
|
11663
|
+
* Handler for swap execution.
|
|
11664
|
+
*
|
|
11665
|
+
* Executes pre-built swap transactions from the stablecoin-service API.
|
|
11666
|
+
* The service handles DEX aggregation and routing; this action handles
|
|
11667
|
+
* transaction preparation and execution. Token approvals are managed
|
|
11668
|
+
* separately by the provider layer.
|
|
11669
|
+
*/
|
|
11670
|
+
'swap.execute': async (params, context) => {
|
|
11671
|
+
return executeSwap(params, adapter, context);
|
|
11672
|
+
},
|
|
9605
11673
|
/**
|
|
9606
11674
|
* Handler for CCTP v2 custom burn with hook operations on EVM chains.
|
|
9607
11675
|
*
|
|
@@ -10439,6 +12507,44 @@ const evmPreparedChainRequestParamsSchema = z.object({
|
|
|
10439
12507
|
invalid_type_error: 'Arguments must be an array',
|
|
10440
12508
|
}),
|
|
10441
12509
|
});
|
|
12510
|
+
/**
|
|
12511
|
+
* Zod schema for validating native token transfer parameters.
|
|
12512
|
+
*
|
|
12513
|
+
* This schema validates the parameters required for native token transfers
|
|
12514
|
+
* (e.g., ETH on Ethereum, MATIC on Polygon):
|
|
12515
|
+
* - Address must be a valid EVM address (42 characters starting with 0x)
|
|
12516
|
+
* - Value must be a positive bigint greater than 0
|
|
12517
|
+
*
|
|
12518
|
+
* @throws KitError if validation fails
|
|
12519
|
+
*
|
|
12520
|
+
* @example
|
|
12521
|
+
* ```typescript
|
|
12522
|
+
* import { nativeTransferParamsSchema } from '@core/adapter-evm/validation'
|
|
12523
|
+
*
|
|
12524
|
+
* const params = {
|
|
12525
|
+
* address: '0x1234567890123456789012345678901234567890',
|
|
12526
|
+
* value: BigInt(1000000)
|
|
12527
|
+
* }
|
|
12528
|
+
*
|
|
12529
|
+
* const result = nativeTransferParamsSchema.safeParse(params)
|
|
12530
|
+
* if (result.success) {
|
|
12531
|
+
* console.log('Native transfer params are valid')
|
|
12532
|
+
* } else {
|
|
12533
|
+
* console.error('Validation failed:', result.error)
|
|
12534
|
+
* }
|
|
12535
|
+
* ```
|
|
12536
|
+
*/
|
|
12537
|
+
const nativeTransferParamsSchema = z.object({
|
|
12538
|
+
address: evmAddressSchema,
|
|
12539
|
+
value: z
|
|
12540
|
+
.bigint({
|
|
12541
|
+
required_error: 'Value is required for native transfers',
|
|
12542
|
+
invalid_type_error: 'Value must be a bigint',
|
|
12543
|
+
})
|
|
12544
|
+
.refine((val) => val > BigInt(0), {
|
|
12545
|
+
message: 'Value must be greater than 0',
|
|
12546
|
+
}),
|
|
12547
|
+
});
|
|
10442
12548
|
/**
|
|
10443
12549
|
* Zod schema for validating Ethereum transaction hashes.
|
|
10444
12550
|
*
|
|
@@ -10583,6 +12689,44 @@ function assertEvmTransactionHash(txHash) {
|
|
|
10583
12689
|
validate(txHash, evmTransactionHashSchema, 'Transaction hash');
|
|
10584
12690
|
}
|
|
10585
12691
|
|
|
12692
|
+
const assertNativeTransferParamsSymbol = Symbol('assertNativeTransferParams');
|
|
12693
|
+
/**
|
|
12694
|
+
* Asserts that the provided parameters are valid for native token transfers.
|
|
12695
|
+
*
|
|
12696
|
+
* The validation includes:
|
|
12697
|
+
* - A valid EVM address (42 characters starting with 0x)
|
|
12698
|
+
* - A positive bigint value greater than 0
|
|
12699
|
+
*
|
|
12700
|
+
* @param params - The parameters to validate
|
|
12701
|
+
* @throws KitError with INPUT_VALIDATION_FAILED code if validation fails, with details about which properties failed
|
|
12702
|
+
*
|
|
12703
|
+
* @example
|
|
12704
|
+
* ```typescript
|
|
12705
|
+
* import { assertNativeTransferParams } from '@core/adapter-evm'
|
|
12706
|
+
*
|
|
12707
|
+
* // Valid native transfer
|
|
12708
|
+
* assertNativeTransferParams({
|
|
12709
|
+
* address: '0x1234567890123456789012345678901234567890',
|
|
12710
|
+
* value: BigInt(1000000)
|
|
12711
|
+
* })
|
|
12712
|
+
*
|
|
12713
|
+
* // This will throw KitError - invalid address
|
|
12714
|
+
* assertNativeTransferParams({
|
|
12715
|
+
* address: '0x123',
|
|
12716
|
+
* value: BigInt(1000000)
|
|
12717
|
+
* })
|
|
12718
|
+
*
|
|
12719
|
+
* // This will throw KitError - zero value
|
|
12720
|
+
* assertNativeTransferParams({
|
|
12721
|
+
* address: '0x1234567890123456789012345678901234567890',
|
|
12722
|
+
* value: BigInt(0)
|
|
12723
|
+
* })
|
|
12724
|
+
* ```
|
|
12725
|
+
*/
|
|
12726
|
+
function assertNativeTransferParams(params) {
|
|
12727
|
+
validateWithStateTracking(params, nativeTransferParamsSchema, 'Native transfer params', assertNativeTransferParamsSymbol);
|
|
12728
|
+
}
|
|
12729
|
+
|
|
10586
12730
|
/**
|
|
10587
12731
|
* Asserts that the provided data matches the EIP-712 TypedData interface.
|
|
10588
12732
|
*
|
|
@@ -11678,15 +13822,21 @@ class EthersAdapter extends EvmAdapter {
|
|
|
11678
13822
|
/**
|
|
11679
13823
|
* Simulates a contract function call using Ethers v6 `.staticCall`.
|
|
11680
13824
|
*/
|
|
11681
|
-
async simulateFunctionCall(contract, functionName, args, chain) {
|
|
13825
|
+
async simulateFunctionCall(contract, functionName, args, chain, overrides) {
|
|
11682
13826
|
// Retry on allowance errors to handle RPC state propagation delays
|
|
11683
13827
|
// (e.g., approve tx confirmed but not yet visible in latest block for staticCall)
|
|
11684
|
-
const MAX_SIMULATION_ATTEMPTS =
|
|
13828
|
+
const MAX_SIMULATION_ATTEMPTS = 5;
|
|
11685
13829
|
const SIMULATION_RETRY_DELAY_MS = 1000;
|
|
11686
13830
|
for (let attempt = 1; attempt <= MAX_SIMULATION_ATTEMPTS; attempt++) {
|
|
11687
13831
|
try {
|
|
11688
13832
|
const func = contract.getFunction(functionName);
|
|
11689
|
-
|
|
13833
|
+
// Pass overrides to staticCall so that value (ETH) is included in simulation
|
|
13834
|
+
if (overrides) {
|
|
13835
|
+
await func.staticCall(...args, overrides);
|
|
13836
|
+
}
|
|
13837
|
+
else {
|
|
13838
|
+
await func.staticCall(...args);
|
|
13839
|
+
}
|
|
11690
13840
|
return;
|
|
11691
13841
|
}
|
|
11692
13842
|
catch (err) {
|
|
@@ -11781,6 +13931,24 @@ class EthersAdapter extends EvmAdapter {
|
|
|
11781
13931
|
if (!txRequest) {
|
|
11782
13932
|
throw new Error(`Failed to populate transaction for function '${functionName}'.`);
|
|
11783
13933
|
}
|
|
13934
|
+
return this.sendTransactionWithNonceManagement(txRequest, fromAddress, chain, overrides);
|
|
13935
|
+
}
|
|
13936
|
+
/**
|
|
13937
|
+
* Common transaction sending logic with nonce management and retry logic.
|
|
13938
|
+
*
|
|
13939
|
+
* This method handles the complete transaction lifecycle:
|
|
13940
|
+
* - Nonce allocation and management via {@link ethersNonceManager}
|
|
13941
|
+
* - Automatic retry on nonce-related errors (up to 3 attempts)
|
|
13942
|
+
* - Graceful handling of user-provided nonces (no retry)
|
|
13943
|
+
* - Proper error handling and wrapping
|
|
13944
|
+
*
|
|
13945
|
+
* @param txRequest - Populated transaction request
|
|
13946
|
+
* @param fromAddress - The address sending the transaction
|
|
13947
|
+
* @param chain - The chain definition for context
|
|
13948
|
+
* @param overrides - Optional transaction overrides
|
|
13949
|
+
* @returns Transaction hash
|
|
13950
|
+
*/
|
|
13951
|
+
async sendTransactionWithNonceManagement(txRequest, fromAddress, chain, overrides) {
|
|
11784
13952
|
// Chain is passed as parameter to avoid race conditions in concurrent requests
|
|
11785
13953
|
const provider = await this.getProvider(chain);
|
|
11786
13954
|
if (!fromAddress) {
|
|
@@ -11937,9 +14105,18 @@ class EthersAdapter extends EvmAdapter {
|
|
|
11937
14105
|
* ```
|
|
11938
14106
|
*/
|
|
11939
14107
|
async prepare(params, ctx) {
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
const
|
|
14108
|
+
const { address, abi, functionName, args, value } = params;
|
|
14109
|
+
// Detect native transfer early: no abi, no functionName, no args, but has value
|
|
14110
|
+
const isNativeTransfer = !abi && !functionName && !args && value !== undefined;
|
|
14111
|
+
// Validate parameters based on transfer type
|
|
14112
|
+
if (isNativeTransfer) {
|
|
14113
|
+
// For native transfers, validate address and value
|
|
14114
|
+
assertNativeTransferParams({ address, value });
|
|
14115
|
+
}
|
|
14116
|
+
else {
|
|
14117
|
+
// For contract calls, use full validation
|
|
14118
|
+
assertEvmPreparedChainRequestParams(params);
|
|
14119
|
+
}
|
|
11943
14120
|
// First, resolve the target chain from the operation context
|
|
11944
14121
|
const targetChain = resolveChainIdentifier(ctx.chain);
|
|
11945
14122
|
if (targetChain.type !== 'evm') {
|
|
@@ -11962,6 +14139,10 @@ class EthersAdapter extends EvmAdapter {
|
|
|
11962
14139
|
if (!resolvedContext) {
|
|
11963
14140
|
throw new Error('OperationContext resolution failed. Ensure the adapter has capabilities configured.');
|
|
11964
14141
|
}
|
|
14142
|
+
// Handle native transfers separately (after context resolution)
|
|
14143
|
+
if (isNativeTransfer) {
|
|
14144
|
+
return this.prepareNativeTransfer(address, value, targetChain, resolvedContext.address);
|
|
14145
|
+
}
|
|
11965
14146
|
const signer = this.getSigner();
|
|
11966
14147
|
const contract = this.createContractInstance(params, signer, resolvedContext.address, provider);
|
|
11967
14148
|
return {
|
|
@@ -11972,18 +14153,33 @@ class EthersAdapter extends EvmAdapter {
|
|
|
11972
14153
|
// gas estimation and fee data retrieval use the correct network.
|
|
11973
14154
|
const estimationProvider = await this.getProvider(targetChain);
|
|
11974
14155
|
const contractForEstimation = contract.connect(estimationProvider);
|
|
11975
|
-
|
|
14156
|
+
// Merge value from params with overrides, with overrides taking precedence
|
|
14157
|
+
// Include 'from' address since connecting to a Provider (not Signer) loses
|
|
14158
|
+
// the ability to infer the sender address, which would otherwise default to
|
|
14159
|
+
// the zero address and cause "transfer from the zero address" errors.
|
|
14160
|
+
const mergedOverrides = {
|
|
14161
|
+
from: resolvedContext.address,
|
|
14162
|
+
...(value !== undefined && { value }),
|
|
14163
|
+
...overrides,
|
|
14164
|
+
};
|
|
14165
|
+
return this.estimateGasForFunction(contractForEstimation, functionName, args, targetChain, mergedOverrides, fallback);
|
|
11976
14166
|
},
|
|
11977
14167
|
execute: async (overrides) => {
|
|
14168
|
+
// Merge value from params with overrides, with overrides taking precedence
|
|
14169
|
+
// Only add value if it's defined (exactOptionalPropertyTypes requires this pattern)
|
|
14170
|
+
const mergedOverrides = {
|
|
14171
|
+
...(value !== undefined && { value }),
|
|
14172
|
+
...overrides,
|
|
14173
|
+
};
|
|
11978
14174
|
// Simulate the function call to catch errors before submission
|
|
11979
|
-
await this.simulateFunctionCall(contract, functionName, args, targetChain);
|
|
14175
|
+
await this.simulateFunctionCall(contract, functionName, args, targetChain, mergedOverrides);
|
|
11980
14176
|
await this.ensureChain(targetChain);
|
|
11981
14177
|
// Reconnect the contract with the current signer, which is on the correct
|
|
11982
14178
|
// chain after `ensureChain`, to ensure the transaction is populated and
|
|
11983
14179
|
// sent correctly.
|
|
11984
14180
|
const currentSigner = this.getSigner();
|
|
11985
14181
|
const contractForExecution = contract.connect(currentSigner);
|
|
11986
|
-
return this.executeTransaction(contractForExecution, functionName, args, resolvedContext.address, targetChain,
|
|
14182
|
+
return this.executeTransaction(contractForExecution, functionName, args, resolvedContext.address, targetChain, mergedOverrides);
|
|
11987
14183
|
},
|
|
11988
14184
|
};
|
|
11989
14185
|
}
|
|
@@ -12021,11 +14217,11 @@ class EthersAdapter extends EvmAdapter {
|
|
|
12021
14217
|
async getAddress(chain) {
|
|
12022
14218
|
// Prevent calling getAddress on developer-controlled adapters
|
|
12023
14219
|
if (this.capabilities?.addressContext === 'developer-controlled') {
|
|
12024
|
-
throw
|
|
14220
|
+
throw createValidationFailedError('adapter', 'invalid-operation', 'Cannot call getAddress() on developer-controlled adapters. Address must be provided explicitly in the operation context.');
|
|
12025
14221
|
}
|
|
12026
14222
|
// Chain parameter should now be provided by resolveOperationContext
|
|
12027
14223
|
if (!chain) {
|
|
12028
|
-
throw
|
|
14224
|
+
throw createValidationFailedError('chain', 'required', 'Chain parameter is required for address resolution. This should be provided by the OperationContext pattern.');
|
|
12029
14225
|
}
|
|
12030
14226
|
const signer = this.getSigner();
|
|
12031
14227
|
const address = await signer.getAddress();
|
|
@@ -12224,15 +14420,15 @@ class EthersAdapter extends EvmAdapter {
|
|
|
12224
14420
|
// Get chain from required OperationContext
|
|
12225
14421
|
const resolvedContext = await resolveOperationContext(this, ctx);
|
|
12226
14422
|
if (!resolvedContext) {
|
|
12227
|
-
throw
|
|
14423
|
+
throw createValidationFailedError('context', 'resolution-failed', 'OperationContext resolution failed. Ensure the adapter has capabilities configured.');
|
|
12228
14424
|
}
|
|
12229
14425
|
const targetChain = resolvedContext.chain;
|
|
12230
14426
|
if (targetChain.type !== 'evm') {
|
|
12231
|
-
throw
|
|
14427
|
+
throw createInvalidChainError(targetChain.name, `Invalid chain type '${String(targetChain.type)}' for EthersAdapter. Expected 'evm' chain type.`);
|
|
12232
14428
|
}
|
|
12233
14429
|
const signer = this.getSigner();
|
|
12234
14430
|
if (!signer) {
|
|
12235
|
-
throw
|
|
14431
|
+
throw createValidationFailedError('signer', 'not-configured', 'No signer is configured. Please provide a signer to sign typed data.');
|
|
12236
14432
|
}
|
|
12237
14433
|
const types = { ...typedData.types };
|
|
12238
14434
|
delete types['EIP712Domain'];
|
|
@@ -12289,6 +14485,93 @@ class EthersAdapter extends EvmAdapter {
|
|
|
12289
14485
|
},
|
|
12290
14486
|
};
|
|
12291
14487
|
}
|
|
14488
|
+
/**
|
|
14489
|
+
* Prepares a native token transfer (ETH, MATIC, etc.) for gas estimation and execution.
|
|
14490
|
+
*
|
|
14491
|
+
* Native transfers are simple value transfers that don't require contract ABI or function calls.
|
|
14492
|
+
* This method reuses the existing transaction execution flow but skips contract-specific logic.
|
|
14493
|
+
*
|
|
14494
|
+
* @param address - The recipient address for the native token transfer
|
|
14495
|
+
* @param value - The amount of native tokens to send (in wei)
|
|
14496
|
+
* @param targetChain - The target chain definition
|
|
14497
|
+
* @param resolvedAddress - The resolved sender address from operation context
|
|
14498
|
+
* @returns Prepared chain request for native transfer
|
|
14499
|
+
* @throws Error when gas estimation fails without fallback
|
|
14500
|
+
* @throws Error when gas price retrieval fails
|
|
14501
|
+
* @throws Error when transaction execution fails
|
|
14502
|
+
*
|
|
14503
|
+
* @example
|
|
14504
|
+
* ```typescript
|
|
14505
|
+
* // Internal usage - called by prepare() when native transfer is detected
|
|
14506
|
+
* const prepared = this.prepareNativeTransfer(
|
|
14507
|
+
* '0x1234567890123456789012345678901234567890',
|
|
14508
|
+
* BigInt(1000000000000000000), // 1 ETH
|
|
14509
|
+
* Ethereum,
|
|
14510
|
+
* '0xsenderAddress'
|
|
14511
|
+
* );
|
|
14512
|
+
* const estimate = await prepared.estimate();
|
|
14513
|
+
* const txHash = await prepared.execute();
|
|
14514
|
+
* ```
|
|
14515
|
+
*/
|
|
14516
|
+
prepareNativeTransfer(address, value, targetChain, resolvedAddress) {
|
|
14517
|
+
return {
|
|
14518
|
+
type: 'evm',
|
|
14519
|
+
estimate: async (overrides, fallback) => {
|
|
14520
|
+
await this.ensureChain(targetChain);
|
|
14521
|
+
const estimationProvider = await this.getProvider(targetChain);
|
|
14522
|
+
let gas;
|
|
14523
|
+
try {
|
|
14524
|
+
gas = await estimationProvider.estimateGas({
|
|
14525
|
+
to: address,
|
|
14526
|
+
value,
|
|
14527
|
+
from: resolvedAddress,
|
|
14528
|
+
...overrides,
|
|
14529
|
+
});
|
|
14530
|
+
}
|
|
14531
|
+
catch (error) {
|
|
14532
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
14533
|
+
if (fallback &&
|
|
14534
|
+
errorMessage.toLowerCase().includes('execution reverted')) {
|
|
14535
|
+
return fallback;
|
|
14536
|
+
}
|
|
14537
|
+
// Wrap gas estimation errors with structured error format
|
|
14538
|
+
throw parseBlockchainError(error, {
|
|
14539
|
+
chain: targetChain.name,
|
|
14540
|
+
operation: 'estimateGas',
|
|
14541
|
+
});
|
|
14542
|
+
}
|
|
14543
|
+
let gasPrice;
|
|
14544
|
+
try {
|
|
14545
|
+
gasPrice = await this.fetchGasPrice(targetChain);
|
|
14546
|
+
}
|
|
14547
|
+
catch (error) {
|
|
14548
|
+
// Wrap gas price errors with structured error format
|
|
14549
|
+
throw parseBlockchainError(error, {
|
|
14550
|
+
chain: targetChain.name,
|
|
14551
|
+
operation: 'getGasPrice',
|
|
14552
|
+
});
|
|
14553
|
+
}
|
|
14554
|
+
return {
|
|
14555
|
+
gas,
|
|
14556
|
+
gasPrice,
|
|
14557
|
+
fee: (gas * gasPrice).toString(),
|
|
14558
|
+
};
|
|
14559
|
+
},
|
|
14560
|
+
execute: async (overrides) => {
|
|
14561
|
+
await this.ensureChain(targetChain);
|
|
14562
|
+
// Create transaction request for native transfer
|
|
14563
|
+
const txRequest = {
|
|
14564
|
+
to: address,
|
|
14565
|
+
value,
|
|
14566
|
+
...overrides,
|
|
14567
|
+
};
|
|
14568
|
+
// Use common transaction sending logic with nonce management
|
|
14569
|
+
const hash = await this.sendTransactionWithNonceManagement(txRequest, resolvedAddress, targetChain, overrides);
|
|
14570
|
+
assertEvmTransactionHash(hash);
|
|
14571
|
+
return hash;
|
|
14572
|
+
},
|
|
14573
|
+
};
|
|
14574
|
+
}
|
|
12292
14575
|
/**
|
|
12293
14576
|
* Reads a contract function using Ethers v6.
|
|
12294
14577
|
*
|
|
@@ -12304,6 +14587,64 @@ class EthersAdapter extends EvmAdapter {
|
|
|
12304
14587
|
const contractFunction = contract.getFunction(functionName);
|
|
12305
14588
|
return (await contractFunction.staticCall(...args));
|
|
12306
14589
|
}
|
|
14590
|
+
/**
|
|
14591
|
+
* Get the decimal places for an ERC-20 token on an EVM chain.
|
|
14592
|
+
*
|
|
14593
|
+
* This method calls the `decimals()` function on the ERC-20 token contract
|
|
14594
|
+
* to fetch the number of decimal places. Ethers v6 returns decimals as bigint,
|
|
14595
|
+
* which is validated and converted to a number.
|
|
14596
|
+
*
|
|
14597
|
+
* @param tokenAddress - The ERC-20 token contract address
|
|
14598
|
+
* @param chain - The EVM chain definition where the token is deployed
|
|
14599
|
+
* @returns Promise resolving to the number of decimal places
|
|
14600
|
+
* @throws Error when the contract doesn't exist, doesn't support decimals(), or returns invalid data
|
|
14601
|
+
*
|
|
14602
|
+
* @remarks
|
|
14603
|
+
* - Ethers v6 returns decimals as bigint
|
|
14604
|
+
* - Validates that decimals are within 0-255 range (ERC-20 uint8 standard)
|
|
14605
|
+
* - Converts bigint to number for consistent API
|
|
14606
|
+
*
|
|
14607
|
+
* @example
|
|
14608
|
+
* ```typescript
|
|
14609
|
+
* import { EthersAdapter } from '@circle-fin/adapter-ethers-v6'
|
|
14610
|
+
* import { Ethereum } from '@core/chains'
|
|
14611
|
+
*
|
|
14612
|
+
* const adapter = new EthersAdapter({ signer })
|
|
14613
|
+
*
|
|
14614
|
+
* // Fetch decimals for DAI token
|
|
14615
|
+
* const decimals = await adapter.getTokenDecimals(
|
|
14616
|
+
* '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
14617
|
+
* Ethereum
|
|
14618
|
+
* )
|
|
14619
|
+
* console.log(decimals) // 18
|
|
14620
|
+
* ```
|
|
14621
|
+
*/
|
|
14622
|
+
async getTokenDecimals(tokenAddress, chain) {
|
|
14623
|
+
try {
|
|
14624
|
+
// Ethers v6 returns bigint for uint8
|
|
14625
|
+
const decimalsResult = await this.readContract({
|
|
14626
|
+
address: tokenAddress,
|
|
14627
|
+
abi: erc20Abi,
|
|
14628
|
+
functionName: 'decimals',
|
|
14629
|
+
args: [],
|
|
14630
|
+
}, chain);
|
|
14631
|
+
// Validate decimals are within valid range (0-255)
|
|
14632
|
+
if (typeof decimalsResult !== 'bigint' ||
|
|
14633
|
+
decimalsResult < 0n ||
|
|
14634
|
+
decimalsResult > 255n) {
|
|
14635
|
+
throw createValidationFailedError('decimals', decimalsResult, 'Token decimals must be a bigint between 0 and 255');
|
|
14636
|
+
}
|
|
14637
|
+
// Convert bigint to number
|
|
14638
|
+
return Number(decimalsResult);
|
|
14639
|
+
}
|
|
14640
|
+
catch (error) {
|
|
14641
|
+
// If it's already a KitError from our validation, re-throw as-is
|
|
14642
|
+
if (error instanceof KitError) {
|
|
14643
|
+
throw error;
|
|
14644
|
+
}
|
|
14645
|
+
throw createValidationFailedError('tokenAddress', tokenAddress, `Failed to fetch decimals for token on ${chain.name}: ${getErrorMessage(error)}`);
|
|
14646
|
+
}
|
|
14647
|
+
}
|
|
12307
14648
|
}
|
|
12308
14649
|
|
|
12309
14650
|
/**
|