@solana/kora 0.2.0-beta.0 → 0.2.0-beta.2
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/dist/src/client.d.ts +78 -7
- package/dist/src/client.js +89 -7
- package/dist/src/types/index.d.ts +109 -7
- package/dist/test/integration.test.js +101 -49
- package/dist/test/unit.test.js +64 -36
- package/package.json +1 -1
package/dist/src/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Config, EstimateTransactionFeeRequest, EstimateTransactionFeeResponse, GetBlockhashResponse, GetSupportedTokensResponse, SignAndSendTransactionRequest, SignAndSendTransactionResponse, SignTransactionRequest, SignTransactionResponse, TransferTransactionRequest, TransferTransactionResponse, KoraClientOptions, GetPayerSignerResponse, GetPaymentInstructionRequest, GetPaymentInstructionResponse } from './types/index.js';
|
|
1
|
+
import { Config, EstimateTransactionFeeRequest, EstimateTransactionFeeResponse, EstimateBundleFeeRequest, EstimateBundleFeeResponse, GetBlockhashResponse, GetSupportedTokensResponse, GetVersionResponse, SignAndSendTransactionRequest, SignAndSendTransactionResponse, SignTransactionRequest, SignTransactionResponse, SignBundleRequest, SignBundleResponse, SignAndSendBundleRequest, SignAndSendBundleResponse, TransferTransactionRequest, TransferTransactionResponse, KoraClientOptions, GetPayerSignerResponse, GetPaymentInstructionRequest, GetPaymentInstructionResponse } from './types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Kora RPC client for interacting with the Kora paymaster service.
|
|
4
4
|
*
|
|
@@ -67,6 +67,18 @@ export declare class KoraClient {
|
|
|
67
67
|
* ```
|
|
68
68
|
*/
|
|
69
69
|
getBlockhash(): Promise<GetBlockhashResponse>;
|
|
70
|
+
/**
|
|
71
|
+
* Gets the version of the Kora server.
|
|
72
|
+
* @returns Object containing the server version
|
|
73
|
+
* @throws {Error} When the RPC call fails
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const { version } = await client.getVersion();
|
|
78
|
+
* console.log('Server version:', version);
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
getVersion(): Promise<GetVersionResponse>;
|
|
70
82
|
/**
|
|
71
83
|
* Retrieves the list of tokens supported for fee payment.
|
|
72
84
|
* @returns Object containing an array of supported token mint addresses
|
|
@@ -99,6 +111,25 @@ export declare class KoraClient {
|
|
|
99
111
|
* ```
|
|
100
112
|
*/
|
|
101
113
|
estimateTransactionFee(request: EstimateTransactionFeeRequest): Promise<EstimateTransactionFeeResponse>;
|
|
114
|
+
/**
|
|
115
|
+
* Estimates the bundle fee in both lamports and the specified token.
|
|
116
|
+
* @param request - Bundle fee estimation request parameters
|
|
117
|
+
* @param request.transactions - Array of base64-encoded transactions to estimate fees for
|
|
118
|
+
* @param request.fee_token - Mint address of the token to calculate fees in
|
|
119
|
+
* @returns Total fee amounts across all transactions in both lamports and the specified token
|
|
120
|
+
* @throws {Error} When the RPC call fails, the bundle is invalid, or the token is not supported
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const fees = await client.estimateBundleFee({
|
|
125
|
+
* transactions: ['base64EncodedTransaction1', 'base64EncodedTransaction2'],
|
|
126
|
+
* fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC
|
|
127
|
+
* });
|
|
128
|
+
* console.log('Total fee in lamports:', fees.fee_in_lamports);
|
|
129
|
+
* console.log('Total fee in USDC:', fees.fee_in_token);
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
estimateBundleFee(request: EstimateBundleFeeRequest): Promise<EstimateBundleFeeResponse>;
|
|
102
133
|
/**
|
|
103
134
|
* Signs a transaction with the Kora fee payer without broadcasting it.
|
|
104
135
|
* @param request - Sign request parameters
|
|
@@ -133,13 +164,55 @@ export declare class KoraClient {
|
|
|
133
164
|
*/
|
|
134
165
|
signAndSendTransaction(request: SignAndSendTransactionRequest): Promise<SignAndSendTransactionResponse>;
|
|
135
166
|
/**
|
|
136
|
-
*
|
|
167
|
+
* Signs a bundle of transactions with the Kora fee payer without broadcasting.
|
|
168
|
+
* @param request - Sign bundle request parameters
|
|
169
|
+
* @param request.transactions - Array of base64-encoded transactions to sign
|
|
170
|
+
* @param request.signer_key - Optional signer address for the transactions
|
|
171
|
+
* @param request.sig_verify - Optional signature verification (defaults to false)
|
|
172
|
+
* @returns Array of signed transactions and signer public key
|
|
173
|
+
* @throws {Error} When the RPC call fails or validation fails
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* const result = await client.signBundle({
|
|
178
|
+
* transactions: ['base64Tx1', 'base64Tx2']
|
|
179
|
+
* });
|
|
180
|
+
* console.log('Signed transactions:', result.signed_transactions);
|
|
181
|
+
* console.log('Signer:', result.signer_pubkey);
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
signBundle(request: SignBundleRequest): Promise<SignBundleResponse>;
|
|
185
|
+
/**
|
|
186
|
+
* Signs a bundle of transactions and sends them to Jito block engine.
|
|
187
|
+
* @param request - Sign and send bundle request parameters
|
|
188
|
+
* @param request.transactions - Array of base64-encoded transactions to sign and send
|
|
189
|
+
* @param request.signer_key - Optional signer address for the transactions
|
|
190
|
+
* @param request.sig_verify - Optional signature verification (defaults to false)
|
|
191
|
+
* @returns Array of signed transactions, signer public key, and Jito bundle UUID
|
|
192
|
+
* @throws {Error} When the RPC call fails, validation fails, or Jito submission fails
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const result = await client.signAndSendBundle({
|
|
197
|
+
* transactions: ['base64Tx1', 'base64Tx2']
|
|
198
|
+
* });
|
|
199
|
+
* console.log('Bundle UUID:', result.bundle_uuid);
|
|
200
|
+
* console.log('Signed transactions:', result.signed_transactions);
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
signAndSendBundle(request: SignAndSendBundleRequest): Promise<SignAndSendBundleResponse>;
|
|
204
|
+
/**
|
|
205
|
+
* Creates an unsigned transfer transaction.
|
|
206
|
+
*
|
|
207
|
+
* @deprecated Use `getPaymentInstruction` instead for fee payment flows.
|
|
208
|
+
*
|
|
137
209
|
* @param request - Transfer request parameters
|
|
138
210
|
* @param request.amount - Amount to transfer (in token's smallest unit)
|
|
139
211
|
* @param request.token - Mint address of the token to transfer
|
|
140
212
|
* @param request.source - Source wallet public key
|
|
141
213
|
* @param request.destination - Destination wallet public key
|
|
142
|
-
* @
|
|
214
|
+
* @param request.signer_key - Optional signer key to select specific Kora signer
|
|
215
|
+
* @returns Unsigned transaction, message, blockhash, and signer info
|
|
143
216
|
* @throws {Error} When the RPC call fails or token is not supported
|
|
144
217
|
*
|
|
145
218
|
* @example
|
|
@@ -148,11 +221,9 @@ export declare class KoraClient {
|
|
|
148
221
|
* amount: 1000000, // 1 USDC (6 decimals)
|
|
149
222
|
* token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
150
223
|
* source: 'sourceWalletPublicKey',
|
|
151
|
-
* destination: 'destinationWalletPublicKey'
|
|
224
|
+
* destination: 'destinationWalletPublicKey',
|
|
152
225
|
* });
|
|
153
|
-
* console.log('
|
|
154
|
-
* console.log('Message:', transfer.message);
|
|
155
|
-
* console.log('Instructions:', transfer.instructions);
|
|
226
|
+
* console.log('Signer:', transfer.signer_pubkey);
|
|
156
227
|
* ```
|
|
157
228
|
*/
|
|
158
229
|
transferTransaction(request: TransferTransactionRequest): Promise<TransferTransactionResponse>;
|
package/dist/src/client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { assertIsAddress, createNoopSigner } from '@solana/kit';
|
|
2
2
|
import crypto from 'crypto';
|
|
3
|
-
import { getInstructionsFromBase64Message } from './utils/transaction.js';
|
|
4
3
|
import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS, getTransferInstruction } from '@solana-program/token';
|
|
4
|
+
import { getInstructionsFromBase64Message } from './utils/transaction.js';
|
|
5
5
|
/**
|
|
6
6
|
* Kora RPC client for interacting with the Kora paymaster service.
|
|
7
7
|
*
|
|
@@ -117,6 +117,20 @@ export class KoraClient {
|
|
|
117
117
|
async getBlockhash() {
|
|
118
118
|
return this.rpcRequest('getBlockhash', undefined);
|
|
119
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Gets the version of the Kora server.
|
|
122
|
+
* @returns Object containing the server version
|
|
123
|
+
* @throws {Error} When the RPC call fails
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* const { version } = await client.getVersion();
|
|
128
|
+
* console.log('Server version:', version);
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
async getVersion() {
|
|
132
|
+
return this.rpcRequest('getVersion', undefined);
|
|
133
|
+
}
|
|
120
134
|
/**
|
|
121
135
|
* Retrieves the list of tokens supported for fee payment.
|
|
122
136
|
* @returns Object containing an array of supported token mint addresses
|
|
@@ -153,6 +167,27 @@ export class KoraClient {
|
|
|
153
167
|
async estimateTransactionFee(request) {
|
|
154
168
|
return this.rpcRequest('estimateTransactionFee', request);
|
|
155
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Estimates the bundle fee in both lamports and the specified token.
|
|
172
|
+
* @param request - Bundle fee estimation request parameters
|
|
173
|
+
* @param request.transactions - Array of base64-encoded transactions to estimate fees for
|
|
174
|
+
* @param request.fee_token - Mint address of the token to calculate fees in
|
|
175
|
+
* @returns Total fee amounts across all transactions in both lamports and the specified token
|
|
176
|
+
* @throws {Error} When the RPC call fails, the bundle is invalid, or the token is not supported
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* const fees = await client.estimateBundleFee({
|
|
181
|
+
* transactions: ['base64EncodedTransaction1', 'base64EncodedTransaction2'],
|
|
182
|
+
* fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC
|
|
183
|
+
* });
|
|
184
|
+
* console.log('Total fee in lamports:', fees.fee_in_lamports);
|
|
185
|
+
* console.log('Total fee in USDC:', fees.fee_in_token);
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
async estimateBundleFee(request) {
|
|
189
|
+
return this.rpcRequest('estimateBundleFee', request);
|
|
190
|
+
}
|
|
156
191
|
/**
|
|
157
192
|
* Signs a transaction with the Kora fee payer without broadcasting it.
|
|
158
193
|
* @param request - Sign request parameters
|
|
@@ -191,13 +226,59 @@ export class KoraClient {
|
|
|
191
226
|
return this.rpcRequest('signAndSendTransaction', request);
|
|
192
227
|
}
|
|
193
228
|
/**
|
|
194
|
-
*
|
|
229
|
+
* Signs a bundle of transactions with the Kora fee payer without broadcasting.
|
|
230
|
+
* @param request - Sign bundle request parameters
|
|
231
|
+
* @param request.transactions - Array of base64-encoded transactions to sign
|
|
232
|
+
* @param request.signer_key - Optional signer address for the transactions
|
|
233
|
+
* @param request.sig_verify - Optional signature verification (defaults to false)
|
|
234
|
+
* @returns Array of signed transactions and signer public key
|
|
235
|
+
* @throws {Error} When the RPC call fails or validation fails
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```typescript
|
|
239
|
+
* const result = await client.signBundle({
|
|
240
|
+
* transactions: ['base64Tx1', 'base64Tx2']
|
|
241
|
+
* });
|
|
242
|
+
* console.log('Signed transactions:', result.signed_transactions);
|
|
243
|
+
* console.log('Signer:', result.signer_pubkey);
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
async signBundle(request) {
|
|
247
|
+
return this.rpcRequest('signBundle', request);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Signs a bundle of transactions and sends them to Jito block engine.
|
|
251
|
+
* @param request - Sign and send bundle request parameters
|
|
252
|
+
* @param request.transactions - Array of base64-encoded transactions to sign and send
|
|
253
|
+
* @param request.signer_key - Optional signer address for the transactions
|
|
254
|
+
* @param request.sig_verify - Optional signature verification (defaults to false)
|
|
255
|
+
* @returns Array of signed transactions, signer public key, and Jito bundle UUID
|
|
256
|
+
* @throws {Error} When the RPC call fails, validation fails, or Jito submission fails
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```typescript
|
|
260
|
+
* const result = await client.signAndSendBundle({
|
|
261
|
+
* transactions: ['base64Tx1', 'base64Tx2']
|
|
262
|
+
* });
|
|
263
|
+
* console.log('Bundle UUID:', result.bundle_uuid);
|
|
264
|
+
* console.log('Signed transactions:', result.signed_transactions);
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
async signAndSendBundle(request) {
|
|
268
|
+
return this.rpcRequest('signAndSendBundle', request);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Creates an unsigned transfer transaction.
|
|
272
|
+
*
|
|
273
|
+
* @deprecated Use `getPaymentInstruction` instead for fee payment flows.
|
|
274
|
+
*
|
|
195
275
|
* @param request - Transfer request parameters
|
|
196
276
|
* @param request.amount - Amount to transfer (in token's smallest unit)
|
|
197
277
|
* @param request.token - Mint address of the token to transfer
|
|
198
278
|
* @param request.source - Source wallet public key
|
|
199
279
|
* @param request.destination - Destination wallet public key
|
|
200
|
-
* @
|
|
280
|
+
* @param request.signer_key - Optional signer key to select specific Kora signer
|
|
281
|
+
* @returns Unsigned transaction, message, blockhash, and signer info
|
|
201
282
|
* @throws {Error} When the RPC call fails or token is not supported
|
|
202
283
|
*
|
|
203
284
|
* @example
|
|
@@ -206,11 +287,9 @@ export class KoraClient {
|
|
|
206
287
|
* amount: 1000000, // 1 USDC (6 decimals)
|
|
207
288
|
* token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
208
289
|
* source: 'sourceWalletPublicKey',
|
|
209
|
-
* destination: 'destinationWalletPublicKey'
|
|
290
|
+
* destination: 'destinationWalletPublicKey',
|
|
210
291
|
* });
|
|
211
|
-
* console.log('
|
|
212
|
-
* console.log('Message:', transfer.message);
|
|
213
|
-
* console.log('Instructions:', transfer.instructions);
|
|
292
|
+
* console.log('Signer:', transfer.signer_pubkey);
|
|
214
293
|
* ```
|
|
215
294
|
*/
|
|
216
295
|
async transferTransaction(request) {
|
|
@@ -268,6 +347,9 @@ export class KoraClient {
|
|
|
268
347
|
tokenProgram: token_program_id,
|
|
269
348
|
mint: fee_token,
|
|
270
349
|
});
|
|
350
|
+
if (fee_in_token === undefined) {
|
|
351
|
+
throw new Error('Fee token was specified but fee_in_token was not returned from server');
|
|
352
|
+
}
|
|
271
353
|
const paymentInstruction = getTransferInstruction({
|
|
272
354
|
source: sourceTokenAccount,
|
|
273
355
|
destination: destinationTokenAccount,
|
|
@@ -3,7 +3,8 @@ import { Instruction } from '@solana/kit';
|
|
|
3
3
|
* Request Types
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* Parameters for creating a
|
|
6
|
+
* Parameters for creating a transfer transaction.
|
|
7
|
+
* @deprecated Use `getPaymentInstruction` instead for fee payment flows.
|
|
7
8
|
*/
|
|
8
9
|
export interface TransferTransactionRequest {
|
|
9
10
|
/** Amount to transfer in the token's smallest unit (e.g., lamports for SOL) */
|
|
@@ -14,7 +15,7 @@ export interface TransferTransactionRequest {
|
|
|
14
15
|
source: string;
|
|
15
16
|
/** Public key of the destination wallet (not token account) */
|
|
16
17
|
destination: string;
|
|
17
|
-
/** Optional signer
|
|
18
|
+
/** Optional signer key to select a specific Kora signer */
|
|
18
19
|
signer_key?: string;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
@@ -39,6 +40,28 @@ export interface SignAndSendTransactionRequest {
|
|
|
39
40
|
/** Optional signer verification during transaction simulation (defaults to false) */
|
|
40
41
|
sig_verify?: boolean;
|
|
41
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Parameters for signing a bundle of transactions.
|
|
45
|
+
*/
|
|
46
|
+
export interface SignBundleRequest {
|
|
47
|
+
/** Array of base64-encoded transactions to sign */
|
|
48
|
+
transactions: string[];
|
|
49
|
+
/** Optional signer address for the transactions */
|
|
50
|
+
signer_key?: string;
|
|
51
|
+
/** Optional signer verification during transaction simulation (defaults to false) */
|
|
52
|
+
sig_verify?: boolean;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Parameters for signing and sending a bundle of transactions via Jito.
|
|
56
|
+
*/
|
|
57
|
+
export interface SignAndSendBundleRequest {
|
|
58
|
+
/** Array of base64-encoded transactions to sign and send */
|
|
59
|
+
transactions: string[];
|
|
60
|
+
/** Optional signer address for the transactions */
|
|
61
|
+
signer_key?: string;
|
|
62
|
+
/** Optional signer verification during transaction simulation (defaults to false) */
|
|
63
|
+
sig_verify?: boolean;
|
|
64
|
+
}
|
|
42
65
|
/**
|
|
43
66
|
* Parameters for estimating transaction fees.
|
|
44
67
|
*/
|
|
@@ -46,12 +69,25 @@ export interface EstimateTransactionFeeRequest {
|
|
|
46
69
|
/** Base64-encoded transaction to estimate fees for */
|
|
47
70
|
transaction: string;
|
|
48
71
|
/** Mint address of the token to calculate fees in */
|
|
49
|
-
fee_token
|
|
72
|
+
fee_token?: string;
|
|
50
73
|
/** Optional signer address for the transaction */
|
|
51
74
|
signer_key?: string;
|
|
52
75
|
/** Optional signer verification during transaction simulation (defaults to false) */
|
|
53
76
|
sig_verify?: boolean;
|
|
54
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Parameters for estimating bundle fees.
|
|
80
|
+
*/
|
|
81
|
+
export interface EstimateBundleFeeRequest {
|
|
82
|
+
/** Array of base64-encoded transactions to estimate fees for */
|
|
83
|
+
transactions: string[];
|
|
84
|
+
/** Mint address of the token to calculate fees in */
|
|
85
|
+
fee_token?: string;
|
|
86
|
+
/** Optional signer address for the transactions */
|
|
87
|
+
signer_key?: string;
|
|
88
|
+
/** Optional signer verification during transaction simulation (defaults to false) */
|
|
89
|
+
sig_verify?: boolean;
|
|
90
|
+
}
|
|
55
91
|
/**
|
|
56
92
|
* Parameters for getting a payment instruction.
|
|
57
93
|
*/
|
|
@@ -74,15 +110,17 @@ export interface GetPaymentInstructionRequest {
|
|
|
74
110
|
*/
|
|
75
111
|
/**
|
|
76
112
|
* Response from creating a transfer transaction.
|
|
113
|
+
* The transaction is unsigned.
|
|
114
|
+
* @deprecated Use `getPaymentInstruction` instead for fee payment flows.
|
|
77
115
|
*/
|
|
78
116
|
export interface TransferTransactionResponse {
|
|
79
|
-
/** Base64-encoded
|
|
117
|
+
/** Base64-encoded unsigned transaction */
|
|
80
118
|
transaction: string;
|
|
81
|
-
/** Base64-encoded message */
|
|
119
|
+
/** Base64-encoded unsigned message */
|
|
82
120
|
message: string;
|
|
83
121
|
/** Recent blockhash used in the transaction */
|
|
84
122
|
blockhash: string;
|
|
85
|
-
/** Public key of the signer
|
|
123
|
+
/** Public key of the Kora signer (fee payer) */
|
|
86
124
|
signer_pubkey: string;
|
|
87
125
|
/** Parsed instructions from the transaction message */
|
|
88
126
|
instructions: Instruction[];
|
|
@@ -107,6 +145,26 @@ export interface SignAndSendTransactionResponse {
|
|
|
107
145
|
/** Public key of the signer used to send the transaction */
|
|
108
146
|
signer_pubkey: string;
|
|
109
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Response from signing a bundle of transactions.
|
|
150
|
+
*/
|
|
151
|
+
export interface SignBundleResponse {
|
|
152
|
+
/** Array of base64-encoded signed transactions */
|
|
153
|
+
signed_transactions: string[];
|
|
154
|
+
/** Public key of the signer used to sign the transactions */
|
|
155
|
+
signer_pubkey: string;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Response from signing and sending a bundle of transactions via Jito.
|
|
159
|
+
*/
|
|
160
|
+
export interface SignAndSendBundleResponse {
|
|
161
|
+
/** Array of base64-encoded signed transactions */
|
|
162
|
+
signed_transactions: string[];
|
|
163
|
+
/** Public key of the signer used to sign the transactions */
|
|
164
|
+
signer_pubkey: string;
|
|
165
|
+
/** UUID of the submitted Jito bundle */
|
|
166
|
+
bundle_uuid: string;
|
|
167
|
+
}
|
|
110
168
|
/**
|
|
111
169
|
* Response containing the latest blockhash.
|
|
112
170
|
*/
|
|
@@ -114,6 +172,13 @@ export interface GetBlockhashResponse {
|
|
|
114
172
|
/** Base58-encoded blockhash */
|
|
115
173
|
blockhash: string;
|
|
116
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Response containing the server version.
|
|
177
|
+
*/
|
|
178
|
+
export interface GetVersionResponse {
|
|
179
|
+
/** Server version string */
|
|
180
|
+
version: string;
|
|
181
|
+
}
|
|
117
182
|
/**
|
|
118
183
|
* Response containing supported token mint addresses.
|
|
119
184
|
*/
|
|
@@ -130,7 +195,22 @@ export interface EstimateTransactionFeeResponse {
|
|
|
130
195
|
/**
|
|
131
196
|
* Transaction fee in the requested token (in decimals value of the token, e.g. 10^6 for USDC)
|
|
132
197
|
*/
|
|
133
|
-
fee_in_token
|
|
198
|
+
fee_in_token?: number;
|
|
199
|
+
/** Public key of the signer used to estimate the fee */
|
|
200
|
+
signer_pubkey: string;
|
|
201
|
+
/** Public key of the payment destination */
|
|
202
|
+
payment_address: string;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Response containing estimated bundle fees.
|
|
206
|
+
*/
|
|
207
|
+
export interface EstimateBundleFeeResponse {
|
|
208
|
+
/** Total bundle fee in lamports across all transactions */
|
|
209
|
+
fee_in_lamports: number;
|
|
210
|
+
/**
|
|
211
|
+
* Total bundle fee in the requested token (in decimals value of the token, e.g. 10^6 for USDC)
|
|
212
|
+
*/
|
|
213
|
+
fee_in_token?: number;
|
|
134
214
|
/** Public key of the signer used to estimate the fee */
|
|
135
215
|
signer_pubkey: string;
|
|
136
216
|
/** Public key of the payment destination */
|
|
@@ -226,8 +306,12 @@ export interface EnabledMethods {
|
|
|
226
306
|
liveness: boolean;
|
|
227
307
|
/** Whether the estimate_transaction_fee method is enabled */
|
|
228
308
|
estimate_transaction_fee: boolean;
|
|
309
|
+
/** Whether the estimate_bundle_fee method is enabled (requires bundle.enabled = true) */
|
|
310
|
+
estimate_bundle_fee: boolean;
|
|
229
311
|
/** Whether the get_supported_tokens method is enabled */
|
|
230
312
|
get_supported_tokens: boolean;
|
|
313
|
+
/** Whether the get_payer_signer method is enabled */
|
|
314
|
+
get_payer_signer: boolean;
|
|
231
315
|
/** Whether the sign_transaction method is enabled */
|
|
232
316
|
sign_transaction: boolean;
|
|
233
317
|
/** Whether the sign_and_send_transaction method is enabled */
|
|
@@ -238,6 +322,12 @@ export interface EnabledMethods {
|
|
|
238
322
|
get_blockhash: boolean;
|
|
239
323
|
/** Whether the get_config method is enabled */
|
|
240
324
|
get_config: boolean;
|
|
325
|
+
/** Whether the get_version method is enabled */
|
|
326
|
+
get_version: boolean;
|
|
327
|
+
/** Whether the sign_and_send_bundle method is enabled (requires bundle.enabled = true) */
|
|
328
|
+
sign_and_send_bundle: boolean;
|
|
329
|
+
/** Whether the sign_bundle method is enabled (requires bundle.enabled = true) */
|
|
330
|
+
sign_bundle: boolean;
|
|
241
331
|
}
|
|
242
332
|
/**
|
|
243
333
|
* Kora server configuration.
|
|
@@ -296,6 +386,12 @@ export interface SplTokenInstructionPolicy {
|
|
|
296
386
|
allow_set_authority: boolean;
|
|
297
387
|
/** Allow fee payer to mint SPL tokens */
|
|
298
388
|
allow_mint_to: boolean;
|
|
389
|
+
/** Allow fee payer to initialize SPL token mints */
|
|
390
|
+
allow_initialize_mint: boolean;
|
|
391
|
+
/** Allow fee payer to initialize SPL token accounts */
|
|
392
|
+
allow_initialize_account: boolean;
|
|
393
|
+
/** Allow fee payer to initialize SPL multisig accounts */
|
|
394
|
+
allow_initialize_multisig: boolean;
|
|
299
395
|
/** Allow fee payer to freeze SPL token accounts */
|
|
300
396
|
allow_freeze_account: boolean;
|
|
301
397
|
/** Allow fee payer to thaw SPL token accounts */
|
|
@@ -319,6 +415,12 @@ export interface Token2022InstructionPolicy {
|
|
|
319
415
|
allow_set_authority: boolean;
|
|
320
416
|
/** Allow fee payer to mint Token2022 tokens */
|
|
321
417
|
allow_mint_to: boolean;
|
|
418
|
+
/** Allow fee payer to initialize Token2022 mints */
|
|
419
|
+
allow_initialize_mint: boolean;
|
|
420
|
+
/** Allow fee payer to initialize Token2022 accounts */
|
|
421
|
+
allow_initialize_account: boolean;
|
|
422
|
+
/** Allow fee payer to initialize Token2022 multisig accounts */
|
|
423
|
+
allow_initialize_multisig: boolean;
|
|
322
424
|
/** Allow fee payer to freeze Token2022 accounts */
|
|
323
425
|
allow_freeze_account: boolean;
|
|
324
426
|
/** Allow fee payer to thaw Token2022 accounts */
|
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
import setupTestSuite from './setup.js';
|
|
2
2
|
import { runAuthenticationTests } from './auth-setup.js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { getBase64Decoder, getBase64Encoder, getTransactionDecoder, getTransactionEncoder, partiallySignTransaction, } from '@solana/kit';
|
|
4
|
+
import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
|
|
5
5
|
function transactionFromBase64(base64) {
|
|
6
6
|
const encoder = getBase64Encoder();
|
|
7
7
|
const decoder = getTransactionDecoder();
|
|
8
8
|
const messageBytes = encoder.encode(base64);
|
|
9
9
|
return decoder.decode(messageBytes);
|
|
10
10
|
}
|
|
11
|
+
function transactionToBase64(transaction) {
|
|
12
|
+
const txEncoder = getTransactionEncoder();
|
|
13
|
+
const txBytes = txEncoder.encode(transaction);
|
|
14
|
+
const base64Decoder = getBase64Decoder();
|
|
15
|
+
return base64Decoder.decode(txBytes);
|
|
16
|
+
}
|
|
11
17
|
const AUTH_ENABLED = process.env.ENABLE_AUTH === 'true';
|
|
12
18
|
const KORA_SIGNER_TYPE = process.env.KORA_SIGNER_TYPE || 'memory';
|
|
13
19
|
describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without auth'} | signer type: ${KORA_SIGNER_TYPE})`, () => {
|
|
14
20
|
let client;
|
|
15
21
|
let testWallet;
|
|
16
22
|
let testWalletAddress;
|
|
17
|
-
let destinationAddress;
|
|
18
23
|
let usdcMint;
|
|
19
24
|
let koraAddress;
|
|
20
|
-
let koraRpcUrl;
|
|
21
25
|
beforeAll(async () => {
|
|
22
26
|
const testSuite = await setupTestSuite();
|
|
23
27
|
client = testSuite.koraClient;
|
|
24
28
|
testWallet = testSuite.testWallet;
|
|
25
29
|
testWalletAddress = testWallet.address;
|
|
26
|
-
destinationAddress = testSuite.destinationAddress;
|
|
27
30
|
usdcMint = testSuite.usdcMint;
|
|
28
31
|
koraAddress = testSuite.koraAddress;
|
|
29
|
-
koraRpcUrl = testSuite.koraRpcUrl;
|
|
30
32
|
}, 90000); // allow adequate time for airdrops and token initialization
|
|
31
33
|
// Run authentication tests only when auth is enabled
|
|
32
34
|
if (AUTH_ENABLED) {
|
|
@@ -91,6 +93,7 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
91
93
|
expect(config.enabled_methods.transfer_transaction).toBeDefined();
|
|
92
94
|
expect(config.enabled_methods.get_blockhash).toBeDefined();
|
|
93
95
|
expect(config.enabled_methods.get_config).toBeDefined();
|
|
96
|
+
expect(config.enabled_methods.get_version).toBeDefined();
|
|
94
97
|
});
|
|
95
98
|
it('should get payer signer', async () => {
|
|
96
99
|
const { signer_address, payment_address } = await client.getPayerSigner();
|
|
@@ -110,43 +113,29 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
110
113
|
expect(blockhash.length).toBeGreaterThanOrEqual(43);
|
|
111
114
|
expect(blockhash.length).toBeLessThanOrEqual(44); // Base58 encoded hash length
|
|
112
115
|
});
|
|
116
|
+
it('should get version', async () => {
|
|
117
|
+
const { version } = await client.getVersion();
|
|
118
|
+
expect(version).toBeDefined();
|
|
119
|
+
expect(typeof version).toBe('string');
|
|
120
|
+
expect(version.length).toBeGreaterThan(0);
|
|
121
|
+
// Version should follow semver format (e.g., "2.1.0" or "2.1.0-beta.0")
|
|
122
|
+
expect(version).toMatch(/^\d+\.\d+\.\d+/);
|
|
123
|
+
});
|
|
113
124
|
});
|
|
114
125
|
describe('Transaction Operations', () => {
|
|
115
|
-
it('should create transfer transaction', async () => {
|
|
116
|
-
const request = {
|
|
117
|
-
amount: 1000000, // 1 USDC
|
|
118
|
-
token: usdcMint,
|
|
119
|
-
source: testWalletAddress,
|
|
120
|
-
destination: destinationAddress,
|
|
121
|
-
};
|
|
122
|
-
const response = await client.transferTransaction(request);
|
|
123
|
-
expect(response).toBeDefined();
|
|
124
|
-
expect(response.transaction).toBeDefined();
|
|
125
|
-
expect(response.blockhash).toBeDefined();
|
|
126
|
-
expect(response.message).toBeDefined();
|
|
127
|
-
expect(response.instructions).toBeDefined();
|
|
128
|
-
// since setup created ATA for destination, we should not expect ata instruction, only transfer instruction
|
|
129
|
-
expect(response.instructions?.length).toBe(1);
|
|
130
|
-
expect(response.instructions?.[0].programAddress).toBe(TOKEN_PROGRAM_ADDRESS);
|
|
131
|
-
});
|
|
132
|
-
it('should create transfer transaction to address with no ATA', async () => {
|
|
133
|
-
const randomDestination = await generateKeyPairSigner();
|
|
126
|
+
it('should create transfer transaction (DEPRECATED endpoint)', async () => {
|
|
134
127
|
const request = {
|
|
135
128
|
amount: 1000000, // 1 USDC
|
|
136
129
|
token: usdcMint,
|
|
137
130
|
source: testWalletAddress,
|
|
138
|
-
destination:
|
|
131
|
+
destination: koraAddress, // user specifies destination
|
|
139
132
|
};
|
|
140
133
|
const response = await client.transferTransaction(request);
|
|
141
134
|
expect(response).toBeDefined();
|
|
142
135
|
expect(response.transaction).toBeDefined();
|
|
143
136
|
expect(response.blockhash).toBeDefined();
|
|
144
137
|
expect(response.message).toBeDefined();
|
|
145
|
-
expect(response.
|
|
146
|
-
// since setup created ATA for destination, we should not expect ata instruction, only transfer instruction
|
|
147
|
-
expect(response.instructions?.length).toBe(2);
|
|
148
|
-
expect(response.instructions?.[0].programAddress).toBe(ASSOCIATED_TOKEN_PROGRAM_ADDRESS);
|
|
149
|
-
expect(response.instructions?.[1].programAddress).toBe(TOKEN_PROGRAM_ADDRESS);
|
|
138
|
+
expect(response.signer_pubkey).toBeDefined();
|
|
150
139
|
});
|
|
151
140
|
it('should estimate transaction fee', async () => {
|
|
152
141
|
// First create a transaction
|
|
@@ -154,7 +143,7 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
154
143
|
amount: 1000000,
|
|
155
144
|
token: usdcMint,
|
|
156
145
|
source: testWalletAddress,
|
|
157
|
-
destination:
|
|
146
|
+
destination: koraAddress,
|
|
158
147
|
};
|
|
159
148
|
const { transaction } = await client.transferTransaction(transferRequest);
|
|
160
149
|
const fee = await client.estimateTransactionFee({ transaction, fee_token: usdcMint });
|
|
@@ -165,13 +154,11 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
165
154
|
expect(fee.fee_in_token).toBeGreaterThan(0);
|
|
166
155
|
});
|
|
167
156
|
it('should sign transaction', async () => {
|
|
168
|
-
const config = await client.getConfig();
|
|
169
|
-
const paymentAddress = config.fee_payers[0];
|
|
170
157
|
const transferRequest = {
|
|
171
158
|
amount: 1000000,
|
|
172
159
|
token: usdcMint,
|
|
173
160
|
source: testWalletAddress,
|
|
174
|
-
destination:
|
|
161
|
+
destination: koraAddress,
|
|
175
162
|
};
|
|
176
163
|
const { transaction } = await client.transferTransaction(transferRequest);
|
|
177
164
|
const signResult = await client.signTransaction({
|
|
@@ -181,19 +168,18 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
181
168
|
expect(signResult.signed_transaction).toBeDefined();
|
|
182
169
|
});
|
|
183
170
|
it('should sign and send transaction', async () => {
|
|
184
|
-
const config = await client.getConfig();
|
|
185
|
-
const paymentAddress = config.fee_payers[0];
|
|
186
171
|
const transferRequest = {
|
|
187
172
|
amount: 1000000,
|
|
188
173
|
token: usdcMint,
|
|
189
174
|
source: testWalletAddress,
|
|
190
|
-
destination:
|
|
175
|
+
destination: koraAddress,
|
|
191
176
|
};
|
|
192
177
|
const { transaction: transactionString } = await client.transferTransaction(transferRequest);
|
|
193
178
|
const transaction = transactionFromBase64(transactionString);
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
const
|
|
179
|
+
// Partially sign transaction with test wallet before sending
|
|
180
|
+
// Kora will add fee payer signature via signAndSendTransaction
|
|
181
|
+
const signedTransaction = await partiallySignTransaction([testWallet.keyPair], transaction);
|
|
182
|
+
const base64SignedTransaction = transactionToBase64(signedTransaction);
|
|
197
183
|
const signResult = await client.signAndSendTransaction({
|
|
198
184
|
transaction: base64SignedTransaction,
|
|
199
185
|
});
|
|
@@ -205,7 +191,7 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
205
191
|
amount: 1000000,
|
|
206
192
|
token: usdcMint,
|
|
207
193
|
source: testWalletAddress,
|
|
208
|
-
destination:
|
|
194
|
+
destination: koraAddress,
|
|
209
195
|
};
|
|
210
196
|
const [expectedSenderAta] = await findAssociatedTokenPda({
|
|
211
197
|
owner: testWalletAddress,
|
|
@@ -236,13 +222,81 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
236
222
|
expect(original_transaction).toBe(transaction);
|
|
237
223
|
});
|
|
238
224
|
});
|
|
225
|
+
describe('Bundle Operations', () => {
|
|
226
|
+
it('should sign bundle of transactions', async () => {
|
|
227
|
+
// Create two transfer transactions for the bundle
|
|
228
|
+
const transferRequest1 = {
|
|
229
|
+
amount: 1000000,
|
|
230
|
+
token: usdcMint,
|
|
231
|
+
source: testWalletAddress,
|
|
232
|
+
destination: koraAddress,
|
|
233
|
+
};
|
|
234
|
+
const transferRequest2 = {
|
|
235
|
+
amount: 500000,
|
|
236
|
+
token: usdcMint,
|
|
237
|
+
source: testWalletAddress,
|
|
238
|
+
destination: koraAddress,
|
|
239
|
+
};
|
|
240
|
+
const { transaction: tx1String } = await client.transferTransaction(transferRequest1);
|
|
241
|
+
const { transaction: tx2String } = await client.transferTransaction(transferRequest2);
|
|
242
|
+
// Partially sign both transactions with test wallet
|
|
243
|
+
const tx1 = transactionFromBase64(tx1String);
|
|
244
|
+
const tx2 = transactionFromBase64(tx2String);
|
|
245
|
+
const signedTx1 = await partiallySignTransaction([testWallet.keyPair], tx1);
|
|
246
|
+
const signedTx2 = await partiallySignTransaction([testWallet.keyPair], tx2);
|
|
247
|
+
const base64Tx1 = transactionToBase64(signedTx1);
|
|
248
|
+
const base64Tx2 = transactionToBase64(signedTx2);
|
|
249
|
+
const result = await client.signBundle({
|
|
250
|
+
transactions: [base64Tx1, base64Tx2],
|
|
251
|
+
});
|
|
252
|
+
expect(result).toBeDefined();
|
|
253
|
+
expect(result.signed_transactions).toBeDefined();
|
|
254
|
+
expect(Array.isArray(result.signed_transactions)).toBe(true);
|
|
255
|
+
expect(result.signed_transactions.length).toBe(2);
|
|
256
|
+
expect(result.signer_pubkey).toBeDefined();
|
|
257
|
+
});
|
|
258
|
+
it('should sign and send bundle of transactions', async () => {
|
|
259
|
+
// Create two transfer transactions for the bundle
|
|
260
|
+
const transferRequest1 = {
|
|
261
|
+
amount: 1000000,
|
|
262
|
+
token: usdcMint,
|
|
263
|
+
source: testWalletAddress,
|
|
264
|
+
destination: koraAddress,
|
|
265
|
+
};
|
|
266
|
+
const transferRequest2 = {
|
|
267
|
+
amount: 500000,
|
|
268
|
+
token: usdcMint,
|
|
269
|
+
source: testWalletAddress,
|
|
270
|
+
destination: koraAddress,
|
|
271
|
+
};
|
|
272
|
+
const { transaction: tx1String } = await client.transferTransaction(transferRequest1);
|
|
273
|
+
const { transaction: tx2String } = await client.transferTransaction(transferRequest2);
|
|
274
|
+
// Partially sign both transactions with test wallet
|
|
275
|
+
const tx1 = transactionFromBase64(tx1String);
|
|
276
|
+
const tx2 = transactionFromBase64(tx2String);
|
|
277
|
+
const signedTx1 = await partiallySignTransaction([testWallet.keyPair], tx1);
|
|
278
|
+
const signedTx2 = await partiallySignTransaction([testWallet.keyPair], tx2);
|
|
279
|
+
const base64Tx1 = transactionToBase64(signedTx1);
|
|
280
|
+
const base64Tx2 = transactionToBase64(signedTx2);
|
|
281
|
+
const result = await client.signAndSendBundle({
|
|
282
|
+
transactions: [base64Tx1, base64Tx2],
|
|
283
|
+
});
|
|
284
|
+
expect(result).toBeDefined();
|
|
285
|
+
expect(result.signed_transactions).toBeDefined();
|
|
286
|
+
expect(Array.isArray(result.signed_transactions)).toBe(true);
|
|
287
|
+
expect(result.signed_transactions.length).toBe(2);
|
|
288
|
+
expect(result.signer_pubkey).toBeDefined();
|
|
289
|
+
expect(result.bundle_uuid).toBeDefined();
|
|
290
|
+
expect(typeof result.bundle_uuid).toBe('string');
|
|
291
|
+
});
|
|
292
|
+
});
|
|
239
293
|
describe('Error Handling', () => {
|
|
240
294
|
it('should handle invalid token address', async () => {
|
|
241
295
|
const request = {
|
|
242
296
|
amount: 1000000,
|
|
243
297
|
token: 'InvalidTokenAddress',
|
|
244
298
|
source: testWalletAddress,
|
|
245
|
-
destination:
|
|
299
|
+
destination: koraAddress,
|
|
246
300
|
};
|
|
247
301
|
await expect(client.transferTransaction(request)).rejects.toThrow();
|
|
248
302
|
});
|
|
@@ -251,7 +305,7 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
251
305
|
amount: -1, // Invalid amount
|
|
252
306
|
token: usdcMint,
|
|
253
307
|
source: testWalletAddress,
|
|
254
|
-
destination:
|
|
308
|
+
destination: koraAddress,
|
|
255
309
|
};
|
|
256
310
|
await expect(client.transferTransaction(request)).rejects.toThrow();
|
|
257
311
|
});
|
|
@@ -268,7 +322,7 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
268
322
|
amount: 1000000,
|
|
269
323
|
token: usdcMint,
|
|
270
324
|
source: testWalletAddress,
|
|
271
|
-
destination:
|
|
325
|
+
destination: koraAddress,
|
|
272
326
|
};
|
|
273
327
|
// TODO: API has an error. this endpoint should verify the provided fee token is supported
|
|
274
328
|
const { transaction } = await client.transferTransaction(transferRequest);
|
|
@@ -280,13 +334,11 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
280
334
|
});
|
|
281
335
|
describe('End-to-End Flows', () => {
|
|
282
336
|
it('should handle transfer and sign flow', async () => {
|
|
283
|
-
const config = await client.getConfig();
|
|
284
|
-
const paymentAddress = config.fee_payers[0];
|
|
285
337
|
const request = {
|
|
286
338
|
amount: 1000000,
|
|
287
339
|
token: usdcMint,
|
|
288
340
|
source: testWalletAddress,
|
|
289
|
-
destination:
|
|
341
|
+
destination: koraAddress,
|
|
290
342
|
};
|
|
291
343
|
// Create and sign the transaction
|
|
292
344
|
const { transaction } = await client.transferTransaction(request);
|
|
@@ -299,7 +351,7 @@ describe(`KoraClient Integration Tests (${AUTH_ENABLED ? 'with auth' : 'without
|
|
|
299
351
|
amount: 1000000,
|
|
300
352
|
token: invalidTokenMint,
|
|
301
353
|
source: testWalletAddress,
|
|
302
|
-
destination:
|
|
354
|
+
destination: koraAddress,
|
|
303
355
|
};
|
|
304
356
|
await expect(client.transferTransaction(request)).rejects.toThrow();
|
|
305
357
|
});
|
package/dist/test/unit.test.js
CHANGED
|
@@ -108,6 +108,9 @@ describe('KoraClient Unit Tests', () => {
|
|
|
108
108
|
allow_revoke: true,
|
|
109
109
|
allow_set_authority: true,
|
|
110
110
|
allow_mint_to: true,
|
|
111
|
+
allow_initialize_mint: true,
|
|
112
|
+
allow_initialize_account: true,
|
|
113
|
+
allow_initialize_multisig: true,
|
|
111
114
|
allow_freeze_account: true,
|
|
112
115
|
allow_thaw_account: true,
|
|
113
116
|
},
|
|
@@ -119,6 +122,9 @@ describe('KoraClient Unit Tests', () => {
|
|
|
119
122
|
allow_revoke: true,
|
|
120
123
|
allow_set_authority: true,
|
|
121
124
|
allow_mint_to: true,
|
|
125
|
+
allow_initialize_mint: true,
|
|
126
|
+
allow_initialize_account: true,
|
|
127
|
+
allow_initialize_multisig: true,
|
|
122
128
|
allow_freeze_account: true,
|
|
123
129
|
allow_thaw_account: true,
|
|
124
130
|
},
|
|
@@ -135,12 +141,17 @@ describe('KoraClient Unit Tests', () => {
|
|
|
135
141
|
enabled_methods: {
|
|
136
142
|
liveness: true,
|
|
137
143
|
estimate_transaction_fee: true,
|
|
144
|
+
estimate_bundle_fee: true,
|
|
138
145
|
get_supported_tokens: true,
|
|
146
|
+
get_payer_signer: true,
|
|
139
147
|
sign_transaction: true,
|
|
140
148
|
sign_and_send_transaction: true,
|
|
141
149
|
transfer_transaction: true,
|
|
142
150
|
get_blockhash: true,
|
|
143
151
|
get_config: true,
|
|
152
|
+
get_version: true,
|
|
153
|
+
sign_and_send_bundle: true,
|
|
154
|
+
sign_bundle: true,
|
|
144
155
|
},
|
|
145
156
|
};
|
|
146
157
|
await testSuccessfulRpcMethod('getConfig', () => client.getConfig(), mockConfig);
|
|
@@ -154,6 +165,14 @@ describe('KoraClient Unit Tests', () => {
|
|
|
154
165
|
await testSuccessfulRpcMethod('getBlockhash', () => client.getBlockhash(), mockResponse);
|
|
155
166
|
});
|
|
156
167
|
});
|
|
168
|
+
describe('getVersion', () => {
|
|
169
|
+
it('should return server version', async () => {
|
|
170
|
+
const mockResponse = {
|
|
171
|
+
version: '2.1.0-beta.0',
|
|
172
|
+
};
|
|
173
|
+
await testSuccessfulRpcMethod('getVersion', () => client.getVersion(), mockResponse);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
157
176
|
describe('getSupportedTokens', () => {
|
|
158
177
|
it('should return supported tokens list', async () => {
|
|
159
178
|
const mockResponse = {
|
|
@@ -219,48 +238,49 @@ describe('KoraClient Unit Tests', () => {
|
|
|
219
238
|
await testSuccessfulRpcMethod('signAndSendTransaction', () => client.signAndSendTransaction(request), mockResponse, request);
|
|
220
239
|
});
|
|
221
240
|
});
|
|
222
|
-
describe('
|
|
223
|
-
it('should
|
|
241
|
+
describe('signBundle', () => {
|
|
242
|
+
it('should sign bundle of transactions', async () => {
|
|
224
243
|
const request = {
|
|
225
|
-
|
|
226
|
-
token: 'SOL',
|
|
227
|
-
source: 'source_address',
|
|
228
|
-
destination: 'destination_address',
|
|
244
|
+
transactions: ['base64_tx_1', 'base64_tx_2'],
|
|
229
245
|
};
|
|
230
246
|
const mockResponse = {
|
|
231
|
-
|
|
232
|
-
message: 'Transfer transaction created',
|
|
233
|
-
blockhash: 'test_blockhash',
|
|
247
|
+
signed_transactions: ['base64_signed_tx_1', 'base64_signed_tx_2'],
|
|
234
248
|
signer_pubkey: 'test_signer_pubkey',
|
|
235
|
-
instructions: [],
|
|
236
249
|
};
|
|
237
|
-
await testSuccessfulRpcMethod('
|
|
250
|
+
await testSuccessfulRpcMethod('signBundle', () => client.signBundle(request), mockResponse, request);
|
|
238
251
|
});
|
|
239
|
-
it('should
|
|
252
|
+
it('should handle RPC error', async () => {
|
|
240
253
|
const request = {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
254
|
+
transactions: ['base64_tx_1'],
|
|
255
|
+
};
|
|
256
|
+
const mockError = { code: -32000, message: 'Bundle validation failed' };
|
|
257
|
+
mockErrorResponse(mockError);
|
|
258
|
+
await expect(client.signBundle(request)).rejects.toThrow('RPC Error -32000: Bundle validation failed');
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
describe('signAndSendBundle', () => {
|
|
262
|
+
it('should sign and send bundle of transactions', async () => {
|
|
263
|
+
const request = {
|
|
264
|
+
transactions: ['base64_tx_1', 'base64_tx_2'],
|
|
245
265
|
};
|
|
246
|
-
// This is a real base64 encoded message for testing
|
|
247
|
-
// In production, this would come from the RPC response
|
|
248
|
-
const mockMessage = 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQABAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIDAAEMAgAAAAEAAAAAAAAA';
|
|
249
266
|
const mockResponse = {
|
|
250
|
-
|
|
251
|
-
message: mockMessage,
|
|
252
|
-
blockhash: 'test_blockhash',
|
|
267
|
+
signed_transactions: ['base64_signed_tx_1', 'base64_signed_tx_2'],
|
|
253
268
|
signer_pubkey: 'test_signer_pubkey',
|
|
254
|
-
|
|
269
|
+
bundle_uuid: 'test-bundle-uuid-123',
|
|
255
270
|
};
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
271
|
+
await testSuccessfulRpcMethod('signAndSendBundle', () => client.signAndSendBundle(request), mockResponse, request);
|
|
272
|
+
});
|
|
273
|
+
it('should handle RPC error', async () => {
|
|
274
|
+
const request = {
|
|
275
|
+
transactions: ['base64_tx_1'],
|
|
276
|
+
};
|
|
277
|
+
const mockError = { code: -32000, message: 'Jito submission failed' };
|
|
278
|
+
mockErrorResponse(mockError);
|
|
279
|
+
await expect(client.signAndSendBundle(request)).rejects.toThrow('RPC Error -32000: Jito submission failed');
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
describe('transferTransaction (DEPRECATED)', () => {
|
|
283
|
+
it('should create transfer transaction', async () => {
|
|
264
284
|
const request = {
|
|
265
285
|
amount: 1000000,
|
|
266
286
|
token: 'SOL',
|
|
@@ -269,15 +289,12 @@ describe('KoraClient Unit Tests', () => {
|
|
|
269
289
|
};
|
|
270
290
|
const mockResponse = {
|
|
271
291
|
transaction: 'base64_encoded_transaction',
|
|
272
|
-
message: '',
|
|
292
|
+
message: 'Transfer transaction created',
|
|
273
293
|
blockhash: 'test_blockhash',
|
|
274
294
|
signer_pubkey: 'test_signer_pubkey',
|
|
275
295
|
instructions: [],
|
|
276
296
|
};
|
|
277
|
-
|
|
278
|
-
const result = await client.transferTransaction(request);
|
|
279
|
-
// Should handle empty message gracefully
|
|
280
|
-
expect(result.instructions).toEqual([]);
|
|
297
|
+
await testSuccessfulRpcMethod('transferTransaction', () => client.transferTransaction(request), mockResponse, request);
|
|
281
298
|
});
|
|
282
299
|
});
|
|
283
300
|
describe('getPaymentInstruction', () => {
|
|
@@ -312,6 +329,9 @@ describe('KoraClient Unit Tests', () => {
|
|
|
312
329
|
allow_revoke: true,
|
|
313
330
|
allow_set_authority: true,
|
|
314
331
|
allow_mint_to: true,
|
|
332
|
+
allow_initialize_mint: true,
|
|
333
|
+
allow_initialize_account: true,
|
|
334
|
+
allow_initialize_multisig: true,
|
|
315
335
|
allow_freeze_account: true,
|
|
316
336
|
allow_thaw_account: true,
|
|
317
337
|
},
|
|
@@ -323,6 +343,9 @@ describe('KoraClient Unit Tests', () => {
|
|
|
323
343
|
allow_revoke: true,
|
|
324
344
|
allow_set_authority: true,
|
|
325
345
|
allow_mint_to: true,
|
|
346
|
+
allow_initialize_mint: true,
|
|
347
|
+
allow_initialize_account: true,
|
|
348
|
+
allow_initialize_multisig: true,
|
|
326
349
|
allow_freeze_account: true,
|
|
327
350
|
allow_thaw_account: true,
|
|
328
351
|
},
|
|
@@ -339,12 +362,17 @@ describe('KoraClient Unit Tests', () => {
|
|
|
339
362
|
enabled_methods: {
|
|
340
363
|
liveness: true,
|
|
341
364
|
estimate_transaction_fee: true,
|
|
365
|
+
estimate_bundle_fee: true,
|
|
342
366
|
get_supported_tokens: true,
|
|
367
|
+
get_payer_signer: true,
|
|
343
368
|
sign_transaction: true,
|
|
344
369
|
sign_and_send_transaction: true,
|
|
345
370
|
transfer_transaction: true,
|
|
346
371
|
get_blockhash: true,
|
|
347
372
|
get_config: true,
|
|
373
|
+
get_version: true,
|
|
374
|
+
sign_and_send_bundle: true,
|
|
375
|
+
sign_bundle: true,
|
|
348
376
|
},
|
|
349
377
|
};
|
|
350
378
|
const mockFeeEstimate = {
|