@solana/kora 0.2.0-beta.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,35 @@
1
1
  # Kora TypeScript SDK
2
2
 
3
- A TypeScript SDK for interacting with the Kora RPC server. This SDK provides a type-safe interface to all Kora RPC methods.
3
+ A TypeScript SDK for interacting with the Kora RPC server. This SDK provides a type-safe interface to all Kora RPC methods (requires a Kora RPC server to be running).
4
4
 
5
- ## Development
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ pnpm install @solana/kora
10
+ ```
11
+
12
+ ## Quick Start
13
+
14
+ ```typescript
15
+ import { KoraClient } from '@solana/kora';
16
+
17
+ // Initialize the client with your RPC endpoint
18
+ const client = new KoraClient({ rpcUrl: 'http://localhost:8080' });
19
+
20
+ // Example: Get Kora to sign a transaction
21
+ const result = await client.signTransaction({
22
+ transaction: 'myBase64EncodedTransaction'
23
+ });
24
+
25
+ // Access the signed transaction (base64 encoded)
26
+ console.log('Signed transaction:', result.signed_transaction);
27
+ ```
28
+
29
+ **[→ API Reference](https://launch.solana.com/docs/kora/json-rpc-api)**
30
+ **[→ Quick Start](https://launch.solana.com/docs/kora/getting-started/quick-start)**
31
+
32
+ ## Local Development
6
33
 
7
34
  ### Building from Source
8
35
 
@@ -33,28 +60,3 @@ pnpm test:ci:integration
33
60
 
34
61
  This will start a local test validator and run all tests.
35
62
 
36
-
37
- ## Quick Start
38
-
39
- ```typescript
40
- import { KoraClient } from '@solana/kora';
41
-
42
- // Initialize the client with your RPC endpoint
43
- const client = new KoraClient({ rpcUrl: 'http://localhost:8080' });
44
-
45
- // Example: Transfer tokens
46
- const result = await client.transferTransaction({
47
- amount: 1000000, // 1 USDC (6 decimals)
48
- token: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC mint
49
- source: "sourceAddress",
50
- destination: "destinationAddress"
51
- });
52
-
53
- // Access the base64 encoded transaction, base64 encoded message, and parsed instructions directly
54
- console.log('Transaction:', result.transaction);
55
- console.log('Message:', result.message);
56
- console.log('Instructions:', result.instructions);
57
- ```
58
-
59
- **[→ API Reference](https://launch.solana.com/docs/kora/json-rpc-api)**
60
- **[→ Quick Start](https://launch.solana.com/docs/kora/getting-started/quick-start)**
@@ -1,21 +1,10 @@
1
- import { Config, EstimateBundleFeeRequest, EstimateBundleFeeResponse, EstimateTransactionFeeRequest, EstimateTransactionFeeResponse, GetBlockhashResponse, GetPayerSignerResponse, GetPaymentInstructionRequest, GetPaymentInstructionResponse, GetSupportedTokensResponse, GetVersionResponse, KoraClientOptions, SignAndSendBundleRequest, SignAndSendBundleResponse, SignAndSendTransactionRequest, SignAndSendTransactionResponse, SignBundleRequest, SignBundleResponse, SignTransactionRequest, SignTransactionResponse } from './types/index.js';
1
+ import { Config, EstimateTransactionFeeRequest, EstimateTransactionFeeResponse, GetBlockhashResponse, GetPayerSignerResponse, GetPaymentInstructionRequest, GetPaymentInstructionResponse, GetSupportedTokensResponse, KoraClientOptions, SignAndSendTransactionRequest, SignAndSendTransactionResponse, SignTransactionRequest, SignTransactionResponse, TransferTransactionRequest, TransferTransactionResponse } from './types/index.js';
2
2
  /**
3
3
  * Kora RPC client for interacting with the Kora paymaster service.
4
4
  *
5
- * Provides methods to estimate fees, sign transactions, and perform gasless transfers
6
- * on Solana as specified by the Kora paymaster operator.
7
- *
8
- * @example Kora Initialization
5
+ * @example
9
6
  * ```typescript
