solana-ruby 0.1.0 → 0.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a89b4b3a79a083057806945963669aab8ca3b312223ea7c1e13a41a26c0063b
4
- data.tar.gz: 824eaaa7913f9b499bc6514f1d5fec3d48f3692f399a3205d069425ea32b328c
3
+ metadata.gz: 9ce5e8285735080d504a24b4a1237a9ea2273939b7d77965e0184baf282853ba
4
+ data.tar.gz: 032a7e179b759db0ddca3f42299837838470bf36649bdf118c93375deba04394
5
5
  SHA512:
6
- metadata.gz: 8317d94e7781fb218a31c73a2270daf7ccf5d782f4ec565e89c90994abf871827593a25cec9cb0c83e4bab9bc42a7fc30029c9b289785e3499d81f2c7549a8b9
7
- data.tar.gz: e50e55dd5237008503167a603959cad90877ee88c1d43a434924d64db59688783de6445b3f8eb42e14575e2006a0dfc2635d324db6319683c7bf3494f1d701f7
6
+ metadata.gz: b3d9b31be76b89d2de951324a037dd5cc61d8c04e60eeff30d81730d49d65844a464b8f0d93e7deb08e127aed155479c6b370993bb0fdf7aa553b89440b0ab90
7
+ data.tar.gz: e71dec47fbd4722efee8ed355d70b7b864d952968cbdbcd97fefc454346a68564da8c4816652899306f88c9cb5f8c13060c82cbfaa7e33ad4a93da596f218217
@@ -1,249 +1,772 @@
1
- require 'httparty'
1
+ require 'faraday'
2
+ require 'faye/websocket'
2
3
  require 'json'
4
+ require 'thread'
5
+
6
+ require_relative 'utils'
3
7
 
4
8
  module SolanaRB
9
+ ##
10
+ # Client class for interacting with the Solana JSON RPC API over HTTP and WS.
5
11
  class Client
6
- include HTTParty
7
- base_uri 'https://api.mainnet-beta.solana.com'
8
-
9
- def initialize(api_key = nil)
12
+ ##
13
+ # Initializes a new Client.
14
+ #
15
+ # @param [String, nil] api_key Optional API key for authentication.
16
+ def initialize(api_endpoint = SolanaRB::Utils::MAINNET, api_key = nil)
10
17
  @api_key = api_key
18
+ @api_endpoint = api_endpoint
19
+ # @api_ws = WebSocket::Handshake::Client.new(url: @api_endpoint::WS)
20
+ @api_http = Faraday.new(url: @api_endpoint::HTTP) do |faraday|
21
+ faraday.request :json
22
+ faraday.response :json, content_type: 'application/json'
23
+ faraday.adapter Faraday.default_adapter
24
+ end
11
25
  end
12
26
 
27
+ ##
28
+ # Retrieves account information for a given public key.
29
+ #
30
+ # @param [String] pubkey The public key of the account.
31
+ # @param [Hash] options Optional parameters for the request.
32
+ # @return [Hash] The account information.
13
33
  def get_account_info(pubkey, options = {})
14
- request('getAccountInfo', [pubkey, options])
34
+ request_http('getAccountInfo', [pubkey, options])
15
35
  end
16
36
 
37
+ ##
38
+ # Retrieves the balance for a given public key.
39
+ #
40
+ # @param [String] pubkey The public key of the account.
41
+ # @param [Hash] options Optional parameters for the request.
42
+ # @return [Integer] The balance in lamports.
17
43
  def get_balance(pubkey, options = {})
18
- request('getBalance', [pubkey, options])
44
+ request_http('getBalance', [pubkey, options])
19
45
  end
20
46
 
47
+ ##
48
+ # Retrieves information about a specific block.
49
+ #
50
+ # @param [Integer] slot_number The slot number of the block.
51
+ # @param [Hash] options Optional parameters for the request.
52
+ # @return [Hash] The block information.
21
53
  def get_block(slot_number, options = {})
22
- request('getBlock', [slot_number, options])
54
+ request_http('getBlock', [slot_number, options])
23
55
  end
24
56
 
57
+ ##
58
+ # Retrieves block commitment information for a specific block.
59
+ #
60
+ # @param [Integer] slot_number The slot number of the block.
61
+ # @param [Hash] options Optional parameters for the request.
62
+ # @return [Hash] The block commitment information.
25
63
  def get_block_commitment(slot_number, options = {})
26
- request('getBlockCommitment', [slot_number, options])
64
+ request_http('getBlockCommitment', [slot_number, options])
27
65
  end
28
66
 
67
+ ##
68
+ # Retrieves the current block height.
69
+ #
70
+ # @param [Hash] options Optional parameters for the request.
71
+ # @return [Integer] The current block height.
29
72
  def get_block_height(options = {})
30
- request('getBlockHeight', [options])
73
+ request_http('getBlockHeight', [options])
31
74
  end
32
75
 
76
+ ##
77
+ # Retrieves block production information.
78
+ #
79
+ # @param [Hash] options Optional parameters for the request.
80
+ # @return [Hash] The block production information.
33
81
  def get_block_production(options = {})
34
- request('getBlockProduction', [options])
82
+ request_http('getBlockProduction', [options])
35
83
  end
36
84
 
85
+ ##
86
+ # Retrieves the estimated production time of a specific block.
87
+ #
88
+ # @param [Integer] slot_number The slot number of the block.
89
+ # @param [Hash] options Optional parameters for the request.
90
+ # @return [Integer] The estimated production time in seconds.
37
91
  def get_block_time(slot_number, options = {})
38
- request('getBlockTime', [slot_number, options])
92
+ request_http('getBlockTime', [slot_number, options])
39
93
  end
