@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.cjs
CHANGED
|
@@ -85,6 +85,10 @@ const ERROR_TYPES = {
|
|
|
85
85
|
RPC: 'RPC',
|
|
86
86
|
/** Internet connectivity, DNS resolution, connection issues */
|
|
87
87
|
NETWORK: 'NETWORK',
|
|
88
|
+
/** API throttling, request frequency limits errors */
|
|
89
|
+
RATE_LIMIT: 'RATE_LIMIT',
|
|
90
|
+
/** Service errors */
|
|
91
|
+
SERVICE: 'SERVICE',
|
|
88
92
|
/** Catch-all for unrecognized errors (code 0) */
|
|
89
93
|
UNKNOWN: 'UNKNOWN',
|
|
90
94
|
};
|
|
@@ -108,6 +112,8 @@ const ERROR_CODE_RANGES = [
|
|
|
108
112
|
{ min: 3000, max: 3999, type: 'NETWORK' },
|
|
109
113
|
{ min: 4000, max: 4999, type: 'RPC' },
|
|
110
114
|
{ min: 5000, max: 5999, type: 'ONCHAIN' },
|
|
115
|
+
{ min: 7000, max: 7999, type: 'RATE_LIMIT' },
|
|
116
|
+
{ min: 8000, max: 8999, type: 'SERVICE' },
|
|
111
117
|
{ min: 9000, max: 9999, type: 'BALANCE' },
|
|
112
118
|
];
|
|
113
119
|
/** Special code for UNKNOWN errors */
|
|
@@ -155,6 +161,8 @@ const errorDetailsSchema = zod.z.object({
|
|
|
155
161
|
* - 3000-3999: NETWORK errors - Connectivity issues
|
|
156
162
|
* - 4000-4999: RPC errors - Provider issues, gas estimation
|
|
157
163
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures
|
|
164
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling
|
|
165
|
+
* - 8000-8999: SERVICE errors - Internal service errors
|
|
158
166
|
* - 9000-9999: BALANCE errors - Insufficient funds
|
|
159
167
|
*/
|
|
160
168
|
code: zod.z
|
|
@@ -245,11 +253,11 @@ function validateErrorDetails(details) {
|
|
|
245
253
|
const MAX_MESSAGE_LENGTH = 950;
|
|
246
254
|
|
|
247
255
|
/**
|
|
248
|
-
* Structured error class for
|
|
256
|
+
* Structured error class for App Kit operations.
|
|
249
257
|
*
|
|
250
258
|
* This class extends the native Error class while implementing the ErrorDetails
|
|
251
259
|
* interface, providing a consistent error format for programmatic handling
|
|
252
|
-
* across the
|
|
260
|
+
* across the App Kits ecosystem. All properties are immutable to ensure
|
|
253
261
|
* error objects cannot be modified after creation.
|
|
254
262
|
*
|
|
255
263
|
* @example
|
|
@@ -259,6 +267,7 @@ const MAX_MESSAGE_LENGTH = 950;
|
|
|
259
267
|
* const error = new KitError({
|
|
260
268
|
* code: 1001,
|
|
261
269
|
* name: 'INPUT_NETWORK_MISMATCH',
|
|
270
|
+
* type: 'INPUT',
|
|
262
271
|
* recoverability: 'FATAL',
|
|
263
272
|
* message: 'Cannot bridge between mainnet and testnet'
|
|
264
273
|
* })
|
|
@@ -276,7 +285,8 @@ const MAX_MESSAGE_LENGTH = 950;
|
|
|
276
285
|
* // Error with cause information
|
|
277
286
|
* const error = new KitError({
|
|
278
287
|
* code: 1002,
|
|
279
|
-
* name: '
|
|
288
|
+
* name: 'INPUT_INVALID_AMOUNT',
|
|
289
|
+
* type: 'INPUT',
|
|
280
290
|
* recoverability: 'FATAL',
|
|
281
291
|
* message: 'Amount must be greater than zero',
|
|
282
292
|
* cause: {
|
|
@@ -360,6 +370,8 @@ class KitError extends Error {
|
|
|
360
370
|
* - 3000-3999: NETWORK errors - Internet connectivity, DNS, connection issues
|
|
361
371
|
* - 4000-4999: RPC errors - Blockchain provider issues, gas estimation, nonce errors
|
|
362
372
|
* - 5000-5999: ONCHAIN errors - Transaction/simulation failures, gas exhaustion, reverts
|
|
373
|
+
* - 7000-7999: RATE_LIMIT errors - API throttling, request frequency limits
|
|
374
|
+
* - 8000-8999: SERVICE errors - Internal service errors, server failures
|
|
363
375
|
* - 9000-9999: BALANCE errors - Insufficient funds, token balance, allowance
|
|
364
376
|
*/
|
|
365
377
|
/**
|
|
@@ -390,19 +402,30 @@ class KitError extends Error {
|
|
|
390
402
|
* ```
|
|
391
403
|
*/
|
|
392
404
|
const InputError = {
|
|
405
|
+
/** Invalid amount format or value (negative, zero, or malformed) */
|
|
406
|
+
INVALID_AMOUNT: {
|
|
407
|
+
code: 1002,
|
|
408
|
+
name: 'INPUT_INVALID_AMOUNT',
|
|
409
|
+
type: 'INPUT',
|
|
410
|
+
},
|
|
393
411
|
/** Invalid or unsupported chain identifier */
|
|
394
412
|
INVALID_CHAIN: {
|
|
395
413
|
code: 1005,
|
|
396
414
|
name: 'INPUT_INVALID_CHAIN',
|
|
397
415
|
type: 'INPUT',
|
|
398
416
|
},
|
|
417
|
+
/** Unsupported token for chain */
|
|
418
|
+
UNSUPPORTED_TOKEN: {
|
|
419
|
+
code: 1006,
|
|
420
|
+
name: 'INPUT_UNSUPPORTED_TOKEN',
|
|
421
|
+
type: 'INPUT',
|
|
422
|
+
},
|
|
399
423
|
/** General validation failure for complex validation rules */
|
|
400
424
|
VALIDATION_FAILED: {
|
|
401
425
|
code: 1098,
|
|
402
426
|
name: 'INPUT_VALIDATION_FAILED',
|
|
403
427
|
type: 'INPUT',
|
|
404
|
-
}
|
|
405
|
-
};
|
|
428
|
+
}};
|
|
406
429
|
/**
|
|
407
430
|
* Standardized error definitions for BALANCE type errors.
|
|
408
431
|
*
|
|
@@ -470,7 +493,20 @@ const OnchainError = {
|
|
|
470
493
|
code: 5003,
|
|
471
494
|
name: 'ONCHAIN_OUT_OF_GAS',
|
|
472
495
|
type: 'ONCHAIN',
|
|
473
|
-
}
|
|
496
|
+
},
|
|
497
|
+
/** Transaction size exceeds blockchain limit */
|
|
498
|
+
TRANSACTION_TOO_LARGE: {
|
|
499
|
+
code: 5005,
|
|
500
|
+
name: 'ONCHAIN_TRANSACTION_TOO_LARGE',
|
|
501
|
+
type: 'ONCHAIN',
|
|
502
|
+
},
|
|
503
|
+
/** Unknown blockchain error that cannot be categorized */
|
|
504
|
+
UNKNOWN_BLOCKCHAIN_ERROR: {
|
|
505
|
+
code: 5099,
|
|
506
|
+
name: 'ONCHAIN_UNKNOWN_BLOCKCHAIN_ERROR',
|
|
507
|
+
type: 'ONCHAIN',
|
|
508
|
+
},
|
|
509
|
+
};
|
|
474
510
|
/**
|
|
475
511
|
* Standardized error definitions for RPC type errors.
|
|
476
512
|
*
|
|
@@ -522,6 +558,66 @@ const NetworkError = {
|
|
|
522
558
|
type: 'NETWORK',
|
|
523
559
|
}};
|
|
524
560
|
|
|
561
|
+
/**
|
|
562
|
+
* Creates error for unsupported token on chain.
|
|
563
|
+
*
|
|
564
|
+
* This error is thrown when a token is not supported on the specified chain.
|
|
565
|
+
*
|
|
566
|
+
* @param token - The token symbol (e.g., 'USDC', 'USDT')
|
|
567
|
+
* @param chain - The chain name where the token is unsupported
|
|
568
|
+
* @returns KitError with specific token support details
|
|
569
|
+
*
|
|
570
|
+
* @example
|
|
571
|
+
* ```typescript
|
|
572
|
+
* import { createUnsupportedTokenError } from '@core/errors'
|
|
573
|
+
*
|
|
574
|
+
* throw createUnsupportedTokenError('USDC', 'UnknownChain')
|
|
575
|
+
* // Message: "USDC is not supported on UnknownChain"
|
|
576
|
+
* ```
|
|
577
|
+
*/
|
|
578
|
+
function createUnsupportedTokenError(token, chain) {
|
|
579
|
+
const errorDetails = {
|
|
580
|
+
...InputError.UNSUPPORTED_TOKEN,
|
|
581
|
+
recoverability: 'FATAL',
|
|
582
|
+
message: `${token} is not supported on ${chain}.`,
|
|
583
|
+
cause: {
|
|
584
|
+
trace: { token, chain },
|
|
585
|
+
},
|
|
586
|
+
};
|
|
587
|
+
return new KitError(errorDetails);
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Creates error for invalid amount format or precision.
|
|
591
|
+
*
|
|
592
|
+
* This error is thrown when the provided amount doesn't meet validation
|
|
593
|
+
* requirements such as precision, range, or format.
|
|
594
|
+
*
|
|
595
|
+
* @param amount - The invalid amount string
|
|
596
|
+
* @param reason - Specific reason why amount is invalid
|
|
597
|
+
* @returns KitError with amount details and validation rule
|
|
598
|
+
*
|
|
599
|
+
* @example
|
|
600
|
+
* ```typescript
|
|
601
|
+
* import { createInvalidAmountError } from '@core/errors'
|
|
602
|
+
*
|
|
603
|
+
* throw createInvalidAmountError('0.000001', 'Amount must be at least 0.01 USDC')
|
|
604
|
+
* // Message: "Invalid amount '0.000001': Amount must be at least 0.01 USDC"
|
|
605
|
+
*
|
|
606
|
+
* throw createInvalidAmountError('1,000.50', 'Amount must be a numeric string with dot (.) as decimal separator, with no thousand separators or comma decimals')
|
|
607
|
+
* // Message: "Invalid amount '1,000.50': Amount must be a numeric string with dot (.) as decimal separator, with no thousand separators or comma decimals."
|
|
608
|
+
* ```
|
|
609
|
+
*/
|
|
610
|
+
function createInvalidAmountError(amount, reason) {
|
|
611
|
+
const errorDetails = {
|
|
612
|
+
...InputError.INVALID_AMOUNT,
|
|
613
|
+
recoverability: 'FATAL',
|
|
614
|
+
message: `Invalid amount '${amount}': ${reason}.`,
|
|
615
|
+
cause: {
|
|
616
|
+
trace: { amount, reason },
|
|
617
|
+
},
|
|
618
|
+
};
|
|
619
|
+
return new KitError(errorDetails);
|
|
620
|
+
}
|
|
525
621
|
/**
|
|
526
622
|
* Creates error for invalid chain configuration.
|
|
527
623
|
*
|
|
@@ -544,7 +640,7 @@ function createInvalidChainError(chain, reason) {
|
|
|
544
640
|
const errorDetails = {
|
|
545
641
|
...InputError.INVALID_CHAIN,
|
|
546
642
|
recoverability: 'FATAL',
|
|
547
|
-
message: `Invalid chain '${chain}': ${reason}
|
|
643
|
+
message: `Invalid chain '${chain}': ${reason}.`,
|
|
548
644
|
cause: {
|
|
549
645
|
trace: { chain, reason },
|
|
550
646
|
},
|
|
@@ -816,6 +912,8 @@ function createSimulationFailedError(chain, reason, trace) {
|
|
|
816
912
|
* @param chain - The blockchain network where the transaction reverted
|
|
817
913
|
* @param reason - The reason for the revert (e.g., revert message)
|
|
818
914
|
* @param trace - Optional trace context to include in error (can include rawError and additional debugging data)
|
|
915
|
+
* @param txHash - The transaction hash if the transaction was submitted (optional)
|
|
916
|
+
* @param explorerUrl - The block explorer URL for the transaction (optional)
|
|
819
917
|
* @returns KitError with transaction revert details
|
|
820
918
|
*
|
|
821
919
|
* @example
|
|
@@ -828,15 +926,17 @@ function createSimulationFailedError(chain, reason, trace) {
|
|
|
828
926
|
*
|
|
829
927
|
* @example
|
|
830
928
|
* ```typescript
|
|
831
|
-
* // With trace context for debugging
|
|
832
|
-
* throw createTransactionRevertedError(
|
|
833
|
-
*
|
|
834
|
-
*
|
|
835
|
-
*
|
|
836
|
-
*
|
|
929
|
+
* // With trace context and transaction details for debugging
|
|
930
|
+
* throw createTransactionRevertedError(
|
|
931
|
+
* 'Base',
|
|
932
|
+
* 'Slippage exceeded',
|
|
933
|
+
* { rawError: error },
|
|
934
|
+
* '0x123...',
|
|
935
|
+
* 'https://basescan.org/tx/0x123...'
|
|
936
|
+
* )
|
|
837
937
|
* ```
|
|
838
938
|
*/
|
|
839
|
-
function createTransactionRevertedError(chain, reason, trace) {
|
|
939
|
+
function createTransactionRevertedError(chain, reason, trace, txHash, explorerUrl) {
|
|
840
940
|
return new KitError({
|
|
841
941
|
...OnchainError.TRANSACTION_REVERTED,
|
|
842
942
|
recoverability: 'FATAL',
|
|
@@ -846,6 +946,8 @@ function createTransactionRevertedError(chain, reason, trace) {
|
|
|
846
946
|
...trace,
|
|
847
947
|
chain,
|
|
848
948
|
reason,
|
|
949
|
+
...(txHash !== undefined && txHash !== '' && { txHash }),
|
|
950
|
+
...(explorerUrl !== undefined && explorerUrl !== '' && { explorerUrl }),
|
|
849
951
|
},
|
|
850
952
|
},
|
|
851
953
|
});
|
|
@@ -858,6 +960,8 @@ function createTransactionRevertedError(chain, reason, trace) {
|
|
|
858
960
|
*
|
|
859
961
|
* @param chain - The blockchain network where the transaction ran out of gas
|
|
860
962
|
* @param trace - Optional trace context to include in error (can include rawError and additional debugging data)
|
|
963
|
+
* @param txHash - The transaction hash if the transaction was submitted (optional)
|
|
964
|
+
* @param explorerUrl - The block explorer URL for the transaction (optional)
|
|
861
965
|
* @returns KitError with out of gas details
|
|
862
966
|
*
|
|
863
967
|
* @example
|
|
@@ -872,13 +976,15 @@ function createTransactionRevertedError(chain, reason, trace) {
|
|
|
872
976
|
* ```typescript
|
|
873
977
|
* // With trace context for debugging
|
|
874
978
|
* throw createOutOfGasError('Polygon', {
|
|
875
|
-
* rawError: error,
|
|
876
979
|
* gasUsed: '50000',
|
|
877
980
|
* gasLimit: '45000',
|
|
878
|
-
* }
|
|
981
|
+
* },
|
|
982
|
+
* '0xabc...',
|
|
983
|
+
* 'https://polygonscan.com/tx/0xabc...'
|
|
984
|
+
* )
|
|
879
985
|
* ```
|
|
880
986
|
*/
|
|
881
|
-
function createOutOfGasError(chain, trace) {
|
|
987
|
+
function createOutOfGasError(chain, trace, txHash, explorerUrl) {
|
|
882
988
|
return new KitError({
|
|
883
989
|
...OnchainError.OUT_OF_GAS,
|
|
884
990
|
recoverability: 'FATAL',
|
|
@@ -887,20 +993,119 @@ function createOutOfGasError(chain, trace) {
|
|
|
887
993
|
trace: {
|
|
888
994
|
...trace,
|
|
889
995
|
chain,
|
|
996
|
+
...(txHash !== undefined && txHash !== '' && { txHash }),
|
|
997
|
+
...(explorerUrl !== undefined && explorerUrl !== '' && { explorerUrl }),
|
|
998
|
+
},
|
|
999
|
+
},
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Creates error for transaction size exceeding blockchain limits.
|
|
1004
|
+
*
|
|
1005
|
+
* This error is thrown when a transaction's serialized size exceeds
|
|
1006
|
+
* the blockchain's maximum transaction size limit. The error is FATAL
|
|
1007
|
+
* as it requires reducing the transaction size (e.g., fewer instructions,
|
|
1008
|
+
* smaller data payloads, or splitting into multiple transactions).
|
|
1009
|
+
*
|
|
1010
|
+
* Common on Solana where transactions have strict size limits (e.g., max 1232 bytes).
|
|
1011
|
+
*
|
|
1012
|
+
* @param chain - The blockchain network where the size limit was exceeded
|
|
1013
|
+
* @param rawError - The original error from the underlying system (optional)
|
|
1014
|
+
* @returns KitError with transaction size exceeded details
|
|
1015
|
+
*
|
|
1016
|
+
* @example
|
|
1017
|
+
* ```typescript
|
|
1018
|
+
* import { createTransactionTooLargeError } from '@core/errors'
|
|
1019
|
+
*
|
|
1020
|
+
* throw createTransactionTooLargeError('Solana')
|
|
1021
|
+
* // Message: "Transaction size exceeds limit on Solana"
|
|
1022
|
+
* ```
|
|
1023
|
+
*
|
|
1024
|
+
* @example
|
|
1025
|
+
* ```typescript
|
|
1026
|
+
* import { createTransactionTooLargeError } from '@core/errors'
|
|
1027
|
+
*
|
|
1028
|
+
* // With raw error containing size details
|
|
1029
|
+
* throw createTransactionTooLargeError(
|
|
1030
|
+
* 'Solana',
|
|
1031
|
+
* new Error('transaction too large: max: encoded/raw 1644/1232')
|
|
1032
|
+
* )
|
|
1033
|
+
* // Error includes size information in cause.trace
|
|
1034
|
+
* ```
|
|
1035
|
+
*/
|
|
1036
|
+
function createTransactionTooLargeError(chain, rawError) {
|
|
1037
|
+
return new KitError({
|
|
1038
|
+
...OnchainError.TRANSACTION_TOO_LARGE,
|
|
1039
|
+
recoverability: 'FATAL',
|
|
1040
|
+
message: `Transaction size exceeds limit on ${chain}`,
|
|
1041
|
+
cause: {
|
|
1042
|
+
trace: {
|
|
1043
|
+
chain,
|
|
1044
|
+
rawError,
|
|
1045
|
+
},
|
|
1046
|
+
},
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Creates error for unknown blockchain errors that cannot be categorized.
|
|
1051
|
+
*
|
|
1052
|
+
* This error is used as a fallback when a blockchain error doesn't match
|
|
1053
|
+
* any known patterns (balance, simulation, gas, network, RPC, etc.).
|
|
1054
|
+
* The error is FATAL as we cannot determine if it's retriable without
|
|
1055
|
+
* understanding the underlying cause.
|
|
1056
|
+
*
|
|
1057
|
+
* The original error message and context are preserved in the trace for
|
|
1058
|
+
* debugging purposes.
|
|
1059
|
+
*
|
|
1060
|
+
* @param chain - The blockchain network where the error occurred
|
|
1061
|
+
* @param originalMessage - The original error message from the blockchain
|
|
1062
|
+
* @param rawError - The original error object from the underlying system (optional)
|
|
1063
|
+
* @returns KitError with unknown blockchain error details
|
|
1064
|
+
*
|
|
1065
|
+
* @example
|
|
1066
|
+
* ```typescript
|
|
1067
|
+
* import { createUnknownBlockchainError } from '@core/errors'
|
|
1068
|
+
*
|
|
1069
|
+
* throw createUnknownBlockchainError('Ethereum', 'Unknown protocol error')
|
|
1070
|
+
* // Message: "Unknown blockchain error on Ethereum: Unknown protocol error"
|
|
1071
|
+
* ```
|
|
1072
|
+
*
|
|
1073
|
+
* @example
|
|
1074
|
+
* ```typescript
|
|
1075
|
+
* import { createUnknownBlockchainError } from '@core/errors'
|
|
1076
|
+
*
|
|
1077
|
+
* // With raw error for debugging
|
|
1078
|
+
* const rawError = new Error('Unexpected blockchain state')
|
|
1079
|
+
* throw createUnknownBlockchainError('Solana', rawError.message, rawError)
|
|
1080
|
+
* // Error preserves full context in cause.trace
|
|
1081
|
+
* ```
|
|
1082
|
+
*/
|
|
1083
|
+
function createUnknownBlockchainError(chain, originalMessage, rawError) {
|
|
1084
|
+
const errorMessage = originalMessage
|
|
1085
|
+
? 'Unknown blockchain error on ' + chain + ': ' + originalMessage
|
|
1086
|
+
: 'Unknown blockchain error on ' + chain;
|
|
1087
|
+
return new KitError({
|
|
1088
|
+
...OnchainError.UNKNOWN_BLOCKCHAIN_ERROR,
|
|
1089
|
+
recoverability: 'FATAL',
|
|
1090
|
+
message: errorMessage,
|
|
1091
|
+
cause: {
|
|
1092
|
+
trace: {
|
|
1093
|
+
chain,
|
|
1094
|
+
rawError,
|
|
890
1095
|
},
|
|
891
1096
|
},
|
|
892
1097
|
});
|
|
893
1098
|
}
|
|
894
1099
|
|
|
895
1100
|
/**
|
|
896
|
-
*
|
|
1101
|
+
* Create error for RPC endpoint failures.
|
|
897
1102
|
*
|
|
898
|
-
*
|
|
1103
|
+
* Throw when an RPC provider endpoint fails, returns an error,
|
|
899
1104
|
* or is unavailable. The error is RETRYABLE as RPC issues are often temporary.
|
|
900
1105
|
*
|
|
901
|
-
* @param chain - The blockchain network where the RPC error occurred
|
|
902
|
-
* @param trace - Optional trace context
|
|
903
|
-
* @returns KitError with RPC endpoint error details
|
|
1106
|
+
* @param chain - The blockchain network where the RPC error occurred.
|
|
1107
|
+
* @param trace - Optional trace context (can include rawError and debugging data).
|
|
1108
|
+
* @returns KitError with RPC endpoint error details.
|
|
904
1109
|
*
|
|
905
1110
|
* @example
|
|
906
1111
|
* ```typescript
|
|
@@ -912,7 +1117,6 @@ function createOutOfGasError(chain, trace) {
|
|
|
912
1117
|
*
|
|
913
1118
|
* @example
|
|
914
1119
|
* ```typescript
|
|
915
|
-
* // With trace context for debugging
|
|
916
1120
|
* throw createRpcEndpointError('Ethereum', {
|
|
917
1121
|
* rawError: error,
|
|
918
1122
|
* endpoint: 'https://mainnet.infura.io/v3/...',
|
|
@@ -935,15 +1139,15 @@ function createRpcEndpointError(chain, trace) {
|
|
|
935
1139
|
}
|
|
936
1140
|
|
|
937
1141
|
/**
|
|
938
|
-
*
|
|
1142
|
+
* Create error for network connection failures.
|
|
939
1143
|
*
|
|
940
|
-
*
|
|
1144
|
+
* Throw when network connectivity issues prevent reaching
|
|
941
1145
|
* the blockchain network. The error is RETRYABLE as network issues are
|
|
942
1146
|
* often temporary.
|
|
943
1147
|
*
|
|
944
|
-
* @param chain - The blockchain network where the connection failed
|
|
945
|
-
* @param trace - Optional trace context
|
|
946
|
-
* @returns KitError with network connection error details
|
|
1148
|
+
* @param chain - The blockchain network where the connection failed.
|
|
1149
|
+
* @param trace - Optional trace context (can include rawError and debugging data).
|
|
1150
|
+
* @returns KitError with network connection error details.
|
|
947
1151
|
*
|
|
948
1152
|
* @example
|
|
949
1153
|
* ```typescript
|
|
@@ -955,7 +1159,6 @@ function createRpcEndpointError(chain, trace) {
|
|
|
955
1159
|
*
|
|
956
1160
|
* @example
|
|
957
1161
|
* ```typescript
|
|
958
|
-
* // With trace context for debugging
|
|
959
1162
|
* throw createNetworkConnectionError('Ethereum', {
|
|
960
1163
|
* rawError: error,
|
|
961
1164
|
* endpoint: 'https://eth-mainnet.g.alchemy.com/v2/...',
|
|
@@ -977,6 +1180,25 @@ function createNetworkConnectionError(chain, trace) {
|
|
|
977
1180
|
});
|
|
978
1181
|
}
|
|
979
1182
|
|
|
1183
|
+
/**
|
|
1184
|
+
* Normalizes optional transaction details for error factories.
|
|
1185
|
+
*
|
|
1186
|
+
* Converts empty strings to undefined to ensure clean error traces.
|
|
1187
|
+
*
|
|
1188
|
+
* @param txHash - The transaction hash.
|
|
1189
|
+
* @param explorerUrl - The explorer URL.
|
|
1190
|
+
* @returns Normalized values or undefined.
|
|
1191
|
+
*/
|
|
1192
|
+
function normalizeTransactionDetails(txHash, explorerUrl) {
|
|
1193
|
+
const normalized = {};
|
|
1194
|
+
if (txHash !== undefined && txHash !== '') {
|
|
1195
|
+
normalized.txHash = txHash;
|
|
1196
|
+
}
|
|
1197
|
+
if (explorerUrl !== undefined && explorerUrl !== '') {
|
|
1198
|
+
normalized.explorerUrl = explorerUrl;
|
|
1199
|
+
}
|
|
1200
|
+
return normalized;
|
|
1201
|
+
}
|
|
980
1202
|
/**
|
|
981
1203
|
* Parses raw blockchain errors into structured KitError instances.
|
|
982
1204
|
*
|
|
@@ -984,12 +1206,17 @@ function createNetworkConnectionError(chain, trace) {
|
|
|
984
1206
|
* types and converts them into standardized KitError format. It handles
|
|
985
1207
|
* errors from viem, ethers, Solana web3.js, and other blockchain libraries.
|
|
986
1208
|
*
|
|
987
|
-
* The parser recognizes
|
|
1209
|
+
* The parser recognizes 6 main error patterns:
|
|
988
1210
|
* 1. Insufficient balance errors
|
|
989
1211
|
* 2. Simulation/execution reverted errors
|
|
990
1212
|
* 3. Gas-related errors
|
|
991
1213
|
* 4. Network connectivity errors
|
|
992
1214
|
* 5. RPC provider errors
|
|
1215
|
+
* 6. Transaction size limit errors
|
|
1216
|
+
*
|
|
1217
|
+
* When errors don't match known patterns, the parser uses operation context
|
|
1218
|
+
* (e.g., 'simulation', 'estimateGas') to categorize them appropriately.
|
|
1219
|
+
* Unrecognized errors without context are categorized as UNKNOWN_BLOCKCHAIN_ERROR.
|
|
993
1220
|
*
|
|
994
1221
|
* @param error - The raw error from the blockchain library
|
|
995
1222
|
* @param context - Context information including chain and optional token
|
|
@@ -1019,6 +1246,25 @@ function createNetworkConnectionError(chain, trace) {
|
|
|
1019
1246
|
* throw parseBlockchainError(error, { chain: 'Solana' })
|
|
1020
1247
|
* }
|
|
1021
1248
|
* ```
|
|
1249
|
+
*
|
|
1250
|
+
* @example
|
|
1251
|
+
* ```typescript
|
|
1252
|
+
* // With transaction hash and explorer URL
|
|
1253
|
+
* import { buildExplorerUrl } from '@core/utils'
|
|
1254
|
+
* import { Ethereum } from '@core/chains'
|
|
1255
|
+
*
|
|
1256
|
+
* try {
|
|
1257
|
+
* const txHash = await walletClient.sendTransaction(...)
|
|
1258
|
+
* await waitForTransaction(txHash)
|
|
1259
|
+
* } catch (error) {
|
|
1260
|
+
* const explorerUrl = buildExplorerUrl(Ethereum, txHash)
|
|
1261
|
+
* throw parseBlockchainError(error, {
|
|
1262
|
+
* chain: 'Ethereum',
|
|
1263
|
+
* txHash,
|
|
1264
|
+
* explorerUrl
|
|
1265
|
+
* })
|
|
1266
|
+
* }
|
|
1267
|
+
* ```
|
|
1022
1268
|
*/
|
|
1023
1269
|
function parseBlockchainError(error, context) {
|
|
1024
1270
|
const msg = extractMessage(error);
|
|
@@ -1033,7 +1279,7 @@ function parseBlockchainError(error, context) {
|
|
|
1033
1279
|
// Pattern 2: Simulation and execution reverts
|
|
1034
1280
|
// Matches contract revert errors and simulation failures
|
|
1035
1281
|
if (/execution reverted|simulation failed|transaction reverted|transaction failed/i.test(msg)) {
|
|
1036
|
-
const reason = extractRevertReason(msg) ?? 'Transaction reverted';
|
|
1282
|
+
const reason = extractRevertReason(msg, error) ?? 'Transaction reverted';
|
|
1037
1283
|
// Distinguish between simulation failures and transaction reverts
|
|
1038
1284
|
// "simulation failed" or "eth_call" indicates pre-flight simulation
|
|
1039
1285
|
// "transaction failed" or context.operation === 'transaction' indicates post-execution
|
|
@@ -1043,9 +1289,11 @@ function parseBlockchainError(error, context) {
|
|
|
1043
1289
|
});
|
|
1044
1290
|
}
|
|
1045
1291
|
// Transaction execution failures or reverts
|
|
1292
|
+
// Include txHash and explorerUrl if available (transaction was submitted)
|
|
1293
|
+
const { txHash, explorerUrl } = normalizeTransactionDetails(context.txHash, context.explorerUrl);
|
|
1046
1294
|
return createTransactionRevertedError(context.chain, reason, {
|
|
1047
1295
|
rawError: error,
|
|
1048
|
-
});
|
|
1296
|
+
}, txHash, explorerUrl);
|
|
1049
1297
|
}
|
|
1050
1298
|
// Pattern 3: Gas-related errors
|
|
1051
1299
|
// Matches gas estimation failures and gas exhaustion
|
|
@@ -1057,7 +1305,8 @@ function parseBlockchainError(error, context) {
|
|
|
1057
1305
|
// Gas exhaustion errors
|
|
1058
1306
|
// Use specific patterns without wildcards to avoid ReDoS
|
|
1059
1307
|
if (/out of gas|gas limit exceeded|exceeds block gas limit/i.test(msg)) {
|
|
1060
|
-
|
|
1308
|
+
const { txHash, explorerUrl } = normalizeTransactionDetails(context.txHash, context.explorerUrl);
|
|
1309
|
+
return createOutOfGasError(context.chain, { rawError: error }, txHash, explorerUrl);
|
|
1061
1310
|
}
|
|
1062
1311
|
// Insufficient funds for gas
|
|
1063
1312
|
if (/insufficient funds for gas/i.test(msg)) {
|
|
@@ -1073,15 +1322,38 @@ function parseBlockchainError(error, context) {
|
|
|
1073
1322
|
if (/rpc|invalid response|rate limit|too many requests/i.test(msg)) {
|
|
1074
1323
|
return createRpcEndpointError(context.chain, { rawError: error });
|
|
1075
1324
|
}
|
|
1325
|
+
// Pattern 6: Transaction size limit errors
|
|
1326
|
+
// Matches transaction size errors from various blockchains:
|
|
1327
|
+
// - Solana: "transaction too large: max: encoded/raw 1644/1232"
|
|
1328
|
+
// - Generic: "transaction exceeds size limit", "max transaction size"
|
|
1329
|
+
// Split into two checks to reduce regex complexity for SonarQube
|
|
1330
|
+
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);
|
|
1331
|
+
if (isSizeError) {
|
|
1332
|
+
return createTransactionTooLargeError(context.chain, error);
|
|
1333
|
+
}
|
|
1076
1334
|
// Fallback based on operation context
|
|
1077
1335
|
// Gas-related operations are RPC calls
|
|
1078
1336
|
if (context.operation === 'estimateGas' ||
|
|
1079
1337
|
context.operation === 'getGasPrice') {
|
|
1080
1338
|
return createRpcEndpointError(context.chain, { rawError: error });
|
|
1081
1339
|
}
|
|
1082
|
-
//
|
|
1083
|
-
//
|
|
1084
|
-
|
|
1340
|
+
// Simulation operations that don't match standard patterns should still be
|
|
1341
|
+
// categorized as simulation failures. This handles cases where blockchain
|
|
1342
|
+
// libraries throw generic errors (e.g., "fail", "error") during staticCall
|
|
1343
|
+
// operations without descriptive messages. The operation context is authoritative
|
|
1344
|
+
// about what was being attempted, even when error messages are unclear.
|
|
1345
|
+
//
|
|
1346
|
+
// Example: ethers.js staticCall rejection with message "fail"
|
|
1347
|
+
// - Message doesn't match /execution reverted|simulation failed/
|
|
1348
|
+
// - But context.operation === 'simulation' tells us it was a simulation
|
|
1349
|
+
// - Result: SIMULATION_FAILED (accurate) vs UNKNOWN_BLOCKCHAIN_ERROR (misleading)
|
|
1350
|
+
if (context.operation === 'simulation') {
|
|
1351
|
+
return createSimulationFailedError(context.chain, msg.length > 0 ? msg : 'Simulation failed', { rawError: error });
|
|
1352
|
+
}
|
|
1353
|
+
// Final fallback for truly unrecognized errors
|
|
1354
|
+
// Only errors that don't match any pattern AND lack operation context
|
|
1355
|
+
// are categorized as unknown.
|
|
1356
|
+
return createUnknownBlockchainError(context.chain, msg.length > 0 ? msg : 'Unknown error', { rawError: error });
|
|
1085
1357
|
}
|
|
1086
1358
|
/**
|
|
1087
1359
|
* Type guard to check if error has Solana-Kit structure with logs.
|
|
@@ -1140,12 +1412,76 @@ function extractMessage(error) {
|
|
|
1140
1412
|
return String(error);
|
|
1141
1413
|
}
|
|
1142
1414
|
/**
|
|
1143
|
-
*
|
|
1415
|
+
* Mapping of custom error selectors to human-readable error names.
|
|
1416
|
+
*
|
|
1417
|
+
* These selectors correspond to custom errors from the contracts.
|
|
1418
|
+
* When a transaction reverts with a custom error, the 4-byte selector
|
|
1419
|
+
* (first 4 bytes of keccak256 of the error signature) is included in the error message.
|
|
1420
|
+
*
|
|
1421
|
+
*/
|
|
1422
|
+
const CUSTOM_ERROR_SELECTORS = {
|
|
1423
|
+
'0xd93c0665': 'This contract is currently paused', // EnforcedPause()
|
|
1424
|
+
'0x3ee5aeb5': 'Security check failed due to a reentrancy attempt', // ReentrancyGuardReentrantCall()
|
|
1425
|
+
'0x8baa579f': 'The provided signature is invalid or could not be verified', // InvalidSignature()
|
|
1426
|
+
'0x1ab7da6b': 'This request has expired', // DeadlineExpired()
|
|
1427
|
+
'0x64eee62e': 'No instructions provided', // EmptyInstructions()
|
|
1428
|
+
'0x3c46992e': 'Too many execution steps were provided', // TooManyInstructions()
|
|
1429
|
+
'0xe066e60e': 'Exceeds maximum token inputs limit', // TooManyTokenInputs()
|
|
1430
|
+
'0x5566df5c': 'The beneficiary address is invalid', // InvalidBeneficiary()
|
|
1431
|
+
'0xf41d7bc6': 'Execution ID already used', // ExecIdUsed()
|
|
1432
|
+
'0x948726e2': 'The account balance does not meet the required minimum', // InvalidBalanceState()
|
|
1433
|
+
'0x01aa0452': 'The permit type provided is not supported', // UnsupportedPermitType()
|
|
1434
|
+
'0x13be252b': 'Token approval failed and the allowance is insufficient', // InsufficientAllowance()
|
|
1435
|
+
'0x5274afe7': 'Token transfer or approval failed', // SafeERC20FailedOperation(address)
|
|
1436
|
+
'0x00bc1dcb': 'One of the execution targets is invalid', // InvalidInstruction(uint256)
|
|
1437
|
+
'0x5d693841': 'Cannot approve a zero address or a native token', // InvalidApprovalConfig(uint256)
|
|
1438
|
+
'0x3ec5cfe1': 'Cannot validate output for a zero address token', // InvalidOutputConfig(uint256)
|
|
1439
|
+
'0x492fd70e': 'Instruction call failed without revert data', // ExecutionFailed(uint256)
|
|
1440
|
+
'0xba235e1a': 'The received token amount is lower than the minimum required', // InsufficientOutput(uint256,address,uint256,uint256)
|
|
1441
|
+
'0x9147d463': 'Final balance is less than the initial balance', // InsufficientFinalBalance(address,uint256,uint256)
|
|
1442
|
+
'0xf4b3b1bc': 'Native token transfer to the beneficiary failed', // NativeTransferFailed()
|
|
1443
|
+
};
|
|
1444
|
+
/**
|
|
1445
|
+
* Attempts to extract an error selector from an error object or message.
|
|
1446
|
+
*
|
|
1447
|
+
* Checks multiple sources in priority order:
|
|
1448
|
+
* 1. `error.data` field
|
|
1449
|
+
* 2. Message pattern: "custom error 0x8baa579f"
|
|
1450
|
+
*
|
|
1451
|
+
* @param msg - The error message
|
|
1452
|
+
* @param error - The error object (optional)
|
|
1453
|
+
* @returns The 4 bytes selector , or undefined if not found
|
|
1454
|
+
*/
|
|
1455
|
+
function extractErrorSelector(msg, error) {
|
|
1456
|
+
// Check error.data field
|
|
1457
|
+
if (error !== null && typeof error === 'object' && 'data' in error) {
|
|
1458
|
+
if (typeof error.data === 'string' && /^0x[0-9a-f]{8}$/i.test(error.data)) {
|
|
1459
|
+
return error.data.toLowerCase();
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
// Check for "custom error 0x8baa579f" in the message
|
|
1463
|
+
const match = /custom error (0x[0-9a-f]{8})\b/i.exec(msg);
|
|
1464
|
+
const selector = match?.[1];
|
|
1465
|
+
if (selector !== undefined && selector.length > 0) {
|
|
1466
|
+
return selector.toLowerCase();
|
|
1467
|
+
}
|
|
1468
|
+
return undefined;
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Extracts the revert reason from an error message and error object.
|
|
1144
1472
|
*
|
|
1145
1473
|
* Attempts to parse out the meaningful reason from execution revert errors,
|
|
1146
1474
|
* removing common prefixes like "execution reverted:" or "reverted:".
|
|
1475
|
+
* If the error contains a custom error selector, it will be resolved to its
|
|
1476
|
+
* human-readable description with the selector included for developer reference.
|
|
1477
|
+
*
|
|
1478
|
+
* Supports multiple error formats:
|
|
1479
|
+
* - Custom error with selector in `error.data` field (e.g., `{ data: "0x8baa579f", ... }`)
|
|
1480
|
+
* - Message with selector pattern: `"Execution reverted with reason: custom error 0x8baa579f"`
|
|
1481
|
+
* - Standard revert: `"execution reverted: Insufficient funds"`
|
|
1147
1482
|
*
|
|
1148
1483
|
* @param msg - The error message to extract from
|
|
1484
|
+
* @param error - The full error object (optional, used to extract selector from `data` field)
|
|
1149
1485
|
* @returns The extracted revert reason, or null if not found
|
|
1150
1486
|
*
|
|
1151
1487
|
* @example
|
|
@@ -1163,10 +1499,48 @@ function extractMessage(error) {
|
|
|
1163
1499
|
* )
|
|
1164
1500
|
* // Returns: 'Insufficient allowance'
|
|
1165
1501
|
* ```
|
|
1502
|
+
*
|
|
1503
|
+
* @example
|
|
1504
|
+
* ```typescript
|
|
1505
|
+
* // Custom error with selector in message
|
|
1506
|
+
* const reason = extractRevertReason(
|
|
1507
|
+
* 'Execution reverted with reason: custom error 0x8baa579f'
|
|
1508
|
+
* )
|
|
1509
|
+
* // Returns: 'The provided signature is invalid or could not be verified (0x8baa579f)'
|
|
1510
|
+
* ```
|
|
1511
|
+
*
|
|
1512
|
+
* @example
|
|
1513
|
+
* ```typescript
|
|
1514
|
+
* // Error with data field
|
|
1515
|
+
* const reason = extractRevertReason(
|
|
1516
|
+
* 'execution reverted (unknown custom error)',
|
|
1517
|
+
* { data: '0x8baa579f' }
|
|
1518
|
+
* )
|
|
1519
|
+
* // Returns: 'The provided signature is invalid or could not be verified (0x8baa579f)'
|
|
1520
|
+
* ```
|
|
1521
|
+
*
|
|
1522
|
+
* @example
|
|
1523
|
+
* ```typescript
|
|
1524
|
+
* // Unrecognized selector preserved for debugging
|
|
1525
|
+
* const reason = extractRevertReason(
|
|
1526
|
+
* 'execution reverted (unknown custom error)',
|
|
1527
|
+
* { data: '0xdeadbeef' }
|
|
1528
|
+
* )
|
|
1529
|
+
* // Returns: 'Transaction reverted with error (0xdeadbeef)'
|
|
1530
|
+
* ```
|
|
1166
1531
|
*/
|
|
1167
|
-
function extractRevertReason(msg) {
|
|
1532
|
+
function extractRevertReason(msg, error) {
|
|
1533
|
+
// Try to extract and decode custom error selector
|
|
1534
|
+
const selector = extractErrorSelector(msg, error);
|
|
1535
|
+
if (selector !== undefined) {
|
|
1536
|
+
const errorMessage = CUSTOM_ERROR_SELECTORS[selector];
|
|
1537
|
+
if (errorMessage !== undefined) {
|
|
1538
|
+
return `${errorMessage} (${selector})`;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1168
1541
|
// Try to extract reason after "execution reverted:" or "reason:"
|
|
1169
1542
|
// Use [^\n.]+ instead of .+? to avoid ReDoS vulnerability
|
|
1543
|
+
// Fall back to standard revert reason extraction
|
|
1170
1544
|
const patterns = [
|
|
1171
1545
|
/(?:execution reverted|reverted):\s*([^\n.]+)/i,
|
|
1172
1546
|
/reason:\s*([^\n.]+)/i,
|
|
@@ -1179,9 +1553,49 @@ function extractRevertReason(msg) {
|
|
|
1179
1553
|
return extractedReason.trim();
|
|
1180
1554
|
}
|
|
1181
1555
|
}
|
|
1556
|
+
// Preserve unrecognized selector so it appears in error output for debugging
|
|
1557
|
+
if (selector !== undefined) {
|
|
1558
|
+
return `Transaction reverted with error (${selector})`;
|
|
1559
|
+
}
|
|
1182
1560
|
return null;
|
|
1183
1561
|
}
|
|
1184
1562
|
|
|
1563
|
+
/**
|
|
1564
|
+
* Safely extracts error message from any error type.
|
|
1565
|
+
*
|
|
1566
|
+
* This utility handles different error types gracefully, extracting
|
|
1567
|
+
* meaningful messages from Error instances, string errors, or providing
|
|
1568
|
+
* a fallback for unknown error types. Never throws.
|
|
1569
|
+
*
|
|
1570
|
+
* @param error - Unknown error to extract message from
|
|
1571
|
+
* @returns Error message string, or fallback message
|
|
1572
|
+
*
|
|
1573
|
+
* @example
|
|
1574
|
+
* ```typescript
|
|
1575
|
+
* import { getErrorMessage } from '@core/errors'
|
|
1576
|
+
*
|
|
1577
|
+
* try {
|
|
1578
|
+
* await riskyOperation()
|
|
1579
|
+
* } catch (error) {
|
|
1580
|
+
* const message = getErrorMessage(error)
|
|
1581
|
+
* console.log('Error occurred:', message)
|
|
1582
|
+
* // Works with Error, KitError, string, or any other type
|
|
1583
|
+
* }
|
|
1584
|
+
* ```
|
|
1585
|
+
*/
|
|
1586
|
+
function getErrorMessage(error) {
|
|
1587
|
+
if (error instanceof Error) {
|
|
1588
|
+
return error.message;
|
|
1589
|
+
}
|
|
1590
|
+
if (typeof error === 'string') {
|
|
1591
|
+
return error;
|
|
1592
|
+
}
|
|
1593
|
+
if (typeof error === 'object' && error !== null && 'message' in error) {
|
|
1594
|
+
return String(error.message);
|
|
1595
|
+
}
|
|
1596
|
+
return 'An unknown error occurred';
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1185
1599
|
// -----------------------------------------------------------------------------
|
|
1186
1600
|
// Blockchain Enum
|
|
1187
1601
|
// -----------------------------------------------------------------------------
|
|
@@ -1214,6 +1628,8 @@ exports.Blockchain = void 0;
|
|
|
1214
1628
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
1215
1629
|
Blockchain["Codex"] = "Codex";
|
|
1216
1630
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
1631
|
+
Blockchain["Edge"] = "Edge";
|
|
1632
|
+
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
1217
1633
|
Blockchain["Ethereum"] = "Ethereum";
|
|
1218
1634
|
Blockchain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
1219
1635
|
Blockchain["Hedera"] = "Hedera";
|
|
@@ -1226,6 +1642,8 @@ exports.Blockchain = void 0;
|
|
|
1226
1642
|
Blockchain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
1227
1643
|
Blockchain["Monad"] = "Monad";
|
|
1228
1644
|
Blockchain["Monad_Testnet"] = "Monad_Testnet";
|
|
1645
|
+
Blockchain["Morph"] = "Morph";
|
|
1646
|
+
Blockchain["Morph_Testnet"] = "Morph_Testnet";
|
|
1229
1647
|
Blockchain["NEAR"] = "NEAR";
|
|
1230
1648
|
Blockchain["NEAR_Testnet"] = "NEAR_Testnet";
|
|
1231
1649
|
Blockchain["Noble"] = "Noble";
|
|
@@ -1257,6 +1675,122 @@ exports.Blockchain = void 0;
|
|
|
1257
1675
|
Blockchain["ZKSync_Era"] = "ZKSync_Era";
|
|
1258
1676
|
Blockchain["ZKSync_Sepolia"] = "ZKSync_Sepolia";
|
|
1259
1677
|
})(exports.Blockchain || (exports.Blockchain = {}));
|
|
1678
|
+
/**
|
|
1679
|
+
* Enum representing the subset of {@link Blockchain} that supports swap operations.
|
|
1680
|
+
*
|
|
1681
|
+
* This enum provides compile-time type safety for swap chain selection,
|
|
1682
|
+
* ensuring only supported chains are available in IDE autocomplete
|
|
1683
|
+
* when building swap parameters.
|
|
1684
|
+
*
|
|
1685
|
+
* @remarks
|
|
1686
|
+
* Unlike the full {@link Blockchain} enum, SwapChain only includes networks
|
|
1687
|
+
* where the swap functionality is actively supported by the library.
|
|
1688
|
+
* Using this enum prevents runtime errors from attempting unsupported
|
|
1689
|
+
* cross-chain swaps.
|
|
1690
|
+
*
|
|
1691
|
+
* Currently supports:
|
|
1692
|
+
* - Ethereum mainnet
|
|
1693
|
+
* - Base mainnet
|
|
1694
|
+
* - Polygon mainnet
|
|
1695
|
+
* - Solana mainnet
|
|
1696
|
+
*
|
|
1697
|
+
* @example
|
|
1698
|
+
* ```typescript
|
|
1699
|
+
* import { SwapChain, swap, createSwapKitContext } from '@circle-fin/swap-kit'
|
|
1700
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
1701
|
+
*
|
|
1702
|
+
* const context = createSwapKitContext()
|
|
1703
|
+
* const adapter = createViemAdapterFromPrivateKey({
|
|
1704
|
+
* privateKey: process.env.PRIVATE_KEY
|
|
1705
|
+
* })
|
|
1706
|
+
*
|
|
1707
|
+
* // ✅ Autocomplete shows only swap-supported chains
|
|
1708
|
+
* const result = await swap(context, {
|
|
1709
|
+
* from: {
|
|
1710
|
+
* adapter,
|
|
1711
|
+
* chain: SwapChain.Ethereum // Autocomplete: Ethereum, Base, Polygon, Solana
|
|
1712
|
+
* },
|
|
1713
|
+
* tokenIn: 'USDC',
|
|
1714
|
+
* tokenOut: 'USDT',
|
|
1715
|
+
* amount: '100.0'
|
|
1716
|
+
* })
|
|
1717
|
+
* ```
|
|
1718
|
+
*
|
|
1719
|
+
* @example
|
|
1720
|
+
* ```typescript
|
|
1721
|
+
* // String literals also work (constrained to SwapChain values)
|
|
1722
|
+
* const result = await swap(context, {
|
|
1723
|
+
* from: {
|
|
1724
|
+
* adapter,
|
|
1725
|
+
* chain: 'Ethereum' // ✅ Only SwapChain strings allowed
|
|
1726
|
+
* },
|
|
1727
|
+
* tokenIn: 'USDC',
|
|
1728
|
+
* tokenOut: 'NATIVE',
|
|
1729
|
+
* amount: '50.0'
|
|
1730
|
+
* })
|
|
1731
|
+
*
|
|
1732
|
+
* // ❌ TypeScript error - Sui not in SwapChain enum
|
|
1733
|
+
* const invalidResult = await swap(context, {
|
|
1734
|
+
* from: {
|
|
1735
|
+
* adapter,
|
|
1736
|
+
* chain: 'Sui' // Compile-time error!
|
|
1737
|
+
* },
|
|
1738
|
+
* tokenIn: 'USDC',
|
|
1739
|
+
* tokenOut: 'USDT',
|
|
1740
|
+
* amount: '100.0'
|
|
1741
|
+
* })
|
|
1742
|
+
* ```
|
|
1743
|
+
*/
|
|
1744
|
+
/**
|
|
1745
|
+
* Enum representing chains that support same-chain swaps through the Swap Kit.
|
|
1746
|
+
*
|
|
1747
|
+
* Unlike the full {@link Blockchain} enum, SwapChain includes only mainnet
|
|
1748
|
+
* networks where adapter contracts are deployed (CCTPv2 support).
|
|
1749
|
+
*
|
|
1750
|
+
* Dynamic validation via {@link isSwapSupportedChain} ensures chains
|
|
1751
|
+
* automatically work when adapter contracts and supported tokens are deployed.
|
|
1752
|
+
*
|
|
1753
|
+
* @example
|
|
1754
|
+
* ```typescript
|
|
1755
|
+
* import { SwapChain } from '@core/chains'
|
|
1756
|
+
* import { swap } from '@circle-fin/swap-kit'
|
|
1757
|
+
*
|
|
1758
|
+
* const result = await swap(context, {
|
|
1759
|
+
* from: {
|
|
1760
|
+
* adapter,
|
|
1761
|
+
* chain: SwapChain.Arbitrum // Now supported!
|
|
1762
|
+
* },
|
|
1763
|
+
* tokenIn: 'USDC',
|
|
1764
|
+
* tokenOut: 'WETH',
|
|
1765
|
+
* amount: '100.0'
|
|
1766
|
+
* })
|
|
1767
|
+
* ```
|
|
1768
|
+
*
|
|
1769
|
+
* @see {@link isSwapSupportedChain} for runtime validation
|
|
1770
|
+
* @see {@link getSwapSupportedChains} for all supported chains
|
|
1771
|
+
*/
|
|
1772
|
+
var SwapChain;
|
|
1773
|
+
(function (SwapChain) {
|
|
1774
|
+
// Original 4 chains
|
|
1775
|
+
SwapChain["Ethereum"] = "Ethereum";
|
|
1776
|
+
SwapChain["Base"] = "Base";
|
|
1777
|
+
SwapChain["Polygon"] = "Polygon";
|
|
1778
|
+
SwapChain["Solana"] = "Solana";
|
|
1779
|
+
// Additional supported chains
|
|
1780
|
+
SwapChain["Arbitrum"] = "Arbitrum";
|
|
1781
|
+
SwapChain["Optimism"] = "Optimism";
|
|
1782
|
+
SwapChain["Avalanche"] = "Avalanche";
|
|
1783
|
+
SwapChain["Linea"] = "Linea";
|
|
1784
|
+
SwapChain["Ink"] = "Ink";
|
|
1785
|
+
SwapChain["World_Chain"] = "World_Chain";
|
|
1786
|
+
SwapChain["Unichain"] = "Unichain";
|
|
1787
|
+
SwapChain["Plume"] = "Plume";
|
|
1788
|
+
SwapChain["Sei"] = "Sei";
|
|
1789
|
+
SwapChain["Sonic"] = "Sonic";
|
|
1790
|
+
SwapChain["XDC"] = "XDC";
|
|
1791
|
+
SwapChain["HyperEVM"] = "HyperEVM";
|
|
1792
|
+
SwapChain["Monad"] = "Monad";
|
|
1793
|
+
})(SwapChain || (SwapChain = {}));
|
|
1260
1794
|
// -----------------------------------------------------------------------------
|
|
1261
1795
|
// Bridge Chain Enum (CCTPv2 Supported Chains)
|
|
1262
1796
|
// -----------------------------------------------------------------------------
|
|
@@ -1313,11 +1847,13 @@ var BridgeChain;
|
|
|
1313
1847
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
1314
1848
|
BridgeChain["Base"] = "Base";
|
|
1315
1849
|
BridgeChain["Codex"] = "Codex";
|
|
1850
|
+
BridgeChain["Edge"] = "Edge";
|
|
1316
1851
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
1317
1852
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
1318
1853
|
BridgeChain["Ink"] = "Ink";
|
|
1319
1854
|
BridgeChain["Linea"] = "Linea";
|
|
1320
1855
|
BridgeChain["Monad"] = "Monad";
|
|
1856
|
+
BridgeChain["Morph"] = "Morph";
|
|
1321
1857
|
BridgeChain["Optimism"] = "Optimism";
|
|
1322
1858
|
BridgeChain["Plume"] = "Plume";
|
|
1323
1859
|
BridgeChain["Polygon"] = "Polygon";
|
|
@@ -1333,11 +1869,13 @@ var BridgeChain;
|
|
|
1333
1869
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
1334
1870
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
1335
1871
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
1872
|
+
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
1336
1873
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
1337
1874
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
1338
1875
|
BridgeChain["Ink_Testnet"] = "Ink_Testnet";
|
|
1339
1876
|
BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
1340
1877
|
BridgeChain["Monad_Testnet"] = "Monad_Testnet";
|
|
1878
|
+
BridgeChain["Morph_Testnet"] = "Morph_Testnet";
|
|
1341
1879
|
BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
|
|
1342
1880
|
BridgeChain["Plume_Testnet"] = "Plume_Testnet";
|
|
1343
1881
|
BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
|
|
@@ -1408,6 +1946,7 @@ const Algorand = defineChain({
|
|
|
1408
1946
|
rpcEndpoints: ['https://mainnet-api.algonode.cloud'],
|
|
1409
1947
|
eurcAddress: null,
|
|
1410
1948
|
usdcAddress: '31566704',
|
|
1949
|
+
usdtAddress: null,
|
|
1411
1950
|
cctp: null,
|
|
1412
1951
|
});
|
|
1413
1952
|
|
|
@@ -1431,6 +1970,7 @@ const AlgorandTestnet = defineChain({
|
|
|
1431
1970
|
rpcEndpoints: ['https://testnet-api.algonode.cloud'],
|
|
1432
1971
|
eurcAddress: null,
|
|
1433
1972
|
usdcAddress: '10458941',
|
|
1973
|
+
usdtAddress: null,
|
|
1434
1974
|
cctp: null,
|
|
1435
1975
|
});
|
|
1436
1976
|
|
|
@@ -1454,6 +1994,7 @@ const Aptos = defineChain({
|
|
|
1454
1994
|
rpcEndpoints: ['https://fullnode.mainnet.aptoslabs.com/v1'],
|
|
1455
1995
|
eurcAddress: null,
|
|
1456
1996
|
usdcAddress: '0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b',
|
|
1997
|
+
usdtAddress: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
1457
1998
|
cctp: {
|
|
1458
1999
|
domain: 9,
|
|
1459
2000
|
contracts: {
|
|
@@ -1491,6 +2032,7 @@ const AptosTestnet = defineChain({
|
|
|
1491
2032
|
rpcEndpoints: ['https://fullnode.testnet.aptoslabs.com/v1'],
|
|
1492
2033
|
eurcAddress: null,
|
|
1493
2034
|
usdcAddress: '0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832',
|
|
2035
|
+
usdtAddress: null,
|
|
1494
2036
|
cctp: {
|
|
1495
2037
|
domain: 9,
|
|
1496
2038
|
contracts: {
|
|
@@ -1508,6 +2050,121 @@ const AptosTestnet = defineChain({
|
|
|
1508
2050
|
},
|
|
1509
2051
|
});
|
|
1510
2052
|
|
|
2053
|
+
/**
|
|
2054
|
+
* Complete swap token registry - single source of truth for all swap-supported tokens.
|
|
2055
|
+
*
|
|
2056
|
+
* @remarks
|
|
2057
|
+
* All packages should import from this registry for swap operations.
|
|
2058
|
+
* Adding a new swap token requires updating only this registry.
|
|
2059
|
+
*
|
|
2060
|
+
* The NATIVE token is handled separately as it resolves dynamically based on chain.
|
|
2061
|
+
*
|
|
2062
|
+
* @example
|
|
2063
|
+
* ```typescript
|
|
2064
|
+
* import { SWAP_TOKEN_REGISTRY } from '@core/chains'
|
|
2065
|
+
*
|
|
2066
|
+
* // Get token decimals
|
|
2067
|
+
* const decimals = SWAP_TOKEN_REGISTRY.USDC.decimals // 6
|
|
2068
|
+
*
|
|
2069
|
+
* // Check if token is stablecoin
|
|
2070
|
+
* const isStable = SWAP_TOKEN_REGISTRY.DAI.category === 'stablecoin' // true
|
|
2071
|
+
* ```
|
|
2072
|
+
*/
|
|
2073
|
+
const SWAP_TOKEN_REGISTRY = {
|
|
2074
|
+
// ============================================================================
|
|
2075
|
+
// Stablecoins (6 decimals)
|
|
2076
|
+
// ============================================================================
|
|
2077
|
+
USDC: {
|
|
2078
|
+
symbol: 'USDC',
|
|
2079
|
+
decimals: 6,
|
|
2080
|
+
category: 'stablecoin',
|
|
2081
|
+
description: 'USD Coin',
|
|
2082
|
+
},
|
|
2083
|
+
EURC: {
|
|
2084
|
+
symbol: 'EURC',
|
|
2085
|
+
decimals: 6,
|
|
2086
|
+
category: 'stablecoin',
|
|
2087
|
+
description: 'Euro Coin',
|
|
2088
|
+
},
|
|
2089
|
+
USDT: {
|
|
2090
|
+
symbol: 'USDT',
|
|
2091
|
+
decimals: 6,
|
|
2092
|
+
category: 'stablecoin',
|
|
2093
|
+
description: 'Tether USD',
|
|
2094
|
+
},
|
|
2095
|
+
PYUSD: {
|
|
2096
|
+
symbol: 'PYUSD',
|
|
2097
|
+
decimals: 6,
|
|
2098
|
+
category: 'stablecoin',
|
|
2099
|
+
description: 'PayPal USD',
|
|
2100
|
+
},
|
|
2101
|
+
// ============================================================================
|
|
2102
|
+
// Stablecoins (18 decimals)
|
|
2103
|
+
// ============================================================================
|
|
2104
|
+
DAI: {
|
|
2105
|
+
symbol: 'DAI',
|
|
2106
|
+
decimals: 18,
|
|
2107
|
+
category: 'stablecoin',
|
|
2108
|
+
description: 'MakerDAO stablecoin',
|
|
2109
|
+
},
|
|
2110
|
+
USDE: {
|
|
2111
|
+
symbol: 'USDE',
|
|
2112
|
+
decimals: 18,
|
|
2113
|
+
category: 'stablecoin',
|
|
2114
|
+
description: 'Ethena USD (synthetic dollar)',
|
|
2115
|
+
},
|
|
2116
|
+
// ============================================================================
|
|
2117
|
+
// Wrapped Tokens
|
|
2118
|
+
// ============================================================================
|
|
2119
|
+
WBTC: {
|
|
2120
|
+
symbol: 'WBTC',
|
|
2121
|
+
decimals: 8,
|
|
2122
|
+
category: 'wrapped',
|
|
2123
|
+
description: 'Wrapped Bitcoin',
|
|
2124
|
+
},
|
|
2125
|
+
WETH: {
|
|
2126
|
+
symbol: 'WETH',
|
|
2127
|
+
decimals: 18,
|
|
2128
|
+
category: 'wrapped',
|
|
2129
|
+
description: 'Wrapped Ethereum',
|
|
2130
|
+
},
|
|
2131
|
+
WSOL: {
|
|
2132
|
+
symbol: 'WSOL',
|
|
2133
|
+
decimals: 9,
|
|
2134
|
+
category: 'wrapped',
|
|
2135
|
+
description: 'Wrapped Solana',
|
|
2136
|
+
},
|
|
2137
|
+
WAVAX: {
|
|
2138
|
+
symbol: 'WAVAX',
|
|
2139
|
+
decimals: 18,
|
|
2140
|
+
category: 'wrapped',
|
|
2141
|
+
description: 'Wrapped Avalanche',
|
|
2142
|
+
},
|
|
2143
|
+
WPOL: {
|
|
2144
|
+
symbol: 'WPOL',
|
|
2145
|
+
decimals: 18,
|
|
2146
|
+
category: 'wrapped',
|
|
2147
|
+
description: 'Wrapped Polygon',
|
|
2148
|
+
},
|
|
2149
|
+
};
|
|
2150
|
+
/**
|
|
2151
|
+
* Special NATIVE token constant for swap operations.
|
|
2152
|
+
*
|
|
2153
|
+
* @remarks
|
|
2154
|
+
* NATIVE is handled separately from SWAP_TOKEN_REGISTRY because it resolves
|
|
2155
|
+
* dynamically based on the chain (ETH on Ethereum, SOL on Solana, etc.).
|
|
2156
|
+
* Its decimals are chain-specific.
|
|
2157
|
+
*/
|
|
2158
|
+
const NATIVE_TOKEN = 'NATIVE';
|
|
2159
|
+
/**
|
|
2160
|
+
* Array of all supported swap token symbols including NATIVE.
|
|
2161
|
+
* Useful for iteration, validation, and filtering.
|
|
2162
|
+
*/
|
|
2163
|
+
[
|
|
2164
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
2165
|
+
NATIVE_TOKEN,
|
|
2166
|
+
];
|
|
2167
|
+
|
|
1511
2168
|
/**
|
|
1512
2169
|
* The bridge contract address for EVM testnet networks.
|
|
1513
2170
|
*
|
|
@@ -1524,6 +2181,13 @@ const BRIDGE_CONTRACT_EVM_TESTNET = '0xC5567a5E3370d4DBfB0540025078e283e36A363d'
|
|
|
1524
2181
|
* USDC transfers on live networks.
|
|
1525
2182
|
*/
|
|
1526
2183
|
const BRIDGE_CONTRACT_EVM_MAINNET = '0xB3FA262d0fB521cc93bE83d87b322b8A23DAf3F0';
|
|
2184
|
+
/**
|
|
2185
|
+
* The adapter contract address for EVM mainnet networks.
|
|
2186
|
+
*
|
|
2187
|
+
* This contract serves as an adapter for integrating with various protocols
|
|
2188
|
+
* on EVM-compatible chains. Use this address for mainnet adapter integrations.
|
|
2189
|
+
*/
|
|
2190
|
+
const ADAPTER_CONTRACT_EVM_MAINNET = '0x7FB8c7260b63934d8da38aF902f87ae6e284a845';
|
|
1527
2191
|
|
|
1528
2192
|
/**
|
|
1529
2193
|
* Arc Testnet chain definition
|
|
@@ -1553,6 +2217,7 @@ const ArcTestnet = defineChain({
|
|
|
1553
2217
|
rpcEndpoints: ['https://rpc.testnet.arc.network/'],
|
|
1554
2218
|
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
1555
2219
|
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
2220
|
+
usdtAddress: null,
|
|
1556
2221
|
cctp: {
|
|
1557
2222
|
domain: 26,
|
|
1558
2223
|
contracts: {
|
|
@@ -1595,6 +2260,7 @@ const Arbitrum = defineChain({
|
|
|
1595
2260
|
rpcEndpoints: ['https://arb1.arbitrum.io/rpc'],
|
|
1596
2261
|
eurcAddress: null,
|
|
1597
2262
|
usdcAddress: '0xaf88d065e77c8cc2239327c5edb3a432268e5831',
|
|
2263
|
+
usdtAddress: null,
|
|
1598
2264
|
cctp: {
|
|
1599
2265
|
domain: 3,
|
|
1600
2266
|
contracts: {
|
|
@@ -1619,6 +2285,7 @@ const Arbitrum = defineChain({
|
|
|
1619
2285
|
},
|
|
1620
2286
|
kitContracts: {
|
|
1621
2287
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2288
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1622
2289
|
},
|
|
1623
2290
|
});
|
|
1624
2291
|
|
|
@@ -1643,6 +2310,7 @@ const ArbitrumSepolia = defineChain({
|
|
|
1643
2310
|
rpcEndpoints: ['https://sepolia-rollup.arbitrum.io/rpc'],
|
|
1644
2311
|
eurcAddress: null,
|
|
1645
2312
|
usdcAddress: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
2313
|
+
usdtAddress: null,
|
|
1646
2314
|
cctp: {
|
|
1647
2315
|
domain: 3,
|
|
1648
2316
|
contracts: {
|
|
@@ -1691,6 +2359,7 @@ const Avalanche = defineChain({
|
|
|
1691
2359
|
rpcEndpoints: ['https://api.avax.network/ext/bc/C/rpc'],
|
|
1692
2360
|
eurcAddress: '0xc891eb4cbdeff6e073e859e987815ed1505c2acd',
|
|
1693
2361
|
usdcAddress: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
2362
|
+
usdtAddress: '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7',
|
|
1694
2363
|
cctp: {
|
|
1695
2364
|
domain: 1,
|
|
1696
2365
|
contracts: {
|
|
@@ -1715,6 +2384,7 @@ const Avalanche = defineChain({
|
|
|
1715
2384
|
},
|
|
1716
2385
|
kitContracts: {
|
|
1717
2386
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2387
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1718
2388
|
},
|
|
1719
2389
|
});
|
|
1720
2390
|
|
|
@@ -1738,6 +2408,7 @@ const AvalancheFuji = defineChain({
|
|
|
1738
2408
|
explorerUrl: 'https://subnets-test.avax.network/c-chain/tx/{hash}',
|
|
1739
2409
|
eurcAddress: '0x5e44db7996c682e92a960b65ac713a54ad815c6b',
|
|
1740
2410
|
usdcAddress: '0x5425890298aed601595a70ab815c96711a31bc65',
|
|
2411
|
+
usdtAddress: null,
|
|
1741
2412
|
cctp: {
|
|
1742
2413
|
domain: 1,
|
|
1743
2414
|
contracts: {
|
|
@@ -1787,6 +2458,7 @@ const Base = defineChain({
|
|
|
1787
2458
|
rpcEndpoints: ['https://mainnet.base.org', 'https://base.publicnode.com'],
|
|
1788
2459
|
eurcAddress: '0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42',
|
|
1789
2460
|
usdcAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
2461
|
+
usdtAddress: null,
|
|
1790
2462
|
cctp: {
|
|
1791
2463
|
domain: 6,
|
|
1792
2464
|
contracts: {
|
|
@@ -1811,6 +2483,7 @@ const Base = defineChain({
|
|
|
1811
2483
|
},
|
|
1812
2484
|
kitContracts: {
|
|
1813
2485
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2486
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
1814
2487
|
},
|
|
1815
2488
|
});
|
|
1816
2489
|
|
|
@@ -1835,6 +2508,7 @@ const BaseSepolia = defineChain({
|
|
|
1835
2508
|
rpcEndpoints: ['https://sepolia.base.org'],
|
|
1836
2509
|
eurcAddress: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
1837
2510
|
usdcAddress: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
2511
|
+
usdtAddress: null,
|
|
1838
2512
|
cctp: {
|
|
1839
2513
|
domain: 6,
|
|
1840
2514
|
contracts: {
|
|
@@ -1883,6 +2557,7 @@ const Celo = defineChain({
|
|
|
1883
2557
|
rpcEndpoints: ['https://forno.celo.org'],
|
|
1884
2558
|
eurcAddress: null,
|
|
1885
2559
|
usdcAddress: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
2560
|
+
usdtAddress: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
1886
2561
|
cctp: null,
|
|
1887
2562
|
});
|
|
1888
2563
|
|
|
@@ -1907,6 +2582,7 @@ const CeloAlfajoresTestnet = defineChain({
|
|
|
1907
2582
|
rpcEndpoints: ['https://alfajores-forno.celo-testnet.org'],
|
|
1908
2583
|
eurcAddress: null,
|
|
1909
2584
|
usdcAddress: '0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B',
|
|
2585
|
+
usdtAddress: null,
|
|
1910
2586
|
cctp: null,
|
|
1911
2587
|
});
|
|
1912
2588
|
|
|
@@ -1931,62 +2607,152 @@ const Codex = defineChain({
|
|
|
1931
2607
|
rpcEndpoints: ['https://rpc.codex.xyz'],
|
|
1932
2608
|
eurcAddress: null,
|
|
1933
2609
|
usdcAddress: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
2610
|
+
usdtAddress: null,
|
|
2611
|
+
cctp: {
|
|
2612
|
+
domain: 12,
|
|
2613
|
+
contracts: {
|
|
2614
|
+
v2: {
|
|
2615
|
+
type: 'split',
|
|
2616
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
2617
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
2618
|
+
confirmations: 65,
|
|
2619
|
+
fastConfirmations: 1,
|
|
2620
|
+
},
|
|
2621
|
+
},
|
|
2622
|
+
forwarderSupported: {
|
|
2623
|
+
source: true,
|
|
2624
|
+
destination: false,
|
|
2625
|
+
},
|
|
2626
|
+
},
|
|
2627
|
+
kitContracts: {
|
|
2628
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2629
|
+
},
|
|
2630
|
+
});
|
|
2631
|
+
|
|
2632
|
+
/**
|
|
2633
|
+
* Codex Testnet chain definition
|
|
2634
|
+
* @remarks
|
|
2635
|
+
* This represents the test network for the Codex blockchain.
|
|
2636
|
+
*/
|
|
2637
|
+
const CodexTestnet = defineChain({
|
|
2638
|
+
type: 'evm',
|
|
2639
|
+
chain: exports.Blockchain.Codex_Testnet,
|
|
2640
|
+
name: 'Codex Testnet',
|
|
2641
|
+
title: 'Codex Testnet',
|
|
2642
|
+
nativeCurrency: {
|
|
2643
|
+
name: 'ETH',
|
|
2644
|
+
symbol: 'ETH',
|
|
2645
|
+
decimals: 18,
|
|
2646
|
+
},
|
|
2647
|
+
chainId: 812242,
|
|
2648
|
+
isTestnet: true,
|
|
2649
|
+
explorerUrl: 'https://explorer.codex-stg.xyz/tx/{hash}',
|
|
2650
|
+
rpcEndpoints: ['https://rpc.codex-stg.xyz'],
|
|
2651
|
+
eurcAddress: null,
|
|
2652
|
+
usdcAddress: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
2653
|
+
usdtAddress: null,
|
|
1934
2654
|
cctp: {
|
|
1935
2655
|
domain: 12,
|
|
1936
2656
|
contracts: {
|
|
1937
2657
|
v2: {
|
|
1938
2658
|
type: 'split',
|
|
1939
|
-
tokenMessenger: '
|
|
1940
|
-
messageTransmitter: '
|
|
2659
|
+
tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
|
|
2660
|
+
messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
|
|
2661
|
+
confirmations: 65,
|
|
2662
|
+
fastConfirmations: 1,
|
|
2663
|
+
},
|
|
2664
|
+
},
|
|
2665
|
+
forwarderSupported: {
|
|
2666
|
+
source: true,
|
|
2667
|
+
destination: false,
|
|
2668
|
+
},
|
|
2669
|
+
},
|
|
2670
|
+
kitContracts: {
|
|
2671
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
2672
|
+
},
|
|
2673
|
+
});
|
|
2674
|
+
|
|
2675
|
+
/**
|
|
2676
|
+
* Edge Mainnet chain definition
|
|
2677
|
+
* @remarks
|
|
2678
|
+
* This represents the official production network for the Edge blockchain.
|
|
2679
|
+
* Edge is an EVM-compatible blockchain.
|
|
2680
|
+
*/
|
|
2681
|
+
const Edge = defineChain({
|
|
2682
|
+
type: 'evm',
|
|
2683
|
+
chain: exports.Blockchain.Edge,
|
|
2684
|
+
name: 'Edge',
|
|
2685
|
+
title: 'Edge Mainnet',
|
|
2686
|
+
nativeCurrency: {
|
|
2687
|
+
name: 'Ether',
|
|
2688
|
+
symbol: 'ETH',
|
|
2689
|
+
decimals: 18,
|
|
2690
|
+
},
|
|
2691
|
+
chainId: 3343,
|
|
2692
|
+
isTestnet: false,
|
|
2693
|
+
explorerUrl: 'https://pro.edgex.exchange/en-US/explorer/tx/{hash}',
|
|
2694
|
+
rpcEndpoints: ['https://edge-mainnet.g.alchemy.com/public'],
|
|
2695
|
+
eurcAddress: null,
|
|
2696
|
+
usdcAddress: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
2697
|
+
usdtAddress: null,
|
|
2698
|
+
cctp: {
|
|
2699
|
+
domain: 28,
|
|
2700
|
+
contracts: {
|
|
2701
|
+
v2: {
|
|
2702
|
+
type: 'split',
|
|
2703
|
+
tokenMessenger: '0x98706A006bc632Df31CAdFCBD43F38887ce2ca5c',
|
|
2704
|
+
messageTransmitter: '0x5b61381Fc9e58E70EfC13a4A97516997019198ee',
|
|
1941
2705
|
confirmations: 65,
|
|
1942
2706
|
fastConfirmations: 1,
|
|
1943
2707
|
},
|
|
1944
2708
|
},
|
|
1945
2709
|
forwarderSupported: {
|
|
1946
2710
|
source: true,
|
|
1947
|
-
destination:
|
|
2711
|
+
destination: true,
|
|
1948
2712
|
},
|
|
1949
2713
|
},
|
|
1950
2714
|
kitContracts: {
|
|
1951
|
-
bridge:
|
|
2715
|
+
bridge: '0x6D1AaE1c34Aeb582022916a67f2A655C6f4eDFF2', //Unique bridge address as CCTP address for Edge is also unique
|
|
1952
2716
|
},
|
|
1953
2717
|
});
|
|
1954
2718
|
|
|
1955
2719
|
/**
|
|
1956
|
-
*
|
|
2720
|
+
* Edge Testnet chain definition
|
|
1957
2721
|
* @remarks
|
|
1958
|
-
* This represents the test network for the
|
|
2722
|
+
* This represents the official test network for the Edge blockchain.
|
|
2723
|
+
* Edge is an EVM-compatible blockchain.
|
|
1959
2724
|
*/
|
|
1960
|
-
const
|
|
2725
|
+
const EdgeTestnet = defineChain({
|
|
1961
2726
|
type: 'evm',
|
|
1962
|
-
chain: exports.Blockchain.
|
|
1963
|
-
name: '
|
|
1964
|
-
title: '
|
|
2727
|
+
chain: exports.Blockchain.Edge_Testnet,
|
|
2728
|
+
name: 'Edge Testnet',
|
|
2729
|
+
title: 'Edge Testnet',
|
|
1965
2730
|
nativeCurrency: {
|
|
1966
|
-
name: '
|
|
2731
|
+
name: 'Ether',
|
|
1967
2732
|
symbol: 'ETH',
|
|
1968
2733
|
decimals: 18,
|
|
1969
2734
|
},
|
|
1970
|
-
chainId:
|
|
2735
|
+
chainId: 33431,
|
|
1971
2736
|
isTestnet: true,
|
|
1972
|
-
explorerUrl: 'https://explorer.
|
|
1973
|
-
rpcEndpoints: ['https://
|
|
2737
|
+
explorerUrl: 'https://edge-testnet.explorer.alchemy.com/tx/{hash}',
|
|
2738
|
+
rpcEndpoints: ['https://edge-testnet.g.alchemy.com/public'],
|
|
1974
2739
|
eurcAddress: null,
|
|
1975
|
-
usdcAddress: '
|
|
2740
|
+
usdcAddress: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
2741
|
+
usdtAddress: null,
|
|
1976
2742
|
cctp: {
|
|
1977
|
-
domain:
|
|
2743
|
+
domain: 28,
|
|
1978
2744
|
contracts: {
|
|
1979
2745
|
v2: {
|
|
1980
2746
|
type: 'split',
|
|
1981
|
-
tokenMessenger: '
|
|
1982
|
-
messageTransmitter: '
|
|
2747
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
2748
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
1983
2749
|
confirmations: 65,
|
|
1984
2750
|
fastConfirmations: 1,
|
|
1985
2751
|
},
|
|
1986
2752
|
},
|
|
1987
2753
|
forwarderSupported: {
|
|
1988
2754
|
source: true,
|
|
1989
|
-
destination:
|
|
2755
|
+
destination: true,
|
|
1990
2756
|
},
|
|
1991
2757
|
},
|
|
1992
2758
|
kitContracts: {
|
|
@@ -2015,6 +2781,7 @@ const Ethereum = defineChain({
|
|
|
2015
2781
|
rpcEndpoints: ['https://eth.merkle.io', 'https://ethereum.publicnode.com'],
|
|
2016
2782
|
eurcAddress: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
2017
2783
|
usdcAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
2784
|
+
usdtAddress: '0xdac17f958d2ee523a2206206994597c13d831ec7',
|
|
2018
2785
|
cctp: {
|
|
2019
2786
|
domain: 0,
|
|
2020
2787
|
contracts: {
|
|
@@ -2039,6 +2806,7 @@ const Ethereum = defineChain({
|
|
|
2039
2806
|
},
|
|
2040
2807
|
kitContracts: {
|
|
2041
2808
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2809
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2042
2810
|
},
|
|
2043
2811
|
});
|
|
2044
2812
|
|
|
@@ -2063,6 +2831,7 @@ const EthereumSepolia = defineChain({
|
|
|
2063
2831
|
rpcEndpoints: ['https://sepolia.drpc.org'],
|
|
2064
2832
|
eurcAddress: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4',
|
|
2065
2833
|
usdcAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
2834
|
+
usdtAddress: null,
|
|
2066
2835
|
cctp: {
|
|
2067
2836
|
domain: 0,
|
|
2068
2837
|
contracts: {
|
|
@@ -2110,6 +2879,7 @@ const Hedera = defineChain({
|
|
|
2110
2879
|
rpcEndpoints: ['https://mainnet.hashio.io/api'],
|
|
2111
2880
|
eurcAddress: null,
|
|
2112
2881
|
usdcAddress: '0.0.456858',
|
|
2882
|
+
usdtAddress: null,
|
|
2113
2883
|
cctp: null,
|
|
2114
2884
|
});
|
|
2115
2885
|
|
|
@@ -2133,6 +2903,7 @@ const HederaTestnet = defineChain({
|
|
|
2133
2903
|
rpcEndpoints: ['https://testnet.hashio.io/api'],
|
|
2134
2904
|
eurcAddress: null,
|
|
2135
2905
|
usdcAddress: '0.0.429274',
|
|
2906
|
+
usdtAddress: null,
|
|
2136
2907
|
cctp: null,
|
|
2137
2908
|
});
|
|
2138
2909
|
|
|
@@ -2159,6 +2930,7 @@ const HyperEVM = defineChain({
|
|
|
2159
2930
|
rpcEndpoints: ['https://rpc.hyperliquid.xyz/evm'],
|
|
2160
2931
|
eurcAddress: null,
|
|
2161
2932
|
usdcAddress: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
2933
|
+
usdtAddress: null,
|
|
2162
2934
|
cctp: {
|
|
2163
2935
|
domain: 19,
|
|
2164
2936
|
contracts: {
|
|
@@ -2177,6 +2949,7 @@ const HyperEVM = defineChain({
|
|
|
2177
2949
|
},
|
|
2178
2950
|
kitContracts: {
|
|
2179
2951
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
2952
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2180
2953
|
},
|
|
2181
2954
|
});
|
|
2182
2955
|
|
|
@@ -2202,6 +2975,7 @@ const HyperEVMTestnet = defineChain({
|
|
|
2202
2975
|
rpcEndpoints: ['https://rpc.hyperliquid-testnet.xyz/evm'],
|
|
2203
2976
|
eurcAddress: null,
|
|
2204
2977
|
usdcAddress: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
2978
|
+
usdtAddress: null,
|
|
2205
2979
|
cctp: {
|
|
2206
2980
|
domain: 19,
|
|
2207
2981
|
contracts: {
|
|
@@ -2249,6 +3023,7 @@ const Ink = defineChain({
|
|
|
2249
3023
|
],
|
|
2250
3024
|
eurcAddress: null,
|
|
2251
3025
|
usdcAddress: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
3026
|
+
usdtAddress: null,
|
|
2252
3027
|
cctp: {
|
|
2253
3028
|
domain: 21,
|
|
2254
3029
|
contracts: {
|
|
@@ -2267,6 +3042,7 @@ const Ink = defineChain({
|
|
|
2267
3042
|
},
|
|
2268
3043
|
kitContracts: {
|
|
2269
3044
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3045
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2270
3046
|
},
|
|
2271
3047
|
});
|
|
2272
3048
|
|
|
@@ -2295,6 +3071,7 @@ const InkTestnet = defineChain({
|
|
|
2295
3071
|
],
|
|
2296
3072
|
eurcAddress: null,
|
|
2297
3073
|
usdcAddress: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
3074
|
+
usdtAddress: null,
|
|
2298
3075
|
cctp: {
|
|
2299
3076
|
domain: 21,
|
|
2300
3077
|
contracts: {
|
|
@@ -2337,6 +3114,7 @@ const Linea = defineChain({
|
|
|
2337
3114
|
rpcEndpoints: ['https://rpc.linea.build'],
|
|
2338
3115
|
eurcAddress: null,
|
|
2339
3116
|
usdcAddress: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
3117
|
+
usdtAddress: null,
|
|
2340
3118
|
cctp: {
|
|
2341
3119
|
domain: 11,
|
|
2342
3120
|
contracts: {
|
|
@@ -2355,6 +3133,7 @@ const Linea = defineChain({
|
|
|
2355
3133
|
},
|
|
2356
3134
|
kitContracts: {
|
|
2357
3135
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3136
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2358
3137
|
},
|
|
2359
3138
|
});
|
|
2360
3139
|
|
|
@@ -2379,6 +3158,7 @@ const LineaSepolia = defineChain({
|
|
|
2379
3158
|
rpcEndpoints: ['https://rpc.sepolia.linea.build'],
|
|
2380
3159
|
eurcAddress: null,
|
|
2381
3160
|
usdcAddress: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
3161
|
+
usdtAddress: null,
|
|
2382
3162
|
cctp: {
|
|
2383
3163
|
domain: 11,
|
|
2384
3164
|
contracts: {
|
|
@@ -2423,6 +3203,7 @@ const Monad = defineChain({
|
|
|
2423
3203
|
rpcEndpoints: ['https://rpc.monad.xyz'],
|
|
2424
3204
|
eurcAddress: null,
|
|
2425
3205
|
usdcAddress: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
3206
|
+
usdtAddress: null,
|
|
2426
3207
|
cctp: {
|
|
2427
3208
|
domain: 15,
|
|
2428
3209
|
contracts: {
|
|
@@ -2441,6 +3222,7 @@ const Monad = defineChain({
|
|
|
2441
3222
|
},
|
|
2442
3223
|
kitContracts: {
|
|
2443
3224
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3225
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2444
3226
|
},
|
|
2445
3227
|
});
|
|
2446
3228
|
|
|
@@ -2467,6 +3249,7 @@ const MonadTestnet = defineChain({
|
|
|
2467
3249
|
rpcEndpoints: ['https://testnet-rpc.monad.xyz'],
|
|
2468
3250
|
eurcAddress: null,
|
|
2469
3251
|
usdcAddress: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
3252
|
+
usdtAddress: null,
|
|
2470
3253
|
cctp: {
|
|
2471
3254
|
domain: 15,
|
|
2472
3255
|
contracts: {
|
|
@@ -2488,6 +3271,94 @@ const MonadTestnet = defineChain({
|
|
|
2488
3271
|
},
|
|
2489
3272
|
});
|
|
2490
3273
|
|
|
3274
|
+
/**
|
|
3275
|
+
* Morph Mainnet chain definition
|
|
3276
|
+
* @remarks
|
|
3277
|
+
* This represents the official production network for the Morph blockchain.
|
|
3278
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
3279
|
+
*/
|
|
3280
|
+
const Morph = defineChain({
|
|
3281
|
+
type: 'evm',
|
|
3282
|
+
chain: exports.Blockchain.Morph,
|
|
3283
|
+
name: 'Morph',
|
|
3284
|
+
title: 'Morph Mainnet',
|
|
3285
|
+
nativeCurrency: {
|
|
3286
|
+
name: 'Ether',
|
|
3287
|
+
symbol: 'ETH',
|
|
3288
|
+
decimals: 18,
|
|
3289
|
+
},
|
|
3290
|
+
chainId: 2818,
|
|
3291
|
+
isTestnet: false,
|
|
3292
|
+
explorerUrl: 'https://explorer.morph.network/tx/{hash}',
|
|
3293
|
+
rpcEndpoints: ['https://rpc.morphl2.io'],
|
|
3294
|
+
eurcAddress: null,
|
|
3295
|
+
usdcAddress: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
3296
|
+
usdtAddress: null,
|
|
3297
|
+
cctp: {
|
|
3298
|
+
domain: 30,
|
|
3299
|
+
contracts: {
|
|
3300
|
+
v2: {
|
|
3301
|
+
type: 'split',
|
|
3302
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
3303
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
3304
|
+
confirmations: 64,
|
|
3305
|
+
fastConfirmations: 1,
|
|
3306
|
+
},
|
|
3307
|
+
},
|
|
3308
|
+
forwarderSupported: {
|
|
3309
|
+
source: false,
|
|
3310
|
+
destination: false,
|
|
3311
|
+
},
|
|
3312
|
+
},
|
|
3313
|
+
kitContracts: {
|
|
3314
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3315
|
+
},
|
|
3316
|
+
});
|
|
3317
|
+
|
|
3318
|
+
/**
|
|
3319
|
+
* Morph Hoodi Testnet chain definition
|
|
3320
|
+
* @remarks
|
|
3321
|
+
* This represents the official test network for the Morph blockchain.
|
|
3322
|
+
* Morph is an EVM-compatible Layer-2 blockchain built on the OP Stack.
|
|
3323
|
+
*/
|
|
3324
|
+
const MorphTestnet = defineChain({
|
|
3325
|
+
type: 'evm',
|
|
3326
|
+
chain: exports.Blockchain.Morph_Testnet,
|
|
3327
|
+
name: 'Morph Hoodi',
|
|
3328
|
+
title: 'Morph Hoodi Testnet',
|
|
3329
|
+
nativeCurrency: {
|
|
3330
|
+
name: 'Ether',
|
|
3331
|
+
symbol: 'ETH',
|
|
3332
|
+
decimals: 18,
|
|
3333
|
+
},
|
|
3334
|
+
chainId: 2910,
|
|
3335
|
+
isTestnet: true,
|
|
3336
|
+
explorerUrl: 'https://explorer-hoodi.morphl2.io/tx/{hash}',
|
|
3337
|
+
rpcEndpoints: ['https://rpc-hoodi.morphl2.io'],
|
|
3338
|
+
eurcAddress: null,
|
|
3339
|
+
usdcAddress: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
3340
|
+
usdtAddress: null,
|
|
3341
|
+
cctp: {
|
|
3342
|
+
domain: 30,
|
|
3343
|
+
contracts: {
|
|
3344
|
+
v2: {
|
|
3345
|
+
type: 'split',
|
|
3346
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
3347
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
3348
|
+
confirmations: 64,
|
|
3349
|
+
fastConfirmations: 1,
|
|
3350
|
+
},
|
|
3351
|
+
},
|
|
3352
|
+
forwarderSupported: {
|
|
3353
|
+
source: false,
|
|
3354
|
+
destination: false,
|
|
3355
|
+
},
|
|
3356
|
+
},
|
|
3357
|
+
kitContracts: {
|
|
3358
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
3359
|
+
},
|
|
3360
|
+
});
|
|
3361
|
+
|
|
2491
3362
|
/**
|
|
2492
3363
|
* NEAR Protocol Mainnet chain definition
|
|
2493
3364
|
* @remarks
|
|
@@ -2508,6 +3379,7 @@ const NEAR = defineChain({
|
|
|
2508
3379
|
rpcEndpoints: ['https://eth-rpc.mainnet.near.org'],
|
|
2509
3380
|
eurcAddress: null,
|
|
2510
3381
|
usdcAddress: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
3382
|
+
usdtAddress: 'usdt.tether-token.near',
|
|
2511
3383
|
cctp: null,
|
|
2512
3384
|
});
|
|
2513
3385
|
|
|
@@ -2531,6 +3403,7 @@ const NEARTestnet = defineChain({
|
|
|
2531
3403
|
rpcEndpoints: ['https://eth-rpc.testnet.near.org'],
|
|
2532
3404
|
eurcAddress: null,
|
|
2533
3405
|
usdcAddress: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
3406
|
+
usdtAddress: null,
|
|
2534
3407
|
cctp: null,
|
|
2535
3408
|
});
|
|
2536
3409
|
|
|
@@ -2554,6 +3427,7 @@ const Noble = defineChain({
|
|
|
2554
3427
|
rpcEndpoints: ['https://noble-rpc.polkachu.com'],
|
|
2555
3428
|
eurcAddress: null,
|
|
2556
3429
|
usdcAddress: 'uusdc',
|
|
3430
|
+
usdtAddress: null,
|
|
2557
3431
|
cctp: {
|
|
2558
3432
|
domain: 4,
|
|
2559
3433
|
contracts: {
|
|
@@ -2590,6 +3464,7 @@ const NobleTestnet = defineChain({
|
|
|
2590
3464
|
rpcEndpoints: ['https://noble-testnet-rpc.polkachu.com'],
|
|
2591
3465
|
eurcAddress: null,
|
|
2592
3466
|
usdcAddress: 'uusdc',
|
|
3467
|
+
usdtAddress: null,
|
|
2593
3468
|
cctp: {
|
|
2594
3469
|
domain: 4,
|
|
2595
3470
|
contracts: {
|
|
@@ -2627,6 +3502,7 @@ const Optimism = defineChain({
|
|
|
2627
3502
|
rpcEndpoints: ['https://mainnet.optimism.io'],
|
|
2628
3503
|
eurcAddress: null,
|
|
2629
3504
|
usdcAddress: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
3505
|
+
usdtAddress: null,
|
|
2630
3506
|
cctp: {
|
|
2631
3507
|
domain: 2,
|
|
2632
3508
|
contracts: {
|
|
@@ -2651,6 +3527,7 @@ const Optimism = defineChain({
|
|
|
2651
3527
|
},
|
|
2652
3528
|
kitContracts: {
|
|
2653
3529
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3530
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2654
3531
|
},
|
|
2655
3532
|
});
|
|
2656
3533
|
|
|
@@ -2675,6 +3552,7 @@ const OptimismSepolia = defineChain({
|
|
|
2675
3552
|
rpcEndpoints: ['https://sepolia.optimism.io'],
|
|
2676
3553
|
eurcAddress: null,
|
|
2677
3554
|
usdcAddress: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
3555
|
+
usdtAddress: null,
|
|
2678
3556
|
cctp: {
|
|
2679
3557
|
domain: 2,
|
|
2680
3558
|
contracts: {
|
|
@@ -2725,6 +3603,7 @@ const Plume = defineChain({
|
|
|
2725
3603
|
rpcEndpoints: ['https://rpc.plume.org'],
|
|
2726
3604
|
eurcAddress: null,
|
|
2727
3605
|
usdcAddress: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
3606
|
+
usdtAddress: null,
|
|
2728
3607
|
cctp: {
|
|
2729
3608
|
domain: 22,
|
|
2730
3609
|
contracts: {
|
|
@@ -2743,6 +3622,7 @@ const Plume = defineChain({
|
|
|
2743
3622
|
},
|
|
2744
3623
|
kitContracts: {
|
|
2745
3624
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3625
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2746
3626
|
},
|
|
2747
3627
|
});
|
|
2748
3628
|
|
|
@@ -2768,6 +3648,7 @@ const PlumeTestnet = defineChain({
|
|
|
2768
3648
|
rpcEndpoints: ['https://testnet-rpc.plume.org'],
|
|
2769
3649
|
eurcAddress: null,
|
|
2770
3650
|
usdcAddress: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
3651
|
+
usdtAddress: null,
|
|
2771
3652
|
cctp: {
|
|
2772
3653
|
domain: 22,
|
|
2773
3654
|
contracts: {
|
|
@@ -2809,6 +3690,7 @@ const PolkadotAssetHub = defineChain({
|
|
|
2809
3690
|
rpcEndpoints: ['https://asset-hub-polkadot-rpc.n.dwellir.com'],
|
|
2810
3691
|
eurcAddress: null,
|
|
2811
3692
|
usdcAddress: '1337',
|
|
3693
|
+
usdtAddress: '1984',
|
|
2812
3694
|
cctp: null,
|
|
2813
3695
|
});
|
|
2814
3696
|
|
|
@@ -2832,6 +3714,7 @@ const PolkadotWestmint = defineChain({
|
|
|
2832
3714
|
rpcEndpoints: ['https://westmint-rpc.polkadot.io'],
|
|
2833
3715
|
eurcAddress: null,
|
|
2834
3716
|
usdcAddress: 'Asset ID 31337',
|
|
3717
|
+
usdtAddress: null,
|
|
2835
3718
|
cctp: null,
|
|
2836
3719
|
});
|
|
2837
3720
|
|
|
@@ -2853,9 +3736,10 @@ const Polygon = defineChain({
|
|
|
2853
3736
|
chainId: 137,
|
|
2854
3737
|
isTestnet: false,
|
|
2855
3738
|
explorerUrl: 'https://polygonscan.com/tx/{hash}',
|
|
2856
|
-
rpcEndpoints: ['https://polygon
|
|
3739
|
+
rpcEndpoints: ['https://polygon.publicnode.com', 'https://polygon.drpc.org'],
|
|
2857
3740
|
eurcAddress: null,
|
|
2858
3741
|
usdcAddress: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
3742
|
+
usdtAddress: null,
|
|
2859
3743
|
cctp: {
|
|
2860
3744
|
domain: 7,
|
|
2861
3745
|
contracts: {
|
|
@@ -2880,6 +3764,7 @@ const Polygon = defineChain({
|
|
|
2880
3764
|
},
|
|
2881
3765
|
kitContracts: {
|
|
2882
3766
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3767
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2883
3768
|
},
|
|
2884
3769
|
});
|
|
2885
3770
|
|
|
@@ -2904,6 +3789,7 @@ const PolygonAmoy = defineChain({
|
|
|
2904
3789
|
rpcEndpoints: ['https://rpc-amoy.polygon.technology'],
|
|
2905
3790
|
eurcAddress: null,
|
|
2906
3791
|
usdcAddress: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
3792
|
+
usdtAddress: null,
|
|
2907
3793
|
cctp: {
|
|
2908
3794
|
domain: 7,
|
|
2909
3795
|
contracts: {
|
|
@@ -2954,6 +3840,7 @@ const Sei = defineChain({
|
|
|
2954
3840
|
rpcEndpoints: ['https://evm-rpc.sei-apis.com'],
|
|
2955
3841
|
eurcAddress: null,
|
|
2956
3842
|
usdcAddress: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
3843
|
+
usdtAddress: null,
|
|
2957
3844
|
cctp: {
|
|
2958
3845
|
domain: 16,
|
|
2959
3846
|
contracts: {
|
|
@@ -2972,6 +3859,7 @@ const Sei = defineChain({
|
|
|
2972
3859
|
},
|
|
2973
3860
|
kitContracts: {
|
|
2974
3861
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3862
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
2975
3863
|
},
|
|
2976
3864
|
});
|
|
2977
3865
|
|
|
@@ -2997,6 +3885,7 @@ const SeiTestnet = defineChain({
|
|
|
2997
3885
|
rpcEndpoints: ['https://evm-rpc-testnet.sei-apis.com'],
|
|
2998
3886
|
eurcAddress: null,
|
|
2999
3887
|
usdcAddress: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
3888
|
+
usdtAddress: null,
|
|
3000
3889
|
cctp: {
|
|
3001
3890
|
domain: 16,
|
|
3002
3891
|
contracts: {
|
|
@@ -3039,6 +3928,7 @@ const Sonic = defineChain({
|
|
|
3039
3928
|
rpcEndpoints: ['https://rpc.soniclabs.com'],
|
|
3040
3929
|
eurcAddress: null,
|
|
3041
3930
|
usdcAddress: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
3931
|
+
usdtAddress: null,
|
|
3042
3932
|
cctp: {
|
|
3043
3933
|
domain: 13,
|
|
3044
3934
|
contracts: {
|
|
@@ -3057,6 +3947,7 @@ const Sonic = defineChain({
|
|
|
3057
3947
|
},
|
|
3058
3948
|
kitContracts: {
|
|
3059
3949
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
3950
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
3060
3951
|
},
|
|
3061
3952
|
});
|
|
3062
3953
|
|
|
@@ -3081,6 +3972,7 @@ const SonicTestnet = defineChain({
|
|
|
3081
3972
|
rpcEndpoints: ['https://rpc.testnet.soniclabs.com'],
|
|
3082
3973
|
eurcAddress: null,
|
|
3083
3974
|
usdcAddress: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
3975
|
+
usdtAddress: null,
|
|
3084
3976
|
cctp: {
|
|
3085
3977
|
domain: 13,
|
|
3086
3978
|
contracts: {
|
|
@@ -3122,6 +4014,7 @@ const Solana = defineChain({
|
|
|
3122
4014
|
rpcEndpoints: ['https://api.mainnet-beta.solana.com'],
|
|
3123
4015
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
3124
4016
|
usdcAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
4017
|
+
usdtAddress: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
3125
4018
|
cctp: {
|
|
3126
4019
|
domain: 5,
|
|
3127
4020
|
contracts: {
|
|
@@ -3168,6 +4061,7 @@ const SolanaDevnet = defineChain({
|
|
|
3168
4061
|
explorerUrl: 'https://solscan.io/tx/{hash}?cluster=devnet',
|
|
3169
4062
|
eurcAddress: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
3170
4063
|
usdcAddress: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
4064
|
+
usdtAddress: null,
|
|
3171
4065
|
cctp: {
|
|
3172
4066
|
domain: 5,
|
|
3173
4067
|
contracts: {
|
|
@@ -3216,6 +4110,7 @@ const Stellar = defineChain({
|
|
|
3216
4110
|
rpcEndpoints: ['https://horizon.stellar.org'],
|
|
3217
4111
|
eurcAddress: 'EURC-GDHU6WRG4IEQXM5NZ4BMPKOXHW76MZM4Y2IEMFDVXBSDP6SJY4ITNPP2',
|
|
3218
4112
|
usdcAddress: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
4113
|
+
usdtAddress: null,
|
|
3219
4114
|
cctp: null,
|
|
3220
4115
|
});
|
|
3221
4116
|
|
|
@@ -3239,6 +4134,7 @@ const StellarTestnet = defineChain({
|
|
|
3239
4134
|
rpcEndpoints: ['https://horizon-testnet.stellar.org'],
|
|
3240
4135
|
eurcAddress: 'EURC-GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO',
|
|
3241
4136
|
usdcAddress: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
4137
|
+
usdtAddress: null,
|
|
3242
4138
|
cctp: null,
|
|
3243
4139
|
});
|
|
3244
4140
|
|
|
@@ -3262,6 +4158,7 @@ const Sui = defineChain({
|
|
|
3262
4158
|
rpcEndpoints: ['https://fullnode.mainnet.sui.io'],
|
|
3263
4159
|
eurcAddress: null,
|
|
3264
4160
|
usdcAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
4161
|
+
usdtAddress: null,
|
|
3265
4162
|
cctp: {
|
|
3266
4163
|
domain: 8,
|
|
3267
4164
|
contracts: {
|
|
@@ -3299,6 +4196,7 @@ const SuiTestnet = defineChain({
|
|
|
3299
4196
|
rpcEndpoints: ['https://fullnode.testnet.sui.io'],
|
|
3300
4197
|
eurcAddress: null,
|
|
3301
4198
|
usdcAddress: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
4199
|
+
usdtAddress: null,
|
|
3302
4200
|
cctp: {
|
|
3303
4201
|
domain: 8,
|
|
3304
4202
|
contracts: {
|
|
@@ -3337,6 +4235,7 @@ const Unichain = defineChain({
|
|
|
3337
4235
|
rpcEndpoints: ['https://mainnet.unichain.org'],
|
|
3338
4236
|
eurcAddress: null,
|
|
3339
4237
|
usdcAddress: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
4238
|
+
usdtAddress: null,
|
|
3340
4239
|
cctp: {
|
|
3341
4240
|
domain: 10,
|
|
3342
4241
|
contracts: {
|
|
@@ -3361,6 +4260,7 @@ const Unichain = defineChain({
|
|
|
3361
4260
|
},
|
|
3362
4261
|
kitContracts: {
|
|
3363
4262
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
4263
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
3364
4264
|
},
|
|
3365
4265
|
});
|
|
3366
4266
|
|
|
@@ -3385,6 +4285,7 @@ const UnichainSepolia = defineChain({
|
|
|
3385
4285
|
rpcEndpoints: ['https://sepolia.unichain.org'],
|
|
3386
4286
|
eurcAddress: null,
|
|
3387
4287
|
usdcAddress: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
4288
|
+
usdtAddress: null,
|
|
3388
4289
|
cctp: {
|
|
3389
4290
|
domain: 10,
|
|
3390
4291
|
contracts: {
|
|
@@ -3433,6 +4334,7 @@ const WorldChain = defineChain({
|
|
|
3433
4334
|
rpcEndpoints: ['https://worldchain-mainnet.g.alchemy.com/public'],
|
|
3434
4335
|
eurcAddress: null,
|
|
3435
4336
|
usdcAddress: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
4337
|
+
usdtAddress: null,
|
|
3436
4338
|
cctp: {
|
|
3437
4339
|
domain: 14,
|
|
3438
4340
|
contracts: {
|
|
@@ -3451,6 +4353,7 @@ const WorldChain = defineChain({
|
|
|
3451
4353
|
},
|
|
3452
4354
|
kitContracts: {
|
|
3453
4355
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
4356
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
3454
4357
|
},
|
|
3455
4358
|
});
|
|
3456
4359
|
|
|
@@ -3478,6 +4381,7 @@ const WorldChainSepolia = defineChain({
|
|
|
3478
4381
|
],
|
|
3479
4382
|
eurcAddress: null,
|
|
3480
4383
|
usdcAddress: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
4384
|
+
usdtAddress: null,
|
|
3481
4385
|
cctp: {
|
|
3482
4386
|
domain: 14,
|
|
3483
4387
|
contracts: {
|
|
@@ -3522,6 +4426,7 @@ const XDC = defineChain({
|
|
|
3522
4426
|
rpcEndpoints: ['https://erpc.xdcrpc.com', 'https://erpc.xinfin.network'],
|
|
3523
4427
|
eurcAddress: null,
|
|
3524
4428
|
usdcAddress: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
4429
|
+
usdtAddress: null,
|
|
3525
4430
|
cctp: {
|
|
3526
4431
|
domain: 18,
|
|
3527
4432
|
contracts: {
|
|
@@ -3540,6 +4445,7 @@ const XDC = defineChain({
|
|
|
3540
4445
|
},
|
|
3541
4446
|
kitContracts: {
|
|
3542
4447
|
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
4448
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET,
|
|
3543
4449
|
},
|
|
3544
4450
|
});
|
|
3545
4451
|
|
|
@@ -3564,6 +4470,7 @@ const XDCApothem = defineChain({
|
|
|
3564
4470
|
rpcEndpoints: ['https://erpc.apothem.network'],
|
|
3565
4471
|
eurcAddress: null,
|
|
3566
4472
|
usdcAddress: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
4473
|
+
usdtAddress: null,
|
|
3567
4474
|
cctp: {
|
|
3568
4475
|
domain: 18,
|
|
3569
4476
|
contracts: {
|
|
@@ -3606,6 +4513,7 @@ const ZKSyncEra = defineChain({
|
|
|
3606
4513
|
rpcEndpoints: ['https://mainnet.era.zksync.io'],
|
|
3607
4514
|
eurcAddress: null,
|
|
3608
4515
|
usdcAddress: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
4516
|
+
usdtAddress: null,
|
|
3609
4517
|
cctp: null,
|
|
3610
4518
|
});
|
|
3611
4519
|
|
|
@@ -3630,6 +4538,7 @@ const ZKSyncEraSepolia = defineChain({
|
|
|
3630
4538
|
rpcEndpoints: ['https://sepolia.era.zksync.dev'],
|
|
3631
4539
|
eurcAddress: null,
|
|
3632
4540
|
usdcAddress: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
4541
|
+
usdtAddress: null,
|
|
3633
4542
|
cctp: null,
|
|
3634
4543
|
});
|
|
3635
4544
|
|
|
@@ -3650,6 +4559,8 @@ var Blockchains = {
|
|
|
3650
4559
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
3651
4560
|
Codex: Codex,
|
|
3652
4561
|
CodexTestnet: CodexTestnet,
|
|
4562
|
+
Edge: Edge,
|
|
4563
|
+
EdgeTestnet: EdgeTestnet,
|
|
3653
4564
|
Ethereum: Ethereum,
|
|
3654
4565
|
EthereumSepolia: EthereumSepolia,
|
|
3655
4566
|
Hedera: Hedera,
|
|
@@ -3662,6 +4573,8 @@ var Blockchains = {
|
|
|
3662
4573
|
LineaSepolia: LineaSepolia,
|
|
3663
4574
|
Monad: Monad,
|
|
3664
4575
|
MonadTestnet: MonadTestnet,
|
|
4576
|
+
Morph: Morph,
|
|
4577
|
+
MorphTestnet: MorphTestnet,
|
|
3665
4578
|
NEAR: NEAR,
|
|
3666
4579
|
NEARTestnet: NEARTestnet,
|
|
3667
4580
|
Noble: Noble,
|
|
@@ -3775,10 +4688,12 @@ const baseChainDefinitionSchema = zod.z.object({
|
|
|
3775
4688
|
rpcEndpoints: zod.z.array(zod.z.string()),
|
|
3776
4689
|
eurcAddress: zod.z.string().nullable(),
|
|
3777
4690
|
usdcAddress: zod.z.string().nullable(),
|
|
4691
|
+
usdtAddress: zod.z.string().nullable(),
|
|
3778
4692
|
cctp: zod.z.any().nullable(), // We'll accept any CCTP config structure
|
|
3779
4693
|
kitContracts: zod.z
|
|
3780
4694
|
.object({
|
|
3781
4695
|
bridge: zod.z.string().optional(),
|
|
4696
|
+
adapter: zod.z.string().optional(),
|
|
3782
4697
|
})
|
|
3783
4698
|
.optional(),
|
|
3784
4699
|
});
|
|
@@ -3893,6 +4808,29 @@ zod.z.union([
|
|
|
3893
4808
|
zod.z.nativeEnum(exports.Blockchain),
|
|
3894
4809
|
chainDefinitionSchema$1,
|
|
3895
4810
|
]);
|
|
4811
|
+
/**
|
|
4812
|
+
* Zod schema for validating swap-specific chain identifiers.
|
|
4813
|
+
*
|
|
4814
|
+
* Validates chains based on:
|
|
4815
|
+
* - CCTPv2 support (adapter contract deployed)
|
|
4816
|
+
* - Mainnet only (no testnets)
|
|
4817
|
+
* - At least one supported token available
|
|
4818
|
+
*
|
|
4819
|
+
*/
|
|
4820
|
+
zod.z.union([
|
|
4821
|
+
// String blockchain identifier (accepts SwapChain enum values)
|
|
4822
|
+
zod.z.string().refine((val) => val in SwapChain, (val) => ({
|
|
4823
|
+
message: `"${val}" is not a supported swap chain. ` +
|
|
4824
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
4825
|
+
})),
|
|
4826
|
+
// SwapChain enum
|
|
4827
|
+
zod.z.nativeEnum(SwapChain),
|
|
4828
|
+
// ChainDefinition object (checks if chain.chain is in SwapChain)
|
|
4829
|
+
chainDefinitionSchema$1.refine((chain) => chain.chain in SwapChain, (chain) => ({
|
|
4830
|
+
message: `"${chain.chain}" is not a supported swap chain. ` +
|
|
4831
|
+
`Supported chains: ${Object.values(SwapChain).join(', ')}`,
|
|
4832
|
+
})),
|
|
4833
|
+
]);
|
|
3896
4834
|
/**
|
|
3897
4835
|
* Zod schema for validating bridge chain identifiers.
|
|
3898
4836
|
*
|
|
@@ -3932,12 +4870,44 @@ zod.z.union([
|
|
|
3932
4870
|
})),
|
|
3933
4871
|
]);
|
|
3934
4872
|
|
|
4873
|
+
/**
|
|
4874
|
+
* @packageDocumentation
|
|
4875
|
+
* @module SwapTokenSchemas
|
|
4876
|
+
*
|
|
4877
|
+
* Zod validation schemas for supported swap tokens.
|
|
4878
|
+
*/
|
|
4879
|
+
// Internal enum used after input normalization.
|
|
4880
|
+
const swapTokenEnumSchema = zod.z.enum([
|
|
4881
|
+
...Object.keys(SWAP_TOKEN_REGISTRY),
|
|
4882
|
+
NATIVE_TOKEN,
|
|
4883
|
+
]);
|
|
4884
|
+
/**
|
|
4885
|
+
* Zod schema for validating supported swap token symbols.
|
|
4886
|
+
*
|
|
4887
|
+
* Accepts any token symbol from the SWAP_TOKEN_REGISTRY plus NATIVE.
|
|
4888
|
+
* Input matching is case-insensitive and normalized to uppercase.
|
|
4889
|
+
*
|
|
4890
|
+
* @example
|
|
4891
|
+
* ```typescript
|
|
4892
|
+
* import { supportedSwapTokenSchema } from '@core/chains'
|
|
4893
|
+
*
|
|
4894
|
+
* const result = supportedSwapTokenSchema.safeParse('USDC')
|
|
4895
|
+
* if (result.success) {
|
|
4896
|
+
* console.log('Valid swap token:', result.data)
|
|
4897
|
+
* }
|
|
4898
|
+
* ```
|
|
4899
|
+
*/
|
|
4900
|
+
zod.z
|
|
4901
|
+
.string()
|
|
4902
|
+
.transform((value) => value.toUpperCase())
|
|
4903
|
+
.pipe(swapTokenEnumSchema);
|
|
4904
|
+
|
|
3935
4905
|
/**
|
|
3936
4906
|
* Get all supported EVM chain definitions.
|
|
3937
4907
|
*
|
|
3938
4908
|
* This function searches through all available blockchain definitions and returns
|
|
3939
4909
|
* only those that are EVM-compatible. It provides a comprehensive list of all
|
|
3940
|
-
* EVM chains supported by the
|
|
4910
|
+
* EVM chains supported by the App Kits ecosystem.
|
|
3941
4911
|
*
|
|
3942
4912
|
* @returns Array of all EVM chain definitions supported by the library
|
|
3943
4913
|
*
|
|
@@ -4031,6 +5001,11 @@ const getChainByEnum = (blockchain) => {
|
|
|
4031
5001
|
* ```
|
|
4032
5002
|
*/
|
|
4033
5003
|
function resolveChainIdentifier(chainIdentifier) {
|
|
5004
|
+
// Handle null explicitly (typeof null === 'object' in JavaScript)
|
|
5005
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
5006
|
+
if (chainIdentifier === null) {
|
|
5007
|
+
throw new Error(`Invalid chain identifier type: null. Expected ChainDefinition object, Blockchain enum, or string literal.`);
|
|
5008
|
+
}
|
|
4034
5009
|
// If it's already a ChainDefinition object, return it unchanged
|
|
4035
5010
|
if (typeof chainIdentifier === 'object') {
|
|
4036
5011
|
return chainIdentifier;
|
|
@@ -4393,11 +5368,11 @@ async function resolveOperationContext(adapter, ctx) {
|
|
|
4393
5368
|
/**
|
|
4394
5369
|
* Abstract class defining the standard interface for an adapter that interacts with a specific blockchain.
|
|
4395
5370
|
*
|
|
4396
|
-
*
|
|
5371
|
+
* An `Adapter` is responsible for encapsulating chain-specific logic necessary to
|
|
4397
5372
|
* perform operations like sending transactions, querying balances, or interacting with smart contracts.
|
|
4398
5373
|
* Implementations of this class will provide concrete logic for a particular blockchain protocol.
|
|
4399
5374
|
*
|
|
4400
|
-
* This abstraction allows the
|
|
5375
|
+
* This abstraction allows the App Kit to work with multiple blockchains in a uniform way.
|
|
4401
5376
|
*
|
|
4402
5377
|
* @typeParam TAdapterCapabilities - The adapter capabilities type for compile-time address validation.
|
|
4403
5378
|
* When provided, enables strict typing of operation context based on the adapter's address control model.
|
|
@@ -4921,6 +5896,439 @@ const convertAddress = (address, targetFormat) => {
|
|
|
4921
5896
|
throw new Error(`Unsupported address format: ${address}`);
|
|
4922
5897
|
};
|
|
4923
5898
|
|
|
5899
|
+
/**
|
|
5900
|
+
* USDC token definition with addresses and metadata.
|
|
5901
|
+
*
|
|
5902
|
+
* @remarks
|
|
5903
|
+
* This is the built-in USDC definition used by the TokenRegistry.
|
|
5904
|
+
* Includes all known USDC addresses across supported chains.
|
|
5905
|
+
*
|
|
5906
|
+
* Keys use the `Blockchain` enum for type safety. Both enum values
|
|
5907
|
+
* and string literals are supported:
|
|
5908
|
+
* - `Blockchain.Ethereum` or `'Ethereum'`
|
|
5909
|
+
*
|
|
5910
|
+
* @example
|
|
5911
|
+
* ```typescript
|
|
5912
|
+
* import { USDC } from '@core/tokens'
|
|
5913
|
+
* import { Blockchain } from '@core/chains'
|
|
5914
|
+
*
|
|
5915
|
+
* console.log(USDC.symbol) // 'USDC'
|
|
5916
|
+
* console.log(USDC.decimals) // 6
|
|
5917
|
+
* console.log(USDC.locators[Blockchain.Ethereum])
|
|
5918
|
+
* // '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
|
5919
|
+
* ```
|
|
5920
|
+
*/
|
|
5921
|
+
const USDC = {
|
|
5922
|
+
symbol: 'USDC',
|
|
5923
|
+
decimals: 6,
|
|
5924
|
+
locators: {
|
|
5925
|
+
// =========================================================================
|
|
5926
|
+
// Mainnets (alphabetically sorted)
|
|
5927
|
+
// =========================================================================
|
|
5928
|
+
[exports.Blockchain.Arbitrum]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
5929
|
+
[exports.Blockchain.Avalanche]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
|
|
5930
|
+
[exports.Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
5931
|
+
[exports.Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
5932
|
+
[exports.Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
5933
|
+
[exports.Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
5934
|
+
[exports.Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
5935
|
+
[exports.Blockchain.Hedera]: '0.0.456858',
|
|
5936
|
+
[exports.Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
5937
|
+
[exports.Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
5938
|
+
[exports.Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
5939
|
+
[exports.Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
5940
|
+
[exports.Blockchain.Morph]: '0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B',
|
|
5941
|
+
[exports.Blockchain.NEAR]: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
5942
|
+
[exports.Blockchain.Noble]: 'uusdc',
|
|
5943
|
+
[exports.Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
|
|
5944
|
+
[exports.Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
|
|
5945
|
+
[exports.Blockchain.Polkadot_Asset_Hub]: '1337',
|
|
5946
|
+
[exports.Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
|
|
5947
|
+
[exports.Blockchain.Sei]: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392',
|
|
5948
|
+
[exports.Blockchain.Solana]: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
5949
|
+
[exports.Blockchain.Sonic]: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894',
|
|
5950
|
+
[exports.Blockchain.Stellar]: 'USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
|
|
5951
|
+
[exports.Blockchain.Sui]: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC',
|
|
5952
|
+
[exports.Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
5953
|
+
[exports.Blockchain.World_Chain]: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
5954
|
+
[exports.Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
5955
|
+
[exports.Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
5956
|
+
// =========================================================================
|
|
5957
|
+
// Testnets (alphabetically sorted)
|
|
5958
|
+
// =========================================================================
|
|
5959
|
+
[exports.Blockchain.Arbitrum_Sepolia]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
|
|
5960
|
+
[exports.Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
5961
|
+
[exports.Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
5962
|
+
[exports.Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
5963
|
+
[exports.Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
5964
|
+
[exports.Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
5965
|
+
[exports.Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
5966
|
+
[exports.Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
5967
|
+
[exports.Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
5968
|
+
[exports.Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
5969
|
+
[exports.Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
5970
|
+
[exports.Blockchain.Morph_Testnet]: '0x7433b41C6c5e1d58D4Da99483609520255ab661B',
|
|
5971
|
+
[exports.Blockchain.NEAR_Testnet]: '3e2210e1184b45b64c8a434c0a7e7b23cc04ea7eb7a6c3c32520d03d4afcb8af',
|
|
5972
|
+
[exports.Blockchain.Noble_Testnet]: 'uusdc',
|
|
5973
|
+
[exports.Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
|
|
5974
|
+
[exports.Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
|
|
5975
|
+
[exports.Blockchain.Polkadot_Westmint]: '31337',
|
|
5976
|
+
[exports.Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
5977
|
+
[exports.Blockchain.Sei_Testnet]: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED',
|
|
5978
|
+
[exports.Blockchain.Solana_Devnet]: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
|
|
5979
|
+
[exports.Blockchain.Sonic_Testnet]: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51',
|
|
5980
|
+
[exports.Blockchain.Stellar_Testnet]: 'USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
|
|
5981
|
+
[exports.Blockchain.Sui_Testnet]: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC',
|
|
5982
|
+
[exports.Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
5983
|
+
[exports.Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
5984
|
+
[exports.Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
5985
|
+
[exports.Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853',
|
|
5986
|
+
},
|
|
5987
|
+
};
|
|
5988
|
+
|
|
5989
|
+
/**
|
|
5990
|
+
* USDT (Tether) token definition with addresses and metadata.
|
|
5991
|
+
*
|
|
5992
|
+
* @remarks
|
|
5993
|
+
* Built-in USDT definition for the TokenRegistry. Includes chain locators
|
|
5994
|
+
* for swap-supported chains.
|
|
5995
|
+
*/
|
|
5996
|
+
const USDT = {
|
|
5997
|
+
symbol: 'USDT',
|
|
5998
|
+
decimals: 6,
|
|
5999
|
+
locators: {
|
|
6000
|
+
[exports.Blockchain.Aptos]: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b',
|
|
6001
|
+
[exports.Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
|
|
6002
|
+
[exports.Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
|
|
6003
|
+
[exports.Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
6004
|
+
[exports.Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
|
6005
|
+
[exports.Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
|
|
6006
|
+
[exports.Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
|
|
6007
|
+
[exports.Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
|
|
6008
|
+
[exports.Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
|
|
6009
|
+
[exports.Blockchain.NEAR]: 'usdt.tether-token.near',
|
|
6010
|
+
[exports.Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
|
|
6011
|
+
[exports.Blockchain.Polkadot_Asset_Hub]: '1984',
|
|
6012
|
+
[exports.Blockchain.Polygon]: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
|
6013
|
+
[exports.Blockchain.Sei]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
6014
|
+
[exports.Blockchain.Solana]: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
6015
|
+
[exports.Blockchain.Unichain]: '0x9151434b16b9763660705744891fA906F660EcC5',
|
|
6016
|
+
},
|
|
6017
|
+
};
|
|
6018
|
+
|
|
6019
|
+
/**
|
|
6020
|
+
* EURC (Euro Coin) token definition with addresses and metadata.
|
|
6021
|
+
*
|
|
6022
|
+
* @remarks
|
|
6023
|
+
* Built-in EURC definition for the TokenRegistry. Includes chain locators
|
|
6024
|
+
* for swap-supported chains.
|
|
6025
|
+
*/
|
|
6026
|
+
const EURC = {
|
|
6027
|
+
symbol: 'EURC',
|
|
6028
|
+
decimals: 6,
|
|
6029
|
+
locators: {
|
|
6030
|
+
[exports.Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
6031
|
+
[exports.Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
6032
|
+
[exports.Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
6033
|
+
[exports.Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
6034
|
+
[exports.Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
6035
|
+
},
|
|
6036
|
+
};
|
|
6037
|
+
|
|
6038
|
+
/**
|
|
6039
|
+
* DAI (Maker DAO) stablecoin token definition with addresses and metadata.
|
|
6040
|
+
*
|
|
6041
|
+
* @remarks
|
|
6042
|
+
* Built-in DAI definition for the TokenRegistry. Includes chain locators
|
|
6043
|
+
* for swap-supported chains.
|
|
6044
|
+
*/
|
|
6045
|
+
const DAI = {
|
|
6046
|
+
symbol: 'DAI',
|
|
6047
|
+
decimals: 18,
|
|
6048
|
+
chainDecimals: {
|
|
6049
|
+
[exports.Blockchain.Solana]: 8,
|
|
6050
|
+
},
|
|
6051
|
+
locators: {
|
|
6052
|
+
[exports.Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
6053
|
+
[exports.Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
|
|
6054
|
+
[exports.Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
|
|
6055
|
+
[exports.Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
6056
|
+
[exports.Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
|
|
6057
|
+
[exports.Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
6058
|
+
[exports.Blockchain.Polygon]: '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063',
|
|
6059
|
+
[exports.Blockchain.Solana]: 'EjmyN6qEC1Tf1JxiG1ae7UTJhUxSwk1TCWNWqxWV4J6o',
|
|
6060
|
+
},
|
|
6061
|
+
};
|
|
6062
|
+
|
|
6063
|
+
/**
|
|
6064
|
+
* USDe (Ethena) synthetic dollar token definition with addresses and metadata.
|
|
6065
|
+
*
|
|
6066
|
+
* @remarks
|
|
6067
|
+
* Built-in USDE definition for the TokenRegistry. Includes chain locators
|
|
6068
|
+
* for swap-supported chains.
|
|
6069
|
+
*/
|
|
6070
|
+
const USDE = {
|
|
6071
|
+
symbol: 'USDe',
|
|
6072
|
+
decimals: 18,
|
|
6073
|
+
chainDecimals: {
|
|
6074
|
+
[exports.Blockchain.Solana]: 9,
|
|
6075
|
+
},
|
|
6076
|
+
locators: {
|
|
6077
|
+
[exports.Blockchain.Arbitrum]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
6078
|
+
[exports.Blockchain.Base]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
6079
|
+
[exports.Blockchain.Ethereum]: '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3',
|
|
6080
|
+
[exports.Blockchain.Linea]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
6081
|
+
[exports.Blockchain.Optimism]: '0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34',
|
|
6082
|
+
[exports.Blockchain.Solana]: 'DEkqHyPN7GMRJ5cArtQFAWefqbZb33Hyf6s5iCwjEonT',
|
|
6083
|
+
},
|
|
6084
|
+
};
|
|
6085
|
+
|
|
6086
|
+
/**
|
|
6087
|
+
* PYUSD (PayPal USD) stablecoin token definition with addresses and metadata.
|
|
6088
|
+
*
|
|
6089
|
+
* @remarks
|
|
6090
|
+
* Built-in PYUSD definition for the TokenRegistry. Includes chain locators
|
|
6091
|
+
* for swap-supported chains.
|
|
6092
|
+
*/
|
|
6093
|
+
const PYUSD = {
|
|
6094
|
+
symbol: 'PYUSD',
|
|
6095
|
+
decimals: 6,
|
|
6096
|
+
locators: {
|
|
6097
|
+
[exports.Blockchain.Arbitrum]: '0x46850aD61C2B7d64d08c9C754F45254596696984',
|
|
6098
|
+
[exports.Blockchain.Ethereum]: '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8',
|
|
6099
|
+
[exports.Blockchain.Solana]: '2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo',
|
|
6100
|
+
},
|
|
6101
|
+
};
|
|
6102
|
+
|
|
6103
|
+
/**
|
|
6104
|
+
* WETH (Wrapped Ether) token definition with addresses and metadata.
|
|
6105
|
+
*
|
|
6106
|
+
* @remarks
|
|
6107
|
+
* Built-in WETH definition for the TokenRegistry. Includes chain locators
|
|
6108
|
+
* for swap-supported chains where WETH is available.
|
|
6109
|
+
*/
|
|
6110
|
+
const WETH = {
|
|
6111
|
+
symbol: 'WETH',
|
|
6112
|
+
decimals: 18,
|
|
6113
|
+
chainDecimals: {
|
|
6114
|
+
[exports.Blockchain.Solana]: 9,
|
|
6115
|
+
},
|
|
6116
|
+
locators: {
|
|
6117
|
+
[exports.Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
|
|
6118
|
+
[exports.Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
|
|
6119
|
+
[exports.Blockchain.Base]: '0x4200000000000000000000000000000000000006',
|
|
6120
|
+
[exports.Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
6121
|
+
[exports.Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
|
|
6122
|
+
[exports.Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
|
|
6123
|
+
[exports.Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs',
|
|
6124
|
+
},
|
|
6125
|
+
};
|
|
6126
|
+
|
|
6127
|
+
/**
|
|
6128
|
+
* WBTC (Wrapped Bitcoin) token definition with addresses and metadata.
|
|
6129
|
+
*
|
|
6130
|
+
* @remarks
|
|
6131
|
+
* Built-in WBTC definition for the TokenRegistry. Includes chain locators
|
|
6132
|
+
* for swap-supported chains where WBTC is available.
|
|
6133
|
+
*/
|
|
6134
|
+
const WBTC = {
|
|
6135
|
+
symbol: 'WBTC',
|
|
6136
|
+
decimals: 8,
|
|
6137
|
+
locators: {
|
|
6138
|
+
[exports.Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
|
|
6139
|
+
[exports.Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
|
|
6140
|
+
[exports.Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218',
|
|
6141
|
+
},
|
|
6142
|
+
};
|
|
6143
|
+
|
|
6144
|
+
/**
|
|
6145
|
+
* WSOL (Wrapped SOL) token definition with addresses and metadata.
|
|
6146
|
+
*
|
|
6147
|
+
* @remarks
|
|
6148
|
+
* Built-in WSOL definition for the TokenRegistry. Includes chain locators
|
|
6149
|
+
* for swap-supported chains where WSOL is available.
|
|
6150
|
+
*/
|
|
6151
|
+
const WSOL = {
|
|
6152
|
+
symbol: 'WSOL',
|
|
6153
|
+
decimals: 9,
|
|
6154
|
+
locators: {
|
|
6155
|
+
[exports.Blockchain.Solana]: 'So11111111111111111111111111111111111111112',
|
|
6156
|
+
},
|
|
6157
|
+
};
|
|
6158
|
+
|
|
6159
|
+
/**
|
|
6160
|
+
* WAVAX (Wrapped AVAX) token definition with addresses and metadata.
|
|
6161
|
+
*
|
|
6162
|
+
* @remarks
|
|
6163
|
+
* Built-in WAVAX definition for the TokenRegistry. Includes chain locators
|
|
6164
|
+
* for swap-supported chains where WAVAX is available.
|
|
6165
|
+
*/
|
|
6166
|
+
const WAVAX = {
|
|
6167
|
+
symbol: 'WAVAX',
|
|
6168
|
+
decimals: 18,
|
|
6169
|
+
locators: {
|
|
6170
|
+
[exports.Blockchain.Avalanche]: '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7',
|
|
6171
|
+
},
|
|
6172
|
+
};
|
|
6173
|
+
|
|
6174
|
+
/**
|
|
6175
|
+
* WPOL (Wrapped POL) token definition with addresses and metadata.
|
|
6176
|
+
*
|
|
6177
|
+
* @remarks
|
|
6178
|
+
* Built-in WPOL definition for the TokenRegistry. Includes chain locators
|
|
6179
|
+
* for swap-supported chains where WPOL is available.
|
|
6180
|
+
*/
|
|
6181
|
+
const WPOL = {
|
|
6182
|
+
symbol: 'WPOL',
|
|
6183
|
+
decimals: 18,
|
|
6184
|
+
locators: {
|
|
6185
|
+
[exports.Blockchain.Polygon]: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
|
|
6186
|
+
},
|
|
6187
|
+
};
|
|
6188
|
+
|
|
6189
|
+
/**
|
|
6190
|
+
* ETH (native Ether alias) token definition with metadata.
|
|
6191
|
+
*
|
|
6192
|
+
* @remarks
|
|
6193
|
+
* Built-in ETH definition for the TokenRegistry. Used as a symbol alias
|
|
6194
|
+
* for native ETH (e.g. in swap flows). Chain locators are TBD and will
|
|
6195
|
+
* be added when addresses are available. Use raw selector with
|
|
6196
|
+
* locator + decimals where native gas token is represented as a contract.
|
|
6197
|
+
*/
|
|
6198
|
+
const ETH = {
|
|
6199
|
+
symbol: 'ETH',
|
|
6200
|
+
decimals: 18,
|
|
6201
|
+
locators: {},
|
|
6202
|
+
};
|
|
6203
|
+
|
|
6204
|
+
/**
|
|
6205
|
+
* POL (Polygon native token) token definition with addresses and metadata.
|
|
6206
|
+
*
|
|
6207
|
+
* @remarks
|
|
6208
|
+
* Built-in POL definition for the TokenRegistry. Includes chain locators
|
|
6209
|
+
* where POL is available as a bridged/wrapped asset.
|
|
6210
|
+
*/
|
|
6211
|
+
const POL = {
|
|
6212
|
+
symbol: 'POL',
|
|
6213
|
+
decimals: 18,
|
|
6214
|
+
locators: {
|
|
6215
|
+
[exports.Blockchain.Ethereum]: '0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6',
|
|
6216
|
+
},
|
|
6217
|
+
};
|
|
6218
|
+
|
|
6219
|
+
/**
|
|
6220
|
+
* PLUME (Plume network token) token definition with addresses and metadata.
|
|
6221
|
+
*
|
|
6222
|
+
* @remarks
|
|
6223
|
+
* Built-in PLUME definition for the TokenRegistry. Includes chain locators
|
|
6224
|
+
* where PLUME is available.
|
|
6225
|
+
*/
|
|
6226
|
+
const PLUME = {
|
|
6227
|
+
symbol: 'PLUME',
|
|
6228
|
+
decimals: 18,
|
|
6229
|
+
locators: {
|
|
6230
|
+
[exports.Blockchain.Ethereum]: '0x4C1746A800D224393fE2470C70A35717eD4eA5F1',
|
|
6231
|
+
},
|
|
6232
|
+
};
|
|
6233
|
+
|
|
6234
|
+
/**
|
|
6235
|
+
* MON token definition with Solana mint metadata.
|
|
6236
|
+
*
|
|
6237
|
+
* @remarks
|
|
6238
|
+
* Built-in MON definition for the TokenRegistry. Includes chain locators
|
|
6239
|
+
* for swap-supported chains.
|
|
6240
|
+
*/
|
|
6241
|
+
const MON = {
|
|
6242
|
+
symbol: 'MON',
|
|
6243
|
+
decimals: 18,
|
|
6244
|
+
chainDecimals: {
|
|
6245
|
+
[exports.Blockchain.Solana]: 8,
|
|
6246
|
+
},
|
|
6247
|
+
locators: {
|
|
6248
|
+
[exports.Blockchain.Solana]: 'CrAr4RRJMBVwRsZtT62pEhfA9H5utymC2mVx8e7FreP2',
|
|
6249
|
+
},
|
|
6250
|
+
};
|
|
6251
|
+
|
|
6252
|
+
// Re-export for consumers
|
|
6253
|
+
/**
|
|
6254
|
+
* All default token definitions.
|
|
6255
|
+
*
|
|
6256
|
+
* @remarks
|
|
6257
|
+
* These tokens are automatically included in the TokenRegistry when created
|
|
6258
|
+
* without explicit defaults. Extensions can override these definitions.
|
|
6259
|
+
* Includes USDC, USDT, EURC, DAI, USDE, PYUSD, WETH, WBTC, WSOL, WAVAX,
|
|
6260
|
+
* WPOL, ETH, POL, PLUME, and MON.
|
|
6261
|
+
*
|
|
6262
|
+
* @example
|
|
6263
|
+
* ```typescript
|
|
6264
|
+
* import { createTokenRegistry } from '@core/tokens'
|
|
6265
|
+
*
|
|
6266
|
+
* // Registry uses these by default
|
|
6267
|
+
* const registry = createTokenRegistry()
|
|
6268
|
+
*
|
|
6269
|
+
* // Add custom tokens (built-ins are still included)
|
|
6270
|
+
* const customRegistry = createTokenRegistry({
|
|
6271
|
+
* tokens: [myCustomToken],
|
|
6272
|
+
* })
|
|
6273
|
+
* ```
|
|
6274
|
+
*/
|
|
6275
|
+
const DEFAULT_TOKENS = [
|
|
6276
|
+
USDC,
|
|
6277
|
+
USDT,
|
|
6278
|
+
EURC,
|
|
6279
|
+
DAI,
|
|
6280
|
+
USDE,
|
|
6281
|
+
PYUSD,
|
|
6282
|
+
WETH,
|
|
6283
|
+
WBTC,
|
|
6284
|
+
WSOL,
|
|
6285
|
+
WAVAX,
|
|
6286
|
+
WPOL,
|
|
6287
|
+
ETH,
|
|
6288
|
+
POL,
|
|
6289
|
+
PLUME,
|
|
6290
|
+
MON,
|
|
6291
|
+
];
|
|
6292
|
+
/**
|
|
6293
|
+
* Uppercased token symbols approved for swap fee collection.
|
|
6294
|
+
*
|
|
6295
|
+
* @remarks
|
|
6296
|
+
* Derived from {@link DEFAULT_TOKENS} so all consumers share a single
|
|
6297
|
+
* allowlist source and stay in sync when defaults change.
|
|
6298
|
+
*/
|
|
6299
|
+
new Set(DEFAULT_TOKENS.map((t) => t.symbol.toUpperCase()));
|
|
6300
|
+
|
|
6301
|
+
/**
|
|
6302
|
+
* Define a schema for token registry interfaces.
|
|
6303
|
+
*
|
|
6304
|
+
* @remarks
|
|
6305
|
+
* Validate that a registry exposes the `resolve()` API used by adapters.
|
|
6306
|
+
*
|
|
6307
|
+
* @example
|
|
6308
|
+
* ```typescript
|
|
6309
|
+
* import { tokenRegistrySchema } from '@core/tokens'
|
|
6310
|
+
*
|
|
6311
|
+
* const registry = {
|
|
6312
|
+
* resolve: () => ({ locator: '0x0', decimals: 6 }),
|
|
6313
|
+
* }
|
|
6314
|
+
*
|
|
6315
|
+
* tokenRegistrySchema.parse(registry)
|
|
6316
|
+
* ```
|
|
6317
|
+
*/
|
|
6318
|
+
zod.z.custom((value) => {
|
|
6319
|
+
if (value === null || typeof value !== 'object') {
|
|
6320
|
+
return false;
|
|
6321
|
+
}
|
|
6322
|
+
const record = value;
|
|
6323
|
+
return (typeof record['resolve'] === 'function' &&
|
|
6324
|
+
typeof record['get'] === 'function' &&
|
|
6325
|
+
typeof record['has'] === 'function' &&
|
|
6326
|
+
typeof record['symbols'] === 'function' &&
|
|
6327
|
+
typeof record['entries'] === 'function');
|
|
6328
|
+
}, {
|
|
6329
|
+
message: 'Invalid token registry',
|
|
6330
|
+
});
|
|
6331
|
+
|
|
4924
6332
|
/**
|
|
4925
6333
|
* Schema for validating hexadecimal strings with '0x' prefix.
|
|
4926
6334
|
*
|
|
@@ -5108,9 +6516,27 @@ const adapterSchema = zod.z.object({
|
|
|
5108
6516
|
* console.log('EVM address is valid')
|
|
5109
6517
|
* ```
|
|
5110
6518
|
*/
|
|
5111
|
-
function assertEvmAddress(address) {
|
|
5112
|
-
validateOrThrow(address, evmAddressSchema, 'Invalid EVM address');
|
|
5113
|
-
}
|
|
6519
|
+
function assertEvmAddress(address) {
|
|
6520
|
+
validateOrThrow(address, evmAddressSchema, 'Invalid EVM address');
|
|
6521
|
+
}
|
|
6522
|
+
|
|
6523
|
+
/**
|
|
6524
|
+
* Permit signature standards for gasless token approvals.
|
|
6525
|
+
*
|
|
6526
|
+
* Defines the permit types that can be used to approve token spending
|
|
6527
|
+
* without requiring a separate approval transaction.
|
|
6528
|
+
*
|
|
6529
|
+
* @remarks
|
|
6530
|
+
* - NONE: No permit, tokens must be pre-approved via separate transaction
|
|
6531
|
+
* - EIP2612: Standard ERC-20 permit (USDC, DAI v2, and most modern tokens)
|
|
6532
|
+
*/
|
|
6533
|
+
var PermitType;
|
|
6534
|
+
(function (PermitType) {
|
|
6535
|
+
/** No permit required - tokens must be pre-approved */
|
|
6536
|
+
PermitType[PermitType["NONE"] = 0] = "NONE";
|
|
6537
|
+
/** EIP-2612 standard permit */
|
|
6538
|
+
PermitType[PermitType["EIP2612"] = 1] = "EIP2612";
|
|
6539
|
+
})(PermitType || (PermitType = {}));
|
|
5114
6540
|
|
|
5115
6541
|
/**
|
|
5116
6542
|
* Creates a no-op prepared chain request.
|
|
@@ -5219,6 +6645,12 @@ function getSupportedChains(ecosystem) {
|
|
|
5219
6645
|
*
|
|
5220
6646
|
* This ABI is used to interact with generic ERC20 tokens on EVM networks.
|
|
5221
6647
|
*
|
|
6648
|
+
* @remarks
|
|
6649
|
+
* The `approve`, `transfer` and `transferFrom` functions have been modified to not expect a return value
|
|
6650
|
+
* (empty `outputs` array) to support non-standard implementations like USDT
|
|
6651
|
+
* that return `void` instead of `bool`. This is safe because the SDK never
|
|
6652
|
+
* uses the return value from these functions - only the transaction hash matters.
|
|
6653
|
+
*
|
|
5222
6654
|
* @see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
|
|
5223
6655
|
*/
|
|
5224
6656
|
const erc20Abi = [
|
|
@@ -5249,12 +6681,7 @@ const erc20Abi = [
|
|
|
5249
6681
|
},
|
|
5250
6682
|
],
|
|
5251
6683
|
name: 'approve',
|
|
5252
|
-
outputs: [
|
|
5253
|
-
{
|
|
5254
|
-
name: '',
|
|
5255
|
-
type: 'bool',
|
|
5256
|
-
},
|
|
5257
|
-
],
|
|
6684
|
+
outputs: [],
|
|
5258
6685
|
payable: false,
|
|
5259
6686
|
stateMutability: 'nonpayable',
|
|
5260
6687
|
type: 'function',
|
|
@@ -5290,12 +6717,7 @@ const erc20Abi = [
|
|
|
5290
6717
|
},
|
|
5291
6718
|
],
|
|
5292
6719
|
name: 'transferFrom',
|
|
5293
|
-
outputs: [
|
|
5294
|
-
{
|
|
5295
|
-
name: '',
|
|
5296
|
-
type: 'bool',
|
|
5297
|
-
},
|
|
5298
|
-
],
|
|
6720
|
+
outputs: [],
|
|
5299
6721
|
payable: false,
|
|
5300
6722
|
stateMutability: 'nonpayable',
|
|
5301
6723
|
type: 'function',
|
|
@@ -5360,12 +6782,7 @@ const erc20Abi = [
|
|
|
5360
6782
|
},
|
|
5361
6783
|
],
|
|
5362
6784
|
name: 'transfer',
|
|
5363
|
-
outputs: [
|
|
5364
|
-
{
|
|
5365
|
-
name: '',
|
|
5366
|
-
type: 'bool',
|
|
5367
|
-
},
|
|
5368
|
-
],
|
|
6785
|
+
outputs: [],
|
|
5369
6786
|
payable: false,
|
|
5370
6787
|
stateMutability: 'nonpayable',
|
|
5371
6788
|
type: 'function',
|
|
@@ -8588,6 +10005,78 @@ const bridgeContractAbi = [
|
|
|
8588
10005
|
},
|
|
8589
10006
|
];
|
|
8590
10007
|
|
|
10008
|
+
/**
|
|
10009
|
+
* Adapter Contract ABI
|
|
10010
|
+
*
|
|
10011
|
+
* This ABI is used to interact with the Adapter smart contract that handles
|
|
10012
|
+
* gasless token approvals via permits and atomic swap execution.
|
|
10013
|
+
*
|
|
10014
|
+
* The execute() function is the primary entry point for swap operations.
|
|
10015
|
+
*/
|
|
10016
|
+
const adapterContractAbi = [
|
|
10017
|
+
{
|
|
10018
|
+
type: 'function',
|
|
10019
|
+
name: 'execute',
|
|
10020
|
+
inputs: [
|
|
10021
|
+
{
|
|
10022
|
+
name: 'params',
|
|
10023
|
+
type: 'tuple',
|
|
10024
|
+
internalType: 'struct IAdapter.ExecutionParams',
|
|
10025
|
+
components: [
|
|
10026
|
+
{
|
|
10027
|
+
name: 'instructions',
|
|
10028
|
+
type: 'tuple[]',
|
|
10029
|
+
internalType: 'struct IAdapter.Instruction[]',
|
|
10030
|
+
components: [
|
|
10031
|
+
{ name: 'target', type: 'address', internalType: 'address' },
|
|
10032
|
+
{ name: 'data', type: 'bytes', internalType: 'bytes' },
|
|
10033
|
+
{ name: 'value', type: 'uint256', internalType: 'uint256' },
|
|
10034
|
+
{ name: 'tokenIn', type: 'address', internalType: 'address' },
|
|
10035
|
+
{
|
|
10036
|
+
name: 'amountToApprove',
|
|
10037
|
+
type: 'uint256',
|
|
10038
|
+
internalType: 'uint256',
|
|
10039
|
+
},
|
|
10040
|
+
{ name: 'tokenOut', type: 'address', internalType: 'address' },
|
|
10041
|
+
{ name: 'minTokenOut', type: 'uint256', internalType: 'uint256' },
|
|
10042
|
+
],
|
|
10043
|
+
},
|
|
10044
|
+
{
|
|
10045
|
+
name: 'tokens',
|
|
10046
|
+
type: 'tuple[]',
|
|
10047
|
+
internalType: 'struct IAdapter.TokenRecipient[]',
|
|
10048
|
+
components: [
|
|
10049
|
+
{ name: 'token', type: 'address', internalType: 'address' },
|
|
10050
|
+
{ name: 'beneficiary', type: 'address', internalType: 'address' },
|
|
10051
|
+
],
|
|
10052
|
+
},
|
|
10053
|
+
{ name: 'execId', type: 'uint256', internalType: 'uint256' },
|
|
10054
|
+
{ name: 'deadline', type: 'uint256', internalType: 'uint256' },
|
|
10055
|
+
{ name: 'metadata', type: 'bytes', internalType: 'bytes' },
|
|
10056
|
+
],
|
|
10057
|
+
},
|
|
10058
|
+
{
|
|
10059
|
+
name: 'tokenInputs',
|
|
10060
|
+
type: 'tuple[]',
|
|
10061
|
+
internalType: 'struct IAdapter.TokenInput[]',
|
|
10062
|
+
components: [
|
|
10063
|
+
{
|
|
10064
|
+
name: 'permitType',
|
|
10065
|
+
type: 'uint8',
|
|
10066
|
+
internalType: 'enum IAdapter.PermitType',
|
|
10067
|
+
},
|
|
10068
|
+
{ name: 'token', type: 'address', internalType: 'address' },
|
|
10069
|
+
{ name: 'amount', type: 'uint256', internalType: 'uint256' },
|
|
10070
|
+
{ name: 'permitCalldata', type: 'bytes', internalType: 'bytes' },
|
|
10071
|
+
],
|
|
10072
|
+
},
|
|
10073
|
+
{ name: 'signature', type: 'bytes', internalType: 'bytes' },
|
|
10074
|
+
],
|
|
10075
|
+
outputs: [],
|
|
10076
|
+
stateMutability: 'payable',
|
|
10077
|
+
},
|
|
10078
|
+
];
|
|
10079
|
+
|
|
8591
10080
|
/**
|
|
8592
10081
|
* Core type definitions for EVM-compatible blockchain transaction execution
|
|
8593
10082
|
* and gas estimation.
|
|
@@ -8597,6 +10086,66 @@ const bridgeContractAbi = [
|
|
|
8597
10086
|
*
|
|
8598
10087
|
* @module constants
|
|
8599
10088
|
*/
|
|
10089
|
+
/**
|
|
10090
|
+
* The zero address constant for EVM chains.
|
|
10091
|
+
*
|
|
10092
|
+
* @remarks
|
|
10093
|
+
* This 20-byte address (`0x00...00`) is commonly used to represent:
|
|
10094
|
+
* - Disabled token approvals in instructions (tokenIn = ZERO_ADDRESS)
|
|
10095
|
+
* - Disabled balance validations (tokenOut = ZERO_ADDRESS)
|
|
10096
|
+
* - Null/unset address values
|
|
10097
|
+
*
|
|
10098
|
+
* **Note**: For native currency representation in adapter contract instructions,
|
|
10099
|
+
* use {@link NATIVE_TOKEN_ADDRESS} (`0xEeee...`) instead.
|
|
10100
|
+
*
|
|
10101
|
+
* @example
|
|
10102
|
+
* ```typescript
|
|
10103
|
+
* import { ZERO_ADDRESS } from '@core/adapter-evm'
|
|
10104
|
+
*
|
|
10105
|
+
* // Check if instruction has no token output (validation disabled)
|
|
10106
|
+
* if (instruction.tokenOut === ZERO_ADDRESS) {
|
|
10107
|
+
* // No output validation needed
|
|
10108
|
+
* }
|
|
10109
|
+
* ```
|
|
10110
|
+
*/
|
|
10111
|
+
/**
|
|
10112
|
+
* The native token address constant used by the Adapter Contract.
|
|
10113
|
+
*
|
|
10114
|
+
* @remarks
|
|
10115
|
+
* This address (`0xEeee...`) is the standard convention used by DEX aggregators
|
|
10116
|
+
* and the Adapter Contract to represent native currency (ETH, MATIC, AVAX, etc.)
|
|
10117
|
+
* in swap instructions.
|
|
10118
|
+
*
|
|
10119
|
+
* **Address Conventions in Adapter Contract:**
|
|
10120
|
+
* - Native Token: `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`
|
|
10121
|
+
* - No Token: `0x0000000000000000000000000000000000000000` (ZERO_ADDRESS)
|
|
10122
|
+
* - ERC20: Any other valid address
|
|
10123
|
+
*
|
|
10124
|
+
* **Native currency swaps:**
|
|
10125
|
+
* - When `tokenIn === NATIVE_TOKEN_ADDRESS`, value is sent via tx.value
|
|
10126
|
+
* - No approval or permit is required for native currency
|
|
10127
|
+
* - Used in instructions from stablecoin-service for ETH/MATIC/AVAX swaps
|
|
10128
|
+
*
|
|
10129
|
+
* @example
|
|
10130
|
+
* ```typescript
|
|
10131
|
+
* import { NATIVE_TOKEN_ADDRESS, ZERO_ADDRESS } from '@core/adapter-evm'
|
|
10132
|
+
*
|
|
10133
|
+
* // Check if token requires approval (exclude native and zero)
|
|
10134
|
+
* function requiresApproval(tokenAddress: string): boolean {
|
|
10135
|
+
* const normalized = tokenAddress.toLowerCase()
|
|
10136
|
+
* return normalized !== NATIVE_TOKEN_ADDRESS.toLowerCase() &&
|
|
10137
|
+
* normalized !== ZERO_ADDRESS.toLowerCase()
|
|
10138
|
+
* }
|
|
10139
|
+
*
|
|
10140
|
+
* // Example: ETH → USDC swap
|
|
10141
|
+
* const instruction = {
|
|
10142
|
+
* tokenIn: NATIVE_TOKEN_ADDRESS, // No approval needed
|
|
10143
|
+
* amount: 1000000000000000000n, // 1 ETH
|
|
10144
|
+
* value: 1000000000000000000n, // Sent via tx.value
|
|
10145
|
+
* }
|
|
10146
|
+
* ```
|
|
10147
|
+
*/
|
|
10148
|
+
const NATIVE_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
|
8600
10149
|
/**
|
|
8601
10150
|
* A constant representing the zero hash value.
|
|
8602
10151
|
*
|
|
@@ -9217,6 +10766,58 @@ const customBurnWithHook = async (params, adapter, context) => {
|
|
|
9217
10766
|
return prepareCustomBurn(params, adapter, context);
|
|
9218
10767
|
};
|
|
9219
10768
|
|
|
10769
|
+
/**
|
|
10770
|
+
* Prepare an EVM-compatible native token transfer transaction.
|
|
10771
|
+
*
|
|
10772
|
+
* Create a prepared chain request to move native tokens from the caller's wallet to a
|
|
10773
|
+
* recipient address on EVM chains.
|
|
10774
|
+
*
|
|
10775
|
+
* The function validates that the current chain is EVM-compatible, then builds a
|
|
10776
|
+
* transaction targeting the provided recipient address. The resulting prepared
|
|
10777
|
+
* request can be simulated or executed by the caller.
|
|
10778
|
+
*
|
|
10779
|
+
* @param params - The action payload for `native.transfer` containing:
|
|
10780
|
+
* - `to`: The recipient wallet address.
|
|
10781
|
+
* - `amount`: The native token amount (as a `bigint`).
|
|
10782
|
+
* - `chain`: The chain to transfer the native tokens on.
|
|
10783
|
+
* @param adapter - The EVM adapter responsible for chain context and transaction preparation.
|
|
10784
|
+
* @returns A promise that resolves to a prepared chain request for the `transfer` call.
|
|
10785
|
+
* @throws {KitError} If chain is not EVM (INPUT_INVALID_CHAIN) or amount is invalid (INPUT_INVALID_AMOUNT).
|
|
10786
|
+
*
|
|
10787
|
+
* @example
|
|
10788
|
+
* ```typescript
|
|
10789
|
+
* const prepared = await transfer(
|
|
10790
|
+
* {
|
|
10791
|
+
* to: '0x1111111111111111111111111111111111111111',
|
|
10792
|
+
* amount: 1_000_000n,
|
|
10793
|
+
* chain: 'Ethereum_Sepolia',
|
|
10794
|
+
* },
|
|
10795
|
+
* adapter
|
|
10796
|
+
* );
|
|
10797
|
+
* await prepared.execute();
|
|
10798
|
+
* ```
|
|
10799
|
+
*/
|
|
10800
|
+
const transfer$3 = async (params, adapter, context) => {
|
|
10801
|
+
const chain = context.chain;
|
|
10802
|
+
if (chain.type !== 'evm') {
|
|
10803
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain definition, but received chain type: ${chain.type}`);
|
|
10804
|
+
}
|
|
10805
|
+
const { to, amount } = params;
|
|
10806
|
+
// Validate the amount
|
|
10807
|
+
if (typeof amount !== 'bigint' || amount <= 0n) {
|
|
10808
|
+
throw createInvalidAmountError(String(amount), 'Transfer amount must be a positive bigint');
|
|
10809
|
+
}
|
|
10810
|
+
// Validate the to address
|
|
10811
|
+
assertEvmAddress(to);
|
|
10812
|
+
// Prepare the transfer transaction
|
|
10813
|
+
// Note: Type assertion needed - native transfers don't use contract ABI
|
|
10814
|
+
return adapter.prepare({
|
|
10815
|
+
type: 'evm',
|
|
10816
|
+
address: to,
|
|
10817
|
+
value: amount,
|
|
10818
|
+
}, context);
|
|
10819
|
+
};
|
|
10820
|
+
|
|
9220
10821
|
/**
|
|
9221
10822
|
* Prepares an EVM-compatible native token balance read (ETH, MATIC, etc.).
|
|
9222
10823
|
*
|
|
@@ -9271,6 +10872,159 @@ const balanceOf$2 = async (params, adapter, context) => {
|
|
|
9271
10872
|
};
|
|
9272
10873
|
};
|
|
9273
10874
|
|
|
10875
|
+
/**
|
|
10876
|
+
* Type guard to check if params is ExecuteSwapEVMParams.
|
|
10877
|
+
*
|
|
10878
|
+
* Uses property-based narrowing: EVM swap params have `executeParams`, `tokenInputs`,
|
|
10879
|
+
* `inputAmount`, and `tokenInAddress`, while Solana swap params have `serializedTransaction`.
|
|
10880
|
+
*
|
|
10881
|
+
* @remarks
|
|
10882
|
+
* Checks both property existence and that values are not undefined to provide
|
|
10883
|
+
* robust runtime validation against malformed inputs.
|
|
10884
|
+
*/
|
|
10885
|
+
const isEVMSwapParams = (params) => {
|
|
10886
|
+
return ('executeParams' in params &&
|
|
10887
|
+
params.executeParams !== undefined &&
|
|
10888
|
+
'tokenInputs' in params &&
|
|
10889
|
+
params.tokenInputs !== undefined &&
|
|
10890
|
+
'inputAmount' in params &&
|
|
10891
|
+
params.inputAmount !== undefined &&
|
|
10892
|
+
'tokenInAddress' in params &&
|
|
10893
|
+
params.tokenInAddress !== undefined);
|
|
10894
|
+
};
|
|
10895
|
+
/**
|
|
10896
|
+
* Executes a swap transaction via the Adapter smart contract.
|
|
10897
|
+
*
|
|
10898
|
+
* This action prepares swap transactions that execute through the Adapter
|
|
10899
|
+
* Contract, which handles gasless token approvals via permits (EIP-2612,
|
|
10900
|
+
* Permit2, etc.) and executes multi-step swap instructions atomically.
|
|
10901
|
+
*
|
|
10902
|
+
* @remarks
|
|
10903
|
+
* **Adapter Contract Pattern**
|
|
10904
|
+
*
|
|
10905
|
+
* The Adapter Contract pattern enables single-transaction swaps with gasless
|
|
10906
|
+
* approvals. The flow is:
|
|
10907
|
+
* 1. Service provides `executeParams` (swap instructions) and `signature` (proxy authorization)
|
|
10908
|
+
* 2. SDK builds `tokenInputs` with permit signatures for token approvals
|
|
10909
|
+
* 3. SDK calls AdapterContract.execute(executeParams, tokenInputs, signature)
|
|
10910
|
+
* 4. Adapter pulls tokens via permits, executes swaps, validates outputs, sweeps residuals
|
|
10911
|
+
*
|
|
10912
|
+
* **Permit Support**
|
|
10913
|
+
*
|
|
10914
|
+
* Token approvals are handled via permits encoded in `tokenInputs`. The SDK
|
|
10915
|
+
* constructs `TokenInput` objects with `permitCalldata` containing the encoded
|
|
10916
|
+
* permit signature. The Adapter Contract executes these permits on-chain before
|
|
10917
|
+
* executing swap instructions, enabling gasless approvals in a single atomic transaction.
|
|
10918
|
+
*
|
|
10919
|
+
* Supported permit types: EIP-2612, Permit2, DAI-like, EIP-3009
|
|
10920
|
+
*
|
|
10921
|
+
* **Service Integration**
|
|
10922
|
+
*
|
|
10923
|
+
* The `executeParams` and `signature` come from the stablecoin-service `createSwap`
|
|
10924
|
+
* endpoint. These are EIP-712 signed by Circle's proxy service and must be passed
|
|
10925
|
+
* to the Adapter Contract exactly as received (no modification).
|
|
10926
|
+
*
|
|
10927
|
+
* @param params - Swap execution parameters:
|
|
10928
|
+
* - `executeParams`: Execution parameters from service (instructions, tokens, execId, deadline)
|
|
10929
|
+
* - `tokenInputs`: Token inputs with permit signatures (built by provider)
|
|
10930
|
+
* - `signature`: EIP-712 signature from service (proxy authorization)
|
|
10931
|
+
* - `inputAmount`: User's swap input amount from service response (source of truth)
|
|
10932
|
+
* @param adapter - EVM adapter for transaction preparation
|
|
10933
|
+
* @param context - Resolved operation context with chain and address information
|
|
10934
|
+
* @returns Prepared chain request ready for estimation or execution
|
|
10935
|
+
*
|
|
10936
|
+
* @throws KitError If chain is not EVM-compatible (INPUT_INVALID_CHAIN)
|
|
10937
|
+
* @throws KitError If executeParams is missing or invalid (INPUT_VALIDATION_FAILED)
|
|
10938
|
+
* @throws KitError If signature is invalid (INPUT_VALIDATION_FAILED)
|
|
10939
|
+
* @throws KitError If tokenInputs is not an array (INPUT_VALIDATION_FAILED)
|
|
10940
|
+
*
|
|
10941
|
+
* @example
|
|
10942
|
+
* ```typescript
|
|
10943
|
+
* import { createSwap } from '@core/service-client'
|
|
10944
|
+
* import { PermitType } from '@core/adapter'
|
|
10945
|
+
* import type { EvmAdapter } from '@core/adapter-evm'
|
|
10946
|
+
*
|
|
10947
|
+
* // 1. Get swap transaction from stablecoin-service
|
|
10948
|
+
* const swapResponse = await createSwap({
|
|
10949
|
+
* tokenInAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
|
|
10950
|
+
* tokenOutAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec8', // USDT
|
|
10951
|
+
* tokenInChain: 'Ethereum',
|
|
10952
|
+
* fromAddress: await adapter.getAddress(),
|
|
10953
|
+
* toAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
|
|
10954
|
+
* amount: '1000000', // 1 USDC in base units
|
|
10955
|
+
* apiKey: process.env.API_KEY,
|
|
10956
|
+
* })
|
|
10957
|
+
*
|
|
10958
|
+
* // 2. Build token inputs with permit signature (provider responsibility)
|
|
10959
|
+
* const tokenInputs: TokenInput[] = [{
|
|
10960
|
+
* permitType: PermitType.EIP2612,
|
|
10961
|
+
* token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
10962
|
+
* from: await adapter.getAddress(Ethereum),
|
|
10963
|
+
* amount: 1000000n,
|
|
10964
|
+
* permitCalldata: '0x...' // Encoded permit signature from provider
|
|
10965
|
+
* }]
|
|
10966
|
+
*
|
|
10967
|
+
* // 3. Execute swap via adapter action
|
|
10968
|
+
* const swapRequest = await adapter.prepareAction(
|
|
10969
|
+
* 'swap.execute',
|
|
10970
|
+
* {
|
|
10971
|
+
* executeParams: swapResponse.transaction.executeParams,
|
|
10972
|
+
* tokenInputs,
|
|
10973
|
+
* signature: swapResponse.transaction.signature,
|
|
10974
|
+
* inputAmount: BigInt(swapResponse.amount) // From service response
|
|
10975
|
+
* },
|
|
10976
|
+
* context
|
|
10977
|
+
* )
|
|
10978
|
+
*
|
|
10979
|
+
* // 4. Estimate gas
|
|
10980
|
+
* const gasEstimate = await swapRequest.estimate()
|
|
10981
|
+
* console.log('Gas required:', gasEstimate.gas)
|
|
10982
|
+
*
|
|
10983
|
+
* // 5. Execute transaction
|
|
10984
|
+
* const txHash = await swapRequest.execute()
|
|
10985
|
+
* console.log('Swap transaction:', txHash)
|
|
10986
|
+
* ```
|
|
10987
|
+
*/
|
|
10988
|
+
const executeSwap = async (params, adapter, context) => {
|
|
10989
|
+
const { chain } = context;
|
|
10990
|
+
// Validate EVM chain first (this is an EVM-specific action)
|
|
10991
|
+
if (chain.type !== 'evm') {
|
|
10992
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain, but received chain type: ${String(chain.type)}`);
|
|
10993
|
+
}
|
|
10994
|
+
const adapterContractAddress = chain.kitContracts?.adapter;
|
|
10995
|
+
if (adapterContractAddress === undefined) {
|
|
10996
|
+
throw createInvalidChainError(chain.name, `Swap action is not supported on this chain: ${chain.name}`);
|
|
10997
|
+
}
|
|
10998
|
+
// Narrow type using property-based guard - this function only handles EVM swaps
|
|
10999
|
+
if (!isEVMSwapParams(params)) {
|
|
11000
|
+
throw createValidationFailedError('params', 'Invalid or incomplete EVM swap parameters', 'This action handler only supports EVM swap parameters (must have executeParams and tokenInputs)');
|
|
11001
|
+
}
|
|
11002
|
+
// Validate executeParams exists
|
|
11003
|
+
if (typeof params.executeParams !== 'object') {
|
|
11004
|
+
throw createValidationFailedError('executeParams', params.executeParams, 'ExecuteParams is required from service response');
|
|
11005
|
+
}
|
|
11006
|
+
// Validate signature
|
|
11007
|
+
if (params.signature === '0x') {
|
|
11008
|
+
throw createValidationFailedError('signature', params.signature, 'Signature is required from service response');
|
|
11009
|
+
}
|
|
11010
|
+
// Validate tokenInputs array (can be empty if no permits needed)
|
|
11011
|
+
if (!Array.isArray(params.tokenInputs)) {
|
|
11012
|
+
throw createValidationFailedError('tokenInputs', params.tokenInputs, 'TokenInputs must be an array');
|
|
11013
|
+
}
|
|
11014
|
+
// Check if swapping native currency (ETH, MATIC, etc.) vs ERC20 tokens
|
|
11015
|
+
const isNativeSwap = params.tokenInAddress.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase();
|
|
11016
|
+
// Prepare transaction to Adapter Contract
|
|
11017
|
+
return adapter.prepare({
|
|
11018
|
+
type: 'evm',
|
|
11019
|
+
abi: adapterContractAbi,
|
|
11020
|
+
address: adapterContractAddress,
|
|
11021
|
+
functionName: 'execute',
|
|
11022
|
+
args: [params.executeParams, params.tokenInputs, params.signature],
|
|
11023
|
+
// Include value only for native currency swaps (ETH → USDC, etc.)
|
|
11024
|
+
...(isNativeSwap && { value: params.inputAmount }),
|
|
11025
|
+
}, context);
|
|
11026
|
+
};
|
|
11027
|
+
|
|
9274
11028
|
/**
|
|
9275
11029
|
* Prepares an EVM-compatible `balanceOf` read for any ERC-20 token.
|
|
9276
11030
|
*
|
|
@@ -9319,66 +11073,228 @@ const balanceOf$1 = async (params, adapter, context) => {
|
|
|
9319
11073
|
args: [walletAddress],
|
|
9320
11074
|
}, context);
|
|
9321
11075
|
}
|
|
9322
|
-
catch (error) {
|
|
9323
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
9324
|
-
throw new Error(`Failed to get token balance for ${walletAddress} from ${tokenAddress}: ${errorMessage}`);
|
|
11076
|
+
catch (error) {
|
|
11077
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
11078
|
+
throw new Error(`Failed to get token balance for ${walletAddress} from ${tokenAddress}: ${errorMessage}`);
|
|
11079
|
+
}
|
|
11080
|
+
};
|
|
11081
|
+
|
|
11082
|
+
/**
|
|
11083
|
+
* Prepares an EVM-compatible `allowance` read for any ERC-20 token.
|
|
11084
|
+
*
|
|
11085
|
+
* This function creates a prepared chain request for reading the allowance of a given wallet (owner)
|
|
11086
|
+
* and delegate (spender) address for a specified ERC-20 token on an EVM-based chain. It validates the chain type
|
|
11087
|
+
* and all addresses, then constructs a read-only contract call using the canonical ERC-20 ABI and the provided token address.
|
|
11088
|
+
* The resulting prepared request can be executed or simulated by the caller.
|
|
11089
|
+
*
|
|
11090
|
+
* @param params - The action payload containing:
|
|
11091
|
+
* - `tokenAddress`: The contract address of the ERC-20 token.
|
|
11092
|
+
* - `walletAddress`: The address of the token owner (if not provided, will use the adapter's address).
|
|
11093
|
+
* - `delegate`: The address to check the allowance for (spender).
|
|
11094
|
+
* @param adapter - The EVM adapter responsible for chain context and contract interaction.
|
|
11095
|
+
* @param context - The resolved operation context providing chain and address information.
|
|
11096
|
+
* @returns A promise that resolves to a prepared chain request for the `allowance` call.
|
|
11097
|
+
* The `execute` method returns the allowance as a string (in the token's smallest unit).
|
|
11098
|
+
* @throws Error if the current chain is not EVM-compatible, if address validation fails, or if the contract call fails.
|
|
11099
|
+
*
|
|
11100
|
+
* @example
|
|
11101
|
+
* ```typescript
|
|
11102
|
+
* const prepared = await allowance(
|
|
11103
|
+
* { tokenAddress: '0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', walletAddress: '0xabc...', delegate: '0xdef...' },
|
|
11104
|
+
* adapter,
|
|
11105
|
+
* context
|
|
11106
|
+
* );
|
|
11107
|
+
* const allowance = await prepared.execute();
|
|
11108
|
+
* console.log(allowance); // e.g., "1000000" (for 1 USDC allowance with 6 decimals)
|
|
11109
|
+
* ```
|
|
11110
|
+
*/
|
|
11111
|
+
const allowance$1 = async (params, adapter, context) => {
|
|
11112
|
+
const chain = context.chain;
|
|
11113
|
+
if (chain.type !== 'evm') {
|
|
11114
|
+
throw new Error(`Expected EVM chain definition, but received chain type: ${chain.type}`);
|
|
11115
|
+
}
|
|
11116
|
+
const { tokenAddress, walletAddress: walletAddressParam, delegate } = params;
|
|
11117
|
+
// Use provided wallet address or fall back to context address
|
|
11118
|
+
const walletAddress = walletAddressParam ?? context.address;
|
|
11119
|
+
// validate the address
|
|
11120
|
+
assertEvmAddress(walletAddress);
|
|
11121
|
+
assertEvmAddress(tokenAddress);
|
|
11122
|
+
assertEvmAddress(delegate);
|
|
11123
|
+
try {
|
|
11124
|
+
return await adapter.prepare({
|
|
11125
|
+
type: 'evm',
|
|
11126
|
+
address: tokenAddress,
|
|
11127
|
+
abi: erc20Abi,
|
|
11128
|
+
functionName: 'allowance',
|
|
11129
|
+
args: [walletAddress, delegate],
|
|
11130
|
+
}, context);
|
|
11131
|
+
}
|
|
11132
|
+
catch (error) {
|
|
11133
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
11134
|
+
throw new Error(`Failed to get token allowance for ${walletAddress} from ${tokenAddress}: ${errorMessage}`);
|
|
11135
|
+
}
|
|
11136
|
+
};
|
|
11137
|
+
|
|
11138
|
+
/**
|
|
11139
|
+
* Prepares an EVM-compatible `approve` transaction for any ERC-20 token.
|
|
11140
|
+
*
|
|
11141
|
+
* This function creates a prepared chain request for approving a delegate (spender)
|
|
11142
|
+
* to spend a specified amount of tokens on behalf of the caller. It validates the
|
|
11143
|
+
* chain type and all addresses, then constructs a transaction using the standard
|
|
11144
|
+
* ERC-20 ABI and the provided token address. The resulting prepared request can be
|
|
11145
|
+
* executed or simulated by the caller.
|
|
11146
|
+
*
|
|
11147
|
+
* @remarks
|
|
11148
|
+
* **Race Condition Consideration**
|
|
11149
|
+
*
|
|
11150
|
+
* The standard ERC-20 `approve()` function has a known theoretical race condition
|
|
11151
|
+
* where a malicious spender could front-run an approval change to spend both the
|
|
11152
|
+
* old and new allowance amounts. However, this is rare in practice and is the
|
|
11153
|
+
* accepted industry standard used by major protocols (Uniswap, 1inch, etc.).
|
|
11154
|
+
*
|
|
11155
|
+
* @param params - The action payload containing:
|
|
11156
|
+
* - `tokenAddress`: The contract address of the ERC-20 token.
|
|
11157
|
+
* - `delegate`: The address to grant the allowance to (spender).
|
|
11158
|
+
* - `amount`: The amount of tokens to approve (as a bigint, in the token's smallest unit).
|
|
11159
|
+
* @param adapter - The EVM adapter responsible for chain context and transaction preparation.
|
|
11160
|
+
* @param context - The resolved operation context providing chain and address information.
|
|
11161
|
+
* @returns A promise that resolves to a prepared chain request for the `approve` call.
|
|
11162
|
+
* The `execute` method returns the transaction hash.
|
|
11163
|
+
* @throws {KitError} If the current chain is not EVM-compatible (INPUT_INVALID_CHAIN).
|
|
11164
|
+
* @throws {KitError} if the amount is not a postive or zero bigint (INPUT_INVALID_AMOUNT).
|
|
11165
|
+
* @throws {ValidationError} If address validation fails for tokenAddress or delegate.
|
|
11166
|
+
*
|
|
11167
|
+
* @example Approve USDT for a swap contract
|
|
11168
|
+
* ```typescript
|
|
11169
|
+
* import { approve } from '@core/adapter-evm/actions/token'
|
|
11170
|
+
* import { createAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
11171
|
+
* import { Ethereum } from '@core/chains'
|
|
11172
|
+
*
|
|
11173
|
+
* const adapter = createAdapterFromPrivateKey({ privateKey: '0x...' })
|
|
11174
|
+
* const context = {
|
|
11175
|
+
* chain: Ethereum,
|
|
11176
|
+
* address: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
|
|
11177
|
+
* }
|
|
11178
|
+
*
|
|
11179
|
+
* // Approve 100 USDT (6 decimals) for a swap contract
|
|
11180
|
+
* const prepared = await approve(
|
|
11181
|
+
* {
|
|
11182
|
+
* tokenAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
|
|
11183
|
+
* delegate: '0x1234567890123456789012345678901234567890', // Swap contract
|
|
11184
|
+
* amount: 100_000000n // 100 USDT
|
|
11185
|
+
* },
|
|
11186
|
+
* adapter,
|
|
11187
|
+
* context
|
|
11188
|
+
* )
|
|
11189
|
+
*
|
|
11190
|
+
* // Execute the approval
|
|
11191
|
+
* const txHash = await prepared.execute()
|
|
11192
|
+
* console.log('Approval transaction:', txHash)
|
|
11193
|
+
* ```
|
|
11194
|
+
*
|
|
11195
|
+
* @example Approve DAI for a lending protocol
|
|
11196
|
+
* ```typescript
|
|
11197
|
+
* // Approve 1000 DAI (18 decimals) for a lending protocol
|
|
11198
|
+
* const prepared = await approve(
|
|
11199
|
+
* {
|
|
11200
|
+
* tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
|
|
11201
|
+
* delegate: '0xLendingProtocolAddress',
|
|
11202
|
+
* amount: 1000_000000000000000000n // 1000 DAI
|
|
11203
|
+
* },
|
|
11204
|
+
* adapter,
|
|
11205
|
+
* context
|
|
11206
|
+
* )
|
|
11207
|
+
*
|
|
11208
|
+
* await prepared.execute()
|
|
11209
|
+
* ```
|
|
11210
|
+
*
|
|
11211
|
+
* @example Revoke approval by setting to zero
|
|
11212
|
+
* ```typescript
|
|
11213
|
+
* // Revoke approval by setting allowance to 0
|
|
11214
|
+
* const prepared = await approve(
|
|
11215
|
+
* {
|
|
11216
|
+
* tokenAddress: '0xTokenAddress',
|
|
11217
|
+
* delegate: '0xSpenderAddress',
|
|
11218
|
+
* amount: 0n // Revoke approval
|
|
11219
|
+
* },
|
|
11220
|
+
* adapter,
|
|
11221
|
+
* context
|
|
11222
|
+
* )
|
|
11223
|
+
*
|
|
11224
|
+
* await prepared.execute()
|
|
11225
|
+
* ```
|
|
11226
|
+
*/
|
|
11227
|
+
const approve = async (params, adapter, context) => {
|
|
11228
|
+
const chain = context.chain;
|
|
11229
|
+
if (chain.type !== 'evm') {
|
|
11230
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain definition, but received chain type: ${chain.type}`);
|
|
11231
|
+
}
|
|
11232
|
+
const { tokenAddress, delegate, amount } = params;
|
|
11233
|
+
// Validate addresses
|
|
11234
|
+
assertEvmAddress(tokenAddress);
|
|
11235
|
+
assertEvmAddress(delegate);
|
|
11236
|
+
// Validate amount (must be bigint and >= 0)
|
|
11237
|
+
if (typeof amount !== 'bigint' || amount < 0n) {
|
|
11238
|
+
throw createInvalidAmountError(String(amount), 'Approval amount must be a non-negative bigint');
|
|
9325
11239
|
}
|
|
11240
|
+
// Prepare the approve transaction
|
|
11241
|
+
return adapter.prepare({
|
|
11242
|
+
type: 'evm',
|
|
11243
|
+
abi: erc20Abi,
|
|
11244
|
+
address: tokenAddress,
|
|
11245
|
+
functionName: 'approve',
|
|
11246
|
+
args: [delegate, amount],
|
|
11247
|
+
}, context);
|
|
9326
11248
|
};
|
|
9327
11249
|
|
|
9328
11250
|
/**
|
|
9329
|
-
*
|
|
11251
|
+
* Prepare an EVM-compatible ERC-20 `transfer` transaction.
|
|
9330
11252
|
*
|
|
9331
|
-
*
|
|
9332
|
-
*
|
|
9333
|
-
* and all addresses, then constructs a read-only contract call using the canonical ERC-20 ABI and the provided token address.
|
|
9334
|
-
* The resulting prepared request can be executed or simulated by the caller.
|
|
11253
|
+
* Create a prepared chain request to move tokens from the caller's wallet to a
|
|
11254
|
+
* recipient address on EVM chains using the standard ERC-20 ABI.
|
|
9335
11255
|
*
|
|
9336
|
-
*
|
|
9337
|
-
*
|
|
9338
|
-
*
|
|
9339
|
-
*
|
|
9340
|
-
* @param
|
|
9341
|
-
*
|
|
9342
|
-
*
|
|
9343
|
-
*
|
|
9344
|
-
* @
|
|
11256
|
+
* The function validates that the current chain is EVM-compatible, then builds a
|
|
11257
|
+
* transaction targeting the provided token contract address. The resulting prepared
|
|
11258
|
+
* request can be simulated or executed by the caller.
|
|
11259
|
+
*
|
|
11260
|
+
* @param params - The action payload for `token.transfer` containing:
|
|
11261
|
+
* - `tokenAddress`: The ERC-20 token contract address.
|
|
11262
|
+
* - `to`: The recipient wallet address.
|
|
11263
|
+
* - `amount`: The token amount in the smallest unit (as a `bigint`).
|
|
11264
|
+
* @param adapter - The EVM adapter responsible for chain context and transaction preparation.
|
|
11265
|
+
* @returns A promise that resolves to a prepared chain request for the `transfer` call.
|
|
11266
|
+
* @throws {KitError} If chain is not EVM (INPUT_INVALID_CHAIN) or amount is invalid (INPUT_INVALID_AMOUNT).
|
|
9345
11267
|
*
|
|
9346
11268
|
* @example
|
|
9347
11269
|
* ```typescript
|
|
9348
|
-
* const prepared = await
|
|
9349
|
-
* {
|
|
9350
|
-
*
|
|
9351
|
-
*
|
|
11270
|
+
* const prepared = await transfer(
|
|
11271
|
+
* {
|
|
11272
|
+
* tokenAddress: '0x0000000000000000000000000000000000000000',
|
|
11273
|
+
* to: '0x1111111111111111111111111111111111111111',
|
|
11274
|
+
* amount: 1_000_000n,
|
|
11275
|
+
* },
|
|
11276
|
+
* adapter
|
|
9352
11277
|
* );
|
|
9353
|
-
*
|
|
9354
|
-
* console.log(allowance); // e.g., "1000000" (for 1 USDC allowance with 6 decimals)
|
|
11278
|
+
* await prepared.execute();
|
|
9355
11279
|
* ```
|
|
9356
11280
|
*/
|
|
9357
|
-
const
|
|
11281
|
+
const transfer$2 = async (params, adapter, context) => {
|
|
9358
11282
|
const chain = context.chain;
|
|
9359
11283
|
if (chain.type !== 'evm') {
|
|
9360
|
-
throw
|
|
9361
|
-
}
|
|
9362
|
-
const { tokenAddress, walletAddress: walletAddressParam, delegate } = params;
|
|
9363
|
-
// Use provided wallet address or fall back to context address
|
|
9364
|
-
const walletAddress = walletAddressParam ?? context.address;
|
|
9365
|
-
// validate the address
|
|
9366
|
-
assertEvmAddress(walletAddress);
|
|
9367
|
-
assertEvmAddress(tokenAddress);
|
|
9368
|
-
assertEvmAddress(delegate);
|
|
9369
|
-
try {
|
|
9370
|
-
return await adapter.prepare({
|
|
9371
|
-
type: 'evm',
|
|
9372
|
-
address: tokenAddress,
|
|
9373
|
-
abi: erc20Abi,
|
|
9374
|
-
functionName: 'allowance',
|
|
9375
|
-
args: [walletAddress, delegate],
|
|
9376
|
-
}, context);
|
|
11284
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain definition, but received chain type: ${chain.type}`);
|
|
9377
11285
|
}
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
throw
|
|
11286
|
+
// Validate the amount
|
|
11287
|
+
if (typeof params.amount !== 'bigint' || params.amount <= 0n) {
|
|
11288
|
+
throw createInvalidAmountError(String(params.amount), 'Transfer amount must be a positive bigint');
|
|
9381
11289
|
}
|
|
11290
|
+
// Prepare the transfer transaction
|
|
11291
|
+
return adapter.prepare({
|
|
11292
|
+
type: 'evm',
|
|
11293
|
+
abi: erc20Abi,
|
|
11294
|
+
address: params.tokenAddress,
|
|
11295
|
+
functionName: 'transfer',
|
|
11296
|
+
args: [params.to, params.amount],
|
|
11297
|
+
}, context);
|
|
9382
11298
|
};
|
|
9383
11299
|
|
|
9384
11300
|
/**
|
|
@@ -9508,6 +11424,106 @@ const allowance = async (params, adapter, context) => {
|
|
|
9508
11424
|
}, adapter, context);
|
|
9509
11425
|
};
|
|
9510
11426
|
|
|
11427
|
+
/**
|
|
11428
|
+
* Prepares a USDC `transfer` transaction for EVM-compatible chains.
|
|
11429
|
+
*
|
|
11430
|
+
* This function validates that the current chain is EVM-compatible and that a canonical
|
|
11431
|
+
* USDC contract address is available for the chain. It then constructs a prepared chain
|
|
11432
|
+
* request to transfer USDC from the caller's wallet to a specified recipient address,
|
|
11433
|
+
* using the standard ERC-20 ABI and the chain's USDC contract address.
|
|
11434
|
+
*
|
|
11435
|
+
* The resulting prepared request can be simulated, estimated, or executed by the caller.
|
|
11436
|
+
*
|
|
11437
|
+
* @param params - The action payload for `usdc.transfer`:
|
|
11438
|
+
* - `to`: The recipient wallet address.
|
|
11439
|
+
* - `amount`: The USDC amount to transfer (in the smallest unit, as a `bigint`).
|
|
11440
|
+
* @param adapter - The EVM adapter providing chain context and contract interaction.
|
|
11441
|
+
* @returns A promise resolving to a prepared chain request for the USDC `transfer` call.
|
|
11442
|
+
* The returned request's `execute` method sends the transaction.
|
|
11443
|
+
* @throws {KitError} If chain is not EVM (INPUT_INVALID_CHAIN) or USDC is not supported (INPUT_UNSUPPORTED_TOKEN).
|
|
11444
|
+
*
|
|
11445
|
+
* @example
|
|
11446
|
+
* ```typescript
|
|
11447
|
+
* const prepared = await transfer(
|
|
11448
|
+
* {
|
|
11449
|
+
* to: '0x1111111111111111111111111111111111111111',
|
|
11450
|
+
* amount: 1_000_000n,
|
|
11451
|
+
* },
|
|
11452
|
+
* adapter
|
|
11453
|
+
* );
|
|
11454
|
+
* await prepared.execute();
|
|
11455
|
+
* ```
|
|
11456
|
+
*/
|
|
11457
|
+
const transfer$1 = async (params, adapter, context) => {
|
|
11458
|
+
const chain = context.chain;
|
|
11459
|
+
if (chain.type !== 'evm') {
|
|
11460
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain definition, but received chain type: ${chain.type}`);
|
|
11461
|
+
}
|
|
11462
|
+
const tokenAddress = chain.usdcAddress;
|
|
11463
|
+
// Check if USDC address exists before validating
|
|
11464
|
+
if (tokenAddress == null) {
|
|
11465
|
+
throw createUnsupportedTokenError('USDC', chain.name);
|
|
11466
|
+
}
|
|
11467
|
+
assertEvmAddress(tokenAddress);
|
|
11468
|
+
// Prepare the usdc transfer transaction using the base token transfer function
|
|
11469
|
+
return transfer$2({
|
|
11470
|
+
tokenAddress,
|
|
11471
|
+
to: params.to,
|
|
11472
|
+
amount: params.amount,
|
|
11473
|
+
}, adapter, context);
|
|
11474
|
+
};
|
|
11475
|
+
|
|
11476
|
+
/**
|
|
11477
|
+
* Prepares a USDT `transfer` transaction for EVM-compatible chains.
|
|
11478
|
+
*
|
|
11479
|
+
* This function validates that the current chain is EVM-compatible and that a canonical
|
|
11480
|
+
* USDT contract address is available for the chain. It then constructs a prepared chain
|
|
11481
|
+
* request to transfer USDT from the caller's wallet to a specified recipient address,
|
|
11482
|
+
* using the standard ERC-20 ABI and the chain's USDT contract address.
|
|
11483
|
+
*
|
|
11484
|
+
* The resulting prepared request can be simulated, estimated, or executed by the caller.
|
|
11485
|
+
*
|
|
11486
|
+
* @param params - The action payload for `usdt.transfer`:
|
|
11487
|
+
* - `to`: The recipient wallet address.
|
|
11488
|
+
* - `amount`: The USDT amount to transfer (in the smallest unit, as a `bigint`).
|
|
11489
|
+
* @param adapter - The EVM adapter providing chain context and contract interaction.
|
|
11490
|
+
* @param context - The resolved operation context containing chain definition.
|
|
11491
|
+
* @returns A promise resolving to a prepared chain request for the USDT `transfer` call.
|
|
11492
|
+
* The returned request's `execute` method sends the transaction.
|
|
11493
|
+
* @throws {KitError} If chain is not EVM (INPUT_INVALID_CHAIN) or USDT is not supported (INPUT_UNSUPPORTED_TOKEN).
|
|
11494
|
+
*
|
|
11495
|
+
* @example
|
|
11496
|
+
* ```typescript
|
|
11497
|
+
* const prepared = await transfer(
|
|
11498
|
+
* {
|
|
11499
|
+
* to: '0x1111111111111111111111111111111111111111',
|
|
11500
|
+
* amount: 1_000_000n,
|
|
11501
|
+
* },
|
|
11502
|
+
* adapter,
|
|
11503
|
+
* context
|
|
11504
|
+
* );
|
|
11505
|
+
* await prepared.execute();
|
|
11506
|
+
* ```
|
|
11507
|
+
*/
|
|
11508
|
+
const transfer = async (params, adapter, context) => {
|
|
11509
|
+
const chain = context.chain;
|
|
11510
|
+
if (chain.type !== 'evm') {
|
|
11511
|
+
throw createInvalidChainError(chain.name, `Expected EVM chain, but received chain type: ${chain.type}`);
|
|
11512
|
+
}
|
|
11513
|
+
const tokenAddress = chain.usdtAddress;
|
|
11514
|
+
// Check if USDT address exists before validating
|
|
11515
|
+
if (tokenAddress == null) {
|
|
11516
|
+
throw createUnsupportedTokenError('USDT', chain.name);
|
|
11517
|
+
}
|
|
11518
|
+
assertEvmAddress(tokenAddress);
|
|
11519
|
+
// Prepare the usdt transfer transaction using the base token transfer function
|
|
11520
|
+
return transfer$2({
|
|
11521
|
+
tokenAddress,
|
|
11522
|
+
to: params.to,
|
|
11523
|
+
amount: params.amount,
|
|
11524
|
+
}, adapter, context);
|
|
11525
|
+
};
|
|
11526
|
+
|
|
9511
11527
|
/**
|
|
9512
11528
|
* Creates a collection of action handlers for EVM blockchain operations.
|
|
9513
11529
|
*
|
|
@@ -9544,6 +11560,15 @@ const getHandlers = (adapter) => {
|
|
|
9544
11560
|
'token.balanceOf': async (params, context) => {
|
|
9545
11561
|
return balanceOf$1(params, adapter, context);
|
|
9546
11562
|
},
|
|
11563
|
+
/**
|
|
11564
|
+
* Handler for token approve operations on EVM chains.
|
|
11565
|
+
*
|
|
11566
|
+
* Approves a delegate to spend tokens on behalf of the caller.
|
|
11567
|
+
* Uses the standard ERC-20 approve function.
|
|
11568
|
+
*/
|
|
11569
|
+
'token.approve': async (params, context) => {
|
|
11570
|
+
return approve(params, adapter, context);
|
|
11571
|
+
},
|
|
9547
11572
|
/**
|
|
9548
11573
|
* Handler for USDC allowance operations on EVM chains.
|
|
9549
11574
|
*
|
|
@@ -9607,6 +11632,49 @@ const getHandlers = (adapter) => {
|
|
|
9607
11632
|
'cctp.v2.customBurn': async (params, context) => {
|
|
9608
11633
|
return customBurn(params, adapter, context);
|
|
9609
11634
|
},
|
|
11635
|
+
/**
|
|
11636
|
+
* Handler for token transfer operations on EVM chains.
|
|
11637
|
+
*
|
|
11638
|
+
* Transfers the specified amount of the token from the caller's wallet to the specified recipient address.
|
|
11639
|
+
*/
|
|
11640
|
+
'token.transfer': async (params, context) => {
|
|
11641
|
+
return transfer$2(params, adapter, context);
|
|
11642
|
+
},
|
|
11643
|
+
/**
|
|
11644
|
+
* Handler for native token transfer operations on EVM chains.
|
|
11645
|
+
*
|
|
11646
|
+
* Transfers the specified amount of native tokens from the caller's wallet to the specified recipient address.
|
|
11647
|
+
*/
|
|
11648
|
+
'native.transfer': async (params, context) => {
|
|
11649
|
+
return transfer$3(params, adapter, context);
|
|
11650
|
+
},
|
|
11651
|
+
/**
|
|
11652
|
+
* Handler for USDC transfer operations on EVM chains.
|
|
11653
|
+
*
|
|
11654
|
+
* Transfers the specified amount of USDC from the caller's wallet to the specified recipient address.
|
|
11655
|
+
*/
|
|
11656
|
+
'usdc.transfer': async (params, context) => {
|
|
11657
|
+
return transfer$1(params, adapter, context);
|
|
11658
|
+
},
|
|
11659
|
+
/**
|
|
11660
|
+
* Handler for USDT transfer operations on EVM chains.
|
|
11661
|
+
*
|
|
11662
|
+
* Transfers the specified amount of USDT from the caller's wallet to the specified recipient address.
|
|
11663
|
+
*/
|
|
11664
|
+
'usdt.transfer': async (params, context) => {
|
|
11665
|
+
return transfer(params, adapter, context);
|
|
11666
|
+
},
|
|
11667
|
+
/**
|
|
11668
|
+
* Handler for swap execution.
|
|
11669
|
+
*
|
|
11670
|
+
* Executes pre-built swap transactions from the stablecoin-service API.
|
|
11671
|
+
* The service handles DEX aggregation and routing; this action handles
|
|
11672
|
+
* transaction preparation and execution. Token approvals are managed
|
|
11673
|
+
* separately by the provider layer.
|
|
11674
|
+
*/
|
|
11675
|
+
'swap.execute': async (params, context) => {
|
|
11676
|
+
return executeSwap(params, adapter, context);
|
|
11677
|
+
},
|
|
9610
11678
|
/**
|
|
9611
11679
|
* Handler for CCTP v2 custom burn with hook operations on EVM chains.
|
|
9612
11680
|
*
|
|
@@ -10444,6 +12512,44 @@ const evmPreparedChainRequestParamsSchema = zod.z.object({
|
|
|
10444
12512
|
invalid_type_error: 'Arguments must be an array',
|
|
10445
12513
|
}),
|
|
10446
12514
|
});
|
|
12515
|
+
/**
|
|
12516
|
+
* Zod schema for validating native token transfer parameters.
|
|
12517
|
+
*
|
|
12518
|
+
* This schema validates the parameters required for native token transfers
|
|
12519
|
+
* (e.g., ETH on Ethereum, MATIC on Polygon):
|
|
12520
|
+
* - Address must be a valid EVM address (42 characters starting with 0x)
|
|
12521
|
+
* - Value must be a positive bigint greater than 0
|
|
12522
|
+
*
|
|
12523
|
+
* @throws KitError if validation fails
|
|
12524
|
+
*
|
|
12525
|
+
* @example
|
|
12526
|
+
* ```typescript
|
|
12527
|
+
* import { nativeTransferParamsSchema } from '@core/adapter-evm/validation'
|
|
12528
|
+
*
|
|
12529
|
+
* const params = {
|
|
12530
|
+
* address: '0x1234567890123456789012345678901234567890',
|
|
12531
|
+
* value: BigInt(1000000)
|
|
12532
|
+
* }
|
|
12533
|
+
*
|
|
12534
|
+
* const result = nativeTransferParamsSchema.safeParse(params)
|
|
12535
|
+
* if (result.success) {
|
|
12536
|
+
* console.log('Native transfer params are valid')
|
|
12537
|
+
* } else {
|
|
12538
|
+
* console.error('Validation failed:', result.error)
|
|
12539
|
+
* }
|
|
12540
|
+
* ```
|
|
12541
|
+
*/
|
|
12542
|
+
const nativeTransferParamsSchema = zod.z.object({
|
|
12543
|
+
address: evmAddressSchema,
|
|
12544
|
+
value: zod.z
|
|
12545
|
+
.bigint({
|
|
12546
|
+
required_error: 'Value is required for native transfers',
|
|
12547
|
+
invalid_type_error: 'Value must be a bigint',
|
|
12548
|
+
})
|
|
12549
|
+
.refine((val) => val > BigInt(0), {
|
|
12550
|
+
message: 'Value must be greater than 0',
|
|
12551
|
+
}),
|
|
12552
|
+
});
|
|
10447
12553
|
/**
|
|
10448
12554
|
* Zod schema for validating Ethereum transaction hashes.
|
|
10449
12555
|
*
|
|
@@ -10588,6 +12694,44 @@ function assertEvmTransactionHash(txHash) {
|
|
|
10588
12694
|
validate(txHash, evmTransactionHashSchema, 'Transaction hash');
|
|
10589
12695
|
}
|
|
10590
12696
|
|
|
12697
|
+
const assertNativeTransferParamsSymbol = Symbol('assertNativeTransferParams');
|
|
12698
|
+
/**
|
|
12699
|
+
* Asserts that the provided parameters are valid for native token transfers.
|
|
12700
|
+
*
|
|
12701
|
+
* The validation includes:
|
|
12702
|
+
* - A valid EVM address (42 characters starting with 0x)
|
|
12703
|
+
* - A positive bigint value greater than 0
|
|
12704
|
+
*
|
|
12705
|
+
* @param params - The parameters to validate
|
|
12706
|
+
* @throws KitError with INPUT_VALIDATION_FAILED code if validation fails, with details about which properties failed
|
|
12707
|
+
*
|
|
12708
|
+
* @example
|
|
12709
|
+
* ```typescript
|
|
12710
|
+
* import { assertNativeTransferParams } from '@core/adapter-evm'
|
|
12711
|
+
*
|
|
12712
|
+
* // Valid native transfer
|
|
12713
|
+
* assertNativeTransferParams({
|
|
12714
|
+
* address: '0x1234567890123456789012345678901234567890',
|
|
12715
|
+
* value: BigInt(1000000)
|
|
12716
|
+
* })
|
|
12717
|
+
*
|
|
12718
|
+
* // This will throw KitError - invalid address
|
|
12719
|
+
* assertNativeTransferParams({
|
|
12720
|
+
* address: '0x123',
|
|
12721
|
+
* value: BigInt(1000000)
|
|
12722
|
+
* })
|
|
12723
|
+
*
|
|
12724
|
+
* // This will throw KitError - zero value
|
|
12725
|
+
* assertNativeTransferParams({
|
|
12726
|
+
* address: '0x1234567890123456789012345678901234567890',
|
|
12727
|
+
* value: BigInt(0)
|
|
12728
|
+
* })
|
|
12729
|
+
* ```
|
|
12730
|
+
*/
|
|
12731
|
+
function assertNativeTransferParams(params) {
|
|
12732
|
+
validateWithStateTracking(params, nativeTransferParamsSchema, 'Native transfer params', assertNativeTransferParamsSymbol);
|
|
12733
|
+
}
|
|
12734
|
+
|
|
10591
12735
|
/**
|
|
10592
12736
|
* Asserts that the provided data matches the EIP-712 TypedData interface.
|
|
10593
12737
|
*
|
|
@@ -11683,15 +13827,21 @@ class EthersAdapter extends EvmAdapter {
|
|
|
11683
13827
|
/**
|
|
11684
13828
|
* Simulates a contract function call using Ethers v6 `.staticCall`.
|
|
11685
13829
|
*/
|
|
11686
|
-
async simulateFunctionCall(contract, functionName, args, chain) {
|
|
13830
|
+
async simulateFunctionCall(contract, functionName, args, chain, overrides) {
|
|
11687
13831
|
// Retry on allowance errors to handle RPC state propagation delays
|
|
11688
13832
|
// (e.g., approve tx confirmed but not yet visible in latest block for staticCall)
|
|
11689
|
-
const MAX_SIMULATION_ATTEMPTS =
|
|
13833
|
+
const MAX_SIMULATION_ATTEMPTS = 5;
|
|
11690
13834
|
const SIMULATION_RETRY_DELAY_MS = 1000;
|
|
11691
13835
|
for (let attempt = 1; attempt <= MAX_SIMULATION_ATTEMPTS; attempt++) {
|
|
11692
13836
|
try {
|
|
11693
13837
|
const func = contract.getFunction(functionName);
|
|
11694
|
-
|
|
13838
|
+
// Pass overrides to staticCall so that value (ETH) is included in simulation
|
|
13839
|
+
if (overrides) {
|
|
13840
|
+
await func.staticCall(...args, overrides);
|
|
13841
|
+
}
|
|
13842
|
+
else {
|
|
13843
|
+
await func.staticCall(...args);
|
|
13844
|
+
}
|
|
11695
13845
|
return;
|
|
11696
13846
|
}
|
|
11697
13847
|
catch (err) {
|
|
@@ -11786,6 +13936,24 @@ class EthersAdapter extends EvmAdapter {
|
|
|
11786
13936
|
if (!txRequest) {
|
|
11787
13937
|
throw new Error(`Failed to populate transaction for function '${functionName}'.`);
|
|
11788
13938
|
}
|
|
13939
|
+
return this.sendTransactionWithNonceManagement(txRequest, fromAddress, chain, overrides);
|
|
13940
|
+
}
|
|
13941
|
+
/**
|
|
13942
|
+
* Common transaction sending logic with nonce management and retry logic.
|
|
13943
|
+
*
|
|
13944
|
+
* This method handles the complete transaction lifecycle:
|
|
13945
|
+
* - Nonce allocation and management via {@link ethersNonceManager}
|
|
13946
|
+
* - Automatic retry on nonce-related errors (up to 3 attempts)
|
|
13947
|
+
* - Graceful handling of user-provided nonces (no retry)
|
|
13948
|
+
* - Proper error handling and wrapping
|
|
13949
|
+
*
|
|
13950
|
+
* @param txRequest - Populated transaction request
|
|
13951
|
+
* @param fromAddress - The address sending the transaction
|
|
13952
|
+
* @param chain - The chain definition for context
|
|
13953
|
+
* @param overrides - Optional transaction overrides
|
|
13954
|
+
* @returns Transaction hash
|
|
13955
|
+
*/
|
|
13956
|
+
async sendTransactionWithNonceManagement(txRequest, fromAddress, chain, overrides) {
|
|
11789
13957
|
// Chain is passed as parameter to avoid race conditions in concurrent requests
|
|
11790
13958
|
const provider = await this.getProvider(chain);
|
|
11791
13959
|
if (!fromAddress) {
|
|
@@ -11942,9 +14110,18 @@ class EthersAdapter extends EvmAdapter {
|
|
|
11942
14110
|
* ```
|
|
11943
14111
|
*/
|
|
11944
14112
|
async prepare(params, ctx) {
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
const
|
|
14113
|
+
const { address, abi, functionName, args, value } = params;
|
|
14114
|
+
// Detect native transfer early: no abi, no functionName, no args, but has value
|
|
14115
|
+
const isNativeTransfer = !abi && !functionName && !args && value !== undefined;
|
|
14116
|
+
// Validate parameters based on transfer type
|
|
14117
|
+
if (isNativeTransfer) {
|
|
14118
|
+
// For native transfers, validate address and value
|
|
14119
|
+
assertNativeTransferParams({ address, value });
|
|
14120
|
+
}
|
|
14121
|
+
else {
|
|
14122
|
+
// For contract calls, use full validation
|
|
14123
|
+
assertEvmPreparedChainRequestParams(params);
|
|
14124
|
+
}
|
|
11948
14125
|
// First, resolve the target chain from the operation context
|
|
11949
14126
|
const targetChain = resolveChainIdentifier(ctx.chain);
|
|
11950
14127
|
if (targetChain.type !== 'evm') {
|
|
@@ -11967,6 +14144,10 @@ class EthersAdapter extends EvmAdapter {
|
|
|
11967
14144
|
if (!resolvedContext) {
|
|
11968
14145
|
throw new Error('OperationContext resolution failed. Ensure the adapter has capabilities configured.');
|
|
11969
14146
|
}
|
|
14147
|
+
// Handle native transfers separately (after context resolution)
|
|
14148
|
+
if (isNativeTransfer) {
|
|
14149
|
+
return this.prepareNativeTransfer(address, value, targetChain, resolvedContext.address);
|
|
14150
|
+
}
|
|
11970
14151
|
const signer = this.getSigner();
|
|
11971
14152
|
const contract = this.createContractInstance(params, signer, resolvedContext.address, provider);
|
|
11972
14153
|
return {
|
|
@@ -11977,18 +14158,33 @@ class EthersAdapter extends EvmAdapter {
|
|
|
11977
14158
|
// gas estimation and fee data retrieval use the correct network.
|
|
11978
14159
|
const estimationProvider = await this.getProvider(targetChain);
|
|
11979
14160
|
const contractForEstimation = contract.connect(estimationProvider);
|
|
11980
|
-
|
|
14161
|
+
// Merge value from params with overrides, with overrides taking precedence
|
|
14162
|
+
// Include 'from' address since connecting to a Provider (not Signer) loses
|
|
14163
|
+
// the ability to infer the sender address, which would otherwise default to
|
|
14164
|
+
// the zero address and cause "transfer from the zero address" errors.
|
|
14165
|
+
const mergedOverrides = {
|
|
14166
|
+
from: resolvedContext.address,
|
|
14167
|
+
...(value !== undefined && { value }),
|
|
14168
|
+
...overrides,
|
|
14169
|
+
};
|
|
14170
|
+
return this.estimateGasForFunction(contractForEstimation, functionName, args, targetChain, mergedOverrides, fallback);
|
|
11981
14171
|
},
|
|
11982
14172
|
execute: async (overrides) => {
|
|
14173
|
+
// Merge value from params with overrides, with overrides taking precedence
|
|
14174
|
+
// Only add value if it's defined (exactOptionalPropertyTypes requires this pattern)
|
|
14175
|
+
const mergedOverrides = {
|
|
14176
|
+
...(value !== undefined && { value }),
|
|
14177
|
+
...overrides,
|
|
14178
|
+
};
|
|
11983
14179
|
// Simulate the function call to catch errors before submission
|
|
11984
|
-
await this.simulateFunctionCall(contract, functionName, args, targetChain);
|
|
14180
|
+
await this.simulateFunctionCall(contract, functionName, args, targetChain, mergedOverrides);
|
|
11985
14181
|
await this.ensureChain(targetChain);
|
|
11986
14182
|
// Reconnect the contract with the current signer, which is on the correct
|
|
11987
14183
|
// chain after `ensureChain`, to ensure the transaction is populated and
|
|
11988
14184
|
// sent correctly.
|
|
11989
14185
|
const currentSigner = this.getSigner();
|
|
11990
14186
|
const contractForExecution = contract.connect(currentSigner);
|
|
11991
|
-
return this.executeTransaction(contractForExecution, functionName, args, resolvedContext.address, targetChain,
|
|
14187
|
+
return this.executeTransaction(contractForExecution, functionName, args, resolvedContext.address, targetChain, mergedOverrides);
|
|
11992
14188
|
},
|
|
11993
14189
|
};
|
|
11994
14190
|
}
|
|
@@ -12026,11 +14222,11 @@ class EthersAdapter extends EvmAdapter {
|
|
|
12026
14222
|
async getAddress(chain) {
|
|
12027
14223
|
// Prevent calling getAddress on developer-controlled adapters
|
|
12028
14224
|
if (this.capabilities?.addressContext === 'developer-controlled') {
|
|
12029
|
-
throw
|
|
14225
|
+
throw createValidationFailedError('adapter', 'invalid-operation', 'Cannot call getAddress() on developer-controlled adapters. Address must be provided explicitly in the operation context.');
|
|
12030
14226
|
}
|
|
12031
14227
|
// Chain parameter should now be provided by resolveOperationContext
|
|
12032
14228
|
if (!chain) {
|
|
12033
|
-
throw
|
|
14229
|
+
throw createValidationFailedError('chain', 'required', 'Chain parameter is required for address resolution. This should be provided by the OperationContext pattern.');
|
|
12034
14230
|
}
|
|
12035
14231
|
const signer = this.getSigner();
|
|
12036
14232
|
const address = await signer.getAddress();
|
|
@@ -12229,15 +14425,15 @@ class EthersAdapter extends EvmAdapter {
|
|
|
12229
14425
|
// Get chain from required OperationContext
|
|
12230
14426
|
const resolvedContext = await resolveOperationContext(this, ctx);
|
|
12231
14427
|
if (!resolvedContext) {
|
|
12232
|
-
throw
|
|
14428
|
+
throw createValidationFailedError('context', 'resolution-failed', 'OperationContext resolution failed. Ensure the adapter has capabilities configured.');
|
|
12233
14429
|
}
|
|
12234
14430
|
const targetChain = resolvedContext.chain;
|
|
12235
14431
|
if (targetChain.type !== 'evm') {
|
|
12236
|
-
throw
|
|
14432
|
+
throw createInvalidChainError(targetChain.name, `Invalid chain type '${String(targetChain.type)}' for EthersAdapter. Expected 'evm' chain type.`);
|
|
12237
14433
|
}
|
|
12238
14434
|
const signer = this.getSigner();
|
|
12239
14435
|
if (!signer) {
|
|
12240
|
-
throw
|
|
14436
|
+
throw createValidationFailedError('signer', 'not-configured', 'No signer is configured. Please provide a signer to sign typed data.');
|
|
12241
14437
|
}
|
|
12242
14438
|
const types = { ...typedData.types };
|
|
12243
14439
|
delete types['EIP712Domain'];
|
|
@@ -12294,6 +14490,93 @@ class EthersAdapter extends EvmAdapter {
|
|
|
12294
14490
|
},
|
|
12295
14491
|
};
|
|
12296
14492
|
}
|
|
14493
|
+
/**
|
|
14494
|
+
* Prepares a native token transfer (ETH, MATIC, etc.) for gas estimation and execution.
|
|
14495
|
+
*
|
|
14496
|
+
* Native transfers are simple value transfers that don't require contract ABI or function calls.
|
|
14497
|
+
* This method reuses the existing transaction execution flow but skips contract-specific logic.
|
|
14498
|
+
*
|
|
14499
|
+
* @param address - The recipient address for the native token transfer
|
|
14500
|
+
* @param value - The amount of native tokens to send (in wei)
|
|
14501
|
+
* @param targetChain - The target chain definition
|
|
14502
|
+
* @param resolvedAddress - The resolved sender address from operation context
|
|
14503
|
+
* @returns Prepared chain request for native transfer
|
|
14504
|
+
* @throws Error when gas estimation fails without fallback
|
|
14505
|
+
* @throws Error when gas price retrieval fails
|
|
14506
|
+
* @throws Error when transaction execution fails
|
|
14507
|
+
*
|
|
14508
|
+
* @example
|
|
14509
|
+
* ```typescript
|
|
14510
|
+
* // Internal usage - called by prepare() when native transfer is detected
|
|
14511
|
+
* const prepared = this.prepareNativeTransfer(
|
|
14512
|
+
* '0x1234567890123456789012345678901234567890',
|
|
14513
|
+
* BigInt(1000000000000000000), // 1 ETH
|
|
14514
|
+
* Ethereum,
|
|
14515
|
+
* '0xsenderAddress'
|
|
14516
|
+
* );
|
|
14517
|
+
* const estimate = await prepared.estimate();
|
|
14518
|
+
* const txHash = await prepared.execute();
|
|
14519
|
+
* ```
|
|
14520
|
+
*/
|
|
14521
|
+
prepareNativeTransfer(address, value, targetChain, resolvedAddress) {
|
|
14522
|
+
return {
|
|
14523
|
+
type: 'evm',
|
|
14524
|
+
estimate: async (overrides, fallback) => {
|
|
14525
|
+
await this.ensureChain(targetChain);
|
|
14526
|
+
const estimationProvider = await this.getProvider(targetChain);
|
|
14527
|
+
let gas;
|
|
14528
|
+
try {
|
|
14529
|
+
gas = await estimationProvider.estimateGas({
|
|
14530
|
+
to: address,
|
|
14531
|
+
value,
|
|
14532
|
+
from: resolvedAddress,
|
|
14533
|
+
...overrides,
|
|
14534
|
+
});
|
|
14535
|
+
}
|
|
14536
|
+
catch (error) {
|
|
14537
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
14538
|
+
if (fallback &&
|
|
14539
|
+
errorMessage.toLowerCase().includes('execution reverted')) {
|
|
14540
|
+
return fallback;
|
|
14541
|
+
}
|
|
14542
|
+
// Wrap gas estimation errors with structured error format
|
|
14543
|
+
throw parseBlockchainError(error, {
|
|
14544
|
+
chain: targetChain.name,
|
|
14545
|
+
operation: 'estimateGas',
|
|
14546
|
+
});
|
|
14547
|
+
}
|
|
14548
|
+
let gasPrice;
|
|
14549
|
+
try {
|
|
14550
|
+
gasPrice = await this.fetchGasPrice(targetChain);
|
|
14551
|
+
}
|
|
14552
|
+
catch (error) {
|
|
14553
|
+
// Wrap gas price errors with structured error format
|
|
14554
|
+
throw parseBlockchainError(error, {
|
|
14555
|
+
chain: targetChain.name,
|
|
14556
|
+
operation: 'getGasPrice',
|
|
14557
|
+
});
|
|
14558
|
+
}
|
|
14559
|
+
return {
|
|
14560
|
+
gas,
|
|
14561
|
+
gasPrice,
|
|
14562
|
+
fee: (gas * gasPrice).toString(),
|
|
14563
|
+
};
|
|
14564
|
+
},
|
|
14565
|
+
execute: async (overrides) => {
|
|
14566
|
+
await this.ensureChain(targetChain);
|
|
14567
|
+
// Create transaction request for native transfer
|
|
14568
|
+
const txRequest = {
|
|
14569
|
+
to: address,
|
|
14570
|
+
value,
|
|
14571
|
+
...overrides,
|
|
14572
|
+
};
|
|
14573
|
+
// Use common transaction sending logic with nonce management
|
|
14574
|
+
const hash = await this.sendTransactionWithNonceManagement(txRequest, resolvedAddress, targetChain, overrides);
|
|
14575
|
+
assertEvmTransactionHash(hash);
|
|
14576
|
+
return hash;
|
|
14577
|
+
},
|
|
14578
|
+
};
|
|
14579
|
+
}
|
|
12297
14580
|
/**
|
|
12298
14581
|
* Reads a contract function using Ethers v6.
|
|
12299
14582
|
*
|
|
@@ -12309,6 +14592,64 @@ class EthersAdapter extends EvmAdapter {
|
|
|
12309
14592
|
const contractFunction = contract.getFunction(functionName);
|
|
12310
14593
|
return (await contractFunction.staticCall(...args));
|
|
12311
14594
|
}
|
|
14595
|
+
/**
|
|
14596
|
+
* Get the decimal places for an ERC-20 token on an EVM chain.
|
|
14597
|
+
*
|
|
14598
|
+
* This method calls the `decimals()` function on the ERC-20 token contract
|
|
14599
|
+
* to fetch the number of decimal places. Ethers v6 returns decimals as bigint,
|
|
14600
|
+
* which is validated and converted to a number.
|
|
14601
|
+
*
|
|
14602
|
+
* @param tokenAddress - The ERC-20 token contract address
|
|
14603
|
+
* @param chain - The EVM chain definition where the token is deployed
|
|
14604
|
+
* @returns Promise resolving to the number of decimal places
|
|
14605
|
+
* @throws Error when the contract doesn't exist, doesn't support decimals(), or returns invalid data
|
|
14606
|
+
*
|
|
14607
|
+
* @remarks
|
|
14608
|
+
* - Ethers v6 returns decimals as bigint
|
|
14609
|
+
* - Validates that decimals are within 0-255 range (ERC-20 uint8 standard)
|
|
14610
|
+
* - Converts bigint to number for consistent API
|
|
14611
|
+
*
|
|
14612
|
+
* @example
|
|
14613
|
+
* ```typescript
|
|
14614
|
+
* import { EthersAdapter } from '@circle-fin/adapter-ethers-v6'
|
|
14615
|
+
* import { Ethereum } from '@core/chains'
|
|
14616
|
+
*
|
|
14617
|
+
* const adapter = new EthersAdapter({ signer })
|
|
14618
|
+
*
|
|
14619
|
+
* // Fetch decimals for DAI token
|
|
14620
|
+
* const decimals = await adapter.getTokenDecimals(
|
|
14621
|
+
* '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
14622
|
+
* Ethereum
|
|
14623
|
+
* )
|
|
14624
|
+
* console.log(decimals) // 18
|
|
14625
|
+
* ```
|
|
14626
|
+
*/
|
|
14627
|
+
async getTokenDecimals(tokenAddress, chain) {
|
|
14628
|
+
try {
|
|
14629
|
+
// Ethers v6 returns bigint for uint8
|
|
14630
|
+
const decimalsResult = await this.readContract({
|
|
14631
|
+
address: tokenAddress,
|
|
14632
|
+
abi: erc20Abi,
|
|
14633
|
+
functionName: 'decimals',
|
|
14634
|
+
args: [],
|
|
14635
|
+
}, chain);
|
|
14636
|
+
// Validate decimals are within valid range (0-255)
|
|
14637
|
+
if (typeof decimalsResult !== 'bigint' ||
|
|
14638
|
+
decimalsResult < 0n ||
|
|
14639
|
+
decimalsResult > 255n) {
|
|
14640
|
+
throw createValidationFailedError('decimals', decimalsResult, 'Token decimals must be a bigint between 0 and 255');
|
|
14641
|
+
}
|
|
14642
|
+
// Convert bigint to number
|
|
14643
|
+
return Number(decimalsResult);
|
|
14644
|
+
}
|
|
14645
|
+
catch (error) {
|
|
14646
|
+
// If it's already a KitError from our validation, re-throw as-is
|
|
14647
|
+
if (error instanceof KitError) {
|
|
14648
|
+
throw error;
|
|
14649
|
+
}
|
|
14650
|
+
throw createValidationFailedError('tokenAddress', tokenAddress, `Failed to fetch decimals for token on ${chain.name}: ${getErrorMessage(error)}`);
|
|
14651
|
+
}
|
|
14652
|
+
}
|
|
12312
14653
|
}
|
|
12313
14654
|
|
|
12314
14655
|
/**
|