@xswap-link/sdk 0.10.7 → 0.10.9
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/.eslintrc.json +10 -1
- package/.github/workflows/publish.yml +10 -10
- package/CHANGELOG.md +12 -0
- package/dist/index.global.js +331 -331
- package/dist/index.js +9 -9
- package/dist/index.mjs +9 -9
- package/package.json +6 -3
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +106 -9
- package/src/components/Swap/SwapView/SwapButton/index.tsx +11 -11
- package/src/components/TxDataCard/TxDataCardUI/index.tsx +12 -18
- package/src/components/TxDataCard/index.tsx +6 -2
- package/src/constants/index.ts +19 -2
- package/src/context/SwapProvider.tsx +7 -3
- package/src/services/api.ts +1 -0
- package/src/services/solana/jupiter/extract-swap-data.ts +6 -7
- package/src/services/svm/README.md +483 -0
- package/src/services/svm/bindings/accounts/AllowedOfframp.ts +73 -0
- package/src/services/svm/bindings/accounts/Config.ts +153 -0
- package/src/services/svm/bindings/accounts/DestChain.ts +113 -0
- package/src/services/svm/bindings/accounts/Nonce.ts +97 -0
- package/src/services/svm/bindings/accounts/index.ts +15 -0
- package/src/services/svm/bindings/accounts/tokenAdminRegistry.ts +128 -0
- package/src/services/svm/bindings/errors/anchor.ts +773 -0
- package/src/services/svm/bindings/errors/custom.ts +375 -0
- package/src/services/svm/bindings/errors/index.ts +62 -0
- package/src/services/svm/bindings/instructions/ccipSend.ts +112 -0
- package/src/services/svm/bindings/instructions/getFee.ts +73 -0
- package/src/services/svm/bindings/instructions/index.ts +4 -0
- package/src/services/svm/bindings/programId.ts +6 -0
- package/src/services/svm/bindings/types/BaseChain.ts +92 -0
- package/src/services/svm/bindings/types/BaseConfig.ts +184 -0
- package/src/services/svm/bindings/types/CodeVersion.ts +88 -0
- package/src/services/svm/bindings/types/CrossChainAmount.ts +53 -0
- package/src/services/svm/bindings/types/DestChainConfig.ts +76 -0
- package/src/services/svm/bindings/types/DestChainState.ts +76 -0
- package/src/services/svm/bindings/types/GetFeeResult.ts +72 -0
- package/src/services/svm/bindings/types/LockOrBurnInV1.ts +102 -0
- package/src/services/svm/bindings/types/LockOrBurnOutV1.ts +79 -0
- package/src/services/svm/bindings/types/RampMessageHeader.ts +94 -0
- package/src/services/svm/bindings/types/RateLimitConfig.ts +72 -0
- package/src/services/svm/bindings/types/RateLimitTokenBucket.ts +76 -0
- package/src/services/svm/bindings/types/ReleaseOrMintInV1.ts +156 -0
- package/src/services/svm/bindings/types/ReleaseOrMintOutV1.ts +53 -0
- package/src/services/svm/bindings/types/RemoteAddress.ts +61 -0
- package/src/services/svm/bindings/types/RemoteConfig.ts +86 -0
- package/src/services/svm/bindings/types/RestoreOnAction.ts +120 -0
- package/src/services/svm/bindings/types/SVM2AnyMessage.ts +128 -0
- package/src/services/svm/bindings/types/SVM2AnyRampMessage.ts +166 -0
- package/src/services/svm/bindings/types/SVM2AnyTokenTransfer.ts +118 -0
- package/src/services/svm/bindings/types/SVMTokenAmount.ts +64 -0
- package/src/services/svm/bindings/types/index.ts +78 -0
- package/src/services/svm/core/client/accounts.ts +97 -0
- package/src/services/svm/core/client/events.ts +95 -0
- package/src/services/svm/core/client/fee.ts +279 -0
- package/src/services/svm/core/client/index.ts +150 -0
- package/src/services/svm/core/client/send.ts +607 -0
- package/src/services/svm/core/client/utils.ts +131 -0
- package/src/services/svm/core/models.ts +236 -0
- package/src/services/svm/index.ts +32 -0
- package/src/services/svm/utils/conversion.ts +62 -0
- package/src/services/svm/utils/errors.ts +51 -0
- package/src/services/svm/utils/keypair.ts +19 -0
- package/src/services/svm/utils/logger.ts +171 -0
- package/src/services/svm/utils/pdas/common.ts +15 -0
- package/src/services/svm/utils/pdas/feeQuoter.ts +68 -0
- package/src/services/svm/utils/pdas/index.ts +12 -0
- package/src/services/svm/utils/pdas/receiver.ts +58 -0
- package/src/services/svm/utils/pdas/rmnRemote.ts +23 -0
- package/src/services/svm/utils/pdas/router.ts +328 -0
- package/src/services/svm/utils/pdas/tokenpool.ts +161 -0
- package/src/services/svm/utils/transaction.ts +132 -0
- package/src/utils/validation.ts +7 -3
- package/tsconfig.json +2 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Logger } from "../../utils/logger";
|
|
2
|
+
import { ExtraArgsOptions } from "../models";
|
|
3
|
+
import { BN } from "@coral-xyz/anchor";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates extra arguments for CCIP send
|
|
7
|
+
* @param options Extra args options
|
|
8
|
+
* @param logger Optional logger instance
|
|
9
|
+
* @returns Buffer with encoded extra args
|
|
10
|
+
*/
|
|
11
|
+
export function createExtraArgs(
|
|
12
|
+
options?: ExtraArgsOptions,
|
|
13
|
+
logger?: Logger
|
|
14
|
+
): Buffer {
|
|
15
|
+
if (logger) {
|
|
16
|
+
logger.debug(`Creating extraArgs buffer for CCIP message`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// If no options provided, create a default buffer with allowOutOfOrderExecution=true
|
|
20
|
+
if (!options) {
|
|
21
|
+
if (logger) {
|
|
22
|
+
logger.warn(
|
|
23
|
+
`No options provided, creating default extraArgs with allowOutOfOrderExecution=true to avoid error 8030`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Use the GENERIC_EXTRA_ARGS_V2_TAG which is bytes4(keccak256("CCIP EVMExtraArgsV2"))
|
|
28
|
+
const typeTag = Buffer.from([0x18, 0x1d, 0xcf, 0x10]);
|
|
29
|
+
|
|
30
|
+
// Default gas limit of 0 in little-endian format (16 bytes)
|
|
31
|
+
const gasLimitLE = Buffer.alloc(16, 0);
|
|
32
|
+
|
|
33
|
+
// Boolean true (1) for allowOutOfOrderExecution
|
|
34
|
+
const allowOutOfOrderExecutionByte = Buffer.from([1]);
|
|
35
|
+
|
|
36
|
+
// Concatenate for a properly formatted default buffer
|
|
37
|
+
const argsData = Buffer.concat([gasLimitLE, allowOutOfOrderExecutionByte]);
|
|
38
|
+
const result = Buffer.concat([typeTag, argsData]);
|
|
39
|
+
|
|
40
|
+
if (logger) {
|
|
41
|
+
logger.trace(
|
|
42
|
+
`Created default extraArgs buffer with allowOutOfOrderExecution=true`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Get values from options with defaults
|
|
50
|
+
const gasLimit = options.gasLimit || 0;
|
|
51
|
+
|
|
52
|
+
// Handle the three cases for allowOutOfOrderExecution:
|
|
53
|
+
// 1. Undefined - we'll use true but inform the user
|
|
54
|
+
// 2. Explicitly false - we'll override to true with warning
|
|
55
|
+
// 3. Explicitly true - we'll use it as is
|
|
56
|
+
|
|
57
|
+
let warningMessage: string | null = null;
|
|
58
|
+
|
|
59
|
+
if (options.allowOutOfOrderExecution === undefined) {
|
|
60
|
+
// If undefined, we'll use true but log a message about the default behavior
|
|
61
|
+
warningMessage = `allowOutOfOrderExecution not specified, defaulting to true to avoid FeeQuoter error 8030`;
|
|
62
|
+
} else if (options.allowOutOfOrderExecution === false) {
|
|
63
|
+
// If explicitly false, we'll override it with a warning
|
|
64
|
+
warningMessage = `allowOutOfOrderExecution=false was explicitly specified but is not supported by FeeQuoter. Forcing to true to avoid error 8030.`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Log warning if needed
|
|
68
|
+
if (warningMessage && logger) {
|
|
69
|
+
logger.warn(warningMessage);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Always use true regardless of what was specified
|
|
73
|
+
const allowOutOfOrderExecution = true;
|
|
74
|
+
|
|
75
|
+
// Log what we're doing
|
|
76
|
+
if (logger) {
|
|
77
|
+
const forcedMsg =
|
|
78
|
+
options.allowOutOfOrderExecution === false
|
|
79
|
+
? " (forced)"
|
|
80
|
+
: options.allowOutOfOrderExecution === undefined
|
|
81
|
+
? " (default)"
|
|
82
|
+
: "";
|
|
83
|
+
logger.debug(
|
|
84
|
+
`ExtraArgs options - gasLimit: ${gasLimit}, allowOutOfOrderExecution: true${forcedMsg}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Use the GENERIC_EXTRA_ARGS_V2_TAG which is bytes4(keccak256("CCIP EVMExtraArgsV2"))
|
|
89
|
+
// 0x181dcf10 in big-endian format
|
|
90
|
+
const typeTag = Buffer.from([0x18, 0x1d, 0xcf, 0x10]);
|
|
91
|
+
if (logger) {
|
|
92
|
+
logger.trace(`Using EVM ExtraArgs V2 type tag: 0x181dcf10`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Now we need to construct the serialized version of GenericExtraArgsV2
|
|
96
|
+
// Based on Anchor's serialization format:
|
|
97
|
+
// 1. gas_limit (u128) - 16 bytes
|
|
98
|
+
// 2. allow_out_of_order_execution (bool) - 1 byte (1 = true, 0 = false)
|
|
99
|
+
|
|
100
|
+
// Convert gas limit to little-endian bytes (Anchor uses little endian)
|
|
101
|
+
const gasLimitLE = new BN(gasLimit).toArrayLike(Buffer, "le", 16);
|
|
102
|
+
|
|
103
|
+
if (logger) {
|
|
104
|
+
logger.trace(
|
|
105
|
+
`Gas limit buffer (LE, 16 bytes): 0x${gasLimitLE.toString("hex")}`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Create bool byte for allowOutOfOrderExecution - ALWAYS true (1)
|
|
110
|
+
const allowOutOfOrderExecutionByte = Buffer.from([1]);
|
|
111
|
+
|
|
112
|
+
if (logger) {
|
|
113
|
+
logger.trace(`AllowOutOfOrderExecution byte: 0x01 (true)`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Concatenate for the data part: gasLimit (LE) + allowOutOfOrderExecution
|
|
117
|
+
const argsData = Buffer.concat([gasLimitLE, allowOutOfOrderExecutionByte]);
|
|
118
|
+
|
|
119
|
+
// Final buffer is tag + serialized args
|
|
120
|
+
const result = Buffer.concat([typeTag, argsData]);
|
|
121
|
+
|
|
122
|
+
if (logger) {
|
|
123
|
+
logger.trace(
|
|
124
|
+
`Final extraArgs buffer (${result.length} bytes): 0x${result.toString(
|
|
125
|
+
"hex"
|
|
126
|
+
)}`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PublicKey,
|
|
3
|
+
Keypair,
|
|
4
|
+
Connection,
|
|
5
|
+
Transaction,
|
|
6
|
+
VersionedTransaction,
|
|
7
|
+
} from "@solana/web3.js";
|
|
8
|
+
import { BN } from "@coral-xyz/anchor";
|
|
9
|
+
import { LogLevel } from "../utils/logger";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* CCIP Send Request
|
|
13
|
+
*/
|
|
14
|
+
export interface CCIPSendRequest {
|
|
15
|
+
readonly destChainSelector: BN;
|
|
16
|
+
readonly receiver: Uint8Array;
|
|
17
|
+
readonly data: Uint8Array;
|
|
18
|
+
readonly tokenAmounts: {
|
|
19
|
+
readonly token: PublicKey;
|
|
20
|
+
readonly amount: BN;
|
|
21
|
+
}[];
|
|
22
|
+
readonly feeToken: PublicKey;
|
|
23
|
+
readonly extraArgs: Uint8Array;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* CCIP Fee Request
|
|
28
|
+
*/
|
|
29
|
+
export interface CCIPFeeRequest {
|
|
30
|
+
readonly destChainSelector: BN;
|
|
31
|
+
readonly message: {
|
|
32
|
+
readonly receiver: Uint8Array;
|
|
33
|
+
readonly data: Uint8Array;
|
|
34
|
+
readonly tokenAmounts: {
|
|
35
|
+
readonly token: PublicKey;
|
|
36
|
+
readonly amount: BN;
|
|
37
|
+
}[];
|
|
38
|
+
readonly feeToken: PublicKey;
|
|
39
|
+
readonly extraArgs: Uint8Array;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Result of a fee calculation
|
|
45
|
+
*/
|
|
46
|
+
export interface GetFeeResult {
|
|
47
|
+
token: PublicKey;
|
|
48
|
+
amount: BN;
|
|
49
|
+
juels: BN;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Result of a CCIP send with message ID
|
|
54
|
+
*/
|
|
55
|
+
export interface CCIPSendResult {
|
|
56
|
+
txSignature: string;
|
|
57
|
+
messageId?: string;
|
|
58
|
+
destinationChainSelector?: string;
|
|
59
|
+
sequenceNumber?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Extra arguments for CCIP send
|
|
64
|
+
*/
|
|
65
|
+
export interface ExtraArgsV1 {
|
|
66
|
+
gasLimit: number;
|
|
67
|
+
strict: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Options for creating extra arguments
|
|
72
|
+
*/
|
|
73
|
+
export interface ExtraArgsOptions {
|
|
74
|
+
gasLimit?: number;
|
|
75
|
+
allowOutOfOrderExecution?: boolean;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Options for CCIPClient configuration
|
|
80
|
+
*/
|
|
81
|
+
export interface CCIPClientOptions {
|
|
82
|
+
/**
|
|
83
|
+
* Log level for the client
|
|
84
|
+
* @default LogLevel.INFO
|
|
85
|
+
*/
|
|
86
|
+
logLevel?: LogLevel;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Options for sending CCIP messages
|
|
91
|
+
*/
|
|
92
|
+
export interface CCIPSendOptions {
|
|
93
|
+
/**
|
|
94
|
+
* Whether to skip the preflight transaction check
|
|
95
|
+
* @default false
|
|
96
|
+
*/
|
|
97
|
+
skipPreflight?: boolean;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Provider interface to abstract wallet and connection
|
|
102
|
+
*/
|
|
103
|
+
export interface CCIPProvider {
|
|
104
|
+
/** Solana RPC connection */
|
|
105
|
+
connection: Connection;
|
|
106
|
+
|
|
107
|
+
/** Wallet or keypair for signing transactions */
|
|
108
|
+
wallet: Keypair;
|
|
109
|
+
|
|
110
|
+
/** Get the public key address of the signer */
|
|
111
|
+
getAddress(): PublicKey;
|
|
112
|
+
|
|
113
|
+
/** Sign a transaction */
|
|
114
|
+
signTransaction(
|
|
115
|
+
tx: Transaction | VersionedTransaction,
|
|
116
|
+
): Promise<Transaction | VersionedTransaction>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Core configuration needed by all CCIP modules
|
|
121
|
+
*/
|
|
122
|
+
export interface CCIPCoreConfig {
|
|
123
|
+
/** CCIP Router program ID */
|
|
124
|
+
ccipRouterProgramId: PublicKey;
|
|
125
|
+
|
|
126
|
+
/** Fee Quoter program ID */
|
|
127
|
+
feeQuoterProgramId: PublicKey;
|
|
128
|
+
|
|
129
|
+
/** RMN Remote program ID */
|
|
130
|
+
rmnRemoteProgramId: PublicKey;
|
|
131
|
+
|
|
132
|
+
/** LINK token mint */
|
|
133
|
+
linkTokenMint: PublicKey;
|
|
134
|
+
|
|
135
|
+
/** Token mint for the application */
|
|
136
|
+
tokenMint: PublicKey;
|
|
137
|
+
|
|
138
|
+
/** Native SOL public key */
|
|
139
|
+
nativeSol: PublicKey;
|
|
140
|
+
|
|
141
|
+
/** System program ID */
|
|
142
|
+
systemProgramId: PublicKey;
|
|
143
|
+
|
|
144
|
+
/** CCIP receiver program ID */
|
|
145
|
+
programId: PublicKey;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Combined context with provider, config and logger
|
|
150
|
+
*/
|
|
151
|
+
export interface CCIPContext {
|
|
152
|
+
/** Provider for connecting to the blockchain */
|
|
153
|
+
provider: CCIPProvider;
|
|
154
|
+
|
|
155
|
+
/** Core configuration */
|
|
156
|
+
config: CCIPCoreConfig;
|
|
157
|
+
|
|
158
|
+
/** Optional logger */
|
|
159
|
+
logger?: Logger;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Options for creating a CCIP client from a keypair
|
|
164
|
+
*/
|
|
165
|
+
export interface CCIPClientKeypairOptions {
|
|
166
|
+
/** Path to keypair file */
|
|
167
|
+
keypairPath: string;
|
|
168
|
+
|
|
169
|
+
/** Core configuration */
|
|
170
|
+
config: CCIPCoreConfig;
|
|
171
|
+
|
|
172
|
+
/** Log level */
|
|
173
|
+
logLevel?: LogLevel;
|
|
174
|
+
|
|
175
|
+
/** RPC endpoint URL */
|
|
176
|
+
endpoint?: string;
|
|
177
|
+
|
|
178
|
+
/** Commitment level */
|
|
179
|
+
commitment?: string;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Logger interface imported from logger.ts
|
|
184
|
+
*/
|
|
185
|
+
export interface Logger {
|
|
186
|
+
trace(...message: any[]): void;
|
|
187
|
+
debug(...message: any[]): void;
|
|
188
|
+
info(...message: any[]): void;
|
|
189
|
+
warn(...message: any[]): void;
|
|
190
|
+
error(...message: any[]): void;
|
|
191
|
+
setLevel(level: LogLevel): void;
|
|
192
|
+
getLevel(): LogLevel;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Rate limit configuration for token pools in user-friendly format
|
|
197
|
+
*/
|
|
198
|
+
export interface TokenPoolRateLimitConfig {
|
|
199
|
+
/** Whether rate limiting is enabled */
|
|
200
|
+
isEnabled: boolean;
|
|
201
|
+
/** Maximum capacity of the rate limit bucket */
|
|
202
|
+
capacity: bigint;
|
|
203
|
+
/** Refill rate of tokens per second */
|
|
204
|
+
rate: bigint;
|
|
205
|
+
/** Last updated timestamp */
|
|
206
|
+
lastTxTimestamp: bigint;
|
|
207
|
+
/** Current number of tokens in the bucket */
|
|
208
|
+
currentBucketValue: bigint;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Chain configuration for burn-mint token pools with consistent naming
|
|
213
|
+
*/
|
|
214
|
+
export interface TokenPoolChainConfigResponse {
|
|
215
|
+
/** Chain config account address */
|
|
216
|
+
address: string;
|
|
217
|
+
/** Base configuration data */
|
|
218
|
+
base: {
|
|
219
|
+
/** Token decimals on remote chain */
|
|
220
|
+
decimals: number;
|
|
221
|
+
/** Pool addresses on remote chain */
|
|
222
|
+
poolAddresses: Array<{
|
|
223
|
+
/** Hex encoded address */
|
|
224
|
+
address: string;
|
|
225
|
+
}>;
|
|
226
|
+
/** Token address on remote chain */
|
|
227
|
+
tokenAddress: {
|
|
228
|
+
/** Hex encoded address */
|
|
229
|
+
address: string;
|
|
230
|
+
};
|
|
231
|
+
/** Inbound rate limit configuration */
|
|
232
|
+
inboundRateLimit: TokenPoolRateLimitConfig;
|
|
233
|
+
/** Outbound rate limit configuration */
|
|
234
|
+
outboundRateLimit: TokenPoolRateLimitConfig;
|
|
235
|
+
};
|
|
236
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Core components
|
|
2
|
+
export * from "./core/client/accounts";
|
|
3
|
+
export * from "./core/client/index";
|
|
4
|
+
|
|
5
|
+
// Export models with specific names to avoid conflicts
|
|
6
|
+
export type {
|
|
7
|
+
CCIPClientOptions,
|
|
8
|
+
CCIPSendRequest,
|
|
9
|
+
CCIPSendOptions,
|
|
10
|
+
CCIPFeeRequest,
|
|
11
|
+
CCIPSendResult,
|
|
12
|
+
ExtraArgsOptions,
|
|
13
|
+
ExtraArgsV1,
|
|
14
|
+
CCIPProvider,
|
|
15
|
+
CCIPCoreConfig,
|
|
16
|
+
CCIPContext,
|
|
17
|
+
CCIPClientKeypairOptions,
|
|
18
|
+
} from "./core/models";
|
|
19
|
+
|
|
20
|
+
// Utilities
|
|
21
|
+
export * from "./utils/pdas";
|
|
22
|
+
export * from "./utils/logger";
|
|
23
|
+
export * from "./utils/errors";
|
|
24
|
+
export * from "./utils/conversion";
|
|
25
|
+
export * from "./utils/keypair";
|
|
26
|
+
|
|
27
|
+
// Bindings exports
|
|
28
|
+
export * from "./bindings/types";
|
|
29
|
+
export * from "./bindings/accounts";
|
|
30
|
+
|
|
31
|
+
// Export version
|
|
32
|
+
export const SDK_VERSION = "0.1.0";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for Solana to EVM address conversion
|
|
3
|
+
*/
|
|
4
|
+
export class AddressConversion {
|
|
5
|
+
/**
|
|
6
|
+
* Converts an EVM address string (0x-prefixed) into a 32-byte left-padded Uint8Array.
|
|
7
|
+
* Required for EVM-to-Solana compatibility in programs expecting 32-byte addresses.
|
|
8
|
+
* @param evmAddress EVM address (0x-prefixed)
|
|
9
|
+
* @returns 32-byte padded address as Uint8Array
|
|
10
|
+
*/
|
|
11
|
+
static evmAddressToSolanaBytes(evmAddress: string): Uint8Array {
|
|
12
|
+
return this.leftPadBytes(this.hexToBytes(evmAddress), 32);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Pretty prints a byte array as a 0x-prefixed hex string
|
|
17
|
+
* @param bytes Byte array
|
|
18
|
+
* @returns Hex string
|
|
19
|
+
*/
|
|
20
|
+
static bytesToHexString(bytes: Uint8Array): string {
|
|
21
|
+
return '0x' + Buffer.from(bytes).toString('hex');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Converts a hex string to a byte array
|
|
26
|
+
* @param hex Hex string
|
|
27
|
+
* @returns Byte array
|
|
28
|
+
*/
|
|
29
|
+
private static hexToBytes(hex: string): Uint8Array {
|
|
30
|
+
if (hex.startsWith('0x')) hex = hex.slice(2);
|
|
31
|
+
if (hex.length !== 40) throw new Error('Invalid Ethereum address length');
|
|
32
|
+
const bytes = new Uint8Array(20);
|
|
33
|
+
for (let i = 0; i < 40; i += 2) {
|
|
34
|
+
bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
|
|
35
|
+
}
|
|
36
|
+
return bytes;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Left pads a byte array to a specified length
|
|
41
|
+
* @param data Data to pad
|
|
42
|
+
* @param length Target length
|
|
43
|
+
* @returns Padded byte array
|
|
44
|
+
*/
|
|
45
|
+
private static leftPadBytes(data: Uint8Array, length: number): Uint8Array {
|
|
46
|
+
if (data.length > length) throw new Error('Data too long to pad');
|
|
47
|
+
const padded = new Uint8Array(length);
|
|
48
|
+
padded.set(data, length - data.length);
|
|
49
|
+
return padded;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Creates a buffer from a BigInt
|
|
55
|
+
* @param value BigInt value
|
|
56
|
+
* @returns Buffer
|
|
57
|
+
*/
|
|
58
|
+
export function createBufferFromBigInt(value: bigint): Buffer {
|
|
59
|
+
const buffer = Buffer.alloc(8);
|
|
60
|
+
buffer.writeBigUInt64LE(value);
|
|
61
|
+
return buffer;
|
|
62
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Logger } from "./logger";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base CCIP error class for standardized error handling
|
|
5
|
+
*/
|
|
6
|
+
export class CCIPError extends Error {
|
|
7
|
+
constructor(message: string, public context?: Record<string, unknown>) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "CCIPError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Enhances an error with additional context for better diagnostics
|
|
15
|
+
* @param error Original error
|
|
16
|
+
* @param context Additional context to add
|
|
17
|
+
* @param logger Optional logger instance
|
|
18
|
+
* @returns Enhanced error with context attached
|
|
19
|
+
*/
|
|
20
|
+
export function enhanceError(
|
|
21
|
+
error: unknown,
|
|
22
|
+
context: Record<string, unknown>,
|
|
23
|
+
logger?: Logger
|
|
24
|
+
): Error {
|
|
25
|
+
const enhancedError =
|
|
26
|
+
error instanceof Error ? error : new Error(String(error));
|
|
27
|
+
|
|
28
|
+
// Attach context to the error
|
|
29
|
+
(enhancedError as any).context = context;
|
|
30
|
+
|
|
31
|
+
// Log the enhanced error if a logger is provided
|
|
32
|
+
if (logger) {
|
|
33
|
+
logger.error(`Error: ${enhancedError.message}`, {
|
|
34
|
+
context,
|
|
35
|
+
stack: enhancedError.stack,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return enhancedError;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Creates a type-safe error enhancer bound to a specific logger instance
|
|
44
|
+
* @param logger Logger instance to use for error logging
|
|
45
|
+
* @returns A function that enhances errors with context
|
|
46
|
+
*/
|
|
47
|
+
export function createErrorEnhancer(logger: Logger) {
|
|
48
|
+
return (error: unknown, context: Record<string, unknown>): Error => {
|
|
49
|
+
return enhanceError(error, context, logger);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Keypair } from "@solana/web3.js";
|
|
2
|
+
|
|
3
|
+
// Default file paths
|
|
4
|
+
export const DEFAULT_KEYPAIR_PATH = "";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Loads a keypair from a file
|
|
8
|
+
* @param filePath Path to keypair file
|
|
9
|
+
* @returns Keypair
|
|
10
|
+
*/
|
|
11
|
+
export function loadKeypair(filePath: string = DEFAULT_KEYPAIR_PATH): Keypair {
|
|
12
|
+
try {
|
|
13
|
+
const keypairJson = JSON.parse("keypairData");
|
|
14
|
+
return Keypair.fromSecretKey(Buffer.from(keypairJson));
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error(`Error loading keypair from ${filePath}:`, error);
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import loglevel from 'loglevel';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Log levels available in the CCIP SDK
|
|
5
|
+
*/
|
|
6
|
+
export enum LogLevel {
|
|
7
|
+
TRACE = 0,
|
|
8
|
+
DEBUG = 1,
|
|
9
|
+
INFO = 2,
|
|
10
|
+
WARN = 3,
|
|
11
|
+
ERROR = 4,
|
|
12
|
+
SILENT = 5
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* SDK logging namespace prefix
|
|
17
|
+
*/
|
|
18
|
+
export const NAMESPACE = 'ccip';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Logger interface with all available logging methods
|
|
22
|
+
*/
|
|
23
|
+
export interface Logger {
|
|
24
|
+
trace(...message: any[]): void;
|
|
25
|
+
debug(...message: any[]): void;
|
|
26
|
+
info(...message: any[]): void;
|
|
27
|
+
warn(...message: any[]): void;
|
|
28
|
+
error(...message: any[]): void;
|
|
29
|
+
setLevel(level: LogLevel): void;
|
|
30
|
+
getLevel(): LogLevel;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Logger options for configuration
|
|
35
|
+
*/
|
|
36
|
+
export interface LoggerOptions {
|
|
37
|
+
level?: LogLevel;
|
|
38
|
+
timestamps?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Default logger options
|
|
43
|
+
*/
|
|
44
|
+
const DEFAULT_OPTIONS: LoggerOptions = {
|
|
45
|
+
level: LogLevel.INFO,
|
|
46
|
+
timestamps: true
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a namespaced logger with the given component name
|
|
51
|
+
* @param component Component name to create a logger for
|
|
52
|
+
* @param options Logger configuration options
|
|
53
|
+
* @returns A configured logger instance
|
|
54
|
+
*/
|
|
55
|
+
export function createLogger(component: string, options?: LoggerOptions): Logger {
|
|
56
|
+
const fullOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
57
|
+
const loggerName = component ? `${NAMESPACE}:${component}` : NAMESPACE;
|
|
58
|
+
|
|
59
|
+
// Get the underlying loglevel logger
|
|
60
|
+
const baseLogger = loglevel.getLogger(loggerName);
|
|
61
|
+
|
|
62
|
+
// Set the initial level
|
|
63
|
+
baseLogger.setLevel(fullOptions.level as unknown as loglevel.LogLevelDesc);
|
|
64
|
+
|
|
65
|
+
// Create our wrapper logger with timestamps if enabled
|
|
66
|
+
const logger: Logger = {
|
|
67
|
+
trace: createLogMethod(baseLogger, 'trace', fullOptions),
|
|
68
|
+
debug: createLogMethod(baseLogger, 'debug', fullOptions),
|
|
69
|
+
info: createLogMethod(baseLogger, 'info', fullOptions),
|
|
70
|
+
warn: createLogMethod(baseLogger, 'warn', fullOptions),
|
|
71
|
+
error: createLogMethod(baseLogger, 'error', fullOptions),
|
|
72
|
+
|
|
73
|
+
setLevel(level: LogLevel) {
|
|
74
|
+
baseLogger.setLevel(level as unknown as loglevel.LogLevelDesc);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
getLevel(): LogLevel {
|
|
78
|
+
return baseLogger.getLevel() as unknown as LogLevel;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return logger;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Create a log method with optional timestamp
|
|
87
|
+
*/
|
|
88
|
+
function createLogMethod(
|
|
89
|
+
logger: loglevel.Logger,
|
|
90
|
+
method: 'trace' | 'debug' | 'info' | 'warn' | 'error',
|
|
91
|
+
options: LoggerOptions
|
|
92
|
+
): (...args: any[]) => void {
|
|
93
|
+
return function(...args: any[]) {
|
|
94
|
+
// Skip logging if the current level is higher than this method's level
|
|
95
|
+
const methodLevel = getMethodLogLevel(method);
|
|
96
|
+
if (methodLevel < (logger.getLevel() as unknown as LogLevel)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (options.timestamps) {
|
|
101
|
+
const timestamp = new Date().toISOString();
|
|
102
|
+
|
|
103
|
+
// For trace level, customize the output to avoid showing stack traces
|
|
104
|
+
if (method === 'trace') {
|
|
105
|
+
// Format objects for better readability
|
|
106
|
+
const formattedArgs = args.map(arg => {
|
|
107
|
+
if (typeof arg === 'object' && arg !== null) {
|
|
108
|
+
return JSON.stringify(arg, null, 2);
|
|
109
|
+
}
|
|
110
|
+
return arg;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Use console.log directly with a prefix for trace level
|
|
114
|
+
console.log(`TRACE: [${timestamp}]`, ...formattedArgs);
|
|
115
|
+
} else {
|
|
116
|
+
// Use loglevel for other log levels
|
|
117
|
+
logger[method](`[${timestamp}]`, ...args);
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
if (method === 'trace') {
|
|
121
|
+
// Format objects for better readability
|
|
122
|
+
const formattedArgs = args.map(arg => {
|
|
123
|
+
if (typeof arg === 'object' && arg !== null) {
|
|
124
|
+
return JSON.stringify(arg, null, 2);
|
|
125
|
+
}
|
|
126
|
+
return arg;
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Use console.log directly without timestamps
|
|
130
|
+
console.log(`TRACE:`, ...formattedArgs);
|
|
131
|
+
} else {
|
|
132
|
+
// Use loglevel for other log levels
|
|
133
|
+
logger[method](...args);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Convert method name to LogLevel enum value
|
|
141
|
+
*/
|
|
142
|
+
function getMethodLogLevel(method: 'trace' | 'debug' | 'info' | 'warn' | 'error'): LogLevel {
|
|
143
|
+
switch (method) {
|
|
144
|
+
case 'trace': return LogLevel.TRACE;
|
|
145
|
+
case 'debug': return LogLevel.DEBUG;
|
|
146
|
+
case 'info': return LogLevel.INFO;
|
|
147
|
+
case 'warn': return LogLevel.WARN;
|
|
148
|
+
case 'error': return LogLevel.ERROR;
|
|
149
|
+
default: return LogLevel.INFO;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Root SDK logger instance
|
|
155
|
+
*/
|
|
156
|
+
export const rootLogger = createLogger('');
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Set the global log level for all CCIP loggers
|
|
160
|
+
* @param level The log level to set globally
|
|
161
|
+
*/
|
|
162
|
+
export function setGlobalLogLevel(level: LogLevel): void {
|
|
163
|
+
loglevel.setLevel(level as unknown as loglevel.LogLevelDesc);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Reset all loggers to their default levels
|
|
168
|
+
*/
|
|
169
|
+
export function resetLoggers(): void {
|
|
170
|
+
loglevel.setDefaultLevel(loglevel.levels.INFO);
|
|
171
|
+
}
|