40
94
 
95
+ ##
96
+ # Retrieves a list of confirmed blocks between two slot numbers.
97
+ #
98
+ # @param [Integer] start_slot The start slot number.
99
+ # @param [Integer] end_slot The end slot number.
100
+ # @param [Hash] options Optional parameters for the request.
101
+ # @return [Array<Integer>] The list of confirmed blocks.
41
102
  def get_blocks(start_slot, end_slot, options = {})
42
- request('getBlocks', [start_slot, end_slot, options])
103
+ request_http('getBlocks', [start_slot, end_slot, options])
43
104
  end
44
105
 
106
+ ##
107
+ # Retrieves a list of confirmed blocks starting from a given slot number with a limit on the number of blocks.
108
+ #
109
+ # @param [Integer] start_slot The start slot number.
110
+ # @param [Integer] limit The maximum number of blocks to return.
111
+ # @param [Hash] options Optional parameters for the request.
112
+ # @return [Array<Integer>] The list of confirmed blocks.
45
113
  def get_blocks_with_limit(start_slot, limit, options = {})
46
- request('getBlocksWithLimit', [start_slot, limit, options])
114
+ request_http('getBlocksWithLimit', [start_slot, limit, options])
47
115
  end
48
116
 
117
+ ##
118
+ # Retrieves the list of cluster nodes.
119
+ #
120
+ # @param [Hash] options Optional parameters for the request.
121
+ # @return [Array<Hash>] The list of cluster nodes.
49
122
  def get_cluster_nodes(options = {})
50
- request('getClusterNodes', [options])
123
+ request_http('getClusterNodes', [options])
51
124
  end
52
125
 
126
+ ##
127
+ # Retrieves epoch information.
128
+ #
129
+ # @param [Hash] options Optional parameters for the request.
130
+ # @return [Hash] The epoch information.
53
131
  def get_epoch_info(options = {})
54
- request('getEpochInfo', [options])
132
+ request_http('getEpochInfo', [options])
55
133
  end
56
134
 
135
+ ##
136
+ # Retrieves the epoch schedule.
137
+ #
138
+ # @param [Hash] options Optional parameters for the request.
139
+ # @return [Hash] The epoch schedule.
57
140
  def get_epoch_schedule(options = {})
58
- request('getEpochSchedule', [options])
141
+ request_http('getEpochSchedule', [options])
59
142
  end
60
143
 
144
+ ##
145
+ # Retrieves the fee for a given message.
146
+ #
147
+ # @param [String] message The message for which the fee is to be calculated.
148
+ # @param [Hash] options Optional parameters for the request.
149
+ # @return [Integer] The fee for the message.
61
150
  def get_fee_for_message(message, options = {})
62
- request('getFeeForMessage', [message, options])
151
+ request_http('getFeeForMessage', [message, options])
63
152
  end
64
153
 
154
+ ##
155
+ # Retrieves the slot of the first available block.
156
+ #
157
+ # @param [Hash] options Optional parameters for the request.
158
+ # @return [Integer] The slot of the first available block.
65
159
  def get_first_available_block(options = {})
66
- request('getFirstAvailableBlock', [options])
160
+ request_http('getFirstAvailableBlock', [options])
67
161
  end
68
162
 
163
+ ##
164
+ # Retrieves the genesis hash.
165
+ #
166
+ # @param [Hash] options Optional parameters for the request.
167
+ # @return [String] The genesis hash.
69
168
  def get_genesis_hash(options = {})
70
- request('getGenesisHash', [options])
169
+ request_http('getGenesisHash', [options])
71
170
  end
72
171
 
172
+ ##
173
+ # Checks the health of the node.
174
+ #
175
+ # @param [Hash] options Optional parameters for the request.
176
+ # @return [String] The health status of the node.
73
177
  def get_health(options = {})
74
- request('getHealth', [options])
178
+ request_http('getHealth', [options])
75
179
  end
76
180
 
181
+ ##
182
+ # Retrieves the highest snapshot slot.
183
+ #
184
+ # @param [Hash] options Optional parameters for the request.
185
+ # @return [Integer] The highest snapshot slot.
77
186
  def get_highest_snapshot_slot(options = {})
78
- request('getHighestSnapshotSlot', [options])
187
+ request_http('getHighestSnapshotSlot', [options])
79
188
  end
80
189
 
190
+ ##
191
+ # Retrieves the identity of the node.
192
+ #
193
+ # @param [Hash] options Optional parameters for the request.
194
+ # @return [Hash] The identity information of the node.
81
195
  def get_identity(options = {})
82
- request('getIdentity', [options])
196
+ request_http('getIdentity', [options])
83
197
  end
84
198
 
199
+ ##
200
+ # Retrieves the current inflation governor settings.
201
+ #
202
+ # @param [Hash] options Optional parameters for the request.
203
+ # @return [Hash] The inflation governor settings.
85
204
  def get_inflation_governor(options = {})
86
- request('getInflationGovernor', [options])
205
+ request_http('getInflationGovernor', [options])
87
206
  end
88
207
 
208
+ ##
209
+ # Retrieves the current inflation rate.
210
+ #
211
+ # @param [Hash] options Optional parameters for the request.
212
+ # @return [Hash] The inflation rate.
89
213
  def get_inflation_rate(options = {})
90
- request('getInflationRate', [options])
214
+ request_http('getInflationRate', [options])
91
215
  end
92
216
 
217
+ ##
218
+ # Retrieves the inflation reward for a given list of addresses.
219
+ #
220
+ # @param [Array<String>] addresses The list of addresses.
221
+ # @param [Hash] options Optional parameters for the request.
222
+ # @return [Array<Hash>] The inflation rewards for the addresses.
93
223
  def get_inflation_reward(addresses, options = {})