10
- * const client = new KoraClient({
11
- * rpcUrl: 'http://localhost:8080',
12
- * // apiKey may be required by some operators
13
- * // apiKey: 'your-api-key',
14
- * // hmacSecret may be required by some operators
15
- * // hmacSecret: 'your-hmac-secret'
16
- * });
17
- *
18
- * // Sample usage: Get config
7
+ * const client = new KoraClient({ rpcUrl: 'http://localhost:8080' });
19
8
  * const config = await client.getConfig();
20
9
  * ```
21
10
  */
@@ -23,202 +12,21 @@ export declare class KoraClient {
23
12
  private rpcUrl;
24
13
  private apiKey?;
25
14
  private hmacSecret?;
26
- /**
27
- * Creates a new Kora client instance.
28
- * @param options - Client configuration options
29
- * @param options.rpcUrl - The Kora RPC server URL
30
- * @param options.apiKey - Optional API key for authentication
31
- * @param options.hmacSecret - Optional HMAC secret for signature-based authentication
32
- */
33
15
  constructor({ rpcUrl, apiKey, hmacSecret }: KoraClientOptions);
34
16
  private getHmacSignature;
35
17
  private getHeaders;
36
18
  private rpcRequest;
37
- /**
38
- * Retrieves the current Kora server configuration.
39
- * @returns The server configuration including fee payer address and validation rules
40
- * @throws {Error} When the RPC call fails
41
- *
42
- * @example
43
- * ```typescript
44
- * const config = await client.getConfig();
45
- * console.log('Fee payer:', config.fee_payer);
46
- * console.log('Validation config:', JSON.stringify(config.validation_config, null, 2));
47
- * ```
48
- */
49
19
  getConfig(): Promise<Config>;
50
- /**
51
- * Retrieves the payer signer and payment destination from the Kora server.
52
- * @returns Object containing the payer signer and payment destination
53
- * @throws {Error} When the RPC call fails
54
- *
55
- * @example
56
- */
57
20
  getPayerSigner(): Promise<GetPayerSignerResponse>;
58
- /**
59
- * Gets the latest blockhash from the Solana RPC that the Kora server is connected to.
60
- * @returns Object containing the current blockhash
61
- * @throws {Error} When the RPC call fails
62
- *
63
- * @example
64
- * ```typescript
65
- * const { blockhash } = await client.getBlockhash();
66
- * console.log('Current blockhash:', blockhash);
67
- * ```
68
- */
69
21
  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>;
82
- /**
83
- * Retrieves the list of tokens supported for fee payment.
84
- * @returns Object containing an array of supported token mint addresses
85
- * @throws {Error} When the RPC call fails
86
- *
87
- * @example
88
- * ```typescript
89
- * const { tokens } = await client.getSupportedTokens();
90
- * console.log('Supported tokens:', tokens);
91
- * // Output: ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', ...]
92
- * ```
93
- */
94
22
  getSupportedTokens(): Promise<GetSupportedTokensResponse>;
95
- /**
96
- * Estimates the transaction fee in both lamports and the specified token.
97
- * @param request - Fee estimation request parameters
98
- * @param request.transaction - Base64-encoded transaction to estimate fees for
99
- * @param request.fee_token - Mint address of the token to calculate fees in
100
- * @returns Fee amounts in both lamports and the specified token
101
- * @throws {Error} When the RPC call fails, the transaction is invalid, or the token is not supported
102
- *
103
- * @example
104
- * ```typescript
105
- * const fees = await client.estimateTransactionFee({
106
- * transaction: 'base64EncodedTransaction',
107
- * fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC
108
- * });
109
- * console.log('Fee in lamports:', fees.fee_in_lamports);
110
- * console.log('Fee in USDC:', fees.fee_in_token);
111
- * ```
112
- */
113
23
  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>;
133
- /**
134
- * Signs a transaction with the Kora fee payer without broadcasting it.
135
- * @param request - Sign request parameters
136
- * @param request.transaction - Base64-encoded transaction to sign
137
- * @returns Signature and the signed transaction
138
- * @throws {Error} When the RPC call fails or transaction validation fails
139
- *
140
- * @example
141
- * ```typescript
142
- * const result = await client.signTransaction({
143
- * transaction: 'base64EncodedTransaction'
144
- * });
145
- * console.log('Signature:', result.signature);
146
- * console.log('Signed tx:', result.signed_transaction);
147
- * ```
148
- */
149
24
  signTransaction(request: SignTransactionRequest): Promise<SignTransactionResponse>;
150
- /**
151
- * Signs a transaction and immediately broadcasts it to the Solana network.
152
- * @param request - Sign and send request parameters
153
- * @param request.transaction - Base64-encoded transaction to sign and send
154
- * @returns Signature and the signed transaction
155
- * @throws {Error} When the RPC call fails, validation fails, or broadcast fails
156
- *
157
- * @example
158
- * ```typescript
159
- * const result = await client.signAndSendTransaction({
160
- * transaction: 'base64EncodedTransaction'
161
- * });
162
- * console.log('Transaction signature:', result.signature);
163
- * ```
164
- */
165
25
  signAndSendTransaction(request: SignAndSendTransactionRequest): Promise<SignAndSendTransactionResponse>;
26
+ transferTransaction(request: TransferTransactionRequest): Promise<TransferTransactionResponse>;
166
27
  /**
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
- * @param request.sign_only_indices - Optional indices of transactions to sign (defaults to all)
173
- * @returns Array of signed transactions and signer public key
174
- * @throws {Error} When the RPC call fails or validation fails
175
- *
176
- * @example
177
- * ```typescript
178
- * const result = await client.signBundle({
179
- * transactions: ['base64Tx1', 'base64Tx2']
180
- * });
181
- * console.log('Signed transactions:', result.signed_transactions);
182
- * console.log('Signer:', result.signer_pubkey);
183
- * ```
184
- */
185
- signBundle(request: SignBundleRequest): Promise<SignBundleResponse>;
186
- /**
187
- * Signs a bundle of transactions and sends them to Jito block engine.
188
- * @param request - Sign and send bundle request parameters
189
- * @param request.transactions - Array of base64-encoded transactions to sign and send
190
- * @param request.signer_key - Optional signer address for the transactions
191
- * @param request.sig_verify - Optional signature verification (defaults to false)
192
- * @param request.sign_only_indices - Optional indices of transactions to sign (defaults to all)
193
- * @returns Array of signed transactions, signer public key, and Jito bundle UUID
194
- * @throws {Error} When the RPC call fails, validation fails, or Jito submission fails
195
- *
196
- * @example
197
- * ```typescript
198
- * const result = await client.signAndSendBundle({
199
- * transactions: ['base64Tx1', 'base64Tx2']
200
- * });
201
- * console.log('Bundle UUID:', result.bundle_uuid);
202
- * console.log('Signed transactions:', result.signed_transactions);
203
- * ```
204
- */
205
- signAndSendBundle(request: SignAndSendBundleRequest): Promise<SignAndSendBundleResponse>;
206
- /**
207
- * Creates a payment instruction to append to a transaction for fee payment to the Kora paymaster.
208
- *
209
- * This method estimates the required fee and generates a token transfer instruction
210
- * from the source wallet to the Kora payment address. The server handles decimal
211
- * conversion internally, so the raw token amount is used directly.
212
- *
213
- * @param request - Payment instruction request parameters
214
- * @param request.transaction - Base64-encoded transaction to estimate fees for
215
- * @param request.fee_token - Mint address of the token to use for payment
216
- * @param request.source_wallet - Public key of the wallet paying the fees
217
- * @param request.token_program_id - Optional token program ID (defaults to TOKEN_PROGRAM_ADDRESS)
218
- * @param request.signer_key - Optional signer address for the transaction
219
- * @param request.sig_verify - Optional signer verification during transaction simulation (defaults to false)
220
- * @returns Payment instruction details including the instruction, amount, and addresses
221
- * @throws {Error} When the token is not supported, payment is not required, or invalid addresses are provided
28
+ * Estimates the fee and builds a payment transfer instruction from the source wallet
29
+ * to the Kora payment address. The server handles decimal conversion internally.
222
30
  *
223
31
  * @example
224
32
  * ```typescript
