@solana/kora 0.2.0 → 0.3.0-beta.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/dist/src/client.d.ts +201 -7
- package/dist/src/client.js +223 -18
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/kit/executor.js +18 -5
- package/dist/src/kit/index.d.ts +4 -1
- package/dist/src/kit/index.js +10 -2
- package/dist/src/kit/payment.js +3 -2
- package/dist/src/plugin.d.ts +85 -0
- package/dist/src/{kit/plugin.js → plugin.js} +88 -18
- package/dist/src/types/index.d.ts +173 -78
- package/dist/test/auth-setup.js +4 -4
- package/dist/test/integration.test.js +168 -291
- package/dist/test/kit-client.test.js +18 -0
- package/dist/test/plugin.test.js +126 -71
- package/dist/test/setup.d.ts +8 -15
- package/dist/test/setup.js +52 -152
- package/dist/test/unit.test.js +318 -166
- package/package.json +8 -16
- package/dist/src/kit/plugin.d.ts +0 -31
package/dist/src/client.d.ts
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import { Config, EstimateTransactionFeeRequest, EstimateTransactionFeeResponse, GetBlockhashResponse, GetPayerSignerResponse, GetPaymentInstructionRequest, GetPaymentInstructionResponse, GetSupportedTokensResponse, KoraClientOptions, SignAndSendTransactionRequest, SignAndSendTransactionResponse,
|
|
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';
|
|
2
2
|
/**
|
|
3
3
|
* Kora RPC client for interacting with the Kora paymaster service.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
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
|
|
6
9
|
* ```typescript
|
|
7
|
-
* const client = new KoraClient({
|
|
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
|
|
8
19
|
* const config = await client.getConfig();
|
|
9
20
|
* ```
|
|
10
21
|
*/
|
|
@@ -12,21 +23,204 @@ export declare class KoraClient {
|
|
|
12
23
|
private rpcUrl;
|
|
13
24
|
private apiKey?;
|
|
14
25
|
private hmacSecret?;
|
|
15
|
-
|
|
26
|
+
private getRecaptchaToken?;
|
|
27
|
+
/**
|
|
28
|
+
* Creates a new Kora client instance.
|
|
29
|
+
* @param options - Client configuration options
|
|
30
|
+
* @param options.rpcUrl - The Kora RPC server URL
|
|
31
|
+
* @param options.apiKey - Optional API key for authentication
|
|
32
|
+
* @param options.hmacSecret - Optional HMAC secret for signature-based authentication
|
|
33
|
+
* @param options.getRecaptchaToken - Optional callback to get reCAPTCHA token for bot protection
|
|
34
|
+
*/
|
|
35
|
+
constructor({ rpcUrl, apiKey, hmacSecret, getRecaptchaToken }: KoraClientOptions);
|
|
16
36
|
private getHmacSignature;
|
|
17
37
|
private getHeaders;
|
|
18
38
|
private rpcRequest;
|
|
39
|
+
/**
|
|
40
|
+
* Retrieves the current Kora server configuration.
|
|
41
|
+
* @returns The server configuration including fee payer address and validation rules
|
|
42
|
+
* @throws {Error} When the RPC call fails
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const config = await client.getConfig();
|
|
47
|
+
* console.log('Fee payer:', config.fee_payer);
|
|
48
|
+
* console.log('Validation config:', JSON.stringify(config.validation_config, null, 2));
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
19
51
|
getConfig(): Promise<Config>;
|
|
52
|
+
/**
|
|
53
|
+
* Retrieves the payer signer and payment destination from the Kora server.
|
|
54
|
+
* @returns Object containing the payer signer and payment destination
|
|
55
|
+
* @throws {Error} When the RPC call fails
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
*/
|
|
20
59
|
getPayerSigner(): Promise<GetPayerSignerResponse>;
|
|
60
|
+
/**
|
|
61
|
+
* Gets the latest blockhash from the Solana RPC that the Kora server is connected to.
|
|
62
|
+
* @returns Object containing the current blockhash
|
|
63
|
+
* @throws {Error} When the RPC call fails
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const { blockhash } = await client.getBlockhash();
|
|
68
|
+
* console.log('Current blockhash:', blockhash);
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
21
71
|
getBlockhash(): Promise<GetBlockhashResponse>;
|
|
72
|
+
/**
|
|
73
|
+
* Gets the version of the Kora server.
|
|
74
|
+
* @returns Object containing the server version
|
|
75
|
+
* @throws {Error} When the RPC call fails
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const { version } = await client.getVersion();
|
|
80
|
+
* console.log('Server version:', version);
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
getVersion(): Promise<GetVersionResponse>;
|
|
84
|
+
/**
|
|
85
|
+
* Retrieves the list of tokens supported for fee payment.
|
|
86
|
+
* @returns Object containing an array of supported token mint addresses
|
|
87
|
+
* @throws {Error} When the RPC call fails
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const { tokens } = await client.getSupportedTokens();
|
|
92
|
+
* console.log('Supported tokens:', tokens);
|
|
93
|
+
* // Output: ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', ...]
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
22
96
|
getSupportedTokens(): Promise<GetSupportedTokensResponse>;
|
|
97
|
+
/**
|
|
98
|
+
* Estimates the transaction fee in both lamports and the specified token.
|
|
99
|
+
* @param request - Fee estimation request parameters
|
|
100
|
+
* @param request.transaction - Base64-encoded transaction to estimate fees for
|
|
101
|
+
* @param request.fee_token - Mint address of the token to calculate fees in
|
|
102
|
+
* @returns Fee amounts in both lamports and the specified token
|
|
103
|
+
* @throws {Error} When the RPC call fails, the transaction is invalid, or the token is not supported
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* const fees = await client.estimateTransactionFee({
|
|
108
|
+
* transaction: 'base64EncodedTransaction',
|
|
109
|
+
* fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC
|
|
110
|
+
* });
|
|
111
|
+
* console.log('Fee in lamports:', fees.fee_in_lamports);
|
|
112
|
+
* console.log('Fee in USDC:', fees.fee_in_token);
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
23
115
|
estimateTransactionFee(request: EstimateTransactionFeeRequest): Promise<EstimateTransactionFeeResponse>;
|
|
116
|
+
/**
|
|
117
|
+
* Estimates the bundle fee in both lamports and the specified token.
|
|
118
|
+
* @param request - Bundle fee estimation request parameters
|
|
119
|
+
* @param request.transactions - Array of base64-encoded transactions to estimate fees for
|
|
120
|
+
* @param request.fee_token - Mint address of the token to calculate fees in
|
|
121
|
+
* @returns Total fee amounts across all transactions in both lamports and the specified token
|
|
122
|
+
* @throws {Error} When the RPC call fails, the bundle is invalid, or the token is not supported
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* const fees = await client.estimateBundleFee({
|
|
127
|
+
* transactions: ['base64EncodedTransaction1', 'base64EncodedTransaction2'],
|
|
128
|
+
* fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC
|
|
129
|
+
* });
|
|
130
|
+
* console.log('Total fee in lamports:', fees.fee_in_lamports);
|
|
131
|
+
* console.log('Total fee in USDC:', fees.fee_in_token);
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
estimateBundleFee(request: EstimateBundleFeeRequest): Promise<EstimateBundleFeeResponse>;
|
|
135
|
+
/**
|
|
136
|
+
* Signs a transaction with the Kora fee payer without broadcasting it.
|
|
137
|
+
* @param request - Sign request parameters
|
|
138
|
+
* @param request.transaction - Base64-encoded transaction to sign
|
|
139
|
+
* @returns Signature and the signed transaction
|
|
140
|
+
* @throws {Error} When the RPC call fails or transaction validation fails
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* const result = await client.signTransaction({
|
|
145
|
+
* transaction: 'base64EncodedTransaction'
|
|
146
|
+
* });
|
|
147
|
+
* console.log('Signature:', result.signature);
|
|
148
|
+
* console.log('Signed tx:', result.signed_transaction);
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
24
151
|
signTransaction(request: SignTransactionRequest): Promise<SignTransactionResponse>;
|
|
152
|
+
/**
|
|
153
|
+
* Signs a transaction and immediately broadcasts it to the Solana network.
|
|
154
|
+
* @param request - Sign and send request parameters
|
|
155
|
+
* @param request.transaction - Base64-encoded transaction to sign and send
|
|
156
|
+
* @returns Signature and the signed transaction
|
|
157
|
+
* @throws {Error} When the RPC call fails, validation fails, or broadcast fails
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const result = await client.signAndSendTransaction({
|
|
162
|
+
* transaction: 'base64EncodedTransaction'
|
|
163
|
+
* });
|
|
164
|
+
* console.log('Transaction signature:', result.signature);
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
25
167
|
signAndSendTransaction(request: SignAndSendTransactionRequest): Promise<SignAndSendTransactionResponse>;
|
|
26
|
-
transferTransaction(request: TransferTransactionRequest): Promise<TransferTransactionResponse>;
|
|
27
168
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
169
|
+
* Signs a bundle of transactions with the Kora fee payer without broadcasting.
|
|
170
|
+
* @param request - Sign bundle request parameters
|
|
171
|
+
* @param request.transactions - Array of base64-encoded transactions to sign
|
|
172
|
+
* @param request.signer_key - Optional signer address for the transactions
|
|
173
|
+
* @param request.sig_verify - Optional signature verification (defaults to false)
|
|
174
|
+
* @param request.sign_only_indices - Optional indices of transactions to sign (defaults to all)
|
|
175
|
+
* @returns Array of signed transactions and signer public key
|
|
176
|
+
* @throws {Error} When the RPC call fails or validation fails
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* const result = await client.signBundle({
|
|
181
|
+
* transactions: ['base64Tx1', 'base64Tx2']
|
|
182
|
+
* });
|
|
183
|
+
* console.log('Signed transactions:', result.signed_transactions);
|
|
184
|
+
* console.log('Signer:', result.signer_pubkey);
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
signBundle(request: SignBundleRequest): Promise<SignBundleResponse>;
|
|
188
|
+
/**
|
|
189
|
+
* Signs a bundle of transactions and sends them to Jito block engine.
|
|
190
|
+
* @param request - Sign and send bundle request parameters
|
|
191
|
+
* @param request.transactions - Array of base64-encoded transactions to sign and send
|
|
192
|
+
* @param request.signer_key - Optional signer address for the transactions
|
|
193
|
+
* @param request.sig_verify - Optional signature verification (defaults to false)
|
|
194
|
+
* @param request.sign_only_indices - Optional indices of transactions to sign (defaults to all)
|
|
195
|
+
* @returns Array of signed transactions, signer public key, and Jito bundle UUID
|
|
196
|
+
* @throws {Error} When the RPC call fails, validation fails, or Jito submission fails
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```typescript
|
|
200
|
+
* const result = await client.signAndSendBundle({
|
|
201
|
+
* transactions: ['base64Tx1', 'base64Tx2']
|
|
202
|
+
* });
|
|
203
|
+
* console.log('Bundle UUID:', result.bundle_uuid);
|
|
204
|
+
* console.log('Signed transactions:', result.signed_transactions);
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
signAndSendBundle(request: SignAndSendBundleRequest): Promise<SignAndSendBundleResponse>;
|
|
208
|
+
/**
|
|
209
|
+
* Creates a payment instruction to append to a transaction for fee payment to the Kora paymaster.
|
|
210
|
+
*
|
|
211
|
+
* This method estimates the required fee and generates a token transfer instruction
|
|
212
|
+
* from the source wallet to the Kora payment address. The server handles decimal
|
|
213
|
+
* conversion internally, so the raw token amount is used directly.
|
|
214
|
+
*
|
|
215
|
+
* @param request - Payment instruction request parameters
|
|
216
|
+
* @param request.transaction - Base64-encoded transaction to estimate fees for
|
|
217
|
+
* @param request.fee_token - Mint address of the token to use for payment
|
|
218
|
+
* @param request.source_wallet - Public key of the wallet paying the fees
|
|
219
|
+
* @param request.token_program_id - Optional token program ID (defaults to TOKEN_PROGRAM_ADDRESS)
|
|
220
|
+
* @param request.signer_key - Optional signer address for the transaction
|
|
221
|
+
* @param request.sig_verify - Optional signer verification during transaction simulation (defaults to false)
|
|
222
|
+
* @returns Payment instruction details including the instruction, amount, and addresses
|
|
223
|
+
* @throws {Error} When the token is not supported, payment is not required, or invalid addresses are provided
|
|
30
224
|
*
|
|
31
225
|
* @example
|
|
32
226
|
* ```typescript
|
package/dist/src/client.js
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
|
-
import { assertIsAddress,
|
|
1
|
+
import { assertIsAddress, isTransactionSigner } 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';
|
|
5
4
|
/**
|
|
6
5
|
* Kora RPC client for interacting with the Kora paymaster service.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
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
|
|
9
11
|
* ```typescript
|
|
10
|
-
* const client = new KoraClient({
|
|
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
|
|
11
21
|
* const config = await client.getConfig();
|
|
12
22
|
* ```
|
|
13
23
|
*/
|
|
@@ -15,10 +25,20 @@ export class KoraClient {
|
|
|
15
25
|
rpcUrl;
|
|
16
26
|
apiKey;
|
|
17
27
|
hmacSecret;
|
|
18
|
-
|
|
28
|
+
getRecaptchaToken;
|
|
29
|
+
/**
|
|
30
|
+
* Creates a new Kora client instance.
|
|
31
|
+
* @param options - Client configuration options
|
|
32
|
+
* @param options.rpcUrl - The Kora RPC server URL
|
|
33
|
+
* @param options.apiKey - Optional API key for authentication
|
|
34
|
+
* @param options.hmacSecret - Optional HMAC secret for signature-based authentication
|
|
35
|
+
* @param options.getRecaptchaToken - Optional callback to get reCAPTCHA token for bot protection
|
|
36
|
+
*/
|
|
37
|
+
constructor({ rpcUrl, apiKey, hmacSecret, getRecaptchaToken }) {
|
|
19
38
|
this.rpcUrl = rpcUrl;
|
|
20
39
|
this.apiKey = apiKey;
|
|
21
40
|
this.hmacSecret = hmacSecret;
|
|
41
|
+
this.getRecaptchaToken = getRecaptchaToken;
|
|
22
42
|
}
|
|
23
43
|
getHmacSignature({ timestamp, body }) {
|
|
24
44
|
if (!this.hmacSecret) {
|
|
@@ -27,7 +47,7 @@ export class KoraClient {
|
|
|
27
47
|
const message = timestamp + body;
|
|
28
48
|
return crypto.createHmac('sha256', this.hmacSecret).update(message).digest('hex');
|
|
29
49
|
}
|
|
30
|
-
getHeaders({ body }) {
|
|
50
|
+
async getHeaders({ body }) {
|
|
31
51
|
const headers = {};
|
|
32
52
|
if (this.apiKey) {
|
|
33
53
|
headers['x-api-key'] = this.apiKey;
|
|
@@ -38,6 +58,10 @@ export class KoraClient {
|
|
|
38
58
|
headers['x-timestamp'] = timestamp;
|
|
39
59
|
headers['x-hmac-signature'] = signature;
|
|
40
60
|
}
|
|
61
|
+
if (this.getRecaptchaToken) {
|
|
62
|
+
const token = await Promise.resolve(this.getRecaptchaToken());
|
|
63
|
+
headers['x-recaptcha-token'] = token;
|
|
64
|
+
}
|
|
41
65
|
return headers;
|
|
42
66
|
}
|
|
43
67
|
async rpcRequest(method, params) {
|
|
@@ -47,7 +71,7 @@ export class KoraClient {
|
|
|
47
71
|
method,
|
|
48
72
|
params,
|
|
49
73
|
});
|
|
50
|
-
const headers = this.getHeaders({ body });
|
|
74
|
+
const headers = await this.getHeaders({ body });
|
|
51
75
|
const response = await fetch(this.rpcUrl, {
|
|
52
76
|
body,
|
|
53
77
|
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
@@ -60,35 +84,213 @@ export class KoraClient {
|
|
|
60
84
|
}
|
|
61
85
|
return json.result;
|
|
62
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Retrieves the current Kora server configuration.
|
|
89
|
+
* @returns The server configuration including fee payer address and validation rules
|
|
90
|
+
* @throws {Error} When the RPC call fails
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* const config = await client.getConfig();
|
|
95
|
+
* console.log('Fee payer:', config.fee_payer);
|
|
96
|
+
* console.log('Validation config:', JSON.stringify(config.validation_config, null, 2));
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
63
99
|
async getConfig() {
|
|
64
100
|
return await this.rpcRequest('getConfig', undefined);
|
|
65
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Retrieves the payer signer and payment destination from the Kora server.
|
|
104
|
+
* @returns Object containing the payer signer and payment destination
|
|
105
|
+
* @throws {Error} When the RPC call fails
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
*/
|
|
66
109
|
async getPayerSigner() {
|
|
67
110
|
return await this.rpcRequest('getPayerSigner', undefined);
|
|
68
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Gets the latest blockhash from the Solana RPC that the Kora server is connected to.
|
|
114
|
+
* @returns Object containing the current blockhash
|
|
115
|
+
* @throws {Error} When the RPC call fails
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* const { blockhash } = await client.getBlockhash();
|
|
120
|
+
* console.log('Current blockhash:', blockhash);
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
69
123
|
async getBlockhash() {
|
|
70
124
|
return await this.rpcRequest('getBlockhash', undefined);
|
|
71
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Gets the version of the Kora server.
|
|
128
|
+
* @returns Object containing the server version
|
|
129
|
+
* @throws {Error} When the RPC call fails
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const { version } = await client.getVersion();
|
|
134
|
+
* console.log('Server version:', version);
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
async getVersion() {
|
|
138
|
+
return await this.rpcRequest('getVersion', undefined);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Retrieves the list of tokens supported for fee payment.
|
|
142
|
+
* @returns Object containing an array of supported token mint addresses
|
|
143
|
+
* @throws {Error} When the RPC call fails
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const { tokens } = await client.getSupportedTokens();
|
|
148
|
+
* console.log('Supported tokens:', tokens);
|
|
149
|
+
* // Output: ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', ...]
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
72
152
|
async getSupportedTokens() {
|
|
73
153
|
return await this.rpcRequest('getSupportedTokens', undefined);
|
|
74
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Estimates the transaction fee in both lamports and the specified token.
|
|
157
|
+
* @param request - Fee estimation request parameters
|
|
158
|
+
* @param request.transaction - Base64-encoded transaction to estimate fees for
|
|
159
|
+
* @param request.fee_token - Mint address of the token to calculate fees in
|
|
160
|
+
* @returns Fee amounts in both lamports and the specified token
|
|
161
|
+
* @throws {Error} When the RPC call fails, the transaction is invalid, or the token is not supported
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const fees = await client.estimateTransactionFee({
|
|
166
|
+
* transaction: 'base64EncodedTransaction',
|
|
167
|
+
* fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC
|
|
168
|
+
* });
|
|
169
|
+
* console.log('Fee in lamports:', fees.fee_in_lamports);
|
|
170
|
+
* console.log('Fee in USDC:', fees.fee_in_token);
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
75
173
|
async estimateTransactionFee(request) {
|
|
76
174
|
return await this.rpcRequest('estimateTransactionFee', request);
|
|
77
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Estimates the bundle fee in both lamports and the specified token.
|
|
178
|
+
* @param request - Bundle fee estimation request parameters
|
|
179
|
+
* @param request.transactions - Array of base64-encoded transactions to estimate fees for
|
|
180
|
+
* @param request.fee_token - Mint address of the token to calculate fees in
|
|
181
|
+
* @returns Total fee amounts across all transactions in both lamports and the specified token
|
|
182
|
+
* @throws {Error} When the RPC call fails, the bundle is invalid, or the token is not supported
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```typescript
|
|
186
|
+
* const fees = await client.estimateBundleFee({
|
|
187
|
+
* transactions: ['base64EncodedTransaction1', 'base64EncodedTransaction2'],
|
|
188
|
+
* fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC
|
|
189
|
+
* });
|
|
190
|
+
* console.log('Total fee in lamports:', fees.fee_in_lamports);
|
|
191
|
+
* console.log('Total fee in USDC:', fees.fee_in_token);
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
async estimateBundleFee(request) {
|
|
195
|
+
return await this.rpcRequest('estimateBundleFee', request);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Signs a transaction with the Kora fee payer without broadcasting it.
|
|
199
|
+
* @param request - Sign request parameters
|
|
200
|
+
* @param request.transaction - Base64-encoded transaction to sign
|
|
201
|
+
* @returns Signature and the signed transaction
|
|
202
|
+
* @throws {Error} When the RPC call fails or transaction validation fails
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* const result = await client.signTransaction({
|
|
207
|
+
* transaction: 'base64EncodedTransaction'
|
|
208
|
+
* });
|
|
209
|
+
* console.log('Signature:', result.signature);
|
|
210
|
+
* console.log('Signed tx:', result.signed_transaction);
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
78
213
|
async signTransaction(request) {
|
|
79
214
|
return await this.rpcRequest('signTransaction', request);
|
|
80
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Signs a transaction and immediately broadcasts it to the Solana network.
|
|
218
|
+
* @param request - Sign and send request parameters
|
|
219
|
+
* @param request.transaction - Base64-encoded transaction to sign and send
|
|
220
|
+
* @returns Signature and the signed transaction
|
|
221
|
+
* @throws {Error} When the RPC call fails, validation fails, or broadcast fails
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* const result = await client.signAndSendTransaction({
|
|
226
|
+
* transaction: 'base64EncodedTransaction'
|
|
227
|
+
* });
|
|
228
|
+
* console.log('Transaction signature:', result.signature);
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
81
231
|
async signAndSendTransaction(request) {
|
|
82
232
|
return await this.rpcRequest('signAndSendTransaction', request);
|
|
83
233
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Signs a bundle of transactions with the Kora fee payer without broadcasting.
|
|
236
|
+
* @param request - Sign bundle request parameters
|
|
237
|
+
* @param request.transactions - Array of base64-encoded transactions to sign
|
|
238
|
+
* @param request.signer_key - Optional signer address for the transactions
|
|
239
|
+
* @param request.sig_verify - Optional signature verification (defaults to false)
|
|
240
|
+
* @param request.sign_only_indices - Optional indices of transactions to sign (defaults to all)
|
|
241
|
+
* @returns Array of signed transactions and signer public key
|
|
242
|
+
* @throws {Error} When the RPC call fails or validation fails
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* const result = await client.signBundle({
|
|
247
|
+
* transactions: ['base64Tx1', 'base64Tx2']
|
|
248
|
+
* });
|
|
249
|
+
* console.log('Signed transactions:', result.signed_transactions);
|
|
250
|
+
* console.log('Signer:', result.signer_pubkey);
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
async signBundle(request) {
|
|
254
|
+
return await this.rpcRequest('signBundle', request);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Signs a bundle of transactions and sends them to Jito block engine.
|
|
258
|
+
* @param request - Sign and send bundle request parameters
|
|
259
|
+
* @param request.transactions - Array of base64-encoded transactions to sign and send
|
|
260
|
+
* @param request.signer_key - Optional signer address for the transactions
|
|
261
|
+
* @param request.sig_verify - Optional signature verification (defaults to false)
|
|
262
|
+
* @param request.sign_only_indices - Optional indices of transactions to sign (defaults to all)
|
|
263
|
+
* @returns Array of signed transactions, signer public key, and Jito bundle UUID
|
|
264
|
+
* @throws {Error} When the RPC call fails, validation fails, or Jito submission fails
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```typescript
|
|
268
|
+
* const result = await client.signAndSendBundle({
|
|
269
|
+
* transactions: ['base64Tx1', 'base64Tx2']
|
|
270
|
+
* });
|
|
271
|
+
* console.log('Bundle UUID:', result.bundle_uuid);
|
|
272
|
+
* console.log('Signed transactions:', result.signed_transactions);
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
async signAndSendBundle(request) {
|
|
276
|
+
return await this.rpcRequest('signAndSendBundle', request);
|
|
88
277
|
}
|
|
89
278
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
279
|
+
* Creates a payment instruction to append to a transaction for fee payment to the Kora paymaster.
|
|
280
|
+
*
|
|
281
|
+
* This method estimates the required fee and generates a token transfer instruction
|
|
282
|
+
* from the source wallet to the Kora payment address. The server handles decimal
|
|
283
|
+
* conversion internally, so the raw token amount is used directly.
|
|
284
|
+
*
|
|
285
|
+
* @param request - Payment instruction request parameters
|
|
286
|
+
* @param request.transaction - Base64-encoded transaction to estimate fees for
|
|
287
|
+
* @param request.fee_token - Mint address of the token to use for payment
|
|
288
|
+
* @param request.source_wallet - Public key of the wallet paying the fees
|
|
289
|
+
* @param request.token_program_id - Optional token program ID (defaults to TOKEN_PROGRAM_ADDRESS)
|
|
290
|
+
* @param request.signer_key - Optional signer address for the transaction
|
|
291
|
+
* @param request.sig_verify - Optional signer verification during transaction simulation (defaults to false)
|
|
292
|
+
* @returns Payment instruction details including the instruction, amount, and addresses
|
|
293
|
+
* @throws {Error} When the token is not supported, payment is not required, or invalid addresses are provided
|
|
92
294
|
*
|
|
93
295
|
* @example
|
|
94
296
|
* ```typescript
|
|
@@ -101,7 +303,9 @@ export class KoraClient {
|
|
|
101
303
|
* ```
|
|
102
304
|
*/
|
|
103
305
|
async getPaymentInstruction({ transaction, fee_token, source_wallet, token_program_id = TOKEN_PROGRAM_ADDRESS, signer_key, sig_verify, }) {
|
|
104
|
-
|
|
306
|
+
const isSigner = typeof source_wallet !== 'string' && isTransactionSigner(source_wallet);
|
|
307
|
+
const walletAddress = isSigner ? source_wallet.address : source_wallet;
|
|
308
|
+
assertIsAddress(walletAddress);
|
|
105
309
|
assertIsAddress(fee_token);
|
|
106
310
|
assertIsAddress(token_program_id);
|
|
107
311
|
const { fee_in_token, payment_address, signer_pubkey } = await this.estimateTransactionFee({
|
|
@@ -113,7 +317,7 @@ export class KoraClient {
|
|
|
113
317
|
assertIsAddress(payment_address);
|
|
114
318
|
const [sourceTokenAccount] = await findAssociatedTokenPda({
|
|
115
319
|
mint: fee_token,
|
|
116
|
-
owner:
|
|
320
|
+
owner: walletAddress,
|
|
117
321
|
tokenProgram: token_program_id,
|
|
118
322
|
});
|
|
119
323
|
const [destinationTokenAccount] = await findAssociatedTokenPda({
|
|
@@ -121,10 +325,12 @@ export class KoraClient {
|
|
|
121
325
|
owner: payment_address,
|
|
122
326
|
tokenProgram: token_program_id,
|
|
123
327
|
});
|
|
124
|
-
|
|
328
|
+
if (fee_in_token === undefined) {
|
|
329
|
+
throw new Error('Fee token was specified but fee_in_token was not returned from server');
|
|
330
|
+
}
|
|
125
331
|
const paymentInstruction = getTransferInstruction({
|
|
126
332
|
amount: fee_in_token,
|
|
127
|
-
authority:
|
|
333
|
+
authority: isSigner ? source_wallet : walletAddress,
|
|
128
334
|
destination: destinationTokenAccount,
|
|
129
335
|
source: sourceTokenAccount,
|
|
130
336
|
});
|
|
@@ -134,7 +340,6 @@ export class KoraClient {
|
|
|
134
340
|
payment_amount: fee_in_token,
|
|
135
341
|
payment_instruction: paymentInstruction,
|
|
136
342
|
payment_token: fee_token,
|
|
137
|
-
signer,
|
|
138
343
|
signer_address: signer_pubkey,
|
|
139
344
|
};
|
|
140
345
|
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export * from './types/index.js';
|
|
2
2
|
export { KoraClient } from './client.js';
|
|
3
|
-
export { koraPlugin, type KoraPlugin } from './kit/plugin.js';
|
|
4
3
|
export { createKitKoraClient, type KoraKitClient } from './kit/index.js';
|
|
4
|
+
export { koraPlugin, type KoraApi } from './plugin.js';
|
package/dist/src/index.js
CHANGED
package/dist/src/kit/executor.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { appendTransactionMessageInstructions, blockhash, createTransactionMessage, createTransactionPlanExecutor, getBase64EncodedWireTransaction, getBase64Encoder, getSignatureFromTransaction, getTransactionDecoder, partiallySignTransactionMessageWithSigners, pipe, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signature, } from '@solana/kit';
|
|
2
2
|
import { removePaymentInstruction, updatePaymentInstructionAmount } from './payment.js';
|
|
3
|
+
// TODO: Create a bundle-aware executor (e.g. `createKoraBundlePlanExecutor`) that collects
|
|
4
|
+
// multiple planned transaction messages into a single `signAndSendBundle` call instead of
|
|
5
|
+
// submitting each one individually via `signAndSendTransaction`. This would let users
|
|
6
|
+
// compose Jito bundles through the Kit plan/execute pipeline rather than manually encoding
|
|
7
|
+
// transactions and calling `client.kora.signAndSendBundle()`.
|
|
3
8
|
export function createKoraTransactionPlanExecutor(koraClient, config, payerSigner, payment, resolveProvisoryComputeUnitLimit) {
|
|
4
9
|
return createTransactionPlanExecutor({
|
|
5
10
|
async executeTransactionMessage(_context, transactionMessage) {
|
|
@@ -20,8 +25,13 @@ export function createKoraTransactionPlanExecutor(koraClient, config, payerSigne
|
|
|
20
25
|
fee_token: config.feeToken,
|
|
21
26
|
transaction: prePaymentTx,
|
|
22
27
|
});
|
|
23
|
-
if (fee_in_token
|
|
24
|
-
|
|
28
|
+
if (fee_in_token == null) {
|
|
29
|
+
console.warn('[kora] fee_in_token is undefined — defaulting to 0. ' +
|
|
30
|
+
'If paid pricing is expected, check that the fee token is correctly configured on the server.');
|
|
31
|
+
}
|
|
32
|
+
const feeInToken = fee_in_token ?? 0;
|
|
33
|
+
if (feeInToken < 0) {
|
|
34
|
+
throw new Error(`Kora fee estimation returned a negative fee (${feeInToken}). This indicates a server-side error.`);
|
|
25
35
|
}
|
|
26
36
|
const currentIxs = 'instructions' in msgForEstimation
|
|
27
37
|
? msgForEstimation.instructions
|
|
@@ -31,8 +41,8 @@ export function createKoraTransactionPlanExecutor(koraClient, config, payerSigne
|
|
|
31
41
|
'The message structure may be incompatible with this version of the Kora SDK.');
|
|
32
42
|
}
|
|
33
43
|
// Replace placeholder with real fee amount, or strip it if fee is 0
|
|
34
|
-
const finalIxs =
|
|
35
|
-
? updatePaymentInstructionAmount(currentIxs, config.feePayerWallet, sourceTokenAccount, destinationTokenAccount,
|
|
44
|
+
const finalIxs = feeInToken > 0
|
|
45
|
+
? updatePaymentInstructionAmount(currentIxs, config.feePayerWallet, sourceTokenAccount, destinationTokenAccount, feeInToken, config.tokenProgramId)
|
|
36
46
|
: removePaymentInstruction(currentIxs, sourceTokenAccount, destinationTokenAccount, config.feePayerWallet, config.tokenProgramId);
|
|
37
47
|
const resolvedMsg = pipe(createTransactionMessage({ version: 0 }), m => setTransactionMessageFeePayerSigner(payerSigner, m), m => setTransactionMessageLifetimeUsingBlockhash({
|
|
38
48
|
blockhash: blockhash(bh),
|
|
@@ -43,7 +53,10 @@ export function createKoraTransactionPlanExecutor(koraClient, config, payerSigne
|
|
|
43
53
|
else {
|
|
44
54
|
finalTx = prePaymentTx;
|
|
45
55
|
}
|
|
46
|
-
const result = await koraClient.signAndSendTransaction({
|
|
56
|
+
const result = await koraClient.signAndSendTransaction({
|
|
57
|
+
transaction: finalTx,
|
|
58
|
+
user_id: config.userId,
|
|
59
|
+
});
|
|
47
60
|
if (result.signature) {
|
|
48
61
|
return signature(result.signature);
|
|
49
62
|
}
|
package/dist/src/kit/index.d.ts
CHANGED
|
@@ -29,15 +29,18 @@ export declare function createKitKoraClient(config: KoraKitClientConfig): Promis
|
|
|
29
29
|
rpcSubscriptions: import("@solana/kit").RpcSubscriptions<import("@solana/kit").SolanaRpcSubscriptionsApi>;
|
|
30
30
|
} & {
|
|
31
31
|
kora: {
|
|
32
|
+
estimateBundleFee(request: import("../types/index.js").EstimateBundleFeeRequest): Promise<import("../types/index.js").KitEstimateBundleFeeResponse>;
|
|
32
33
|
estimateTransactionFee(request: import("../types/index.js").EstimateTransactionFeeRequest): Promise<import("../types/index.js").KitEstimateFeeResponse>;
|
|
33
34
|
getBlockhash(): Promise<import("../types/index.js").KitBlockhashResponse>;
|
|
34
35
|
getConfig(): Promise<import("../types/index.js").KitConfigResponse>;
|
|
35
36
|
getPayerSigner(): Promise<import("../types/index.js").KitPayerSignerResponse>;
|
|
36
37
|
getPaymentInstruction(request: import("../types/index.js").GetPaymentInstructionRequest): Promise<import("../types/index.js").KitPaymentInstructionResponse>;
|
|
37
38
|
getSupportedTokens(): Promise<import("../types/index.js").KitSupportedTokensResponse>;
|
|
39
|
+
getVersion(): Promise<import("../types/index.js").GetVersionResponse>;
|
|
40
|
+
signAndSendBundle(request: import("../types/index.js").SignAndSendBundleRequest): Promise<import("../types/index.js").KitSignAndSendBundleResponse>;
|
|
38
41
|
signAndSendTransaction(request: import("../types/index.js").SignAndSendTransactionRequest): Promise<import("../types/index.js").KitSignAndSendTransactionResponse>;
|
|
42
|
+
signBundle(request: import("../types/index.js").SignBundleRequest): Promise<import("../types/index.js").KitSignBundleResponse>;
|
|
39
43
|
signTransaction(request: import("../types/index.js").SignTransactionRequest): Promise<import("../types/index.js").KitSignTransactionResponse>;
|
|
40
|
-
transferTransaction(request: import("../types/index.js").TransferTransactionRequest): Promise<import("../types/index.js").KitTransferTransactionResponse>;
|
|
41
44
|
};
|
|
42
45
|
} & {
|
|
43
46
|
payer: import("@solana/kit").TransactionSigner;
|