94
- request('getInflationReward', [addresses, options])
224
+ request_http('getInflationReward', [addresses, options])
95
225
  end
96
226
 
227
+ ##
228
+ # Retrieves the largest accounts.
229
+ #
230
+ # @param [Hash] options Optional parameters for the request.
231
+ # @return [Array<Hash>] The largest accounts.
97
232
  def get_largest_accounts(options = {})
98
- request('getLargestAccounts', [options])
233
+ request_http('getLargestAccounts', [options])
99
234
  end
100
235
 
236
+ ##
237
+ # Retrieves the latest blockhash.
238
+ #
239
+ # @param [Hash] options Optional parameters for the request.
240
+ # @return [Hash] The latest blockhash.
101
241
  def get_latest_blockhash(options = {})
102
- request('getLatestBlockhash', [options])
242
+ request_http('getLatestBlockhash', [options])
103
243
  end
104
244
 
245
+ ##
246
+ # Retrieves the leader schedule.
247
+ #
248
+ # @param [Hash] options Optional parameters for the request.
249
+ # @return [Hash] The leader schedule.
105
250
  def get_leader_schedule(options = {})
106
- request('getLeaderSchedule', [options])
251
+ request_http('getLeaderSchedule', [options])
107
252
  end
108
253
 
254
+ ##
255
+ # Retrieves the maximum retransmit slot.
256
+ #
257
+ # @param [Hash] options Optional parameters for the request.
258
+ # @return [Integer] The maximum retransmit slot.
109
259
  def get_max_retransmit_slot(options = {})
110
- request('getMaxRetransmitSlot', [options])
260
+ request_http('getMaxRetransmitSlot', [options])
111
261
  end
112
262
 
263
+ ##
264
+ # Retrieves the maximum shred insert slot.
265
+ #
266
+ # @param [Hash] options Optional parameters for the request.
267
+ # @return [Integer] The maximum shred insert slot.
113
268
  def get_max_shred_insert_slot(options = {})
114
- request('getMaxShredInsertSlot', [options])
269
+ request_http('getMaxShredInsertSlot', [options])
115
270
  end
116
271
 
272
+ ##
273
+ # Retrieves the minimum balance required for rent exemption for a given data length.
274
+ #
275
+ # @param [Integer] data_length The length of the data in bytes.
276
+ # @param [Hash] options Optional parameters for the request.
277
+ # @return [Integer] The minimum balance for rent exemption.
117
278
  def get_minimum_balance_for_rent_exemption(data_length, options = {})
118
- request('getMinimumBalanceForRentExemption', [data_length, options])
279
+ request_http('getMinimumBalanceForRentExemption', [data_length, options])
119
280
  end
120
281
 
282
+ ##
283
+ # Retrieves information for multiple accounts.
284
+ #
285
+ # @param [Array<String>] pubkeys The list of public keys.
286
+ # @param [Hash] options Optional parameters for the request.
287
+ # @return [Array<Hash>] The information for the accounts.
121
288
  def get_multiple_accounts(pubkeys, options = {})
122
- request('getMultipleAccounts', [pubkeys, options])
289
+ request_http('getMultipleAccounts', [pubkeys, options])
123
290
  end
124
291
 
292
+ ##
293
+ # Retrieves information for accounts owned by a specific program.
294
+ #
295
+ # @param [String] pubkey The public key of the program.
296
+ # @param [Hash] options Optional parameters for the request.
297
+ # @return [Array<Hash>] The information for the program accounts.
125
298
  def get_program_accounts(pubkey, options = {})
126
- request('getProgramAccounts', [pubkey, options])
299
+ request_http('getProgramAccounts', [pubkey, options])
127
300
  end
128
301
 
302
+ ##
303
+ # Retrieves recent performance samples.
304
+ #
305
+ # @param [Hash] options Optional parameters for the request.
306
+ # @return [Array<Hash>] The recent performance samples.
129
307
  def get_recent_performance_samples(options = {})
130
- request('getRecentPerformanceSamples', [options])
308
+ request_http('getRecentPerformanceSamples', [options])
131
309
  end
132
310
 
311
+ ##
312
+ # Retrieves recent prioritization fees.
313
+ #
314
+ # @param [Hash] options Optional parameters for the request.
315
+ # @return [Hash] The recent prioritization fees.
133
316
  def get_recent_prioritization_fees(options = {})
134
- request('getRecentPrioritizationFees', [options])
317
+ request_http('getRecentPrioritizationFees', [options])
135
318
  end
136
319
 
320
+ ##
321
+ # Retrieves the status of given transaction signatures.
322
+ #
323
+ # @param [Array<String>] signatures The list of transaction signatures.
324
+ # @param [Hash] options Optional parameters for the request.
325
+ # @return [Array<Hash>] The status of the transaction signatures.
137
326
  def get_signature_statuses(signatures, options = {})
138
- request('getSignatureStatuses', [signatures, options])
327
+ request_http('getSignatureStatuses', [signatures, options])
139
328
  end
140
329
 
330
+ ##
331
+ # Retrieves the signatures for a given address.
332
+ #
333
+ # @param [String] address The address for which to retrieve signatures.
334
+ # @param [Hash] options Optional parameters for the request.
335
+ # @return [Array<Hash>] The signatures for the address.
141
336
  def get_signatures_for_address(address, options = {})
142
- request('getSignaturesForAddress', [address, options])
337
+ request_http('getSignaturesForAddress', [address, options])
143
338
  end
144
339
 