@@ -1,23 +1,13 @@
1
1
  import { assertIsAddress, createNoopSigner } from '@solana/kit';
2
2
  import { findAssociatedTokenPda, getTransferInstruction, TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
3
3
  import crypto from 'crypto';
4
+ import { getInstructionsFromBase64Message } from './utils/transaction.js';
4
5
  /**
5
6
  * Kora RPC client for interacting with the Kora paymaster service.
6
7
  *
7
- * Provides methods to estimate fees, sign transactions, and perform gasless transfers
8
- * on Solana as specified by the Kora paymaster operator.
9
- *
10
- * @example Kora Initialization
8
+ * @example
11
9
  * ```typescript
12
- * const client = new KoraClient({
13
- * rpcUrl: 'http://localhost:8080',
14
- * // apiKey may be required by some operators
15
- * // apiKey: 'your-api-key',
16
- * // hmacSecret may be required by some operators
17
- * // hmacSecret: 'your-hmac-secret'
18
- * });
19
- *
20
- * // Sample usage: Get config
10
+ * const client = new KoraClient({ rpcUrl: 'http://localhost:8080' });
21
11
  * const config = await client.getConfig();
22
12
  * ```
23
13
  */
@@ -25,13 +15,6 @@ export class KoraClient {
25
15
  rpcUrl;
26
16
  apiKey;
27
17
  hmacSecret;
28
- /**
29
- * Creates a new Kora client instance.
30
- * @param options - Client configuration options
31
- * @param options.rpcUrl - The Kora RPC server URL
32
- * @param options.apiKey - Optional API key for authentication
33
- * @param options.hmacSecret - Optional HMAC secret for signature-based authentication
34
- */
35
18
  constructor({ rpcUrl, apiKey, hmacSecret }) {
36
19
  this.rpcUrl = rpcUrl;
37
20
  this.apiKey = apiKey;
@@ -77,213 +60,35 @@ export class KoraClient {
77
60
  }
78
61
  return json.result;
79
62
  }
80
- /**
81
- * Retrieves the current Kora server configuration.
82
- * @returns The server configuration including fee payer address and validation rules
83
- * @throws {Error} When the RPC call fails
84
- *
85
- * @example
86
- * ```typescript
87
- * const config = await client.getConfig();
88
- * console.log('Fee payer:', config.fee_payer);
89
- * console.log('Validation config:', JSON.stringify(config.validation_config, null, 2));
90
- * ```
91
- */
92
63
  async getConfig() {
93
64
  return await this.rpcRequest('getConfig', undefined);
94
65
  }
95
- /**
96
- * Retrieves the payer signer and payment destination from the Kora server.
97
- * @returns Object containing the payer signer and payment destination
98
- * @throws {Error} When the RPC call fails
99
- *
100
- * @example
101
- */
102
66
  async getPayerSigner() {
103
67
  return await this.rpcRequest('getPayerSigner', undefined);
104
68
  }
105
- /**
106
- * Gets the latest blockhash from the Solana RPC that the Kora server is connected to.
107
- * @returns Object containing the current blockhash
108
- * @throws {Error} When the RPC call fails
109
- *
110
- * @example
111
- * ```typescript
112
- * const { blockhash } = await client.getBlockhash();
113
- * console.log('Current blockhash:', blockhash);
114
- * ```
115
- */
116
69
  async getBlockhash() {
117
70
  return await this.rpcRequest('getBlockhash', undefined);
118
71
  }
119
- /**
120
- * Gets the version of the Kora server.
121
- * @returns Object containing the server version
122
- * @throws {Error} When the RPC call fails
123
- *
124
- * @example
125
- * ```typescript
126
- * const { version } = await client.getVersion();
127
- * console.log('Server version:', version);
128
- * ```
129
- */
130
- async getVersion() {
131
- return await this.rpcRequest('getVersion', undefined);
132
- }
133
- /**
134
- * Retrieves the list of tokens supported for fee payment.
135
- * @returns Object containing an array of supported token mint addresses
136
- * @throws {Error} When the RPC call fails
137
- *
138
- * @example
139
- * ```typescript
140
- * const { tokens } = await client.getSupportedTokens();
141
- * console.log('Supported tokens:', tokens);
142
- * // Output: ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', ...]
143
- * ```
144
- */
145
72
  async getSupportedTokens() {
146
73
  return await this.rpcRequest('getSupportedTokens', undefined);
147
74
  }
148
- /**
149
- * Estimates the transaction fee in both lamports and the specified token.
150
- * @param request - Fee estimation request parameters
151
- * @param request.transaction - Base64-encoded transaction to estimate fees for
152
- * @param request.fee_token - Mint address of the token to calculate fees in
153
- * @returns Fee amounts in both lamports and the specified token
154
- * @throws {Error} When the RPC call fails, the transaction is invalid, or the token is not supported
155
- *
156
- * @example
157
- * ```typescript
158
- * const fees = await client.estimateTransactionFee({
159
- * transaction: 'base64EncodedTransaction',
160
- * fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC
161
- * });
162
- * console.log('Fee in lamports:', fees.fee_in_lamports);
163
- * console.log('Fee in USDC:', fees.fee_in_token);
164
- * ```
165
- */
166
75
  async estimateTransactionFee(request) {
167
76
  return await this.rpcRequest('estimateTransactionFee', request);
168
77
  }
169
- /**
170
- * Estimates the bundle fee in both lamports and the specified token.
171
- * @param request - Bundle fee estimation request parameters
172
- * @param request.transactions - Array of base64-encoded transactions to estimate fees for
173
- * @param request.fee_token - Mint address of the token to calculate fees in
174
- * @returns Total fee amounts across all transactions in both lamports and the specified token
175
- * @throws {Error} When the RPC call fails, the bundle is invalid, or the token is not supported
176
- *
177
- * @example
178
- * ```typescript
179
- * const fees = await client.estimateBundleFee({
180
- * transactions: ['base64EncodedTransaction1', 'base64EncodedTransaction2'],
181
- * fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC
182
- * });
183
- * console.log('Total fee in lamports:', fees.fee_in_lamports);
184
- * console.log('Total fee in USDC:', fees.fee_in_token);
185
- * ```
186
- */
187
- async estimateBundleFee(request) {
188
- return await this.rpcRequest('estimateBundleFee', request);
189
- }
190
- /**
191
- * Signs a transaction with the Kora fee payer without broadcasting it.
192
- * @param request - Sign request parameters
193
- * @param request.transaction - Base64-encoded transaction to sign
194
- * @returns Signature and the signed transaction
195
- * @throws {Error} When the RPC call fails or transaction validation fails
196
- *
197
- * @example
198
- * ```typescript
199
- * const result = await client.signTransaction({
200
- * transaction: 'base64EncodedTransaction'
201
- * });
202
- * console.log('Signature:', result.signature);
203
- * console.log('Signed tx:', result.signed_transaction);
204
- * ```
205
- */
206
78
  async signTransaction(request) {
207
79
  return await this.rpcRequest('signTransaction', request);
208
80
  }
209
- /**
210
- * Signs a transaction and immediately broadcasts it to the Solana network.
211
- * @param request - Sign and send request parameters
212
- * @param request.transaction - Base64-encoded transaction to sign and send
213
- * @returns Signature and the signed transaction
214
- * @throws {Error} When the RPC call fails, validation fails, or broadcast fails
215
- *
216
- * @example
217
- * ```typescript
218
- * const result = await client.signAndSendTransaction({
219
- * transaction: 'base64EncodedTransaction'
220
- * });
221
- * console.log('Transaction signature:', result.signature);
222
- * ```
223
- */
224
81
  async signAndSendTransaction(request) {
225
82
  return await this.rpcRequest('signAndSendTransaction', request);
226
83
  }
227
- /**
228
- * Signs a bundle of transactions with the Kora fee payer without broadcasting.
229
- * @param request - Sign bundle request parameters
230
- * @param request.transactions - Array of base64-encoded transactions to sign
231
- * @param request.signer_key - Optional signer address for the transactions
232
- * @param request.sig_verify - Optional signature verification (defaults to false)
233
- * @param request.sign_only_indices - Optional indices of transactions to sign (defaults to all)
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 await 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
- * @param request.sign_only_indices - Optional indices of transactions to sign (defaults to all)
256
- * @returns Array of signed transactions, signer public key, and Jito bundle UUID
257
- * @throws {Error} When the RPC call fails, validation fails, or Jito submission fails
258
- *
259
- * @example
260
- * ```typescript
261
- * const result = await client.signAndSendBundle({
262
- * transactions: ['base64Tx1', 'base64Tx2']
263
- * });
264
- * console.log('Bundle UUID:', result.bundle_uuid);
265
- * console.log('Signed transactions:', result.signed_transactions);
266
- * ```
267
- */
268
- async signAndSendBundle(request) {
269
- return await this.rpcRequest('signAndSendBundle', request);
84
+ async transferTransaction(request) {
85
+ const response = await this.rpcRequest('transferTransaction', request);
86
+ response.instructions = getInstructionsFromBase64Message(response.message || '');
87
+ return response;
270
88
  }
271
89
  /**
272
- * Creates a payment instruction to append to a transaction for fee payment to the Kora paymaster.
273
- *
274
- * This method estimates the required fee and generates a token transfer instruction
275
- * from the source wallet to the Kora payment address. The server handles decimal
276
- * conversion internally, so the raw token amount is used directly.
277
- *
278
- * @param request - Payment instruction request parameters
279
- * @param request.transaction - Base64-encoded transaction to estimate fees for
280
- * @param request.fee_token - Mint address of the token to use for payment
281
- * @param request.source_wallet - Public key of the wallet paying the fees
282
- * @param request.token_program_id - Optional token program ID (defaults to TOKEN_PROGRAM_ADDRESS)
283
- * @param request.signer_key - Optional signer address for the transaction
284
- * @param request.sig_verify - Optional signer verification during transaction simulation (defaults to false)
285
- * @returns Payment instruction details including the instruction, amount, and addresses
286
- * @throws {Error} When the token is not supported, payment is not required, or invalid addresses are provided
90
+ * Estimates the fee and builds a payment transfer instruction from the source wallet
91
+ * to the Kora payment address. The server handles decimal conversion internally.
287
92
  *
288
93
  * @example
289
94
  * ```typescript
@@ -316,12 +121,10 @@ export class KoraClient {
316
121
  owner: payment_address,
317
122
  tokenProgram: token_program_id,
318
123
  });
319
- if (fee_in_token === undefined) {
320
- throw new Error('Fee token was specified but fee_in_token was not returned from server');
321
- }
124
+ const signer = createNoopSigner(source_wallet);
322
125
  const paymentInstruction = getTransferInstruction({
323
126
  amount: fee_in_token,
324
- authority: createNoopSigner(source_wallet),
127
+ authority: signer,
325
128
  destination: destinationTokenAccount,
326
129
  source: sourceTokenAccount,
327
130
  });
@@ -331,6 +134,7 @@ export class KoraClient {
331
134
  payment_amount: fee_in_token,
332
135
  payment_instruction: paymentInstruction,
333
136
  payment_token: fee_token,
137
+ signer,
334
138
  signer_address: signer_pubkey,
335
139
  };
336
140
  }
@@ -1,3 +1,4 @@
1
1
  export * from './types/index.js';
2
2
  export { KoraClient } from './client.js';
3
- export { koraPlugin, type KoraApi } from './plugin.js';
3
+ export { koraPlugin, type KoraPlugin } from './kit/plugin.js';
4
+ export { createKitKoraClient, type KoraKitClient } from './kit/index.js';
package/dist/src/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './types/index.js';
2
2
  export { KoraClient } from './client.js';
3
- export { koraPlugin } from './plugin.js';
3
+ export { koraPlugin } from './kit/plugin.js';
4
+ export { createKitKoraClient } from './kit/index.js';
@@ -0,0 +1,7 @@
1
+ import { type Address, type TransactionMessage, type TransactionMessageWithFeePayer, type TransactionSigner } from '@solana/kit';
2
+ import { KoraClient } from '../client.js';
3
+ import type { KoraKitClientConfig } from '../types/index.js';
4
+ export declare function createKoraTransactionPlanExecutor(koraClient: KoraClient, config: KoraKitClientConfig, payerSigner: TransactionSigner, payment: {
5
+ destinationTokenAccount: Address;
6
+ sourceTokenAccount: Address;
7
+ } | undefined, resolveProvisoryComputeUnitLimit: (<T extends TransactionMessage & TransactionMessageWithFeePayer>(transactionMessage: T) => Promise<T>) | undefined): import("@solana/kit").TransactionPlanExecutor<import("@solana/kit").TransactionPlanResultContext>;
@@ -0,0 +1,55 @@
1
+ import { appendTransactionMessageInstructions, blockhash, createTransactionMessage, createTransactionPlanExecutor, getBase64EncodedWireTransaction, getBase64Encoder, getSignatureFromTransaction, getTransactionDecoder, partiallySignTransactionMessageWithSigners, pipe, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signature, } from '@solana/kit';
2
+ import { removePaymentInstruction, updatePaymentInstructionAmount } from './payment.js';
3
+ export function createKoraTransactionPlanExecutor(koraClient, config, payerSigner, payment, resolveProvisoryComputeUnitLimit) {
4
+ return createTransactionPlanExecutor({
5
+ async executeTransactionMessage(_context, transactionMessage) {
6
+ // Kora manages blockhash validity; set max height to avoid premature client-side expiry checks
7
+ const { blockhash: bh } = await koraClient.getBlockhash();
8
+ const msgWithLifetime = setTransactionMessageLifetimeUsingBlockhash({
9
+ blockhash: blockhash(bh),
10
+ lastValidBlockHeight: BigInt(Number.MAX_SAFE_INTEGER),
11
+ }, transactionMessage);
12
+ const msgForEstimation = resolveProvisoryComputeUnitLimit
13
+ ? await resolveProvisoryComputeUnitLimit(msgWithLifetime)
14
+ : msgWithLifetime;
15
+ const prePaymentTx = getBase64EncodedWireTransaction(await partiallySignTransactionMessageWithSigners(msgForEstimation));
16
+ let finalTx;
17
+ if (payment) {
18
+ const { sourceTokenAccount, destinationTokenAccount } = payment;
19
+ const { fee_in_token } = await koraClient.estimateTransactionFee({
20
+ fee_token: config.feeToken,
21
+ transaction: prePaymentTx,
22
+ });
23
+ if (fee_in_token < 0) {
24
+ throw new Error(`Kora fee estimation returned a negative fee (${fee_in_token}). This indicates a server-side error.`);
25
+ }
26
+ const currentIxs = 'instructions' in msgForEstimation
27
+ ? msgForEstimation.instructions
28
+ : undefined;
29
+ if (!currentIxs) {
30
+ throw new Error('Cannot extract instructions from transaction message. ' +
31
+ 'The message structure may be incompatible with this version of the Kora SDK.');
32
+ }
33
+ // Replace placeholder with real fee amount, or strip it if fee is 0
34
+ const finalIxs = fee_in_token > 0
35
+ ? updatePaymentInstructionAmount(currentIxs, config.feePayerWallet, sourceTokenAccount, destinationTokenAccount, fee_in_token, config.tokenProgramId)
36
+ : removePaymentInstruction(currentIxs, sourceTokenAccount, destinationTokenAccount, config.feePayerWallet, config.tokenProgramId);
37
+ const resolvedMsg = pipe(createTransactionMessage({ version: 0 }), m => setTransactionMessageFeePayerSigner(payerSigner, m), m => setTransactionMessageLifetimeUsingBlockhash({
38
+ blockhash: blockhash(bh),
39
+ lastValidBlockHeight: BigInt(Number.MAX_SAFE_INTEGER),
40
+ }, m), m => appendTransactionMessageInstructions(finalIxs, m));
41
+ finalTx = getBase64EncodedWireTransaction(await partiallySignTransactionMessageWithSigners(resolvedMsg));
42
+ }
43
+ else {
44
+ finalTx = prePaymentTx;
45
+ }
46
+ const result = await koraClient.signAndSendTransaction({ transaction: finalTx });
47
+ if (result.signature) {
48
+ return signature(result.signature);
49
+ }
50
+ const signedTxBytes = getBase64Encoder().encode(result.signed_transaction);
51
+ const decodedTx = getTransactionDecoder().decode(signedTxBytes);
52
+ return getSignatureFromTransaction(decodedTx);
53
+ },
54
+ });
55
+ }