@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.
@@ -1,5 +1,5 @@
1
1
  import { createEmptyClient } from '@solana/kit';
2
- import { koraPlugin } from '../src/kit/plugin.js';
2
+ import { koraPlugin } from '../src/plugin.js';
3
3
  // Mock fetch globally
4
4
  const mockFetch = jest.fn();
5
5
  global.fetch = mockFetch;
@@ -12,8 +12,8 @@ describe('Kora Kit Plugin', () => {
12
12
  const mockSuccessfulResponse = (result) => {
13
13
  mockFetch.mockResolvedValueOnce({
14
14
  json: jest.fn().mockResolvedValueOnce({
15
- jsonrpc: '2.0',
16
15
  id: 1,
16
+ jsonrpc: '2.0',
17
17
  result,
18
18
  }),
19
19
  });
@@ -22,9 +22,9 @@ describe('Kora Kit Plugin', () => {
22
22
  const mockErrorResponse = (error) => {
23
23
  mockFetch.mockResolvedValueOnce({
24
24
  json: jest.fn().mockResolvedValueOnce({
25
- jsonrpc: '2.0',
26
- id: 1,
27
25
  error,
26
+ id: 1,
27
+ jsonrpc: '2.0',
28
28
  }),
29
29
  });
30
30
  };
@@ -41,11 +41,14 @@ describe('Kora Kit Plugin', () => {
41
41
  expect(typeof enhanced.kora.getConfig).toBe('function');
42
42
  expect(typeof enhanced.kora.getPayerSigner).toBe('function');
43
43
  expect(typeof enhanced.kora.getBlockhash).toBe('function');
44
+ expect(typeof enhanced.kora.getVersion).toBe('function');
44
45
  expect(typeof enhanced.kora.getSupportedTokens).toBe('function');
45
46
  expect(typeof enhanced.kora.estimateTransactionFee).toBe('function');
47
+ expect(typeof enhanced.kora.estimateBundleFee).toBe('function');
46
48
  expect(typeof enhanced.kora.signTransaction).toBe('function');
47
49
  expect(typeof enhanced.kora.signAndSendTransaction).toBe('function');
48
- expect(typeof enhanced.kora.transferTransaction).toBe('function');
50
+ expect(typeof enhanced.kora.signBundle).toBe('function');
51
+ expect(typeof enhanced.kora.signAndSendBundle).toBe('function');
49
52
  expect(typeof enhanced.kora.getPaymentInstruction).toBe('function');
50
53
  });
51
54
  it('should work with empty client object', () => {
@@ -55,8 +58,8 @@ describe('Kora Kit Plugin', () => {
55
58
  });
56
59
  it('should support authentication options', () => {
57
60
  const authConfig = {
58
- endpoint: mockEndpoint,
59
61
  apiKey: 'test-api-key',
62
+ endpoint: mockEndpoint,
60
63
  hmacSecret: 'test-hmac-secret',
61
64
  };
62
65
  const plugin = koraPlugin(authConfig);
@@ -74,67 +77,67 @@ describe('Kora Kit Plugin', () => {
74
77
  describe('getConfig', () => {
75
78
  it('should return Kit-typed Address arrays', async () => {
76
79
  const rawResponse = {
80
+ enabled_methods: {
81
+ estimate_transaction_fee: true,
82
+ get_blockhash: true,
83
+ get_config: true,
84
+ get_supported_tokens: true,
85
+ liveness: true,
86
+ sign_and_send_transaction: true,
87
+ sign_transaction: true,
88
+ transfer_transaction: true,
89
+ },
77
90
  fee_payers: ['DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7'],
78
91
  validation_config: {
79
- max_allowed_lamports: 1000000,
80
- max_signatures: 10,
81
- price_source: 'Jupiter',
82
92
  allowed_programs: ['11111111111111111111111111111111'],
83
- allowed_tokens: ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'],
84
93
  allowed_spl_paid_tokens: ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'],
94
+ allowed_tokens: ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'],
85
95
  disallowed_accounts: [],
86
96
  fee_payer_policy: {
87
- system: {
97
+ spl_token: {
98
+ allow_approve: true,
99
+ allow_burn: true,
100
+ allow_close_account: true,
101
+ allow_freeze_account: true,
102
+ allow_mint_to: true,
103
+ allow_revoke: true,
104
+ allow_set_authority: true,
105
+ allow_thaw_account: true,
88
106
  allow_transfer: true,
107
+ },
108
+ system: {
109
+ allow_allocate: true,
89
110
  allow_assign: true,
90
111
  allow_create_account: true,
91
- allow_allocate: true,
112
+ allow_transfer: true,
92
113
  nonce: {
93
- allow_initialize: true,
94
114
  allow_advance: true,
95
115
  allow_authorize: true,
116
+ allow_initialize: true,
96
117
  allow_withdraw: true,
97
118
  },
98
119
  },
99
- spl_token: {
100
- allow_transfer: true,
101
- allow_burn: true,
102
- allow_close_account: true,
103
- allow_approve: true,
104
- allow_revoke: true,
105
- allow_set_authority: true,
106
- allow_mint_to: true,
107
- allow_freeze_account: true,
108
- allow_thaw_account: true,
109
- },
110
120
  token_2022: {
111
- allow_transfer: true,
121
+ allow_approve: true,
112
122
  allow_burn: true,
113
123
  allow_close_account: true,
114
- allow_approve: true,
124
+ allow_freeze_account: true,
125
+ allow_mint_to: true,
115
126
  allow_revoke: true,
116
127
  allow_set_authority: true,
117
- allow_mint_to: true,
118
- allow_freeze_account: true,
119
128
  allow_thaw_account: true,
129
+ allow_transfer: true,
120
130
  },
121
131
  },
122
- price: { type: 'margin', margin: 0.1 },
132
+ max_allowed_lamports: 1000000,
133
+ max_signatures: 10,
134
+ price: { margin: 0.1, type: 'margin' },
135
+ price_source: 'Jupiter',
123
136
  token2022: {
124
- blocked_mint_extensions: [],
125
137
  blocked_account_extensions: [],
138
+ blocked_mint_extensions: [],
126
139
  },
127
140
  },
128
- enabled_methods: {
129
- liveness: true,
130
- estimate_transaction_fee: true,
131
- get_supported_tokens: true,
132
- sign_transaction: true,
133
- sign_and_send_transaction: true,
134
- transfer_transaction: true,
135
- get_blockhash: true,
136
- get_config: true,
137
- },
138
141
  };
139
142
  mockSuccessfulResponse(rawResponse);
140
143
  const result = await kora.getConfig();
@@ -150,8 +153,8 @@ describe('Kora Kit Plugin', () => {
150
153
  describe('getPayerSigner', () => {
151
154
  it('should return Kit-typed Address fields', async () => {
152
155
  const rawResponse = {
153
- signer_address: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
154
156
  payment_address: 'PayKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
157
+ signer_address: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
155
158
  };
156
159
  mockSuccessfulResponse(rawResponse);
157
160
  const result = await kora.getPayerSigner();
@@ -174,6 +177,16 @@ describe('Kora Kit Plugin', () => {
174
177
  expect(hash).toBe('4NxM2D4kQcipkzMWBWQME5YSVnj5kT8QKA7rvb3rKLvE');
175
178
  });
176
179
  });
180
+ describe('getVersion', () => {
181
+ it('should return version string', async () => {
182
+ const rawResponse = {
183
+ version: '2.0.0',
184
+ };
185
+ mockSuccessfulResponse(rawResponse);
186
+ const result = await kora.getVersion();
187
+ expect(result.version).toBe('2.0.0');
188
+ });
189
+ });
177
190
  describe('getSupportedTokens', () => {
178
191
  it('should return Kit-typed Address array', async () => {
179
192
  const rawResponse = {
@@ -197,13 +210,13 @@ describe('Kora Kit Plugin', () => {
197
210
  const rawResponse = {
198
211
  fee_in_lamports: 5000,
199
212
  fee_in_token: 50,
200
- signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
201
213
  payment_address: 'PayKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
214
+ signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
202
215
  };
203
216
  mockSuccessfulResponse(rawResponse);
204
217
  const result = await kora.estimateTransactionFee({
205
- transaction: 'base64EncodedTransaction',
206
218
  fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
219
+ transaction: 'base64EncodedTransaction',
207
220
  });
208
221
  // Type assertions
209
222
  const signerPubkey = result.signer_pubkey;
@@ -214,6 +227,28 @@ describe('Kora Kit Plugin', () => {
214
227
  expect(paymentAddr).toBe('PayKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7');
215
228
  });
216
229
  });
230
+ describe('estimateBundleFee', () => {
231
+ it('should return Kit-typed Address fields for bundle', async () => {
232
+ const rawResponse = {
233
+ fee_in_lamports: 15000,
234
+ fee_in_token: 150,
235
+ payment_address: 'PayKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
236
+ signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
237
+ };
238
+ mockSuccessfulResponse(rawResponse);
239
+ const result = await kora.estimateBundleFee({
240
+ fee_token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
241
+ transactions: ['base64Tx1', 'base64Tx2', 'base64Tx3'],
242
+ });
243
+ // Type assertions
244
+ const signerPubkey = result.signer_pubkey;
245
+ const paymentAddr = result.payment_address;
246
+ expect(result.fee_in_lamports).toBe(15000);
247
+ expect(result.fee_in_token).toBe(150);
248
+ expect(signerPubkey).toBe('DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7');
249
+ expect(paymentAddr).toBe('PayKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7');
250
+ });
251
+ });
217
252
  describe('signTransaction', () => {
218
253
  it('should return Kit-typed response with Base64EncodedWireTransaction', async () => {
219
254
  const rawResponse = {
@@ -232,9 +267,11 @@ describe('Kora Kit Plugin', () => {
232
267
  });
233
268
  });
234
269
  describe('signAndSendTransaction', () => {
235
- it('should return Kit-typed response with Base64EncodedWireTransaction', async () => {
270
+ it('should return Kit-typed response with Signature and Base64EncodedWireTransaction', async () => {
271
+ // Use a valid base58 signature (88 characters, valid base58 alphabet)
272
+ const mockSignature = '5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW';
236
273
  const rawResponse = {
237
- signature: '5wBzExmp8yR5M6m4KjV8WT9T6B1NMQkaMbsFWqBoDPBMYWxDx6EuSGxNqKfXnBhDhAkEqMiGRjEwKnGhSN3pi3n',
274
+ signature: mockSignature,
238
275
  signed_transaction: 'base64SignedTransaction',
239
276
  signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
240
277
  };
@@ -243,37 +280,52 @@ describe('Kora Kit Plugin', () => {
243
280
  transaction: 'base64EncodedTransaction',
244
281
  });
245
282
  // Type assertions - verify Kit types
283
+ const sig = result.signature;
246
284
  const signedTx = result.signed_transaction;
247
285
  const signerPubkey = result.signer_pubkey;
286
+ expect(sig).toBe(mockSignature);
248
287
  expect(signedTx).toBe('base64SignedTransaction');
249
288
  expect(signerPubkey).toBe('DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7');
250
289
  });
251
290
  });
252
- describe('transferTransaction', () => {
253
- it('should return Kit-typed response with Base64EncodedWireTransaction and Blockhash', async () => {
291
+ describe('signBundle', () => {
292
+ it('should return Kit-typed response with Base64EncodedWireTransaction array', async () => {
254
293
  const rawResponse = {
255
- transaction: 'base64Transaction',
256
- message: 'base64Message',
257
- blockhash: '4NxM2D4kQcipkzMWBWQME5YSVnj5kT8QKA7rvb3rKLvE',
294
+ signed_transactions: ['base64SignedTx1', 'base64SignedTx2'],
258
295
  signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
259
- instructions: [],
260
296
  };
261
297
  mockSuccessfulResponse(rawResponse);
262
- const result = await kora.transferTransaction({
263
- amount: 1000000,
264
- token: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
265
- source: 'sourceWallet',
266
- destination: 'destWallet',
298
+ const result = await kora.signBundle({
299
+ transactions: ['base64Tx1', 'base64Tx2'],
267
300
  });
268
301
  // Type assertions - verify Kit types
269
- const tx = result.transaction;
270
- const hash = result.blockhash;
302
+ const signedTxs = result.signed_transactions;
271
303
  const signerPubkey = result.signer_pubkey;
272
- expect(tx).toBe('base64Transaction');
273
- expect(result.message).toBe('base64Message');
274
- expect(hash).toBe('4NxM2D4kQcipkzMWBWQME5YSVnj5kT8QKA7rvb3rKLvE');
304
+ expect(signedTxs).toHaveLength(2);
305
+ expect(signedTxs[0]).toBe('base64SignedTx1');
306
+ expect(signedTxs[1]).toBe('base64SignedTx2');
307
+ expect(signerPubkey).toBe('DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7');
308
+ });
309
+ });
310
+ describe('signAndSendBundle', () => {
311
+ it('should return Kit-typed response with Base64EncodedWireTransaction array and bundle UUID', async () => {
312
+ const rawResponse = {
313
+ bundle_uuid: 'jito-bundle-uuid-12345',
314
+ signed_transactions: ['base64SignedTx1', 'base64SignedTx2'],
315
+ signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
316
+ };
317
+ mockSuccessfulResponse(rawResponse);
318
+ const result = await kora.signAndSendBundle({
319
+ transactions: ['base64Tx1', 'base64Tx2'],
320
+ });
321
+ // Type assertions - verify Kit types
322
+ const signedTxs = result.signed_transactions;
323
+ const signerPubkey = result.signer_pubkey;
324
+ expect(signedTxs).toHaveLength(2);
325
+ expect(signedTxs[0]).toBe('base64SignedTx1');
326
+ expect(signedTxs[1]).toBe('base64SignedTx2');
275
327
  expect(signerPubkey).toBe('DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7');
276
- expect(result.instructions).toEqual([]);
328
+ expect(result.bundle_uuid).toBe('jito-bundle-uuid-12345');
277
329
  });
278
330
  });
279
331
  describe('getPaymentInstruction', () => {
@@ -281,16 +333,16 @@ describe('Kora Kit Plugin', () => {
281
333
  const mockFeeEstimate = {
282
334
  fee_in_lamports: 5000,
283
335
  fee_in_token: 50000,
284
- signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
285
336
  payment_address: 'PayKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
337
+ signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
286
338
  };
287
339
  const testTx = 'Aoq7ymA5OGP+gmDXiY5m3cYXlY2Rz/a/gFjOgt9ZuoCS7UzuiGGaEnW2OOtvHvMQHkkD7Z4LRF5B63ftu+1oZwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgECB1urjQEjgFgzqYhJ8IXJeSg4cJP1j1g2CJstOQTDchOKUzqH3PxgGW3c4V3vZV05A5Y30/MggOBs0Kd00s1JEwg5TaEeaV4+KL2y7fXIAuf6cN0ZQitbhY+G9ExtBSChspOXPgNcy9pYpETe4bmB+fg4bfZx1tnicA/kIyyubczAmbcIKIuniNOOQYG2ggKCz8NjEsHVezrWMatndu1wk6J5miGP26J6Vwp31AljiAajAFuP0D9mWJwSeFuA7J5rPwbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpd/O36SW02zRtNtqk6GFeip2+yBQsVTeSbLL4rWJRkd4CBgQCBQQBCgxAQg8AAAAAAAYGBAIFAwEKDBAnAAAAAAAABg==';
288
340
  mockSuccessfulResponse(mockFeeEstimate);
289
341
  const result = await kora.getPaymentInstruction({
290
- transaction: testTx,
291
342
  fee_token: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
292
343
  source_wallet: '11111111111111111111111111111111',
293
344
  token_program_id: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
345
+ transaction: testTx,
294
346
  });
295
347
  // Type assertions - verify Kit types
296
348
  const originalTx = result.original_transaction;
@@ -321,12 +373,12 @@ describe('Kora Kit Plugin', () => {
321
373
  await expect(kora.getConfig()).rejects.toThrow('Network error');
322
374
  });
323
375
  });
324
- describe('KoraPlugin Type Export', () => {
325
- it('should export KoraPlugin type correctly', () => {
326
- // This test verifies the KoraPlugin type is correctly exported
376
+ describe('KoraApi Type Export', () => {
377
+ it('should export KoraApi type correctly', () => {
378
+ // This test verifies the KoraApi type is correctly exported
327
379
  const plugin = koraPlugin(mockConfig);
328
380
  const client = plugin({});
329
- // Type check - assign to KoraPlugin type
381
+ // Type check - assign to KoraApi type
330
382
  const api = client.kora;
331
383
  expect(api).toBeDefined();
332
384
  });
@@ -342,17 +394,20 @@ describe('Kora Kit Plugin', () => {
342
394
  expect(typeof client.kora.getConfig).toBe('function');
343
395
  expect(typeof client.kora.getPayerSigner).toBe('function');
344
396
  expect(typeof client.kora.getBlockhash).toBe('function');
397
+ expect(typeof client.kora.getVersion).toBe('function');
345
398
  expect(typeof client.kora.getSupportedTokens).toBe('function');
346
399
  expect(typeof client.kora.estimateTransactionFee).toBe('function');
400
+ expect(typeof client.kora.estimateBundleFee).toBe('function');
347
401
  expect(typeof client.kora.signTransaction).toBe('function');
348
402
  expect(typeof client.kora.signAndSendTransaction).toBe('function');
349
- expect(typeof client.kora.transferTransaction).toBe('function');
403
+ expect(typeof client.kora.signBundle).toBe('function');
404
+ expect(typeof client.kora.signAndSendBundle).toBe('function');
350
405
  expect(typeof client.kora.getPaymentInstruction).toBe('function');
351
406
  });
352
407
  it('should work with authentication config', () => {
353
408
  const authConfig = {
354
- endpoint: mockEndpoint,
355
409
  apiKey: 'test-api-key',
410
+ endpoint: mockEndpoint,
356
411
  hmacSecret: 'test-hmac-secret',
357
412
  };
358
413
  const client = createEmptyClient().use(koraPlugin(authConfig));
@@ -374,8 +429,8 @@ describe('Kora Kit Plugin', () => {
374
429
  });
375
430
  it('should call RPC methods correctly', async () => {
376
431
  const mockResponse = {
377
- signer_address: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
378
432
  payment_address: 'PayKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
433
+ signer_address: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
379
434
  };
380
435
  mockSuccessfulResponse(mockResponse);
381
436
  const client = createEmptyClient().use(koraPlugin(mockConfig));
@@ -1,30 +1,23 @@
1
- import { Commitment, KeyPairSigner, Address } from '@solana/kit';
1
+ import { Address, KeyPairSigner } from '@solana/kit';
2
2
  import { KoraClient } from '../src/index.js';
3
3
  interface TestSuite {
4
+ destinationAddress: Address<string>;
5
+ koraAddress: Address<string>;
4
6
  koraClient: KoraClient;
5
7
  koraRpcUrl: string;
6
8
  testWallet: KeyPairSigner<string>;
7
9
  usdcMint: Address<string>;
8
- destinationAddress: Address<string>;
9
- koraAddress: Address<string>;
10
- authConfig?: {
11
- apiKey: string;
12
- hmacSecret: string;
13
- };
14
10
  }
15
11
  export declare function loadEnvironmentVariables(): {
16
- koraRpcUrl: string;
12
+ destinationAddress: Address<string>;
17
13
  koraAddress: Address<string>;
14
+ koraRpcUrl: string;
18
15
  koraSignerType: string;
19
- commitment: Commitment;
20
- tokenDecimals: number;
21
- tokenDropAmount: number;
22
16
  solDropAmount: bigint;
23
- solanaRpcUrl: string;
24
- solanaWsUrl: string;
25
- testWalletSecret: string;
26
17
  testUsdcMintSecret: string;
27
- destinationAddress: Address<string>;
18
+ testWalletSecret: string;
19
+ tokenDecimals: number;
20
+ tokenDropAmount: number;
28
21
  };
29
22
  declare function setupTestSuite(): Promise<TestSuite>;
30
23
  export default setupTestSuite;