340
+ ##
341
+ # Retrieves the current slot.
342
+ #
343
+ # @param [Hash] options Optional parameters for the request.
344
+ # @return [Integer] The current slot.
145
345
  def get_slot(options = {})
146
- request('getSlot', [options])
346
+ request_http('getSlot', [options])
147
347
  end
148
348
 
349
+ ##
350
+ # Retrieves the current slot leader.
351
+ #
352
+ # @param [Hash] options Optional parameters for the request.
353
+ # @return [String] The current slot leader.
149
354
  def get_slot_leader(options = {})
150
- request('getSlotLeader', [options])
355
+ request_http('getSlotLeader', [options])
151
356
  end
152
357
 
358
+ ##
359
+ # Retrieves the slot leaders starting from a given slot with a limit on the number of leaders.
360
+ #
361
+ # @param [Integer] start_slot The start slot number.
362
+ # @param [Integer] limit The maximum number of leaders to return.
363
+ # @param [Hash] options Optional parameters for the request.
364
+ # @return [Array<String>] The slot leaders.
153
365
  def get_slot_leaders(start_slot, limit, options = {})
154
- request('getSlotLeaders', [start_slot, limit, options])
366
+ request_http('getSlotLeaders', [start_slot, limit, options])
155
367
  end
156
368
 
369
+ ##
370
+ # Retrieves the stake activation information for a given public key.
371
+ #
372
+ # @param [String] pubkey The public key of the stake account.
373
+ # @param [Hash] options Optional parameters for the request.
374
+ # @return [Hash] The stake activation information.
157
375
  def get_stake_activation(pubkey, options = {})
158
- request('getStakeActivation', [pubkey, options])
376
+ request_http('getStakeActivation', [pubkey, options])
159
377
  end
160
378
 
379
+ ##
380
+ # Retrieves the minimum delegation for a stake account.
381
+ #
382
+ # @param [Hash] options Optional parameters for the request.
383
+ # @return [Integer] The minimum delegation.
161
384
  def get_stake_minimum_delegation(options = {})
162
- request('getStakeMinimumDelegation', [options])
385
+ request_http('getStakeMinimumDelegation', [options])
163
386
  end
164
387
 
388
+ ##
389
+ # Retrieves the supply information.
390
+ #
391
+ # @param [Hash] options Optional parameters for the request.
392
+ # @return [Hash] The supply information.
165
393
  def get_supply(options = {})
166
- request('getSupply', [options])
394
+ request_http('getSupply', [options])
167
395
  end
168
396
 
397
+ ##
398
+ # Retrieves the token balance for a given token account.
399
+ #
400
+ # @param [String] pubkey The public key of the token account.
401
+ # @param [Hash] options Optional parameters for the request.
402
+ # @return [Hash] The token balance.
169
403
  def get_token_account_balance(pubkey, options = {})
170
- request('getTokenAccountBalance', [pubkey, options])
404
+ request_http('getTokenAccountBalance', [pubkey, options])
171
405
  end
172
406
 
407
+ ##
408
+ # Retrieves token accounts by delegate.
409
+ #
410
+ # @param [String] delegate The delegate address.
411
+ # @param [Hash] opts Additional options for the request.
412
+ # @param [Hash] options Optional parameters for the request.
413
+ # @return [Array<Hash>] The token accounts by delegate.
173
414
  def get_token_accounts_by_delegate(delegate, opts = {}, options = {})
174
- request('getTokenAccountsByDelegate', [delegate, opts, options])
415
+ request_http('getTokenAccountsByDelegate', [delegate, opts, options])
175
416
  end
176
417
 
418
+ ##
419
+ # Retrieves token accounts by owner.
420
+ #
421
+ # @param [String] owner The owner address.
422
+ # @param [Hash] opts Additional options for the request.
423
+ # @param [Hash] options Optional parameters for the request.
424
+ # @return [Array<Hash>] The token accounts by owner.
177
425
  def get_token_accounts_by_owner(owner, opts = {}, options = {})
178
- request('getTokenAccountsByOwner', [owner, opts, options])
426
+ request_http('getTokenAccountsByOwner', [owner, opts, options])
179
427
  end
180
428
 
429
+ ##
430
+ # Retrieves the largest accounts for a given token.
431
+ #
432
+ # @param [String] pubkey The public key of the token.
433
+ # @param [Hash] options Optional parameters for the request.
434
+ # @return [Array<Hash>] The largest accounts for the token.
181
435
  def get_token_largest_accounts(pubkey, options = {})
182
- request('getTokenLargestAccounts', [pubkey, options])
436
+ request_http('getTokenLargestAccounts', [pubkey, options])
183
437
  end
184
438
 
439
+ ##
440
+ # Retrieves the supply of a given token.
441
+ #
442
+ # @param [String] pubkey The public key of the token.
443
+ # @param [Hash] options Optional parameters for the request.
444
+ # @return [Hash] The token supply.
185
445
  def get_token_supply(pubkey, options = {})
186
- request('getTokenSupply', [pubkey, options])
446
+ request_http('getTokenSupply', [pubkey, options])
187
447
  end
188
448
 
449
+ ##
450
+ # Retrieves transaction details for a given signature.
451
+ #
452
+ # @param [String] signature The transaction signature.
453
+ # @param [Hash] options Optional parameters for the request.
454
+ # @return [Hash] The transaction details.
189
455
  def get_transaction(signature, options = {})
190
- request('getTransaction', [signature, options])
456
+ request_http('getTransaction', [signature, options])
191
457
  end
192
458
 
459
+ ##
460
+ # Retrieves the total number of transactions processed by the network.
461
+ #
462
+ # @param [Hash] options Optional parameters for the request.
463
+ # @return [Integer] The total number of transactions.
193
464
  def get_transaction_count(options = {})
