solana-ruby-web3js 1.0.1.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|