solace 0.0.7 → 0.0.8
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 +4 -4
- data/CHANGELOG +16 -0
- data/lib/solace/composers/associated_token_account_program_create_account_composer.rb +7 -7
- data/lib/solace/composers/spl_token_program_transfer_checked_composer.rb +5 -5
- data/lib/solace/composers/system_program_transfer_composer.rb +3 -3
- data/lib/solace/connection.rb +93 -94
- data/lib/solace/constants.rb +63 -5
- data/lib/solace/errors/confirmation_timeout.rb +36 -0
- data/lib/solace/errors/http_error.rb +43 -0
- data/lib/solace/errors/parse_error.rb +26 -0
- data/lib/solace/errors/rpc_error.rb +37 -0
- data/lib/solace/errors.rb +17 -0
- data/lib/solace/keypair.rb +20 -2
- data/lib/solace/programs/associated_token_account.rb +5 -5
- data/lib/solace/programs/spl_token.rb +15 -15
- data/lib/solace/public_key.rb +7 -6
- data/lib/solace/transaction_composer.rb +2 -2
- data/lib/solace/utils/rpc_client.rb +134 -0
- data/lib/solace/version.rb +1 -1
- data/lib/solace.rb +1 -0
- metadata +7 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18749af83cf5133c767914f6321a473a710caa5b5c3c613529af9547d6fcd079
|
4
|
+
data.tar.gz: df4de15d443d6033ea92998f7af6450a0bbeae62b5eb389d86fa6ff839ee6f16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e0aad6a855c4721363f353deeb46ecb68429995db8366f1f475ac98b25fe4caa2616b26f584316e0511e3f8ffb8e0fe7a22d97fea92e1904c6e70834d750477
|
7
|
+
data.tar.gz: 47b02239af795269f2e287fe598961b265283a303ac4c37fff0f4f29b6758a60511794dd85a85809edd390580b0aee9590c49a3420c1e0b2610bed4903d05017
|
data/CHANGELOG
CHANGED
@@ -16,6 +16,22 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|
16
16
|
### Fixed
|
17
17
|
```
|
18
18
|
|
19
|
+
## [0.0.8] - 2025-08-11
|
20
|
+
|
21
|
+
### Added
|
22
|
+
1. Added `load` method to `Solace::Constants` to load constants from a YAML file. This method allows for loading constants from a YAML file (i.e. custom program addresses and mint accounts).
|
23
|
+
2. Added `to_s` and `address` method to `Solace::Keypair` and `Solace::PublicKey` to return the public key as a Base58 string.
|
24
|
+
3. Added `get_signature_status` and `get_signature_statuses` to `Solace::Connection`.
|
25
|
+
4. Added `RPCClient` to `Solace::Utils` to handle HTTP requests to a Solana RPC node.
|
26
|
+
5. Added `Errors` module to `Solace::Utils` to handle errors from the HTTP requests made to the Solana RPC node.
|
27
|
+
|
28
|
+
### Changed
|
29
|
+
1. All methods that take a `Solace::Keypair` or `Solace::Pubkey` where an address is needed now also accept a plain string address. This prevents the need of creating instances of the classes when all that is needed is the address. This is with the exception of the low-level instruction builders, which only expect the correct data and indicies with no required casting.
|
30
|
+
2. Changed `wait_for_confirmed_signature` method to accept a `timeout`, `interval`, and `commitment` keyword arguments (breaking change on commitment).
|
31
|
+
|
32
|
+
### Fixed
|
33
|
+
1. Fixed `get_or_create_address` method in `Solace::Programs::AssociatedTokenAccount` to return the address of the associated token account if it already exists by checking if there is any data at the address.
|
34
|
+
|
19
35
|
## [0.0.7] - 2025-08-09
|
20
36
|
|
21
37
|
### Added
|
@@ -32,49 +32,49 @@ module Solace
|
|
32
32
|
#
|
33
33
|
# @return [String] The owner address
|
34
34
|
def owner
|
35
|
-
params[:owner].
|
35
|
+
params[:owner].to_s
|
36
36
|
end
|
37
37
|
|
38
38
|
# Extracts the mint address from the params
|
39
39
|
#
|
40
40
|
# @return [String] The mint address
|
41
41
|
def mint
|
42
|
-
params[:mint].
|
42
|
+
params[:mint].to_s
|
43
43
|
end
|
44
44
|
|
45
45
|
# Extracts the ata_address from the params
|
46
46
|
#
|
47
47
|
# @return [String] The ata_address
|
48
48
|
def ata_address
|
49
|
-
params[:ata_address].
|
49
|
+
params[:ata_address].to_s
|
50
50
|
end
|
51
51
|
|
52
52
|
# Extracts the funder address from the params
|
53
53
|
#
|
54
54
|
# @return [String] The funder address
|
55
55
|
def funder
|
56
|
-
params[:funder].
|
56
|
+
params[:funder].to_s
|
57
57
|
end
|
58
58
|
|
59
59
|
# Extracts the system program id from the constants
|
60
60
|
#
|
61
61
|
# @return [String] The system program id
|
62
62
|
def system_program_id
|
63
|
-
Constants::SYSTEM_PROGRAM_ID
|
63
|
+
Constants::SYSTEM_PROGRAM_ID.to_s
|
64
64
|
end
|
65
65
|
|
66
66
|
# Extracts the token program id from the constants
|
67
67
|
#
|
68
68
|
# @return [String] The token program id
|
69
69
|
def token_program_id
|
70
|
-
Constants::TOKEN_PROGRAM_ID
|
70
|
+
Constants::TOKEN_PROGRAM_ID.to_s
|
71
71
|
end
|
72
72
|
|
73
73
|
# Extracts the associated token account program id from the constants
|
74
74
|
#
|
75
75
|
# @return [String] The associated token account program id
|
76
76
|
def associated_token_account_program_id
|
77
|
-
Constants::ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID
|
77
|
+
Constants::ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID.to_s
|
78
78
|
end
|
79
79
|
|
80
80
|
# Setup accounts required for associated token account program create account instruction
|
@@ -34,14 +34,14 @@ module Solace
|
|
34
34
|
#
|
35
35
|
# @return [String] The to address
|
36
36
|
def to
|
37
|
-
params[:to].
|
37
|
+
params[:to].to_s
|
38
38
|
end
|
39
39
|
|
40
40
|
# Extracts the from address from the params
|
41
41
|
#
|
42
42
|
# @return [String] The from address
|
43
43
|
def from
|
44
|
-
params[:from].
|
44
|
+
params[:from].to_s
|
45
45
|
end
|
46
46
|
|
47
47
|
# Extracts the authority address from the params
|
@@ -50,21 +50,21 @@ module Solace
|
|
50
50
|
#
|
51
51
|
# @return [String] The authority address
|
52
52
|
def authority
|
53
|
-
params[:authority].
|
53
|
+
params[:authority].to_s
|
54
54
|
end
|
55
55
|
|
56
56
|
# Extracts the mint address from the params
|
57
57
|
#
|
58
58
|
# @return [String] The mint address
|
59
59
|
def mint
|
60
|
-
params[:mint].
|
60
|
+
params[:mint].to_s
|
61
61
|
end
|
62
62
|
|
63
63
|
# Returns the spl token program id
|
64
64
|
#
|
65
65
|
# @return [String] The spl token program id
|
66
66
|
def spl_token_program
|
67
|
-
Constants::TOKEN_PROGRAM_ID
|
67
|
+
Constants::TOKEN_PROGRAM_ID.to_s
|
68
68
|
end
|
69
69
|
|
70
70
|
# Returns the lamports to transfer
|
@@ -29,21 +29,21 @@ module Solace
|
|
29
29
|
#
|
30
30
|
# @return [String] The to address
|
31
31
|
def to
|
32
|
-
params[:to].
|
32
|
+
params[:to].to_s
|
33
33
|
end
|
34
34
|
|
35
35
|
# Extracts the from address from the params
|
36
36
|
#
|
37
37
|
# @return [String] The from address
|
38
38
|
def from
|
39
|
-
params[:from].
|
39
|
+
params[:from].to_s
|
40
40
|
end
|
41
41
|
|
42
42
|
# Returns the system program id
|
43
43
|
#
|
44
44
|
# @return [String] The system program id
|
45
45
|
def system_program
|
46
|
-
Solace::Constants::SYSTEM_PROGRAM_ID
|
46
|
+
Solace::Constants::SYSTEM_PROGRAM_ID.to_s
|
47
47
|
end
|
48
48
|
|
49
49
|
# Returns the lamports to transfer
|
data/lib/solace/connection.rb
CHANGED
@@ -4,6 +4,9 @@ require 'net/http'
|
|
4
4
|
require 'json'
|
5
5
|
require 'uri'
|
6
6
|
|
7
|
+
require 'solace/errors'
|
8
|
+
require 'solace/utils/rpc_client'
|
9
|
+
|
7
10
|
module Solace
|
8
11
|
# Connection to a Solana RPC node
|
9
12
|
#
|
@@ -23,13 +26,17 @@ module Solace
|
|
23
26
|
# # Wait for the transaction to be finalized
|
24
27
|
# connection.wait_for_confirmed_signature('finalized') { result['result'] }
|
25
28
|
#
|
29
|
+
# @raise [
|
30
|
+
# Solace::Errors::HTTPError,
|
31
|
+
# Solace::Errors::ParseError,
|
32
|
+
# Solace::Errors::RPCError,
|
33
|
+
# Solace::Errors::ConfirmationTimeout
|
34
|
+
# ]
|
26
35
|
# @since 0.0.1
|
27
|
-
#
|
28
|
-
# rubocop:disable Metrics/ClassLength
|
29
36
|
class Connection
|
30
37
|
# @!attribute [r] rpc_url
|
31
38
|
# The URL of the Solana RPC node
|
32
|
-
attr_reader :
|
39
|
+
attr_reader :rpc_client
|
33
40
|
|
34
41
|
# @!attribute [r] default_options
|
35
42
|
# The default options for RPC requests
|
@@ -40,11 +47,22 @@ module Solace
|
|
40
47
|
# @param rpc_url [String] The URL of the Solana RPC node
|
41
48
|
# @param commitment [String] The commitment level for RPC requests
|
42
49
|
# @return [Solace::Connection] The connection object
|
43
|
-
|
44
|
-
|
45
|
-
|
50
|
+
# @param [Integer] http_open_timeout The timeout for opening an HTTP connection
|
51
|
+
# @param [Integer] http_read_timeout The timeout for reading an HTTP response
|
52
|
+
def initialize(
|
53
|
+
rpc_url = 'http://localhost:8899',
|
54
|
+
commitment: 'confirmed',
|
55
|
+
http_open_timeout: 30,
|
56
|
+
http_read_timeout: 60
|
57
|
+
)
|
58
|
+
# Initialize the RPC client
|
59
|
+
@rpc_client = Utils::RPCClient.new(
|
60
|
+
rpc_url,
|
61
|
+
open_timeout: http_open_timeout,
|
62
|
+
read_timeout: http_read_timeout
|
63
|
+
)
|
46
64
|
|
47
|
-
# Set default options
|
65
|
+
# Set default options for rpc requests
|
48
66
|
@default_options = {
|
49
67
|
commitment: commitment,
|
50
68
|
encoding: 'base64'
|
@@ -56,7 +74,12 @@ module Solace
|
|
56
74
|
# @param method [String] the JSON-RPC method name
|
57
75
|
# @param params [Array] the parameters for the RPC method
|
58
76
|
# @return [Hash] the parsed JSON response
|
59
|
-
# @raise [
|
77
|
+
# @raise [
|
78
|
+
# Solace::Errors::HTTPError,
|
79
|
+
# Solace::Errors::ParseError,
|
80
|
+
# Solace::Errors::RPCError,
|
81
|
+
# Solace::Errors::ConfirmationTimeout
|
82
|
+
# ]
|
60
83
|
def rpc_request(method, params = [])
|
61
84
|
request = build_rpc_request(method, params)
|
62
85
|
response = perform_http_request(request)
|
@@ -70,7 +93,7 @@ module Solace
|
|
70
93
|
# @param [Hash{Symbol => Object}] options The options for the request
|
71
94
|
# @return [String] The transaction signature of the airdrop
|
72
95
|
def request_airdrop(pubkey, lamports, options = {})
|
73
|
-
rpc_request(
|
96
|
+
@rpc_client.rpc_request(
|
74
97
|
'requestAirdrop',
|
75
98
|
[
|
76
99
|
pubkey,
|
@@ -84,7 +107,7 @@ module Solace
|
|
84
107
|
#
|
85
108
|
# @return [String] The latest blockhash
|
86
109
|
def get_latest_blockhash
|
87
|
-
rpc_request('getLatestBlockhash')
|
110
|
+
@rpc_client.rpc_request('getLatestBlockhash').dig('result', 'value', 'blockhash')
|
88
111
|
end
|
89
112
|
|
90
113
|
# Get the minimum required lamports for rent exemption
|
@@ -92,7 +115,7 @@ module Solace
|
|
92
115
|
# @param space [Integer] Number of bytes to allocate for the account
|
93
116
|
# @return [Integer] The minimum required lamports
|
94
117
|
def get_minimum_lamports_for_rent_exemption(space)
|
95
|
-
rpc_request('getMinimumBalanceForRentExemption', [space])['result']
|
118
|
+
@rpc_client.rpc_request('getMinimumBalanceForRentExemption', [space])['result']
|
96
119
|
end
|
97
120
|
|
98
121
|
# Get the account information from the Solana node
|
@@ -100,17 +123,7 @@ module Solace
|
|
100
123
|
# @param pubkey [String] The public key of the account
|
101
124
|
# @return [Object] The account information
|
102
125
|
def get_account_info(pubkey)
|
103
|
-
|
104
|
-
'getAccountInfo',
|
105
|
-
[
|
106
|
-
pubkey,
|
107
|
-
default_options
|
108
|
-
]
|
109
|
-
)['result']
|
110
|
-
|
111
|
-
return if response.nil?
|
112
|
-
|
113
|
-
response['value']
|
126
|
+
@rpc_client.rpc_request('getAccountInfo', [pubkey, default_options]).dig('result', 'value')
|
114
127
|
end
|
115
128
|
|
116
129
|
# Get the balance of a specific account
|
@@ -118,13 +131,7 @@ module Solace
|
|
118
131
|
# @param pubkey [String] The public key of the account
|
119
132
|
# @return [Integer] The balance of the account
|
120
133
|
def get_balance(pubkey)
|
121
|
-
rpc_request(
|
122
|
-
'getBalance',
|
123
|
-
[
|
124
|
-
pubkey,
|
125
|
-
default_options
|
126
|
-
]
|
127
|
-
)['result']['value']
|
134
|
+
@rpc_client.rpc_request('getBalance', [pubkey, default_options]).dig('result', 'value')
|
128
135
|
end
|
129
136
|
|
130
137
|
# Get the balance of a token account
|
@@ -132,13 +139,7 @@ module Solace
|
|
132
139
|
# @param token_account [String] The public key of the token account
|
133
140
|
# @return [Hash] Token account balance information with amount and decimals
|
134
141
|
def get_token_account_balance(token_account)
|
135
|
-
rpc_request(
|
136
|
-
'getTokenAccountBalance',
|
137
|
-
[
|
138
|
-
token_account,
|
139
|
-
default_options
|
140
|
-
]
|
141
|
-
)['result']['value']
|
142
|
+
@rpc_client.rpc_request('getTokenAccountBalance', [token_account, default_options]).dig('result', 'value')
|
142
143
|
end
|
143
144
|
|
144
145
|
# Get the transaction by signature
|
@@ -147,27 +148,24 @@ module Solace
|
|
147
148
|
# @return [Solace::Transaction] The transaction object
|
148
149
|
# @param [Hash{Symbol => Object}] options
|
149
150
|
def get_transaction(signature, options = { maxSupportedTransactionVersion: 0 })
|
150
|
-
rpc_request(
|
151
|
-
'getTransaction',
|
152
|
-
[
|
153
|
-
signature,
|
154
|
-
default_options.merge(options)
|
155
|
-
]
|
156
|
-
)['result']
|
151
|
+
@rpc_client.rpc_request('getTransaction', [signature, default_options.merge(options)])['result']
|
157
152
|
end
|
158
153
|
|
159
154
|
# Get the signature status
|
160
155
|
#
|
161
156
|
# @param signatures [Array] The signatures of the transactions
|
162
157
|
# @return [Object] The signature status
|
163
|
-
def
|
164
|
-
rpc_request(
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
158
|
+
def get_signature_statuses(signatures)
|
159
|
+
@rpc_client.rpc_request('getSignatureStatuses',
|
160
|
+
[signatures, default_options.merge({ 'searchTransactionHistory' => true })])['result']
|
161
|
+
end
|
162
|
+
|
163
|
+
# Get the signature status
|
164
|
+
#
|
165
|
+
# @param signature [String] The signature of the transaction
|
166
|
+
# @return [Object] The signature status
|
167
|
+
def get_signature_status(signature)
|
168
|
+
get_signature_statuses([signature])
|
171
169
|
end
|
172
170
|
|
173
171
|
# Send a transaction to the Solana node
|
@@ -176,69 +174,70 @@ module Solace
|
|
176
174
|
# @return [String] The signature of the transaction
|
177
175
|
# @param [Hash{Symbol => Object}] options
|
178
176
|
def send_transaction(transaction, options = {})
|
179
|
-
rpc_request(
|
180
|
-
'sendTransaction',
|
181
|
-
[
|
182
|
-
transaction,
|
183
|
-
default_options.merge(options)
|
184
|
-
]
|
185
|
-
)
|
177
|
+
@rpc_client.rpc_request('sendTransaction', [transaction, default_options.merge(options)])
|
186
178
|
end
|
187
179
|
|
188
|
-
# Wait
|
180
|
+
# Wait until the yielded signature reaches the desired commitment or timeout.
|
189
181
|
#
|
190
|
-
# @param commitment [String]
|
191
|
-
# @
|
192
|
-
|
182
|
+
# @param commitment [String] One of "processed", "confirmed", "finalized"
|
183
|
+
# @param timeout [Numeric] seconds to wait before raising
|
184
|
+
# @param interval [Numeric] polling interval in seconds
|
185
|
+
# @yieldreturn [String, Hash] a signature string or a JSON-RPC hash with "result"
|
186
|
+
# @return [String] the signature when the commitment is reached
|
187
|
+
# @raise [ArgumentError, Errors::ConfirmationTimeout]
|
188
|
+
def wait_for_confirmed_signature(
|
189
|
+
commitment = 'confirmed',
|
190
|
+
timeout: 60,
|
191
|
+
interval: 0.1
|
192
|
+
)
|
193
193
|
raise ArgumentError, 'Block required' unless block_given?
|
194
194
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
interval = 0.1
|
195
|
+
signature = extract_signature_from(yield)
|
196
|
+
deadline = monotonic_deadline(timeout)
|
199
197
|
|
200
198
|
# Wait for confirmation
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
break if status && status['confirmationStatus'] == commitment
|
199
|
+
until dealine_passed?(deadline)
|
200
|
+
return signature if commitment_reached?(signature, commitment)
|
205
201
|
|
206
202
|
sleep interval
|
207
203
|
end
|
208
204
|
|
209
|
-
signature
|
205
|
+
raise Errors::ConfirmationTimeout.format(signature, commitment, timeout)
|
210
206
|
end
|
211
207
|
|
212
208
|
private
|
213
209
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
req.body = {
|
222
|
-
jsonrpc: '2.0',
|
223
|
-
id: @request_id,
|
224
|
-
method: method,
|
225
|
-
params: params
|
226
|
-
}.to_json
|
227
|
-
|
228
|
-
[uri, req]
|
210
|
+
# Confirms the commitment is reached
|
211
|
+
#
|
212
|
+
# @param signature [String] The signature of the transaction
|
213
|
+
# @param commitment [String] The commitment level not reached
|
214
|
+
# @return [Boolean] Whether the commitment is reached
|
215
|
+
def commitment_reached?(signature, commitment)
|
216
|
+
get_signature_status(signature).dig('value', 0, 'confirmationStatus') == commitment
|
229
217
|
end
|
230
218
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
219
|
+
# Extracts signature from given value
|
220
|
+
#
|
221
|
+
# @param value [String, Object] The result of the yielded block
|
222
|
+
# @return [String] The signature
|
223
|
+
def extract_signature_from(value)
|
224
|
+
value.is_a?(String) ? value : value['result']
|
235
225
|
end
|
236
226
|
|
237
|
-
|
238
|
-
|
227
|
+
# Checks if a timeout deadline has been reached
|
228
|
+
#
|
229
|
+
# @params deadline [Integer] The deadline for the timeout
|
230
|
+
# @return [boolean] whether the dealine has passed
|
231
|
+
def dealine_passed?(deadline)
|
232
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline
|
233
|
+
end
|
239
234
|
|
240
|
-
|
235
|
+
# Sets a deadline given a timeout in seconds
|
236
|
+
#
|
237
|
+
# @params seconds [Integer] The seconds for the deadline
|
238
|
+
# @return [Integer] The deadline in seconds
|
239
|
+
def monotonic_deadline(seconds)
|
240
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) + seconds
|
241
241
|
end
|
242
242
|
end
|
243
|
-
# rubocop:enable Metrics/ClassLength
|
244
243
|
end
|
data/lib/solace/constants.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Constants module
|
4
|
-
#
|
5
|
-
# Contains constants used across the library.
|
6
|
-
#
|
7
|
-
# @return [Module] Constants module
|
8
3
|
module Solace
|
4
|
+
# Constants module
|
5
|
+
#
|
6
|
+
# Contains constants used across the library.
|
7
|
+
#
|
8
|
+
# @return [Module] Constants module
|
9
9
|
module Constants
|
10
10
|
# @!attribute SYSTEM_PROGRAM_ID
|
11
11
|
# The public key of the System Program (native SOL transfers, account creation, etc)
|
@@ -41,5 +41,63 @@ module Solace
|
|
41
41
|
# The public key of the Address Lookup Table Program
|
42
42
|
# This is the same across all Solana clusters
|
43
43
|
ADDRESS_LOOKUP_TABLE_PROGRAM_ID = 'AddressLookupTab1e1111111111111111111111111'
|
44
|
+
|
45
|
+
# Loads the constants declared in a YAML file
|
46
|
+
#
|
47
|
+
# Developers require adding program addresses and mint accounts that will not
|
48
|
+
# be added directly to Solace. This method allows for loading those constants
|
49
|
+
# from a YAML file and extends the Constants module with them.
|
50
|
+
#
|
51
|
+
# The YAML file should be a hash of key-value pairs, where the key is the constant
|
52
|
+
# name and the value is the constant value.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# # constants.yml
|
56
|
+
# devnet:
|
57
|
+
# my_program_id: some_devnet_program_id
|
58
|
+
# squads_program_id: some_devnet_program_id
|
59
|
+
# usdc_mint_account: some_devnet_program_id
|
60
|
+
# usdt_mint_account: some_devnet_program_id
|
61
|
+
#
|
62
|
+
# mainnet:
|
63
|
+
# my_program_id: some_mainnet_program_id
|
64
|
+
# squads_program_id: some_mainnet_program_id
|
65
|
+
# usdc_mint_account: some_mainnet_program_id
|
66
|
+
# usdt_mint_account: some_mainnet_program_id
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# Solace::Constants.load(
|
70
|
+
# path: '/home/user/my-project/config/constants.yml',
|
71
|
+
# namespace: 'devnet',
|
72
|
+
# protect_overrides: false
|
73
|
+
# )
|
74
|
+
#
|
75
|
+
# Solace::Constants::MY_PROGRAM_ID
|
76
|
+
# Solace::Constants::SQUADS_PROGRAM_ID
|
77
|
+
# Solace::Constants::USDC_MINT_ACCOUNT
|
78
|
+
# Solace::Constants::USDT_MINT_ACCOUNT
|
79
|
+
#
|
80
|
+
# @param path [String] The path to the YAML file
|
81
|
+
# @param namespace [String] The namespace to load the constants from
|
82
|
+
# @param protect_overrides [Boolean] Whether to protect constants that are already defined
|
83
|
+
# @return [void]
|
84
|
+
# @raise [ArgumentError] If protect_overrides is on and a constant is already defined
|
85
|
+
def self.load(
|
86
|
+
path:,
|
87
|
+
namespace: 'default',
|
88
|
+
protect_overrides: true
|
89
|
+
)
|
90
|
+
content = YAML.load_file(path)
|
91
|
+
|
92
|
+
content[namespace].each do |key, value|
|
93
|
+
if const_defined?(key.upcase)
|
94
|
+
raise ArgumentError, "Constant #{key} is already defined" if protect_overrides
|
95
|
+
|
96
|
+
remove_const(key.upcase)
|
97
|
+
end
|
98
|
+
|
99
|
+
const_set(key.upcase, value)
|
100
|
+
end
|
101
|
+
end
|
44
102
|
end
|
45
103
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solace
|
4
|
+
module Errors
|
5
|
+
# Waiting for confirmation exceeded timeout
|
6
|
+
class ConfirmationTimeout < StandardError
|
7
|
+
attr_reader :signature, :commitment, :timeout
|
8
|
+
|
9
|
+
# @param [String] message The error message
|
10
|
+
# @param [String] signature The signature of the transaction
|
11
|
+
# @param [String] commitment The commitment level not reached
|
12
|
+
# @param [Integer] timeout The time out reached
|
13
|
+
def initialize(message, signature:, commitment:, timeout:)
|
14
|
+
super(message)
|
15
|
+
@signature = signature
|
16
|
+
@commitment = commitment
|
17
|
+
@timeout = timeout
|
18
|
+
end
|
19
|
+
|
20
|
+
# Formats a confirmation timeout error
|
21
|
+
#
|
22
|
+
# @params [String] signature The signature of the transaction
|
23
|
+
# @params [String] commitment The commitment level not reached
|
24
|
+
# @params [Integer] timeout The time out reached
|
25
|
+
# @return [Solace::Errors::ConfirmationTimeout] The formatted error
|
26
|
+
def self.format(signature, commitment, timeout)
|
27
|
+
new(
|
28
|
+
"Timed out waiting for signature #{signature} at commitment=#{commitment} after #{timeout}s",
|
29
|
+
signature: signature,
|
30
|
+
commitment: commitment,
|
31
|
+
timeout: timeout
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solace
|
4
|
+
module Errors
|
5
|
+
# Non-2xx HTTP or low-level network issues
|
6
|
+
class HTTPError < StandardError
|
7
|
+
attr_reader :code, :body
|
8
|
+
|
9
|
+
# @param [String] message The error message
|
10
|
+
# @param [Integer] code The HTTP status code
|
11
|
+
# @param [String] body The HTTP response body
|
12
|
+
def initialize(message, code:, body: nil)
|
13
|
+
super(message)
|
14
|
+
@code = code
|
15
|
+
@body = body
|
16
|
+
end
|
17
|
+
|
18
|
+
# Formats a response to an error
|
19
|
+
#
|
20
|
+
# @param response [Net::HTTPResponse] The HTTP response
|
21
|
+
# @return [Solace::Errors::HTTPError] The formatted error
|
22
|
+
def self.format_response(response)
|
23
|
+
new("HTTP error: #{response.message}", code: response.code.to_i, body: response.body)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Formats transport errors
|
27
|
+
#
|
28
|
+
# @param error [SocketError, IOError] The transport error
|
29
|
+
# @return [Solace::Errors::HTTPError] The formatted error
|
30
|
+
def self.format_transport_error(error)
|
31
|
+
new("HTTP transport error: #{error.message}", code: 0)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Formats timeout errors
|
35
|
+
#
|
36
|
+
# @param error [Net::OpenTimeout, Net::ReadTimeout] The timeout error
|
37
|
+
# @return [Solace::Errors::HTTPError] The formatted error
|
38
|
+
def self.format_timeout_error(error)
|
39
|
+
new("HTTP timeout: #{error.class}", code: 408)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solace
|
4
|
+
module Errors
|
5
|
+
# JSON parsing failed
|
6
|
+
class ParseError < StandardError
|
7
|
+
attr_reader :body
|
8
|
+
|
9
|
+
# @param [String] message The error message
|
10
|
+
# @param [Object] body The response body
|
11
|
+
def initialize(message, body:)
|
12
|
+
super(message)
|
13
|
+
@body = body
|
14
|
+
end
|
15
|
+
|
16
|
+
# Formats a response to an error
|
17
|
+
#
|
18
|
+
# @param error [JSON::ParserError] The JSON-RPC error
|
19
|
+
# @param [Object] response The response from the RPC
|
20
|
+
# @return [Solace::Errors::ParseError] The formatted error
|
21
|
+
def self.format_response(error, response)
|
22
|
+
new("Invalid JSON from RPC: #{error.message}", body: response.body)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solace
|
4
|
+
module Errors
|
5
|
+
# JSON-RPC returned an "error" object
|
6
|
+
class RPCError < StandardError
|
7
|
+
attr_reader :rpc_code, :rpc_message, :rpc_data
|
8
|
+
|
9
|
+
# @param [String] message The error message
|
10
|
+
# @param [Integer] rpc_code The JSON-RPC error code
|
11
|
+
# @param [String] rpc_message The JSON-RPC error message
|
12
|
+
# @param [Object] rpc_data The JSON-RPC error data
|
13
|
+
def initialize(message, rpc_code:, rpc_message:, rpc_data: nil)
|
14
|
+
super(message)
|
15
|
+
@rpc_code = rpc_code
|
16
|
+
@rpc_message = rpc_message
|
17
|
+
@rpc_data = rpc_data
|
18
|
+
end
|
19
|
+
|
20
|
+
# Formats a response to an error
|
21
|
+
#
|
22
|
+
# @param response [Hash] The JSON-RPC response
|
23
|
+
# @return [Solace::Errors::RPCError] The formatted error
|
24
|
+
def self.format_response(response)
|
25
|
+
new(
|
26
|
+
"RPC error #{response['error']['code']}: #{response['error']['message']}",
|
27
|
+
rpc_data: response['error']['data'],
|
28
|
+
rpc_code: response['error']['code'],
|
29
|
+
rpc_message: response['error']['message']
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Hash] The error as a hash
|
34
|
+
def to_h = { code: rpc_code, message: rpc_message, data: rpc_data }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solace
|
4
|
+
# Error handling module
|
5
|
+
#
|
6
|
+
# This module provides error classes for handling different types of errors that may occur during
|
7
|
+
# Solana RPC requests and processing transactions.
|
8
|
+
#
|
9
|
+
# @since 0.0.8
|
10
|
+
module Errors
|
11
|
+
# JSON-RPC Errors
|
12
|
+
require 'solace/errors/rpc_error'
|
13
|
+
require 'solace/errors/http_error'
|
14
|
+
require 'solace/errors/parse_error'
|
15
|
+
require 'solace/errors/confirmation_timeout'
|
16
|
+
end
|
17
|
+
end
|
data/lib/solace/keypair.rb
CHANGED
@@ -132,13 +132,31 @@ module Solace
|
|
132
132
|
# Returns the public key address as a Base58 string
|
133
133
|
#
|
134
134
|
# @example
|
135
|
-
# pubkey_str = instance.
|
135
|
+
# pubkey_str = instance.to_base58
|
136
136
|
#
|
137
137
|
# @return [String] Base58 encoded public key
|
138
|
-
def
|
138
|
+
def to_base58
|
139
139
|
public_key.to_base58
|
140
140
|
end
|
141
141
|
|
142
|
+
# Returns the public key address as a Base58 string
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
# pubkey_str = instance.to_s
|
146
|
+
#
|
147
|
+
# @return [String] Base58 encoded public key
|
148
|
+
# @since 0.0.8
|
149
|
+
alias to_s to_base58
|
150
|
+
|
151
|
+
# Returns the public key address as a Base58 string
|
152
|
+
#
|
153
|
+
# @example
|
154
|
+
# pubkey_str = instance.to_base58
|
155
|
+
#
|
156
|
+
# @return [String] Base58 encoded public key
|
157
|
+
# @since 0.0.8
|
158
|
+
alias address to_base58
|
159
|
+
|
142
160
|
# Signs a message (string or binary)
|
143
161
|
#
|
144
162
|
# @example
|
@@ -33,9 +33,9 @@ module Solace
|
|
33
33
|
def get_address(owner:, mint:)
|
34
34
|
Solace::Utils::PDA.find_program_address(
|
35
35
|
[
|
36
|
-
owner.
|
36
|
+
owner.to_s,
|
37
37
|
Solace::Constants::TOKEN_PROGRAM_ID,
|
38
|
-
mint.
|
38
|
+
mint.to_s
|
39
39
|
],
|
40
40
|
Solace::Constants::ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID
|
41
41
|
)
|
@@ -67,15 +67,15 @@ module Solace
|
|
67
67
|
def get_or_create_address(payer:, owner:, mint:, commitment: 'confirmed')
|
68
68
|
ata_address, _bump = get_address(owner: owner, mint: mint)
|
69
69
|
|
70
|
-
account_balance = @connection.
|
70
|
+
account_balance = @connection.get_account_info(ata_address)
|
71
71
|
|
72
|
-
return ata_address
|
72
|
+
return ata_address unless account_balance.nil?
|
73
73
|
|
74
74
|
response = create_associated_token_account(payer: payer, owner: owner, mint: mint)
|
75
75
|
|
76
76
|
raise 'Failed to create associated token account' unless response['result']
|
77
77
|
|
78
|
-
@connection.wait_for_confirmed_signature(commitment) { response
|
78
|
+
@connection.wait_for_confirmed_signature(commitment) { response }
|
79
79
|
|
80
80
|
ata_address
|
81
81
|
end
|
@@ -63,8 +63,8 @@ module Solace
|
|
63
63
|
mint_keypair: Solace::Keypair.generate
|
64
64
|
)
|
65
65
|
accounts = [
|
66
|
-
payer.
|
67
|
-
mint_keypair.
|
66
|
+
payer.to_s,
|
67
|
+
mint_keypair.to_s,
|
68
68
|
Solace::Constants::SYSVAR_RENT_PROGRAM_ID,
|
69
69
|
Solace::Constants::TOKEN_PROGRAM_ID,
|
70
70
|
Solace::Constants::SYSTEM_PROGRAM_ID
|
@@ -81,15 +81,15 @@ module Solace
|
|
81
81
|
owner: program_id
|
82
82
|
)
|
83
83
|
|
84
|
-
|
84
|
+
freeze_authority = freeze_authority.to_s unless freeze_authority.nil?
|
85
85
|
|
86
86
|
initialize_mint_ix = Solace::Instructions::SplToken::InitializeMintInstruction.build(
|
87
87
|
mint_account_index: 1,
|
88
88
|
rent_sysvar_index: 2,
|
89
89
|
program_index: 3,
|
90
90
|
decimals: decimals,
|
91
|
-
mint_authority: mint_authority.
|
92
|
-
freeze_authority:
|
91
|
+
mint_authority: mint_authority.to_s,
|
92
|
+
freeze_authority: freeze_authority
|
93
93
|
)
|
94
94
|
|
95
95
|
message = Message.new(
|
@@ -134,11 +134,11 @@ module Solace
|
|
134
134
|
mint_authority:
|
135
135
|
)
|
136
136
|
accounts = [
|
137
|
-
payer.
|
138
|
-
mint_authority.
|
139
|
-
mint.
|
140
|
-
destination,
|
141
|
-
Solace::Constants::TOKEN_PROGRAM_ID
|
137
|
+
payer.to_s,
|
138
|
+
mint_authority.to_s,
|
139
|
+
mint.to_s,
|
140
|
+
destination.to_s,
|
141
|
+
Solace::Constants::TOKEN_PROGRAM_ID.to_s
|
142
142
|
]
|
143
143
|
|
144
144
|
ix = Solace::Instructions::SplToken::MintToInstruction.build(
|
@@ -191,11 +191,11 @@ module Solace
|
|
191
191
|
owner:
|
192
192
|
)
|
193
193
|
accounts = [
|
194
|
-
payer.
|
195
|
-
owner.
|
196
|
-
source,
|
197
|
-
destination,
|
198
|
-
Solace::Constants::TOKEN_PROGRAM_ID
|
194
|
+
payer.to_s,
|
195
|
+
owner.to_s,
|
196
|
+
source.to_s,
|
197
|
+
destination.to_s,
|
198
|
+
Solace::Constants::TOKEN_PROGRAM_ID.to_s
|
199
199
|
]
|
200
200
|
|
201
201
|
ix = Solace::Instructions::SplToken::TransferInstruction.build(
|
data/lib/solace/public_key.rb
CHANGED
@@ -51,6 +51,7 @@ module Solace
|
|
51
51
|
# pubkey_str = instance.to_base58
|
52
52
|
#
|
53
53
|
# @return [String]
|
54
|
+
# @since 0.0.1
|
54
55
|
def to_base58
|
55
56
|
Solace::Utils::Codecs.bytes_to_base58(@bytes)
|
56
57
|
end
|
@@ -61,9 +62,8 @@ module Solace
|
|
61
62
|
# pubkey_str = instance.to_s
|
62
63
|
#
|
63
64
|
# @return [String]
|
64
|
-
|
65
|
-
|
66
|
-
end
|
65
|
+
# @since 0.0.8
|
66
|
+
alias to_s to_base58
|
67
67
|
|
68
68
|
# Return the address of the public key
|
69
69
|
#
|
@@ -71,9 +71,8 @@ module Solace
|
|
71
71
|
# pubkey_str = instance.address
|
72
72
|
#
|
73
73
|
# @return [String]
|
74
|
-
|
75
|
-
|
76
|
-
end
|
74
|
+
# @since 0.0.8
|
75
|
+
alias address to_base58
|
77
76
|
|
78
77
|
# Compare two public keys for equality
|
79
78
|
#
|
@@ -82,6 +81,7 @@ module Solace
|
|
82
81
|
#
|
83
82
|
# @param other [PublicKey]
|
84
83
|
# @return [Boolean]
|
84
|
+
# @since 0.0.1
|
85
85
|
def ==(other)
|
86
86
|
other.is_a?(Solace::PublicKey) && other.bytes == bytes
|
87
87
|
end
|
@@ -92,6 +92,7 @@ module Solace
|
|
92
92
|
# pubkey_bytes = instance.to_bytes
|
93
93
|
#
|
94
94
|
# @return [Array<Integer>]
|
95
|
+
# @since 0.0.1
|
95
96
|
def to_bytes
|
96
97
|
@bytes.dup
|
97
98
|
end
|
@@ -38,7 +38,7 @@ module Solace
|
|
38
38
|
# # Sign the transaction with all required signers
|
39
39
|
# tx.sign(*required_signers)
|
40
40
|
#
|
41
|
-
# @since 0.0.
|
41
|
+
# @since 0.0.6
|
42
42
|
class TransactionComposer
|
43
43
|
# @!attribute connection
|
44
44
|
# The connection to the Solana cluster
|
@@ -76,7 +76,7 @@ module Solace
|
|
76
76
|
# @param pubkey [String, Solace::PublicKey, Solace::Keypair] The fee payer pubkey
|
77
77
|
# @return [TransactionComposer] Self for chaining
|
78
78
|
def set_fee_payer(pubkey)
|
79
|
-
context.set_fee_payer(pubkey)
|
79
|
+
context.set_fee_payer(pubkey.to_s)
|
80
80
|
self
|
81
81
|
end
|
82
82
|
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
require 'solace/errors'
|
8
|
+
|
9
|
+
module Solace
|
10
|
+
module Utils
|
11
|
+
# RPCClient provides Net::HTTP based HTTP client for sending HTTP
|
12
|
+
# requests to a Solana RPC node and parsing responses.
|
13
|
+
#
|
14
|
+
# @since 0.0.8
|
15
|
+
class RPCClient
|
16
|
+
# @!attribute [r] url
|
17
|
+
# The URL for the HTTP request
|
18
|
+
attr_reader :url
|
19
|
+
|
20
|
+
# @!attribute [r] open_timeout
|
21
|
+
# The timeout for opening an HTTP connection
|
22
|
+
attr_reader :open_timeout
|
23
|
+
|
24
|
+
# @!attribute [r] read_timeout
|
25
|
+
# The timeout for reading an HTTP response
|
26
|
+
attr_reader :read_timeout
|
27
|
+
|
28
|
+
# Initialize the connection with a default or custom RPC URL
|
29
|
+
#
|
30
|
+
# @param url [String] The URL of the Solana RPC node
|
31
|
+
# @param open_timeout [Integer] The timeout for opening an HTTP connection
|
32
|
+
# @param read_timeout [Integer] The timeout for reading an HTTP response
|
33
|
+
def initialize(
|
34
|
+
url,
|
35
|
+
open_timeout:,
|
36
|
+
read_timeout:
|
37
|
+
)
|
38
|
+
@url = url
|
39
|
+
@open_timeout = open_timeout
|
40
|
+
@read_timeout = read_timeout
|
41
|
+
end
|
42
|
+
|
43
|
+
# Sends a JSON-RPC request to the configured Solana RPC server.
|
44
|
+
#
|
45
|
+
# @param method [String] the JSON-RPC method name
|
46
|
+
# @param params [Array] the parameters for the RPC method
|
47
|
+
# @return [Hash] the parsed JSON response
|
48
|
+
# @raise [
|
49
|
+
# Solace::Errors::HTTPError,
|
50
|
+
# Solace::Errors::ParseError,
|
51
|
+
# Solace::Errors::RPCError,
|
52
|
+
# Solace::Errors::ConfirmationTimeout
|
53
|
+
# ]
|
54
|
+
def rpc_request(method, params = [])
|
55
|
+
request = build_rpc_request(method, params)
|
56
|
+
response = perform_http_request(*request)
|
57
|
+
handle_rpc_response(response)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# Builds a JSON-RPC request
|
63
|
+
#
|
64
|
+
# @param method [String] the JSON-RPC method name
|
65
|
+
# @param params [Array] the parameters for the RPC method
|
66
|
+
# @return [Array] the URI and request object
|
67
|
+
def build_rpc_request(method, params)
|
68
|
+
uri = URI(url)
|
69
|
+
|
70
|
+
req = Net::HTTP::Post.new(uri)
|
71
|
+
req['Accept'] = 'application/json'
|
72
|
+
req['Content-Type'] = 'application/json'
|
73
|
+
req.body = build_request_body(method, params)
|
74
|
+
|
75
|
+
[uri, req]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Builds request body
|
79
|
+
#
|
80
|
+
# @param method [String] the JSON-RPC method name
|
81
|
+
# @param params [Array] the parameters for the RPC method
|
82
|
+
# @return [String] the request body
|
83
|
+
def build_request_body(method, params)
|
84
|
+
{
|
85
|
+
jsonrpc: '2.0',
|
86
|
+
id: SecureRandom.uuid,
|
87
|
+
method: method,
|
88
|
+
params: params
|
89
|
+
}.to_json
|
90
|
+
end
|
91
|
+
|
92
|
+
# Performs an HTTP request to the configured Solana RPC server.
|
93
|
+
#
|
94
|
+
# @param uri [URI] the URI for the HTTP request
|
95
|
+
# @param req [Net::HTTP::Post] the request object
|
96
|
+
# @return [Net::HTTPResponse] the HTTP response
|
97
|
+
# @raise [Solace::Errors::HTTPError]
|
98
|
+
def perform_http_request(uri, req)
|
99
|
+
Net::HTTP.start(
|
100
|
+
uri.hostname,
|
101
|
+
uri.port,
|
102
|
+
use_ssl: uri.scheme == 'https',
|
103
|
+
open_timeout: open_timeout,
|
104
|
+
read_timeout: read_timeout
|
105
|
+
) do |http|
|
106
|
+
http.request(req)
|
107
|
+
end
|
108
|
+
rescue Net::OpenTimeout, Net::ReadTimeout => e
|
109
|
+
raise Errors::HTTPError.format_timeout_error(e)
|
110
|
+
rescue SocketError, IOError => e
|
111
|
+
raise Errors::HTTPError.format_transport_error(e)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Handles the response from the HTTP request
|
115
|
+
#
|
116
|
+
# @param response [Net::HTTPResponse] The HTTP response
|
117
|
+
# @return [Hash] The parsed JSON response
|
118
|
+
# @raise [Solace::Errors::HTTPError]
|
119
|
+
# @raise [Solace::Errors::ParseError]
|
120
|
+
# @raise [Solace::Errors::RPCError]
|
121
|
+
def handle_rpc_response(response)
|
122
|
+
raise Errors::HTTPError.format_response(response) unless response.is_a?(Net::HTTPSuccess)
|
123
|
+
|
124
|
+
json = JSON.parse(response.body)
|
125
|
+
|
126
|
+
raise Errors::RPCError.format_response(json) if json['error']
|
127
|
+
|
128
|
+
json
|
129
|
+
rescue JSON::ParserError => e
|
130
|
+
raise Errors::ParseError.format_response(e, response)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
data/lib/solace/version.rb
CHANGED
data/lib/solace.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Scholl
|
@@ -100,6 +100,11 @@ files:
|
|
100
100
|
- lib/solace/concerns/binary_serializable.rb
|
101
101
|
- lib/solace/connection.rb
|
102
102
|
- lib/solace/constants.rb
|
103
|
+
- lib/solace/errors.rb
|
104
|
+
- lib/solace/errors/confirmation_timeout.rb
|
105
|
+
- lib/solace/errors/http_error.rb
|
106
|
+
- lib/solace/errors/parse_error.rb
|
107
|
+
- lib/solace/errors/rpc_error.rb
|
103
108
|
- lib/solace/instruction.rb
|
104
109
|
- lib/solace/instructions/associated_token_account/create_associated_token_account_instruction.rb
|
105
110
|
- lib/solace/instructions/spl_token/initialize_account_instruction.rb
|
@@ -134,6 +139,7 @@ files:
|
|
134
139
|
- lib/solace/utils/libcurve25519_dalek-macos/libcurve25519_dalek.dylib
|
135
140
|
- lib/solace/utils/libcurve25519_dalek-windows/curve25519_dalek.dll
|
136
141
|
- lib/solace/utils/pda.rb
|
142
|
+
- lib/solace/utils/rpc_client.rb
|
137
143
|
- lib/solace/version.rb
|
138
144
|
homepage: https://github.com/sebscholl/solace
|
139
145
|
licenses:
|