194
- request('getTransactionCount', [options])
465
+ request_http('getTransactionCount', [options])
195
466
  end
196
467
 
197
- def get_version(options = {})
198
- request('getVersion', [options])
468
+ ##
469
+ # Retrieves the current version of the Solana software.
470
+ #
471
+ # @return [Hash] The current version information.
472
+ def get_version
473
+ request_http('getVersion')
199
474
  end
200
475
 
476
+ ##
477
+ # Retrieves the list of vote accounts.
478
+ #
479
+ # @param [Hash] options Optional parameters for the request.
480
+ # @return [Hash] The list of vote accounts.
201
481
  def get_vote_accounts(options = {})
202
- request('getVoteAccounts', [options])
482
+ request_http('getVoteAccounts', [options])
203
483
  end
204
484
 
485
+ ##
486
+ # Checks if a given blockhash is valid.
487
+ #
488
+ # @param [String] blockhash The blockhash to check.
489
+ # @param [Hash] options Optional parameters for the request.
490
+ # @return [Boolean] Whether the blockhash is valid.
205
491
  def is_blockhash_valid(blockhash, options = {})
206
- request('isBlockhashValid', [blockhash, options])
492
+ request_http('isBlockhashValid', [blockhash, options])
207
493
  end
208
494
 
495
+ ##
496
+ # Retrieves the minimum ledger slot.
497
+ #
498
+ # @param [Hash] options Optional parameters for the request.
499
+ # @return [Integer] The minimum ledger slot.
209
500
  def minimum_ledger_slot(options = {})
210
- request('minimumLedgerSlot', [options])
501
+ request_http('minimumLedgerSlot', [options])
211
502
  end
212
503
 
504
+ ##
505
+ # Requests an airdrop to a given public key.
506
+ #
507
+ # @param [String] pubkey The public key to receive the airdrop.
508
+ # @param [Integer] lamports The amount of lamports to airdrop.
509
+ # @param [Hash] options Optional parameters for the request.
510
+ # @return [Hash] The airdrop request response.
213
511
  def request_airdrop(pubkey, lamports, options = {})
214
- request('requestAirdrop', [pubkey, lamports, options])
512
+ request_http('requestAirdrop', [pubkey, lamports, options])
215
513
  end
216
514
 
217
- def send_transaction(transaction, options = {})
218
- request('sendTransaction', [transaction, options])
515
+ ##
516
+ # Sends a transaction.
517
+ #
518
+ # @param [Hash] transaction The transaction to send.
519
+ # @return [Hash] The response from the send transaction request.
520
+ def send_transaction(transaction)
521
+ request_http('sendTransaction', [transaction.to_json])
219
522
  end
220
523
 
524
+ ##
525
+ # Simulates a transaction.
526
+ #
527
+ # @param [Hash] transaction The transaction to simulate.
528
+ # @param [Hash] options Optional parameters for the request.
529
+ # @return [Hash] The simulation response.
221
530
  def simulate_transaction(transaction, options = {})
