solana-ruby-web3js 1.0.1.beta1
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 +7 -0
- data/.DS_Store +0 -0
- data/.rspec +1 -0
- data/.rubocop.yml +13 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +184 -0
- data/README.md +273 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/.DS_Store +0 -0
- data/lib/solana_ruby/.DS_Store +0 -0
- data/lib/solana_ruby/base_client.rb +46 -0
- data/lib/solana_ruby/http_client.rb +42 -0
- data/lib/solana_ruby/http_methods/account_methods.rb +98 -0
- data/lib/solana_ruby/http_methods/basic_methods.rb +108 -0
- data/lib/solana_ruby/http_methods/block_methods.rb +89 -0
- data/lib/solana_ruby/http_methods/blockhash_methods.rb +30 -0
- data/lib/solana_ruby/http_methods/lookup_table_methods.rb +55 -0
- data/lib/solana_ruby/http_methods/signature_methods.rb +30 -0
- data/lib/solana_ruby/http_methods/slot_methods.rb +44 -0
- data/lib/solana_ruby/http_methods/token_methods.rb +32 -0
- data/lib/solana_ruby/http_methods/transaction_methods.rb +85 -0
- data/lib/solana_ruby/version.rb +5 -0
- data/lib/solana_ruby/web_socket_client.rb +93 -0
- data/lib/solana_ruby/web_socket_handlers.rb +34 -0
- data/lib/solana_ruby/web_socket_methods/account_methods.rb +37 -0
- data/lib/solana_ruby/web_socket_methods/log_methods.rb +27 -0
- data/lib/solana_ruby/web_socket_methods/root_methods.rb +16 -0
- data/lib/solana_ruby/web_socket_methods/signature_methods.rb +25 -0
- data/lib/solana_ruby/web_socket_methods/slot_methods.rb +20 -0
- data/lib/solana_ruby.rb +10 -0
- metadata +136 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
require 'uri'
|
6
|
+
require 'base64'
|
7
|
+
require 'base58'
|
8
|
+
require_relative 'base_client'
|
9
|
+
Dir[File.join(__dir__, 'http_methods', '*.rb')].each { |file| require file }
|
10
|
+
|
11
|
+
module SolanaRuby
|
12
|
+
class HttpClient < BaseClient
|
13
|
+
[HttpMethods::BasicMethods, HttpMethods::LookupTableMethods, HttpMethods::TransactionMethods,
|
14
|
+
HttpMethods::SignatureMethods, HttpMethods::BlockhashMethods, HttpMethods::BlockMethods,
|
15
|
+
HttpMethods::AccountMethods, HttpMethods::TokenMethods, HttpMethods::SlotMethods].each do |mod|
|
16
|
+
include mod
|
17
|
+
end
|
18
|
+
BASE_URL = 'https://api.mainnet-beta.solana.com'
|
19
|
+
|
20
|
+
def initialize(endpoint = BASE_URL)
|
21
|
+
@uri = URI.parse(endpoint)
|
22
|
+
end
|
23
|
+
|
24
|
+
def request(method, params = [])
|
25
|
+
http = Net::HTTP.new(@uri.host, @uri.port)
|
26
|
+
http.use_ssl = true
|
27
|
+
|
28
|
+
request = Net::HTTP::Post.new(@uri.request_uri, {'Content-Type' => 'application/json'})
|
29
|
+
request.body = {
|
30
|
+
jsonrpc: '2.0',
|
31
|
+
id: 1,
|
32
|
+
method: method,
|
33
|
+
params: params
|
34
|
+
}.to_json
|
35
|
+
|
36
|
+
response = http.request(request)
|
37
|
+
handle_http_response(response)
|
38
|
+
rescue StandardError => e
|
39
|
+
handle_error(e)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolanaRuby
|
4
|
+
module HttpMethods
|
5
|
+
# Account Related HTTP Methods
|
6
|
+
module AccountMethods
|
7
|
+
ENCODING_JSON_OPTIONS = { encoding: "jsonParsed", commitment: "finalized" }.freeze
|
8
|
+
FINALIZED_OPTIONS = { commitment: "finalized" }.freeze
|
9
|
+
ENCODING_BASE58_OPTIONS = { encoding: "base58" }.freeze
|
10
|
+
|
11
|
+
def get_account_info(pubkey)
|
12
|
+
account_info = get_account_info_and_context(pubkey)
|
13
|
+
account_info["value"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_parsed_account_info(pubkey, options = ENCODING_JSON_OPTIONS)
|
17
|
+
get_account_info_and_context(pubkey, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_account_info_and_context(pubkey, options = {})
|
21
|
+
account_info = request("getAccountInfo", [pubkey, options])
|
22
|
+
account_info["result"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_multiple_account_info(pubkeys, options = ENCODING_BASE58_OPTIONS)
|
26
|
+
accounts_info = get_multiple_account_info_and_context(pubkeys, options)
|
27
|
+
accounts_info["value"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_multiple_account_info_and_context(pubkeys, options = ENCODING_BASE58_OPTIONS)
|
31
|
+
params = [pubkeys, options]
|
32
|
+
accounts_info = request("getMultipleAccounts", params)
|
33
|
+
accounts_info["result"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_multiple_parsed_accounts(pubkeys, options = ENCODING_JSON_OPTIONS)
|
37
|
+
get_multiple_account_info_and_context(pubkeys, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_largest_accounts(options = ENCODING_BASE58_OPTIONS.merge(FINALIZED_OPTIONS))
|
41
|
+
account_info = request("getLargestAccounts", [options])
|
42
|
+
account_info["result"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_program_accounts(program_id, options = FINALIZED_OPTIONS)
|
46
|
+
params = [program_id, options]
|
47
|
+
account_info = request("getProgramAccounts", params)
|
48
|
+
account_info["result"]
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_parsed_program_accounts(program_id, options = ENCODING_JSON_OPTIONS)
|
52
|
+
get_program_accounts(program_id, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_vote_accounts(options = FINALIZED_OPTIONS)
|
56
|
+
account_info = request("getVoteAccounts", [options])
|
57
|
+
account_info["result"]
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_parsed_token_accounts_by_owner(owner_pubkey, filters = {}, options = ENCODING_JSON_OPTIONS)
|
61
|
+
params = [owner_pubkey, filters, options]
|
62
|
+
parsed_token_accounts = request("getTokenAccountsByOwner", params)
|
63
|
+
parsed_token_accounts["result"]
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_nonce_and_context(pubkey)
|
67
|
+
account_info_and_context = get_account_info_and_context(pubkey)
|
68
|
+
unless account_info_and_context["value"]["owner"] == "11111111111111111111111111111111"
|
69
|
+
raise "Provided account is not a nonce account"
|
70
|
+
end
|
71
|
+
|
72
|
+
data = account_info_and_context["value"]["data"][0]
|
73
|
+
raise "Nonce account data is empty" if data.nil? || data.empty?
|
74
|
+
|
75
|
+
decoded_data = Base64.decode64(data)
|
76
|
+
nonce_info = parse_nonce_account(decoded_data)
|
77
|
+
{
|
78
|
+
context: account_info_and_context["context"],
|
79
|
+
value: nonce_info
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_nonce(pubkey)
|
84
|
+
nonce_info = get_nonce_and_context(pubkey)
|
85
|
+
nonce_info[:value]
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def parse_nonce_account(data)
|
91
|
+
{
|
92
|
+
blockhash: data[4, 32].unpack1("H*"),
|
93
|
+
fee_calculator: { lamports_per_signature: data[36, 8].unpack1("Q<") }
|
94
|
+
}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolanaRuby
|
4
|
+
module HttpMethods
|
5
|
+
# Basic Methods
|
6
|
+
module BasicMethods
|
7
|
+
FINALIZED_OPTIONS = { commitment: "finalized" }.freeze
|
8
|
+
|
9
|
+
def get_balance(pubkey)
|
10
|
+
balance_info = request("getBalance", [pubkey])
|
11
|
+
balance_info["result"]["value"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_balance_and_context(pubkey)
|
15
|
+
balance_info = request("getBalance", [pubkey])
|
16
|
+
balance_info["result"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_epoch_info(options = FINALIZED_OPTIONS)
|
20
|
+
epoch_info = request("getEpochInfo", [options])
|
21
|
+
epoch_info["result"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_epoch_schedule
|
25
|
+
epoch_schedule = request("getEpochSchedule")
|
26
|
+
epoch_schedule["result"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_genesis_hash
|
30
|
+
genesis_hash = request("getGenesisHash")
|
31
|
+
genesis_hash["result"]
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_inflation_governor
|
35
|
+
inflation_governor = request("getInflationGovernor")
|
36
|
+
inflation_governor["result"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_inflation_rate
|
40
|
+
inflation_rate = request("getInflationRate")
|
41
|
+
inflation_rate["result"]
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_inflation_reward(addresses, options = {})
|
45
|
+
params = [addresses, options]
|
46
|
+
request("getInflationReward", params)
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_leader_schedule(options = { epoch: nil })
|
50
|
+
leader_schedule = request("getLeaderSchedule", [options])
|
51
|
+
leader_schedule["result"]
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_minimum_balance_for_rent_exemption(account_data_size, options = FINALIZED_OPTIONS)
|
55
|
+
params = [account_data_size, options]
|
56
|
+
minimum_balance_for_rent_exemption = request("getMinimumBalanceForRentExemption", params)
|
57
|
+
minimum_balance_for_rent_exemption["result"]
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_stake_activation(account_pubkey, options = FINALIZED_OPTIONS.merge(epoch: nil))
|
61
|
+
params = [account_pubkey, options]
|
62
|
+
stake_activation = request("getStakeActivation", params)
|
63
|
+
stake_activation["result"]
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_stake_minimum_delegation(options = FINALIZED_OPTIONS)
|
67
|
+
stake_minimum_delagation = request("getStakeMinimumDelegation", [FINALIZED_OPTIONS])
|
68
|
+
stake_minimum_delagation["result"]
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_supply(options = FINALIZED_OPTIONS)
|
72
|
+
supply_info = request("getSupply", [options])
|
73
|
+
supply_info["result"]
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_version
|
77
|
+
version_info = request("getVersion")
|
78
|
+
version_info["result"]
|
79
|
+
end
|
80
|
+
|
81
|
+
def get_total_supply(options = FINALIZED_OPTIONS)
|
82
|
+
supply_info = get_supply(options)
|
83
|
+
supply_info["value"]["total"]
|
84
|
+
end
|
85
|
+
|
86
|
+
def get_health
|
87
|
+
health_info = request("getHealth")
|
88
|
+
health_info["result"]
|
89
|
+
end
|
90
|
+
|
91
|
+
def get_identity
|
92
|
+
health_info = request("getIdentity")
|
93
|
+
health_info["result"]
|
94
|
+
end
|
95
|
+
|
96
|
+
def get_recent_performance_samples(limit = 10)
|
97
|
+
performance_samples = request("getRecentPerformanceSamples", [limit])
|
98
|
+
performance_samples["result"]
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_recent_prioritization_fees(addresses)
|
102
|
+
params = [addresses]
|
103
|
+
prioritization_fees = request("getRecentPrioritizationFees", params)
|
104
|
+
prioritization_fees["result"]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolanaRuby
|
4
|
+
module HttpMethods
|
5
|
+
# Block Related HTTP Methods
|
6
|
+
module BlockMethods
|
7
|
+
DEFAULT_OPTIONS = { maxSupportedTransactionVersion: 0 }.freeze
|
8
|
+
|
9
|
+
def get_blocks(start_slot, end_slot)
|
10
|
+
params = [start_slot, end_slot]
|
11
|
+
block_info = request("getBlocks", params)
|
12
|
+
block_info["result"]
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_block(slot, options = DEFAULT_OPTIONS)
|
16
|
+
params = [slot, options]
|
17
|
+
block_info = request("getBlock", params)
|
18
|
+
block_info["result"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_block_production
|
22
|
+
request("getBlockProduction")
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_block_time(slot)
|
26
|
+
block_info = request("getBlockTime", [slot])
|
27
|
+
block_info["result"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_block_signatures(slot, options = DEFAULT_OPTIONS)
|
31
|
+
block_info = get_block(slot, options)
|
32
|
+
block_signatures(block_info)
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_cluster_nodes
|
36
|
+
cluster_nodes_info = request("getClusterNodes")
|
37
|
+
cluster_nodes_info["result"]
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_confirmed_block(slot, options = DEFAULT_OPTIONS)
|
41
|
+
block_info = get_block(slot, options)
|
42
|
+
block_info["result"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_confirmed_block_signatures(slot)
|
46
|
+
block_info = get_confirmed_block(slot)
|
47
|
+
block_signatures(block_info)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_parsed_block(slot, options = {})
|
51
|
+
params = [slot, { encoding: "jsonParsed", transactionDetails: "full" }.merge(options)]
|
52
|
+
result = request("getBlock", params)
|
53
|
+
result["result"]
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_first_available_block
|
57
|
+
result = request("getFirstAvailableBlock")
|
58
|
+
result["result"]
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_blocks_with_limit(start_slot, limit)
|
62
|
+
params = [start_slot, limit]
|
63
|
+
response = request("getBlocksWithLimit", params)
|
64
|
+
response["result"]
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_block_height
|
68
|
+
block_height = request("getBlockHeight")
|
69
|
+
block_height["result"]
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_block_commitment(block_slot)
|
73
|
+
block_commitment = request("getBlockCommitment", [block_slot])
|
74
|
+
block_commitment["result"]
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def block_signatures(block_info)
|
80
|
+
signatures = block_info["transactions"][0]["transaction"]["signatures"]
|
81
|
+
block_info.delete("transactions")
|
82
|
+
block_info.delete("rewards")
|
83
|
+
block_info.merge({
|
84
|
+
signatures: signatures
|
85
|
+
})
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolanaRuby
|
4
|
+
module HttpMethods
|
5
|
+
# Blockhash Related HTTP Methods
|
6
|
+
module BlockhashMethods
|
7
|
+
def get_latest_blockhash
|
8
|
+
recent_blockhash_info = get_latest_blockhash_and_context
|
9
|
+
recent_blockhash_info["value"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_latest_blockhash_and_context
|
13
|
+
recent_blockhash_info = request("getLatestBlockhash")
|
14
|
+
recent_blockhash_info["result"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_fee_for_message(blockhash, options = { commitment: "processed" })
|
18
|
+
params = [blockhash, options]
|
19
|
+
fee_for_blockhash_info = request("getFeeForMessage", params)
|
20
|
+
fee_for_blockhash_info["result"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def is_blockhash_valid?(blockhash, options = { commitment: "processed" })
|
24
|
+
params = [blockhash, options]
|
25
|
+
blockhash_info = request("isBlockhashValid", params)
|
26
|
+
blockhash_info["result"]["value"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolanaRuby
|
4
|
+
module HttpMethods
|
5
|
+
# Lookup Table Related HTTP Methods
|
6
|
+
module LookupTableMethods
|
7
|
+
def get_address_lookup_table(pubkey)
|
8
|
+
response = get_account_info_and_context(pubkey)
|
9
|
+
|
10
|
+
# Handle the response to ensure the account is a valid Address Lookup Table
|
11
|
+
unless response && response["value"]
|
12
|
+
raise SolanaError.new("Address Lookup Table not found or invalid account data.")
|
13
|
+
end
|
14
|
+
|
15
|
+
account_data = response["value"]["data"]
|
16
|
+
|
17
|
+
# Decode the account data
|
18
|
+
decode_lookup_table_data(Base64.decode64(account_data))
|
19
|
+
|
20
|
+
# Return the parsed lookup table details
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def decode_lookup_table_data(data)
|
26
|
+
lookup_table_state = {}
|
27
|
+
|
28
|
+
lookup_table_state[:last_extended_slot],
|
29
|
+
lookup_table_state[:last_extended_block_height],
|
30
|
+
deactivation_slot = data[0, 24].unpack("Q<Q<Q<")
|
31
|
+
|
32
|
+
lookup_table_state[:deactivation_slot] = deactivation_slot == 0xFFFFFFFFFFFFFFFF ? nil : deactivation_slot
|
33
|
+
|
34
|
+
authority_offset = 24
|
35
|
+
addresses_offset = authority_offset + 32
|
36
|
+
|
37
|
+
authority_key = data[authority_offset, 32]
|
38
|
+
lookup_table_state[:authority] = if authority_key == ("\x00" * 32)
|
39
|
+
nil
|
40
|
+
else
|
41
|
+
Base58.binary_to_base58(authority_key, :bitcoin)
|
42
|
+
end
|
43
|
+
|
44
|
+
addresses_data = data[addresses_offset..-1]
|
45
|
+
address_count = addresses_data.size / 32
|
46
|
+
lookup_table_state[:addresses] = address_count.times.map do |i|
|
47
|
+
address_data = addresses_data[i * 32, 32]
|
48
|
+
Base58.binary_to_base58(address_data, :bitcoin)
|
49
|
+
end
|
50
|
+
|
51
|
+
lookup_table_state
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolanaRuby
|
4
|
+
module HttpMethods
|
5
|
+
# Signature Related Web Socket Methods
|
6
|
+
module SignatureMethods
|
7
|
+
def get_signature_statuses(signatures, options = {})
|
8
|
+
params = [signatures, options]
|
9
|
+
signature_request("getSignatureStatuses", params)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_signature_status(signature, options = {})
|
13
|
+
signature_status = get_signature_statuses([signature], options)
|
14
|
+
signature_status["value"].first
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_signatures_for_address(address, options = {})
|
18
|
+
params = [address, options]
|
19
|
+
signature_request("getSignaturesForAddress", params)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def signature_request(method, params)
|
25
|
+
signatures_info = request(method, params)
|
26
|
+
signatures_info["result"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolanaRuby
|
4
|
+
module HttpMethods
|
5
|
+
# Slot Related HTTP Methods
|
6
|
+
module SlotMethods
|
7
|
+
def get_slot
|
8
|
+
slot_info = request("getSlot")
|
9
|
+
slot_info["result"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_slot_leader(options = {})
|
13
|
+
slot_leader = request("getSlotLeader", [options])
|
14
|
+
slot_leader["result"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_slot_leaders(start_slot, limit)
|
18
|
+
params = [start_slot, limit]
|
19
|
+
slot_leaders = request("getSlotLeaders", params)
|
20
|
+
slot_leaders["result"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_highest_snapshot_slot
|
24
|
+
slot_leaders = request("getHighestSnapshotSlot")
|
25
|
+
slot_leaders["result"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_minimum_ledger_slot
|
29
|
+
minimum_ladger_slot = request("minimumLedgerSlot")
|
30
|
+
minimum_ladger_slot["result"]
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_max_retransmit_slot
|
34
|
+
max_retransmit_slot = request("getMaxRetransmitSlot")
|
35
|
+
max_retransmit_slot["result"]
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_max_shred_insert_slot
|
39
|
+
max_shred_insert_slot = request("getMaxShredInsertSlot")
|
40
|
+
max_shred_insert_slot["result"]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolanaRuby
|
4
|
+
module HttpMethods
|
5
|
+
# Token Related HTTP Methods
|
6
|
+
module TokenMethods
|
7
|
+
FINALIZED_OPTIONS = { commitment: "finalized" }.freeze
|
8
|
+
|
9
|
+
def get_token_balance(pubkey, options = FINALIZED_OPTIONS)
|
10
|
+
balance_info = request("getTokenAccountBalance", [pubkey, options])
|
11
|
+
balance_info["result"]["value"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_token_supply(pubkey)
|
15
|
+
balance_info = request("getTokenSupply", [pubkey])
|
16
|
+
balance_info["result"]["value"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_token_accounts_by_owner(owner_pubkey, filters = {}, options = {})
|
20
|
+
params = [owner_pubkey, filters, options]
|
21
|
+
response = request("getTokenAccountsByOwner", params)
|
22
|
+
response["result"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_token_largest_accounts(mint_pubkey, options = {})
|
26
|
+
params = [mint_pubkey, options]
|
27
|
+
response = request("getTokenLargestAccounts", params)
|
28
|
+
response["result"]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolanaRuby
|
4
|
+
module HttpMethods
|
5
|
+
# Transaction Related HTTP Methods
|
6
|
+
module TransactionMethods
|
7
|
+
DEFAULT_COMMITMENT = "finalized"
|
8
|
+
TIMEOUT = 60 # seconds
|
9
|
+
RETRY_INTERVAL = 2 # seconds
|
10
|
+
ENCODED_TRANSACTION_OPTIONS = { skipPreflight: false }.freeze
|
11
|
+
FINALIZED_OPTIONS = { commitment: "finalized" }.freeze
|
12
|
+
|
13
|
+
def send_transaction(signed_transaction, options = {})
|
14
|
+
params = [signed_transaction, options]
|
15
|
+
result = request("sendTransaction", params)
|
16
|
+
result["result"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def confirm_transaction(signature, commitment = DEFAULT_COMMITMENT, timeout = TIMEOUT)
|
20
|
+
start_time = Time.now
|
21
|
+
|
22
|
+
loop do
|
23
|
+
# Fetch transaction status
|
24
|
+
options = { searchTransactionHistory: true }
|
25
|
+
status_info = get_signature_status(signature, options)
|
26
|
+
|
27
|
+
# Check if the transaction is confirmed based on the commitment level
|
28
|
+
if status_info && (status_info["confirmationStatus"] == commitment || status_info["confirmationStatus"] == "confirmed")
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
|
32
|
+
# Break the loop if timeout is reached
|
33
|
+
if Time.now - start_time > timeout
|
34
|
+
raise "Transaction #{signature} was not confirmed within #{timeout} seconds."
|
35
|
+
end
|
36
|
+
|
37
|
+
sleep(RETRY_INTERVAL)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_transaction(signature, options = {})
|
42
|
+
params = [signature, options]
|
43
|
+
response = request("getTransaction", params)
|
44
|
+
response["result"]
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_transaction_count(options = FINALIZED_OPTIONS)
|
48
|
+
result = request("getTransactionCount", [options])
|
49
|
+
result["result"]
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_transactions(signatures, options = FINALIZED_OPTIONS)
|
53
|
+
transactions = []
|
54
|
+
signatures.each do |signature|
|
55
|
+
transaction = get_transaction(signature, options)
|
56
|
+
transactions << transaction
|
57
|
+
end
|
58
|
+
transactions
|
59
|
+
end
|
60
|
+
|
61
|
+
def request_airdrop(pubkey, lamports, options = FINALIZED_OPTIONS)
|
62
|
+
params = [pubkey, lamports, options]
|
63
|
+
response = request("requestAirdrop", params)
|
64
|
+
response["result"]
|
65
|
+
end
|
66
|
+
|
67
|
+
def simulate_transaction(transaction, options = { encoding: "base64" })
|
68
|
+
params = [transaction, options]
|
69
|
+
response = request("simulateTransaction", params)
|
70
|
+
response["result"]
|
71
|
+
end
|
72
|
+
|
73
|
+
def send_encoded_transaction(encoded_transaction, options = ENCODED_TRANSACTION_OPTIONS.merge(FINALIZED_OPTIONS))
|
74
|
+
send_transaction(encoded_transaction, options)
|
75
|
+
end
|
76
|
+
|
77
|
+
def send_raw_transaction(raw_transaction, options = ENCODED_TRANSACTION_OPTIONS.merge(FINALIZED_OPTIONS))
|
78
|
+
# Convert the raw hexadecimal transaction to base64 encoding
|
79
|
+
base64_encoded_transaction = Base64.encode64(raw_transaction)
|
80
|
+
|
81
|
+
send_transaction(base64_encoded_transaction, options)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|