@solana/kora 0.2.0-beta.1 → 0.2.0-beta.3

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
- import { KoraClient } from '../src/client.js';
2
1
  import { TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
2
+ import { KoraClient } from '../src/client.js';
3
3
  import { getInstructionsFromBase64Message } from '../src/utils/transaction.js';
4
4
  // Mock fetch globally
5
5
  const mockFetch = jest.fn();
@@ -11,8 +11,8 @@ describe('KoraClient Unit Tests', () => {
11
11
  const mockSuccessfulResponse = (result) => {
12
12
  mockFetch.mockResolvedValueOnce({
13
13
  json: jest.fn().mockResolvedValueOnce({
14
- jsonrpc: '2.0',
15
14
  id: 1,
15
+ jsonrpc: '2.0',
16
16
  result,
17
17
  }),
18
18
  });
@@ -20,24 +20,24 @@ describe('KoraClient Unit Tests', () => {
20
20
  const mockErrorResponse = (error) => {
21
21
  mockFetch.mockResolvedValueOnce({
22
22
  json: jest.fn().mockResolvedValueOnce({
23
- jsonrpc: '2.0',
24
- id: 1,
25
23
  error,
24
+ id: 1,
25
+ jsonrpc: '2.0',
26
26
  }),
27
27
  });
28
28
  };
29
29
  const expectRpcCall = (method, params = undefined) => {
30
30
  expect(mockFetch).toHaveBeenCalledWith(mockRpcUrl, {
31
- method: 'POST',
32
- headers: {
33
- 'Content-Type': 'application/json',
34
- },
35
31
  body: JSON.stringify({
36
- jsonrpc: '2.0',
37
32
  id: 1,
33
+ jsonrpc: '2.0',
38
34
  method,
39
35
  params,
40
36
  }),
37
+ headers: {
38
+ 'Content-Type': 'application/json',
39
+ },
40
+ method: 'POST',
41
41
  });
42
42
  };
43
43
  const testSuccessfulRpcMethod = async (methodName, clientMethod, expectedResult, params = undefined) => {
@@ -78,80 +78,81 @@ describe('KoraClient Unit Tests', () => {
78
78
  describe('getConfig', () => {
79
79
  it('should return configuration', async () => {
80
80
  const mockConfig = {
81
+ enabled_methods: {
82
+ estimate_bundle_fee: true,
83
+ estimate_transaction_fee: true,
84
+ get_blockhash: true,
85
+ get_config: true,
86
+ get_payer_signer: true,
87
+ get_supported_tokens: true,
88
+ get_version: true,
89
+ liveness: true,
90
+ sign_and_send_bundle: true,
91
+ sign_and_send_transaction: true,
92
+ sign_bundle: true,
93
+ sign_transaction: true,
94
+ transfer_transaction: true,
95
+ },
81
96
  fee_payers: ['test_fee_payer_address'],
82
97
  validation_config: {
83
- max_allowed_lamports: 1000000,
84
- max_signatures: 10,
85
- price_source: 'Jupiter',
86
98
  allowed_programs: ['program1', 'program2'],
87
- allowed_tokens: ['token1', 'token2'],
88
99
  allowed_spl_paid_tokens: ['spl_token1'],
100
+ allowed_tokens: ['token1', 'token2'],
89
101
  disallowed_accounts: ['account1'],
90
102
  fee_payer_policy: {
91
- system: {
103
+ spl_token: {
104
+ allow_approve: true,
105
+ allow_burn: true,
106
+ allow_close_account: true,
107
+ allow_freeze_account: true,
108
+ allow_initialize_account: true,
109
+ allow_initialize_mint: true,
110
+ allow_initialize_multisig: true,
111
+ allow_mint_to: true,
112
+ allow_revoke: true,
113
+ allow_set_authority: true,
114
+ allow_thaw_account: true,
92
115
  allow_transfer: true,
116
+ },
117
+ system: {
118
+ allow_allocate: true,
93
119
  allow_assign: true,
94
120
  allow_create_account: true,
95
- allow_allocate: true,
121
+ allow_transfer: true,
96
122
  nonce: {
97
- allow_initialize: true,
98
123
  allow_advance: true,
99
124
  allow_authorize: true,
125
+ allow_initialize: true,
100
126
  allow_withdraw: true,
101
127
  },
102
128
  },
103
- spl_token: {
104
- allow_transfer: true,
129
+ token_2022: {
130
+ allow_approve: true,
105
131
  allow_burn: true,
106
132
  allow_close_account: true,
107
- allow_approve: true,
108
- allow_revoke: true,
109
- allow_set_authority: true,
110
- allow_mint_to: true,
111
- allow_initialize_mint: true,
133
+ allow_freeze_account: true,
112
134
  allow_initialize_account: true,
135
+ allow_initialize_mint: true,
113
136
  allow_initialize_multisig: true,
114
- allow_freeze_account: true,
115
- allow_thaw_account: true,
116
- },
117
- token_2022: {
118
- allow_transfer: false,
119
- allow_burn: true,
120
- allow_close_account: true,
121
- allow_approve: true,
137
+ allow_mint_to: true,
122
138
  allow_revoke: true,
123
139
  allow_set_authority: true,
124
- allow_mint_to: true,
125
- allow_initialize_mint: true,
126
- allow_initialize_account: true,
127
- allow_initialize_multisig: true,
128
- allow_freeze_account: true,
129
140
  allow_thaw_account: true,
141
+ allow_transfer: false,
130
142
  },
131
143
  },
144
+ max_allowed_lamports: 1000000,
145
+ max_signatures: 10,
132
146
  price: {
133
- type: 'margin',
134
147
  margin: 0.1,
148
+ type: 'margin',
135
149
  },
150
+ price_source: 'Jupiter',
136
151
  token2022: {
137
- blocked_mint_extensions: ['extension1', 'extension2'],
138
152
  blocked_account_extensions: ['account_extension1', 'account_extension2'],
153
+ blocked_mint_extensions: ['extension1', 'extension2'],
139
154
  },
140
155
  },
141
- enabled_methods: {
142
- liveness: true,
143
- estimate_transaction_fee: true,
144
- get_supported_tokens: true,
145
- get_payer_signer: true,
146
- sign_transaction: true,
147
- sign_and_send_transaction: true,
148
- transfer_transaction: true,
149
- get_blockhash: true,
150
- get_config: true,
151
- get_version: true,
152
- sign_and_send_bundle: true,
153
- sign_bundle: true,
154
- },
155
156
  };
156
157
  await testSuccessfulRpcMethod('getConfig', () => client.getConfig(), mockConfig);
157
158
  });
@@ -183,15 +184,15 @@ describe('KoraClient Unit Tests', () => {
183
184
  describe('getPayerSigner', () => {
184
185
  it('should return payer signer and payment destination', async () => {
185
186
  const mockResponse = {
186
- signer_address: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
187
187
  payment_address: 'PayKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
188
+ signer_address: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
188
189
  };
189
190
  await testSuccessfulRpcMethod('getPayerSigner', () => client.getPayerSigner(), mockResponse);
190
191
  });
191
192
  it('should return same address for signer and payment_destination when no separate paymaster', async () => {
192
193
  const mockResponse = {
193
- signer_address: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
194
194
  payment_address: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
195
+ signer_address: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
195
196
  };
196
197
  await testSuccessfulRpcMethod('getPayerSigner', () => client.getPayerSigner(), mockResponse);
197
198
  expect(mockResponse.signer_address).toBe(mockResponse.payment_address);
@@ -200,14 +201,14 @@ describe('KoraClient Unit Tests', () => {
200
201
  describe('estimateTransactionFee', () => {
201
202
  it('should estimate transaction fee', async () => {
202
203
  const request = {
203
- transaction: 'base64_encoded_transaction',
204
204
  fee_token: 'SOL',
205
+ transaction: 'base64_encoded_transaction',
205
206
  };
206
207
  const mockResponse = {
207
208
  fee_in_lamports: 5000,
208
209
  fee_in_token: 25,
209
- signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
210
210
  payment_address: 'PayKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
211
+ signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
211
212
  };
212
213
  await testSuccessfulRpcMethod('estimateTransactionFee', () => client.estimateTransactionFee(request), mockResponse, request);
213
214
  });
@@ -263,9 +264,9 @@ describe('KoraClient Unit Tests', () => {
263
264
  transactions: ['base64_tx_1', 'base64_tx_2'],
264
265
  };
265
266
  const mockResponse = {
267
+ bundle_uuid: 'test-bundle-uuid-123',
266
268
  signed_transactions: ['base64_signed_tx_1', 'base64_signed_tx_2'],
267
269
  signer_pubkey: 'test_signer_pubkey',
268
- bundle_uuid: 'test-bundle-uuid-123',
269
270
  };
270
271
  await testSuccessfulRpcMethod('signAndSendBundle', () => client.signAndSendBundle(request), mockResponse, request);
271
272
  });
@@ -278,115 +279,98 @@ describe('KoraClient Unit Tests', () => {
278
279
  await expect(client.signAndSendBundle(request)).rejects.toThrow('RPC Error -32000: Jito submission failed');
279
280
  });
280
281
  });
281
- describe('transferTransaction (DEPRECATED)', () => {
282
- it('should create transfer transaction', async () => {
283
- const request = {
284
- amount: 1000000,
285
- token: 'SOL',
286
- source: 'source_address',
287
- destination: 'destination_address',
288
- };
289
- const mockResponse = {
290
- transaction: 'base64_encoded_transaction',
291
- message: 'Transfer transaction created',
292
- blockhash: 'test_blockhash',
293
- signer_pubkey: 'test_signer_pubkey',
294
- instructions: [],
295
- };
296
- await testSuccessfulRpcMethod('transferTransaction', () => client.transferTransaction(request), mockResponse, request);
297
- });
298
- });
299
282
  describe('getPaymentInstruction', () => {
300
- const mockConfig = {
283
+ const _mockConfig = {
284
+ enabled_methods: {
285
+ estimate_bundle_fee: true,
286
+ estimate_transaction_fee: true,
287
+ get_blockhash: true,
288
+ get_config: true,
289
+ get_payer_signer: true,
290
+ get_supported_tokens: true,
291
+ get_version: true,
292
+ liveness: true,
293
+ sign_and_send_bundle: true,
294
+ sign_and_send_transaction: true,
295
+ sign_bundle: true,
296
+ sign_transaction: true,
297
+ transfer_transaction: true,
298
+ },
301
299
  fee_payers: ['11111111111111111111111111111111'],
302
300
  validation_config: {
303
- max_allowed_lamports: 1000000,
304
- max_signatures: 10,
305
- price_source: 'Jupiter',
306
301
  allowed_programs: ['program1'],
307
- allowed_tokens: ['token1'],
308
302
  allowed_spl_paid_tokens: ['4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU'],
303
+ allowed_tokens: ['token1'],
309
304
  disallowed_accounts: [],
310
305
  fee_payer_policy: {
311
- system: {
306
+ spl_token: {
307
+ allow_approve: true,
308
+ allow_burn: true,
309
+ allow_close_account: true,
310
+ allow_freeze_account: true,
311
+ allow_initialize_account: true,
312
+ allow_initialize_mint: true,
313
+ allow_initialize_multisig: true,
314
+ allow_mint_to: true,
315
+ allow_revoke: true,
316
+ allow_set_authority: true,
317
+ allow_thaw_account: true,
312
318
  allow_transfer: true,
319
+ },
320
+ system: {
321
+ allow_allocate: true,
313
322
  allow_assign: true,
314
323
  allow_create_account: true,
315
- allow_allocate: true,
324
+ allow_transfer: true,
316
325
  nonce: {
317
- allow_initialize: true,
318
326
  allow_advance: true,
319
327
  allow_authorize: true,
328
+ allow_initialize: true,
320
329
  allow_withdraw: true,
321
330
  },
322
331
  },
323
- spl_token: {
324
- allow_transfer: true,
332
+ token_2022: {
333
+ allow_approve: true,
325
334
  allow_burn: true,
326
335
  allow_close_account: true,
327
- allow_approve: true,
328
- allow_revoke: true,
329
- allow_set_authority: true,
330
- allow_mint_to: true,
331
- allow_initialize_mint: true,
336
+ allow_freeze_account: true,
332
337
  allow_initialize_account: true,
338
+ allow_initialize_mint: true,
333
339
  allow_initialize_multisig: true,
334
- allow_freeze_account: true,
335
- allow_thaw_account: true,
336
- },
337
- token_2022: {
338
- allow_transfer: true,
339
- allow_burn: true,
340
- allow_close_account: true,
341
- allow_approve: true,
340
+ allow_mint_to: true,
342
341
  allow_revoke: true,
343
342
  allow_set_authority: true,
344
- allow_mint_to: true,
345
- allow_initialize_mint: true,
346
- allow_initialize_account: true,
347
- allow_initialize_multisig: true,
348
- allow_freeze_account: true,
349
343
  allow_thaw_account: true,
344
+ allow_transfer: true,
350
345
  },
351
346
  },
347
+ max_allowed_lamports: 1000000,
348
+ max_signatures: 10,
352
349
  price: {
353
- type: 'margin',
354
350
  margin: 0.1,
351
+ type: 'margin',
355
352
  },
353
+ price_source: 'Jupiter',
356
354
  token2022: {
357
- blocked_mint_extensions: [],
358
355
  blocked_account_extensions: [],
356
+ blocked_mint_extensions: [],
359
357
  },
360
358
  },
361
- enabled_methods: {
362
- liveness: true,
363
- estimate_transaction_fee: true,
364
- get_supported_tokens: true,
365
- get_payer_signer: true,
366
- sign_transaction: true,
367
- sign_and_send_transaction: true,
368
- transfer_transaction: true,
369
- get_blockhash: true,
370
- get_config: true,
371
- get_version: true,
372
- sign_and_send_bundle: true,
373
- sign_bundle: true,
374
- },
375
359
  };
376
360
  const mockFeeEstimate = {
377
361
  fee_in_lamports: 5000,
378
362
  fee_in_token: 50000,
379
- signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
380
363
  payment_address: 'PayKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
364
+ signer_pubkey: 'DemoKMZWkk483QoFPLRPQ2XVKB7bWnuXwSjvDE1JsWk7',
381
365
  };
382
366
  // Create a mock base64-encoded transaction
383
367
  // This is a minimal valid transaction structure
384
368
  const mockTransactionBase64 = 'Aoq7ymA5OGP+gmDXiY5m3cYXlY2Rz/a/gFjOgt9ZuoCS7UzuiGGaEnW2OOtvHvMQHkkD7Z4LRF5B63ftu+1oZwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgECB1urjQEjgFgzqYhJ8IXJeSg4cJP1j1g2CJstOQTDchOKUzqH3PxgGW3c4V3vZV05A5Y30/MggOBs0Kd00s1JEwg5TaEeaV4+KL2y7fXIAuf6cN0ZQitbhY+G9ExtBSChspOXPgNcy9pYpETe4bmB+fg4bfZx1tnicA/kIyyubczAmbcIKIuniNOOQYG2ggKCz8NjEsHVezrWMatndu1wk6J5miGP26J6Vwp31AljiAajAFuP0D9mWJwSeFuA7J5rPwbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpd/O36SW02zRtNtqk6GFeip2+yBQsVTeSbLL4rWJRkd4CBgQCBQQBCgxAQg8AAAAAAAYGBAIFAwEKDBAnAAAAAAAABg==';
385
369
  const validRequest = {
386
- transaction: mockTransactionBase64,
387
370
  fee_token: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',
388
371
  source_wallet: '11111111111111111111111111111111',
389
372
  token_program_id: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
373
+ transaction: mockTransactionBase64,
390
374
  };
391
375
  beforeEach(() => {
392
376
  // Mock console.log to avoid noise in tests
@@ -399,16 +383,17 @@ describe('KoraClient Unit Tests', () => {
399
383
  // Mock estimateTransactionFee call
400
384
  mockFetch.mockResolvedValueOnce({
401
385
  json: jest.fn().mockResolvedValueOnce({
402
- jsonrpc: '2.0',
403
386
  id: 1,
387
+ jsonrpc: '2.0',
404
388
  result: mockFeeEstimate,
405
389
  }),
406
390
  });
407
391
  const result = await client.getPaymentInstruction(validRequest);
408
392
  expect(result).toEqual({
409
393
  original_transaction: validRequest.transaction,
394
+ payment_address: mockFeeEstimate.payment_address,
395
+ payment_amount: mockFeeEstimate.fee_in_token,
410
396
  payment_instruction: expect.objectContaining({
411
- programAddress: TOKEN_PROGRAM_ADDRESS,
412
397
  accounts: [
413
398
  expect.objectContaining({
414
399
  role: 1, // writable
@@ -417,44 +402,44 @@ describe('KoraClient Unit Tests', () => {
417
402
  role: 1, // writable
418
403
  }), // Destination token account
419
404
  expect.objectContaining({
420
- role: 2, // readonly-signer
405
+ // readonly-signer
421
406
  address: validRequest.source_wallet,
407
+ role: 2,
422
408
  signer: expect.objectContaining({
423
409
  address: validRequest.source_wallet,
424
410
  }),
425
411
  }), // Authority
426
412
  ],
427
413
  data: expect.any(Uint8Array),
414
+ programAddress: TOKEN_PROGRAM_ADDRESS,
428
415
  }),
429
- payment_amount: mockFeeEstimate.fee_in_token,
430
416
  payment_token: validRequest.fee_token,
431
- payment_address: mockFeeEstimate.payment_address,
432
417
  signer_address: mockFeeEstimate.signer_pubkey,
433
418
  });
434
419
  // Verify only estimateTransactionFee was called
435
420
  expect(mockFetch).toHaveBeenCalledTimes(1);
436
421
  expect(mockFetch).toHaveBeenCalledWith(mockRpcUrl, {
437
- method: 'POST',
438
- headers: {
439
- 'Content-Type': 'application/json',
440
- },
441
422
  body: JSON.stringify({
442
- jsonrpc: '2.0',
443
423
  id: 1,
424
+ jsonrpc: '2.0',
444
425
  method: 'estimateTransactionFee',
445
426
  params: {
446
- transaction: validRequest.transaction,
447
427
  fee_token: validRequest.fee_token,
428
+ transaction: validRequest.transaction,
448
429
  },
449
430
  }),
431
+ headers: {
432
+ 'Content-Type': 'application/json',
433
+ },
434
+ method: 'POST',
450
435
  });
451
436
  });
452
437
  it('should handle fixed pricing configuration', async () => {
453
438
  // Mock estimateTransactionFee call
454
439
  mockFetch.mockResolvedValueOnce({
455
440
  json: jest.fn().mockResolvedValueOnce({
456
- jsonrpc: '2.0',
457
441
  id: 1,
442
+ jsonrpc: '2.0',
458
443
  result: mockFeeEstimate,
459
444
  }),
460
445
  });
@@ -477,9 +462,9 @@ describe('KoraClient Unit Tests', () => {
477
462
  const mockError = { code: -32602, message: 'Invalid transaction' };
478
463
  mockFetch.mockResolvedValueOnce({
479
464
  json: jest.fn().mockResolvedValueOnce({
480
- jsonrpc: '2.0',
481
- id: 1,
482
465
  error: mockError,
466
+ id: 1,
467
+ jsonrpc: '2.0',
483
468
  }),
484
469
  });
485
470
  await expect(client.getPaymentInstruction(validRequest)).rejects.toThrow('RPC Error -32602: Invalid transaction');
@@ -491,18 +476,18 @@ describe('KoraClient Unit Tests', () => {
491
476
  it('should return correct payment details in response', async () => {
492
477
  mockFetch.mockResolvedValueOnce({
493
478
  json: jest.fn().mockResolvedValueOnce({
494
- jsonrpc: '2.0',
495
479
  id: 1,
480
+ jsonrpc: '2.0',
496
481
  result: mockFeeEstimate,
497
482
  }),
498
483
  });
499
484
  const result = await client.getPaymentInstruction(validRequest);
500
485
  expect(result).toMatchObject({
501
486
  original_transaction: validRequest.transaction,
502
- payment_instruction: expect.any(Object),
487
+ payment_address: mockFeeEstimate.payment_address,
503
488
  payment_amount: mockFeeEstimate.fee_in_token,
489
+ payment_instruction: expect.any(Object),
504
490
  payment_token: validRequest.fee_token,
505
- payment_address: mockFeeEstimate.payment_address,
506
491
  signer_address: mockFeeEstimate.signer_pubkey,
507
492
  });
508
493
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/kora",
3
- "version": "0.2.0-beta.1",
3
+ "version": "0.2.0-beta.3",
4
4
  "description": "TypeScript SDK for Kora RPC",
5
5
  "main": "dist/src/index.js",
6
6
  "type": "module",
@@ -24,7 +24,8 @@
24
24
  "@solana-program/compute-budget": "^0.11.0",
25
25
  "@solana-program/system": "^0.10.0",
26
26
  "@solana-program/token": "^0.9.0",
27
- "@solana/kit": "^5.1.0",
27
+ "@solana/eslint-config-solana": "^6.0.0",
28
+ "@solana/kit": "^5.4.0",
28
29
  "@solana/prettier-config-solana": "^0.0.6",
29
30
  "@types/jest": "^29.5.12",
30
31
  "@types/node": "^20.17.27",
@@ -55,7 +56,7 @@
55
56
  "test:ci:integration": "node scripts/test-with-validator.js",
56
57
  "test:ci:integration:auth": "ENABLE_AUTH=true node scripts/test-with-validator.js",
57
58
  "test:ci:unit": "jest test/unit.test.ts",
58
- "lint": "eslint src --ext .ts",
59
+ "lint": "eslint src test",
59
60
  "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
60
61
  "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
61
62
  "type-check": "tsc --noEmit",