222
- request('simulateTransaction', [transaction, options])
223
- end
224
-
225
- private
226
-
227
- def request(method, params = [])
228
- options = {
229
- headers: { 'Content-Type' => 'application/json' },
230
- body: {
231
- jsonrpc: '2.0',
232
- method: method,
233
- params: params,
234
- id: 1
235
- }.to_json
531
+ request_http('simulateTransaction', [transaction.to_json, options])
532
+ end
533
+
534
+ ##
535
+ # Subscribes to account changes.
536
+ #
537
+ # @param [String] pubkey The public key of the account.
538
+ # @param [Hash] options Optional parameters for the subscription.
539
+ # @yield [Object] The response from the subscription.
540
+ def account_subscribe(pubkey, options = {}, &block)
541
+ request_ws('accountSubscribe', [pubkey, options], &block)
542
+ end
543
+
544
+ ##
545
+ # Unsubscribes from account changes.
546
+ #
547
+ # @param [Integer] subscription_id The subscription ID.
548
+ # @yield [Object] The response from the unsubscription.
549
+ def account_unsubscribe(subscription_id, &block)
550
+ request_ws('accountUnsubscribe', [subscription_id], &block)
551
+ end
552
+
553
+ ##
554
+ # Subscribes to new blocks.
555
+ #
556
+ # @param [Hash] options Optional parameters for the subscription.
557
+ # @yield [Object] The response from the subscription.
558
+ def block_subscribe(options = {}, &block)
559
+ request_ws('blockSubscribe', [options], &block)
560
+ end
561
+
562
+ ##
563
+ # Unsubscribes from new blocks.
564
+ #
565
+ # @param [Integer] subscription_id The subscription ID.
566
+ # @yield [Object] The response from the unsubscription.
567
+ def block_unsubscribe(subscription_id, &block)
568
+ request_ws('blockUnsubscribe', [subscription_id], &block)
569
+ end
570
+
571
+ ##
572
+ # Subscribes to log messages.
573
+ #
574
+ # @param [String, Hash] filter The filter for log messages (e.g., a public key or a set of options).
575
+ # @param [Hash] options Optional parameters for the subscription.
576
+ # @yield [Object] The response from the subscription.
577
+ def logs_subscribe(filter, options = {}, &block)
578
+ request_ws('logsSubscribe', [filter, options], &block)
579
+ end
580
+
581
+ ##
582
+ # Unsubscribes from log messages.
583
+ #
584
+ # @param [Integer] subscription_id The subscription ID.
585
+ # @yield [Object] The response from the unsubscription.
586
+ def logs_unsubscribe(subscription_id, &block)
587
+ request_ws('logsUnsubscribe', [subscription_id], &block)
588
+ end
589
+
590
+ ##
591
+ # Subscribes to program changes.
592
+ #
593
+ # @param [String] pubkey The public key of the program.
594
+ # @param [Hash] options Optional parameters for the subscription.
595
+ # @yield [Object] The response from the subscription.
596
+ def program_subscribe(pubkey, options = {}, &block)
597
+ request_ws('programSubscribe', [pubkey, options], &block)
598
+ end
599
+
600
+ ##
601
+ # Unsubscribes from program changes.
602
+ #
603
+ # @param [Integer] subscription_id The subscription ID.
604
+ # @yield [Object] The response from the unsubscription.
605
+ def program_unsubscribe(subscription_id, &block)
606
+ request_ws('programUnsubscribe', [subscription_id], &block)
607
+ end
608
+
609
+ ##
610
+ # Subscribes to root changes.
611
+ #
612
+ # @yield [Object] The response from the subscription.
613
+ def root_subscribe(&block)
614
+ request_ws('rootSubscribe', &block)
615
+ end
616
+
617
+ ##
618
+ # Unsubscribes from root changes.
619
+ #
620
+ # @param [Integer] subscription_id The subscription ID.
621
+ # @yield [Object] The response from the unsubscription.
622
+ def root_unsubscribe(subscription_id, &block)
623
+ request_ws('rootUnsubscribe', [subscription_id], &block)
624
+ end
625
+
626
+ ##
627
+ # Subscribes to signature status changes.
628
+ #
629
+ # @param [String] signature The signature to monitor.
630
+ # @param [Hash] options Optional parameters for the subscription.
631
+ # @yield [Object] The response from the subscription.
632
+ def signature_subscribe(signature, options = {}, &block)
633
+ request_ws('signatureSubscribe', [signature, options], &block)
634
+ end
635
+
636
+ ##
637
+ # Unsubscribes from signature status changes.
638
+ #
639
+ # @param [Integer] subscription_id The subscription ID.
640
+ # @yield [Object] The response from the unsubscription.
641
+ def signature_unsubscribe(subscription_id, &block)
642
+ request_ws('signatureUnsubscribe', [subscription_id], &block)
643
+ end
644
+
645
+ ##
646
+ # Subscribes to slot changes.
647
+ #
648
+ # @yield [Object] The response from the subscription.
649
+ def slot_subscribe(&block)
650
+ request_ws('slotSubscribe', &block)
651
+ end
652
+
653
+ ##
654
+ # Unsubscribes from slot changes.
655
+ #
656
+ # @param [Integer] subscription_id The subscription ID.
657
+ # @yield [Object] The response from the unsubscription.
658
+ def slot_unsubscribe(subscription_id, &block)
659
+ request_ws('slotUnsubscribe', [subscription_id], &block)
660
+ end
661
+
662
+ ##
663
+ # Subscribes to slot updates.
664
+ #
665
+ # @yield [Object] The response from the subscription.
666
+ def slots_updates_subscribe(&block)
667
+ request_ws('slotsUpdatesSubscribe', &block)
668
+ end
669
+
670
+ ##
671
+ # Unsubscribes from slot updates.
672
+ #
673
+ # @param [Integer] subscription_id The subscription ID.
674
+ # @yield [Object] The response from the unsubscription.
675
+ def slots_updates_unsubscribe(subscription_id, &block)
676
+ request_ws('slotsUpdatesUnsubscribe', [subscription_id], &block)
677
+ end
678
+
679
+ ##
680
+ # Subscribes to vote updates.
681
+ #
682
+ # @yield [Object] The response from the subscription.
683
+ def vote_subscribe(&block)
684
+ request_ws('voteSubscribe', &block)
685
+ end
686
+
687
+ ##
688
+ # Unsubscribes from vote updates.
689
+ #
690
+ # @param [Integer] subscription_id The subscription ID.
691
+ # @yield [Object] The response from the unsubscription.
692
+ def vote_unsubscribe(subscription_id, &block)
693
+ request_ws('voteUnsubscribe', [subscription_id], &block)
694
+ end
695
+
696
+ ##
697
+ # Sends a JSON-RPC request to the Solana API.
698
+ #
699
+ # @param [String] method The RPC method to call.
700
+ # @param [Array] params The parameters for the RPC method.
701
+ # @return [Object] The parsed response from the API.
702
+ def request_http(method, params = nil)
703
+ body = {
704
+ jsonrpc: '2.0',
705
+ method: method,
706
+ id: 1
236
707
  }
708
+ body[:params] = params if params
237
709
 
238
- response = self.class.post('/', options)
239
- handle_response(response)
710
+ response = @api_http.post do |req|
711
+ req.headers['Content-Type'] = 'application/json'
712
+ req.body = body.to_json
713
+ end
714
+
715
+ handle_response_http(response)
240
716
  end
241
717
 
242
- def handle_response(response)
718
+ ##
719
+ # Handles the API response, checking for success and parsing the result.
720
+ #
721
+ # @param [Faraday::Response] response The HTTP response object.
722
+ # @raise [RuntimeError] If the request fails (non-success response).
723
+ # @return [Object] The parsed result from the API response.
724
+ def handle_response_http(response)
243
725
  if response.success?
244
- response.parsed_response['result']
726
+ response.body['result']
245
727
  else
246
- raise "Request failed: #{response.code} #{response.message}"
728
+ raise "Request failed: #{response.status} #{response.reason_phrase}"
729
+ end
730
+ end
731
+
732
+ ##
733
+ # Sends a JSON-RPC request to the Solana API over WebSocket.
734
+ #
735
+ # @param [String] method The RPC method to call.
736
+ # @param [Array] params The parameters for the RPC method.
737
+ # @yield [Object] The parsed response from the API.
738
+
739
+ def request_ws(method, params = nil, &block)
740
+ EM.run do
741
+ ws = Faye::WebSocket::Client.new(@api_endpoint::WS)
742
+
743
+ ws.on :open do |event|
744
+ body = {
745
+ jsonrpc: '2.0',
746
+ method: method,
747
+ id: 1
748
+ }
749
+ body[:params] = params if params
750
+
751
+ ws.send(body.to_json)
752
+ end
753
+
754
+ ws.on :message do |event|
755
+ response = JSON.parse(event.data)
756
+ yield response['result'] if block_given?
757
+ ws.close
758
+ end
759
+
760
+ ws.on :close do |event|
761
+ ws = nil
762
+ EM.stop
763
+ end
764
+
765
+ ws.on :error do |event|
766
+ puts "WebSocket error: #{event.message}"
767
+ ws = nil
768
+ EM.stop
769
+ end
247
770
  end
248
771
  end
249
772
  end
@@ -0,0 +1,105 @@
1
+ require 'rbnacl'
2
+ require 'json'
3
+ require_relative 'utils'
4
+
5
+ module SolanaRB
6
+ ##
7
+ # The Keypair class represents a keypair for signing transactions on the Solana blockchain.
8
+ #
9
+ class Keypair
10
+ attr_reader :public_key, :secret_key
11
+
12
+ ##
13
+ # Initializes a new Keypair.
14
+ #
15
+ # If a +secret_key+ is provided, it must be 64 bytes long. The first 32 bytes are used as the signing key,
16
+ # and the public key is derived from it. If no +secret_key+ is provided, a new keypair is generated.
17
+ #
18
+ # Raises an error if the +secret_key+ is not 64 bytes long.
19
+ #
20
+ # @param [String, nil] secret_key The secret key to use for the keypair, in binary format (optional).
21
+ def initialize(secret_key = nil)
22
+ if secret_key
23
+ raise 'Bad secret key size' unless secret_key.bytesize == 64
24
+ @signing_key = RbNaCl::Signatures::Ed25519::SigningKey.new(secret_key[0, 32])
25
+ @public_key = @signing_key.verify_key.to_bytes
26
+ else
27
+ @signing_key = RbNaCl::Signatures::Ed25519::SigningKey.generate
28
+ @public_key = @signing_key.verify_key.to_bytes
29
+ end
30
+ @secret_key = @signing_key.to_bytes + @public_key
31
+ end
32
+
33
+ ##
34
+ # Generates a new Keypair.
35
+ #
36
+ # @return [Keypair] A new Keypair instance.
37
+ def self.generate
38
+ new
39
+ end
40
+
41
+ ##
42
+ # Creates a Keypair from a provided secret key.
43
+ #
44
+ # @param [String] secret_key The secret key in binary format.
45
+ # @return [Keypair] A new Keypair instance initialized with the provided secret key.
46
+ def self.from_secret_key(secret_key)
47
+ new(secret_key)
48
+ end
49
+
50
+ ##
51
+ # Saves the keypair to a JSON file.
52
+ #
53
+ # The public and secret keys are encoded in Base58 format before being saved.
54
+ #
55
+ # @param [String] file_path The path to the file where the keypair will be saved.
56
+ def save_to_json(file_path)
57
+ data = {
58
+ public_key: Utils::base58_encode(@public_key),
59
+ secret_key: Utils::base58_encode(@secret_key)
60
+ }
61
+ File.write(file_path, data.to_json)
62
+ end
63
+
64
+ ##
65
+ # Loads a keypair from a JSON file.
66
+ #
67
+ # The file must contain the public and secret keys in Base58 format. The method verifies the size of the secret key and
68
+ # checks that the derived public key matches the saved public key.
69
+ #
70
+ # Raises an error if the +secret_key+ is not 64 bytes long or if the derived public key does not match the saved public key.
71
+ #
72
+ # @param [String] file_path The path to the file from which the keypair will be loaded.
73
+ # @return [Keypair] The loaded keypair.
74
+ def self.load_from_json(file_path)
75
+ data = JSON.parse(File.read(file_path), symbolize_names: true)
76
+ secret_key = Utils::base58_decode(data[:secret_key])
77
+ public_key = Utils::base58_decode(data[:public_key])
78
+
79
+ raise 'Bad secret key size' unless secret_key.bytesize == 64
80
+
81
+ signing_key = RbNaCl::Signatures::Ed25519::SigningKey.new(secret_key[0, 32])
82
+ loaded_public_key = signing_key.verify_key.to_bytes
83
+
84
+ raise 'Provided secretKey is invalid' unless loaded_public_key == public_key
85
+
86
+ new(secret_key)
87
+ end
88
+
89
+ ##
90
+ # Returns the public key for this keypair in Base58 format.
91
+ #
92
+ # @return [String] The public key in Base58 format.
93
+ def public_key_base58
94
+ Utils::base58_encode(@public_key)
95
+ end
96
+
97
+ ##
98
+ # Returns the raw secret key for this keypair in Base58 format.
99
+ #
100
+ # @return [String] The secret key in Base58 format.
101
+ def secret_key_base58
102
+ Utils::base58_encode(@secret_key)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,107 @@
1
+ require 'base58'
2
+ require 'base64'
3
+
4
+ module SolanaRB
5
+ ##
6
+ # The Utils module provides utility methods and constants for interacting with the Solana blockchain.
7
+ #
8
+ module Utils
9
+ ##
10
+ # The system program ID for Solana.
11
+ SYSTEM_PROGRAM_ID = '11111111111111111111111111111111'
12
+
13
+ ##
14
+ # The maximum packet data size for Solana transactions.
15
+ PACKET_DATA_SIZE = 1232
16
+
17
+ ##
18
+ # Endpoints for the mainnet.
19
+ module MAINNET
20
+ ##
21
+ # HTTP endpoint for the mainnet.
22
+ HTTP = 'https://api.mainnet-beta.solana.com'
23
+
24
+ ##
25
+ # WebSocket endpoint for the mainnet.
26
+ WS = 'wss://api.mainnet-beta.solana.com'
27
+ end
28
+
29
+ ##
30
+ # Endpoints for the testnet.
31
+ module TESTNET
32
+ ##
33
+ # HTTP endpoint for the testnet.
34
+ HTTP = 'https://api.testnet.solana.com'
35
+
36
+ ##
37
+ # WebSocket endpoint for the testnet.
38
+ WS = 'wss://api.testnet.solana.com'
39
+ end
40
+
41
+ ##
42
+ # Endpoints for the devnet.
43
+ module DEVNET
44
+ ##
45
+ # HTTP endpoint for the devnet.
46
+ HTTP = 'https://api.devnet.solana.com'
47
+
48
+ ##
49
+ # WebSocket endpoint for the devnet.
50
+ WS = 'wss://api.devnet.solana.com'
51
+ end
52
+
53
+ ##
54
+ # Instruction types for Solana transactions.
55
+ module InstructionType
56
+ CREATE_ACCOUNT = 0
57
+ ASSIGN = 1
58
+ TRANSFER = 2
59
+ CREATE_ACCOUNT_WITH_SEED = 3
60
+ ADVANCE_NONCE_ACCOUNT = 4
61
+ WITHDRAW_NONCE_ACCOUNT = 5
62
+ INITIALIZE_NONCE_ACCOUNT = 6
63
+ AUTHORIZE_NONCE_ACCOUNT = 7
64
+ ALLOCATE = 8
65
+ ALLOCATE_WITH_SEED = 9
66
+ ASSIGN_WITH_SEED = 10
67
+ TRANSFER_WITH_SEED = 11
68
+ end
69
+
70
+ ##
71
+ # Encodes a byte array into a Base58 string.
72
+ #
73
+ # @param [String] bytes The byte array to encode.
74
+ # @return [String] The Base58-encoded string.
75
+ def self.base58_encode(bytes)
76
+ Base58.binary_to_base58(bytes, :bitcoin)
77
+ end
78
+
79
+ ##
80
+ # Decodes a Base58 string into a byte array.
81
+ #
82
+ # @param [String] base58 The Base58 string to decode.
83
+ # @return [String] The decoded byte array.
84
+ def self.base58_decode(base58)
85
+ Base58.base58_to_binary(base58, :bitcoin)
86
+ end
87
+
88
+ ##
89
+ # Encodes a byte array into a Base64 string.
90
+ #
91
+ # @param [String] bytes The byte array to encode.
92
+ # @return [String] The Base64-encoded string.
93
+ def self.base64_encode(bytes)
94
+ Base64.strict_encode64(bytes)
95
+ end
96
+
97
+ ##
98
+ # Decodes a Base64 string into a byte array.
99
+ #
100
+ # @param [String] base64 The Base64 string to decode.
101
+ # @return [String] The decoded byte array.
102
+ def self.base64_decode(base64)
103
+ Base64.strict_decode64(base64)
104
+ end
105
+ end
106
+ Utils.freeze
107
+ end
@@ -1,3 +1,3 @@
1
1
  module SolanaRB
2
- VERSION = '0.1.0'.freeze
3
- end
2
+ VERSION = '0.1.1'.freeze
3
+ end
data/lib/solana-ruby.rb CHANGED
@@ -1,5 +1,7 @@
1
- require_relative 'solana-ruby/version'
2
1
  require_relative 'solana-ruby/client'
2
+ require_relative 'solana-ruby/keypair'
3
+ require_relative 'solana-ruby/utils'
4
+ require_relative 'solana-ruby/version'
3
5
 
4
6
  module SolanaRB
5
7
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solana-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fabrice Renard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-23 00:00:00.000000000 Z
11
+ date: 2024-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: httparty
14
+ name: faraday
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.18.0
19
+ version: 2.9.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.18.0
26
+ version: 2.9.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: faye-websocket
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.10
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.2.10
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: csv
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,76 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '3.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ed25519
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: base58
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.2.3
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.2.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: base64
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.2.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.2.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rdoc
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 6.7.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 6.7.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rqrcode
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.0'
41
125
  - !ruby/object:Gem::Dependency
42
126
  name: rspec
43
127
  requirement: !ruby/object:Gem::Requirement
@@ -75,11 +159,14 @@ extra_rdoc_files: []
75
159
  files:
76
160
  - lib/solana-ruby.rb
77
161
  - lib/solana-ruby/client.rb
162
+ - lib/solana-ruby/keypair.rb
163
+ - lib/solana-ruby/utils.rb
78
164
  - lib/solana-ruby/version.rb
79
165
  homepage: https://github.com/fabricerenard12/solana-ruby
80
166
  licenses:
81
167
  - MIT
82
- metadata: {}
168
+ metadata:
169
+ homepage_uri: https://github.com/fabricerenard12/solana-ruby
83
170
  post_install_message:
84
171
  rdoc_options: []
85
172
  require_paths:
@@ -98,5 +185,5 @@ requirements: []
98
185
  rubygems_version: 3.5.9
99
186
  signing_key:
100
187
  specification_version: 4
101
- summary: A Ruby wrapper for the Solana blockchain API
188
+ summary: A Ruby SDK for the Solana blockchain API
102
189
  test_files: []