solace 0.0.10 → 0.1.0
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 +104 -23
- data/README.md +10 -8
- data/lib/solace/composers/base.rb +35 -0
- data/lib/solace/composers/spl_token_program_initialize_mint_composer.rb +95 -0
- data/lib/solace/composers/spl_token_program_mint_to_composer.rb +86 -0
- data/lib/solace/composers/spl_token_program_transfer_composer.rb +90 -0
- data/lib/solace/composers/system_program_create_account_composer.rb +98 -0
- data/lib/solace/connection.rb +88 -13
- data/lib/solace/errors/confirmation_timeout.rb +18 -4
- data/lib/solace/errors/http_error.rb +16 -1
- data/lib/solace/errors/parse_error.rb +15 -1
- data/lib/solace/errors/rpc_error.rb +17 -1
- data/lib/solace/errors.rb +8 -3
- data/lib/solace/instructions/associated_token_account/create_associated_token_account_instruction.rb +9 -2
- data/lib/solace/instructions/spl_token/initialize_mint_instruction.rb +0 -1
- data/lib/solace/instructions/spl_token/transfer_instruction.rb +21 -0
- data/lib/solace/instructions/system_program/create_account_instruction.rb +30 -0
- data/lib/solace/instructions/system_program/transfer_instruction.rb +11 -0
- data/lib/solace/programs/associated_token_account.rb +57 -30
- data/lib/solace/programs/base.rb +23 -0
- data/lib/solace/programs/spl_token.rb +197 -125
- data/lib/solace/serializers/base_serializer.rb +29 -1
- data/lib/solace/tokens/token.rb +53 -0
- data/lib/solace/tokens.rb +86 -0
- data/lib/solace/transaction.rb +24 -21
- data/lib/solace/transaction_composer.rb +77 -3
- data/lib/solace/utils/account_context.rb +1 -1
- data/lib/solace/utils/codecs.rb +17 -0
- data/lib/solace/utils/pda.rb +13 -5
- data/lib/solace/version.rb +3 -2
- data/lib/solace.rb +38 -11
- metadata +21 -1
data/lib/solace/connection.rb
CHANGED
@@ -42,6 +42,12 @@ module Solace
|
|
42
42
|
# The default options for RPC requests
|
43
43
|
attr_reader :default_options
|
44
44
|
|
45
|
+
# Last fetched blockhash
|
46
|
+
attr_reader :last_fetched_blockhash
|
47
|
+
|
48
|
+
# Last fetched blockhash timestamp
|
49
|
+
attr_reader :last_fetched_block_height
|
50
|
+
|
45
51
|
# Initialize the connection with a default or custom RPC URL
|
46
52
|
#
|
47
53
|
# @param rpc_url [String] The URL of the Solana RPC node
|
@@ -69,6 +75,27 @@ module Solace
|
|
69
75
|
}
|
70
76
|
end
|
71
77
|
|
78
|
+
# Gets the version of the Solana node
|
79
|
+
#
|
80
|
+
# @return [Hash] The version information
|
81
|
+
def get_version
|
82
|
+
@rpc_client.rpc_request('getVersion')['result']
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get the health status of the Solana node
|
86
|
+
#
|
87
|
+
# @return [String] The health status
|
88
|
+
def get_health
|
89
|
+
@rpc_client.rpc_request('getHealth')['result']
|
90
|
+
end
|
91
|
+
|
92
|
+
# Get the genesis hash of the Solana node
|
93
|
+
#
|
94
|
+
# @return [String] The genesis hash
|
95
|
+
def get_genesis_hash
|
96
|
+
@rpc_client.rpc_request('getGenesisHash')['result']
|
97
|
+
end
|
98
|
+
|
72
99
|
# Request an airdrop of lamports to a given address
|
73
100
|
#
|
74
101
|
# @param pubkey [String] The public key of the account to receive the airdrop
|
@@ -97,12 +124,34 @@ module Solace
|
|
97
124
|
|
98
125
|
# Get the latest blockhash from the Solana node
|
99
126
|
#
|
127
|
+
# Stores the last fetched blockhash and last valid block height in the connection, as
|
128
|
+
# different clients may need to access these values.
|
129
|
+
#
|
130
|
+
# @example
|
131
|
+
# # Initialize the connection
|
132
|
+
# connection = Solace::Connection.new('http://localhost:8899', commitment: 'confirmed')
|
133
|
+
#
|
134
|
+
# # Get the latest blockhash
|
135
|
+
# blockhash, last_valid_block_height = connection.get_latest_blockhash
|
136
|
+
#
|
137
|
+
# puts "Latest blockhash: #{blockhash}"
|
138
|
+
# puts "Last valid block height: #{last_valid_block_height}"
|
139
|
+
#
|
140
|
+
# # Access the last fetched blockhash and height from the connection
|
141
|
+
# puts "Stored blockhash: #{connection.last_fetched_blockhash}"
|
142
|
+
# puts "Stored last valid block height: #{connection.last_fetched_block_height}"
|
143
|
+
#
|
100
144
|
# @return [Array<String, Integer>] The latest blockhash and lastValidBlockHeight
|
101
145
|
def get_latest_blockhash
|
102
|
-
@rpc_client
|
103
|
-
|
104
|
-
|
105
|
-
|
146
|
+
result = @rpc_client
|
147
|
+
.rpc_request('getLatestBlockhash', [build_get_latest_blockhash_options])
|
148
|
+
.dig('result', 'value')
|
149
|
+
|
150
|
+
# Set the last fetched blockhash and last valid block height in the connection
|
151
|
+
@last_fetched_blockhash, @last_fetched_block_height = result.values_at('blockhash', 'lastValidBlockHeight')
|
152
|
+
|
153
|
+
# Return the blockhash and last valid block height
|
154
|
+
[@last_fetched_blockhash, @last_fetched_block_height]
|
106
155
|
end
|
107
156
|
|
108
157
|
# Get the minimum required lamports for rent exemption
|
@@ -121,6 +170,14 @@ module Solace
|
|
121
170
|
@rpc_client.rpc_request('getAccountInfo', [pubkey, default_options]).dig('result', 'value')
|
122
171
|
end
|
123
172
|
|
173
|
+
# Get multiple accounts information from the Solana node
|
174
|
+
#
|
175
|
+
# @param pubkeys [Array<String>] The public keys of the accounts
|
176
|
+
# @return [Array<Object>] The accounts information
|
177
|
+
def get_multiple_accounts(pubkeys)
|
178
|
+
@rpc_client.rpc_request('getMultipleAccounts', [pubkeys, default_options]).dig('result', 'value')
|
179
|
+
end
|
180
|
+
|
124
181
|
# Get the balance of a specific account
|
125
182
|
#
|
126
183
|
# @param pubkey [String] The public key of the account
|
@@ -137,10 +194,19 @@ module Solace
|
|
137
194
|
@rpc_client.rpc_request('getTokenAccountBalance', [token_account, default_options]).dig('result', 'value')
|
138
195
|
end
|
139
196
|
|
197
|
+
# Gets the token accounts by owner
|
198
|
+
#
|
199
|
+
# @param owner [String] The public key of the owner
|
200
|
+
# @return [Array<Hash>] The token accounts owned by the owner for the specified mint
|
201
|
+
def get_token_accounts_by_owner(owner)
|
202
|
+
params = [owner, { programId: Constants::TOKEN_PROGRAM_ID }, default_options]
|
203
|
+
@rpc_client.rpc_request('getTokenAccountsByOwner', params).dig('result', 'value')
|
204
|
+
end
|
205
|
+
|
140
206
|
# Get the transaction by signature
|
141
207
|
#
|
142
208
|
# @param signature [String] The signature of the transaction
|
143
|
-
# @return [
|
209
|
+
# @return [Transaction] The transaction object
|
144
210
|
# @param [Hash{Symbol => Object}] options
|
145
211
|
def get_transaction(signature, options = { maxSupportedTransactionVersion: 0 })
|
146
212
|
@rpc_client.rpc_request('getTransaction', [signature, default_options.merge(options)])['result']
|
@@ -173,9 +239,9 @@ module Solace
|
|
173
239
|
get_signature_statuses([signature])
|
174
240
|
end
|
175
241
|
|
176
|
-
# Builds
|
242
|
+
# Builds send_transaction options
|
177
243
|
#
|
178
|
-
# @
|
244
|
+
# @param overrides[Hash] The overrides for the options
|
179
245
|
# @return [Hash] The options for the send_transaction call
|
180
246
|
def build_send_transaction_options(overrides)
|
181
247
|
{
|
@@ -188,13 +254,22 @@ module Solace
|
|
188
254
|
|
189
255
|
# Send a transaction to the Solana node
|
190
256
|
#
|
191
|
-
# @param transaction [
|
257
|
+
# @param transaction [Transaction] The transaction to send
|
192
258
|
# @param [Hash{Symbol => Object}] overrides
|
193
259
|
# @return [String] The signature of the transaction
|
194
260
|
def send_transaction(transaction, overrides = {})
|
195
261
|
@rpc_client.rpc_request('sendTransaction', [transaction, build_send_transaction_options(overrides)])
|
196
262
|
end
|
197
263
|
|
264
|
+
# Simulate a transaction on the Solana node
|
265
|
+
#
|
266
|
+
# @param transaction [Transaction] The transaction to simulate
|
267
|
+
# @param [Hash{Symbol => Object}] overrides
|
268
|
+
# @return [Object] The result of the simulation
|
269
|
+
def simulate_transaction(transaction, overrides = {})
|
270
|
+
@rpc_client.rpc_request('simulateTransaction', [transaction, build_send_transaction_options(overrides)])
|
271
|
+
end
|
272
|
+
|
198
273
|
# Wait until the yielded signature reaches the desired commitment or timeout.
|
199
274
|
#
|
200
275
|
# @param commitment [String] One of "processed", "confirmed", "finalized"
|
@@ -214,7 +289,7 @@ module Solace
|
|
214
289
|
deadline = monotonic_deadline(timeout)
|
215
290
|
|
216
291
|
# Wait for confirmation
|
217
|
-
until
|
292
|
+
until deadline_passed?(deadline)
|
218
293
|
return signature if commitment_reached?(signature, commitment)
|
219
294
|
|
220
295
|
sleep interval
|
@@ -244,15 +319,15 @@ module Solace
|
|
244
319
|
|
245
320
|
# Checks if a timeout deadline has been reached
|
246
321
|
#
|
247
|
-
# @
|
248
|
-
# @return [
|
249
|
-
def
|
322
|
+
# @param deadline [Integer] The deadline for the timeout
|
323
|
+
# @return [Boolean] whether the deadline has passed
|
324
|
+
def deadline_passed?(deadline)
|
250
325
|
Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline
|
251
326
|
end
|
252
327
|
|
253
328
|
# Sets a deadline given a timeout in seconds
|
254
329
|
#
|
255
|
-
# @
|
330
|
+
# @param seconds [Integer] The seconds for the deadline
|
256
331
|
# @return [Integer] The deadline in seconds
|
257
332
|
def monotonic_deadline(seconds)
|
258
333
|
Process.clock_gettime(Process::CLOCK_MONOTONIC) + seconds
|
@@ -2,7 +2,21 @@
|
|
2
2
|
|
3
3
|
module Solace
|
4
4
|
module Errors
|
5
|
-
#
|
5
|
+
# Raised when a transaction confirmation times out.
|
6
|
+
#
|
7
|
+
# This error is raised when waiting for a transaction to be confirmed by the
|
8
|
+
# network exceeds the specified timeout period. This can happen when the
|
9
|
+
# network is congested, the transaction fee is too low, or the transaction
|
10
|
+
# was not successfully processed by the validators.
|
11
|
+
#
|
12
|
+
# @example Handling confirmation timeout
|
13
|
+
# begin
|
14
|
+
# connection.wait_for_confirmed_signature(signature, timeout: 30)
|
15
|
+
# rescue Solace::Errors::ConfirmationTimeout => e
|
16
|
+
# puts "Transaction confirmation timed out: #{e.message}"
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# @since 0.0.1
|
6
20
|
class ConfirmationTimeout < StandardError
|
7
21
|
attr_reader :signature, :commitment, :timeout
|
8
22
|
|
@@ -19,9 +33,9 @@ module Solace
|
|
19
33
|
|
20
34
|
# Formats a confirmation timeout error
|
21
35
|
#
|
22
|
-
# @
|
23
|
-
# @
|
24
|
-
# @
|
36
|
+
# @param signature [String] The signature of the transaction
|
37
|
+
# @param commitment [String] The commitment level not reached
|
38
|
+
# @param timeout [Integer] The time out reached
|
25
39
|
# @return [Solace::Errors::ConfirmationTimeout] The formatted error
|
26
40
|
def self.format(signature, commitment, timeout)
|
27
41
|
new(
|
@@ -2,7 +2,22 @@
|
|
2
2
|
|
3
3
|
module Solace
|
4
4
|
module Errors
|
5
|
-
#
|
5
|
+
# Raised when an HTTP request to the RPC node fails.
|
6
|
+
#
|
7
|
+
# This error is raised for network-level failures when communicating with the
|
8
|
+
# Solana RPC node, including connection timeouts, DNS resolution failures,
|
9
|
+
# and HTTP protocol errors. This is distinct from RPC-level errors, which are
|
10
|
+
# raised as {Solace::Errors::RPCError}.
|
11
|
+
#
|
12
|
+
# @example Handling HTTP errors
|
13
|
+
# begin
|
14
|
+
# connection.get_account_info(address)
|
15
|
+
# rescue Solace::Errors::HTTPError => e
|
16
|
+
# puts "Network error: #{e.message}"
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# @see Solace::Errors::RPCError
|
20
|
+
# @since 0.0.1
|
6
21
|
class HTTPError < StandardError
|
7
22
|
attr_reader :code, :body
|
8
23
|
|
@@ -2,7 +2,21 @@
|
|
2
2
|
|
3
3
|
module Solace
|
4
4
|
module Errors
|
5
|
-
#
|
5
|
+
# Raised when parsing or deserializing data fails.
|
6
|
+
#
|
7
|
+
# This error is raised when the gem encounters data that cannot be properly
|
8
|
+
# parsed or deserialized, such as malformed JSON responses from the RPC node,
|
9
|
+
# invalid binary data, or unexpected data structures. This typically indicates
|
10
|
+
# either a bug in the gem or an incompatibility with the RPC node's response format.
|
11
|
+
#
|
12
|
+
# @example Handling parse errors
|
13
|
+
# begin
|
14
|
+
# transaction = Solace::Transaction.deserialize(binary_data)
|
15
|
+
# rescue Solace::Errors::ParseError => e
|
16
|
+
# puts "Failed to parse transaction: #{e.message}"
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# @since 0.0.1
|
6
20
|
class ParseError < StandardError
|
7
21
|
attr_reader :body
|
8
22
|
|
@@ -2,7 +2,23 @@
|
|
2
2
|
|
3
3
|
module Solace
|
4
4
|
module Errors
|
5
|
-
#
|
5
|
+
# Raised when the RPC node returns an error response.
|
6
|
+
#
|
7
|
+
# This error is raised when the Solana RPC node successfully processes the HTTP
|
8
|
+
# request but returns an error in the JSON-RPC response. This includes errors
|
9
|
+
# like invalid parameters, insufficient funds, blockhash not found, and other
|
10
|
+
# RPC method-specific errors. The error message and code from the RPC response
|
11
|
+
# are included in the exception.
|
12
|
+
#
|
13
|
+
# @example Handling RPC errors
|
14
|
+
# begin
|
15
|
+
# connection.send_transaction(transaction)
|
16
|
+
# rescue Solace::Errors::RPCError => e
|
17
|
+
# puts "RPC error (code #{e.code}): #{e.message}"
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @see Solace::Errors::HTTPError
|
21
|
+
# @since 0.0.1
|
6
22
|
class RPCError < StandardError
|
7
23
|
attr_reader :rpc_code, :rpc_message, :rpc_data
|
8
24
|
|
data/lib/solace/errors.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Solace
|
4
|
-
#
|
4
|
+
# The Errors module contains custom exception classes for the Solace gem.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# These exceptions provide specific error handling for various failure scenarios
|
7
|
+
# when interacting with the Solana blockchain, including:
|
8
|
+
# - {Solace::Errors::HTTPError} - HTTP communication failures
|
9
|
+
# - {Solace::Errors::RPCError} - RPC method errors returned by the node
|
10
|
+
# - {Solace::Errors::ParseError} - Data parsing and deserialization errors
|
11
|
+
# - {Solace::Errors::ConfirmationTimeout} - Transaction confirmation timeouts
|
8
12
|
#
|
13
|
+
# @see Solace::Connection
|
9
14
|
# @since 0.0.8
|
10
15
|
module Errors
|
11
16
|
# JSON-RPC Errors
|
data/lib/solace/instructions/associated_token_account/create_associated_token_account_instruction.rb
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
|
3
3
|
module Solace
|
4
4
|
module Instructions
|
5
|
+
# The AssociatedTokenAccount module contains instruction builders for the
|
6
|
+
# Associated Token Account Program.
|
7
|
+
#
|
8
|
+
# The Associated Token Account (ATA) Program provides a deterministic way to
|
9
|
+
# derive token account addresses for a given wallet and mint. This ensures that
|
10
|
+
# each wallet has a single, predictable token account for each token type.
|
11
|
+
#
|
12
|
+
# @see https://spl.solana.com/associated-token-account
|
13
|
+
# @since 0.0.2
|
5
14
|
module AssociatedTokenAccount
|
6
15
|
# Instruction for creating an Associated Token Account.
|
7
16
|
#
|
@@ -18,8 +27,6 @@ module Solace
|
|
18
27
|
# token_program_index: 5,
|
19
28
|
# program_index: 6
|
20
29
|
# )
|
21
|
-
#
|
22
|
-
# @since 0.0.2
|
23
30
|
class CreateAssociatedTokenAccountInstruction
|
24
31
|
# !@const INSTRUCTION_INDEX
|
25
32
|
# Instruction index for CreateAssociatedTokenAccount
|
@@ -2,6 +2,27 @@
|
|
2
2
|
|
3
3
|
module Solace
|
4
4
|
module Instructions
|
5
|
+
# The SplToken module contains instruction builders for the SPL Token Program.
|
6
|
+
#
|
7
|
+
# The SPL Token Program is Solana's standard for fungible and non-fungible tokens.
|
8
|
+
# It provides instructions for creating token mints, creating token accounts,
|
9
|
+
# minting tokens, transferring tokens, and managing token authorities.
|
10
|
+
#
|
11
|
+
# This module contains classes that build the low-level instruction data required
|
12
|
+
# to interact with the SPL Token Program. Each class corresponds to a specific
|
13
|
+
# instruction in the program.
|
14
|
+
#
|
15
|
+
# @example Building a transfer instruction
|
16
|
+
# instruction = Solace::Instructions::SplToken::TransferInstruction.build(
|
17
|
+
# source_index: 0,
|
18
|
+
# destination_index: 1,
|
19
|
+
# owner_index: 2,
|
20
|
+
# program_index: 3,
|
21
|
+
# amount: 1_000_000
|
22
|
+
# )
|
23
|
+
#
|
24
|
+
# @see https://spl.solana.com/token
|
25
|
+
# @since 0.0.2
|
5
26
|
module SplToken
|
6
27
|
# Instruction for transferring SPL tokens.
|
7
28
|
#
|
@@ -1,6 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Solace
|
4
|
+
# The Instructions module contains low-level instruction builders for Solana programs.
|
5
|
+
#
|
6
|
+
# Instructions are the fundamental building blocks of Solana transactions. Each
|
7
|
+
# instruction represents a single operation to be executed by an on-chain program.
|
8
|
+
# The classes in this module build the binary instruction data and specify the
|
9
|
+
# accounts required for each operation.
|
10
|
+
#
|
11
|
+
# Instructions are organized by program:
|
12
|
+
# - {Solace::Instructions::SystemProgram} - System Program instructions
|
13
|
+
# - {Solace::Instructions::SplToken} - SPL Token Program instructions
|
14
|
+
# - {Solace::Instructions::AssociatedTokenAccount} - Associated Token Account Program instructions
|
15
|
+
#
|
16
|
+
# Being a low-level primitive, you must build instructions manually.
|
17
|
+
#
|
18
|
+
# @example Building a system transfer instruction
|
19
|
+
#
|
20
|
+
# # Assuming the transaction's accounts are ordered as follows:
|
21
|
+
# accounts = %w[from_address to_address system_program_id]
|
22
|
+
#
|
23
|
+
# # Build the instruction by specifying the account indices directly
|
24
|
+
# instruction = Solace::Instructions::SystemProgram::TransferInstruction.build(
|
25
|
+
# from_index: 0,
|
26
|
+
# to_index: 1,
|
27
|
+
# program_index: 2,
|
28
|
+
# lamports: 1_000_000
|
29
|
+
# )
|
30
|
+
#
|
31
|
+
# @see Solace::Instruction
|
32
|
+
# @see Solace::Composers
|
33
|
+
# @since 0.0.1
|
4
34
|
module Instructions
|
5
35
|
module SystemProgram
|
6
36
|
# Instruction for creating a new account.
|
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
module Solace
|
4
4
|
module Instructions
|
5
|
+
# The SystemProgram module contains instruction builders for the System Program.
|
6
|
+
#
|
7
|
+
# The System Program is Solana's native program for fundamental operations like
|
8
|
+
# creating accounts, transferring SOL, and allocating account data. It is the
|
9
|
+
# only program that can create new accounts and assign them to other programs.
|
10
|
+
#
|
11
|
+
# This module contains classes that build the low-level instruction data required
|
12
|
+
# to interact with the System Program.
|
13
|
+
#
|
14
|
+
# @see https://docs.solana.com/developing/runtime-facilities/programs#system-program
|
15
|
+
# @since 0.0.1
|
5
16
|
module SystemProgram
|
6
17
|
# Instruction for transferring SOL.
|
7
18
|
#
|
@@ -24,20 +24,21 @@ module Solace
|
|
24
24
|
# # Create an associated token account
|
25
25
|
# result = program.create_associated_token_account(
|
26
26
|
# payer: payer,
|
27
|
+
# funder: funder,
|
27
28
|
# owner: owner,
|
28
29
|
# mint: mint
|
29
30
|
# )
|
30
31
|
#
|
31
32
|
# # Wait for the transaction to be finalized
|
32
|
-
#
|
33
|
+
# connection.wait_for_confirmed_signature('finalized') { result['result'] }
|
33
34
|
#
|
34
35
|
# @since 0.0.2
|
35
36
|
class AssociatedTokenAccount < Base
|
36
37
|
class << self
|
37
38
|
# Gets the address of an associated token account.
|
38
39
|
#
|
39
|
-
# @param owner [
|
40
|
-
# @param mint [
|
40
|
+
# @param owner [Keypair, PublicKey] The keypair of the owner.
|
41
|
+
# @param mint [Keypair, PublicKey] The keypair of the mint.
|
41
42
|
# @return [String] The address of the associated token account.
|
42
43
|
def get_address(owner:, mint:)
|
43
44
|
Solace::Utils::PDA.find_program_address(
|
@@ -68,48 +69,76 @@ module Solace
|
|
68
69
|
|
69
70
|
# Gets the address of an associated token account, creating it if it doesn't exist.
|
70
71
|
#
|
71
|
-
# @param payer [
|
72
|
-
# @param
|
73
|
-
# @param
|
74
|
-
# @param
|
72
|
+
# @param payer [Keypair] The keypair that will pay for fees and rent.
|
73
|
+
# @param funder [Keypair] The keypair that will pay for rent of the new associated token account.
|
74
|
+
# @param owner [Keypair, PublicKey] The keypair of the owner.
|
75
|
+
# @param mint [Keypair, PublicKey] The keypair of the mint.
|
75
76
|
# @return [String] The address of the associated token account
|
76
|
-
def get_or_create_address(
|
77
|
-
|
77
|
+
def get_or_create_address(
|
78
|
+
payer:,
|
79
|
+
funder:,
|
80
|
+
owner:,
|
81
|
+
mint:
|
82
|
+
)
|
83
|
+
ata_address, = get_address(owner: owner, mint: mint)
|
78
84
|
|
79
|
-
account_balance =
|
85
|
+
account_balance = connection.get_account_info(ata_address)
|
80
86
|
|
81
87
|
return ata_address unless account_balance.nil?
|
82
88
|
|
83
|
-
|
84
|
-
|
85
|
-
|
89
|
+
tx = create_associated_token_account(
|
90
|
+
payer: payer,
|
91
|
+
funder: funder,
|
92
|
+
owner: owner,
|
93
|
+
mint: mint
|
94
|
+
)
|
86
95
|
|
87
|
-
|
96
|
+
connection.wait_for_confirmed_signature { tx.signature }
|
88
97
|
|
89
98
|
ata_address
|
90
99
|
end
|
91
100
|
|
92
101
|
# Creates a new associated token account.
|
93
102
|
#
|
94
|
-
# @param
|
95
|
-
# @
|
96
|
-
|
97
|
-
|
103
|
+
# @param payer [#to_s, Keypair] The keypair that will pay for fees and rent.
|
104
|
+
# @param sign [Boolean] Whether to sign the transaction before sending it.
|
105
|
+
# @param execute [Boolean] Whether to send the transaction to the cluster.
|
106
|
+
# @param composer_opts [Hash] Options for calling the compose_create_associated_token_account method.
|
107
|
+
# @return [Transaction] The created or sent transaction.
|
108
|
+
def create_associated_token_account(
|
109
|
+
payer:,
|
110
|
+
sign: true,
|
111
|
+
execute: true,
|
112
|
+
**composer_opts
|
113
|
+
)
|
114
|
+
composer = compose_create_associated_token_account(**composer_opts)
|
115
|
+
|
116
|
+
yield composer if block_given?
|
117
|
+
|
118
|
+
tx = composer
|
119
|
+
.set_fee_payer(payer)
|
120
|
+
.compose_transaction
|
121
|
+
|
122
|
+
if sign
|
123
|
+
tx.sign(
|
124
|
+
payer,
|
125
|
+
composer_opts[:funder]
|
126
|
+
)
|
98
127
|
|
99
|
-
|
128
|
+
connection.send_transaction(tx.serialize) if execute
|
129
|
+
end
|
100
130
|
|
101
|
-
|
131
|
+
tx
|
102
132
|
end
|
103
133
|
|
104
134
|
# Prepares a new associated token account and returns the signed transaction.
|
105
135
|
#
|
106
|
-
# @param owner [
|
107
|
-
# @param mint [
|
108
|
-
# @param
|
109
|
-
# @return [
|
110
|
-
|
111
|
-
|
112
|
-
payer:,
|
136
|
+
# @param owner [#to_s, PublicKey] The keypair of the owner.
|
137
|
+
# @param mint [#to_s, PublicKey] The keypair of the mint.
|
138
|
+
# @param funder [#to_s, PublicKey] The keypair that will pay for rent of the new associated token account.
|
139
|
+
# @return [Transaction] The signed transaction.
|
140
|
+
def compose_create_associated_token_account(
|
141
|
+
funder:,
|
113
142
|
owner:,
|
114
143
|
mint:
|
115
144
|
)
|
@@ -118,15 +147,13 @@ module Solace
|
|
118
147
|
ix = Solace::Composers::AssociatedTokenAccountProgramCreateAccountComposer.new(
|
119
148
|
mint: mint,
|
120
149
|
owner: owner,
|
121
|
-
funder:
|
150
|
+
funder: funder,
|
122
151
|
ata_address: ata_address
|
123
152
|
)
|
124
153
|
|
125
154
|
TransactionComposer
|
126
155
|
.new(connection: connection)
|
127
|
-
.set_fee_payer(payer)
|
128
156
|
.add_instruction(ix)
|
129
|
-
.compose_transaction
|
130
157
|
end
|
131
158
|
end
|
132
159
|
end
|
data/lib/solace/programs/base.rb
CHANGED
@@ -3,6 +3,29 @@
|
|
3
3
|
# lib/solace/programs/base.rb
|
4
4
|
|
5
5
|
module Solace
|
6
|
+
# The Programs module contains high-level interfaces to Solana on-chain programs.
|
7
|
+
#
|
8
|
+
# Programs in this module provide convenient methods for interacting with
|
9
|
+
# on-chain programs without needing to manually construct instructions or
|
10
|
+
# manage account ordering. They serve as a bridge between the low-level
|
11
|
+
# instruction builders and high-level application code.
|
12
|
+
#
|
13
|
+
# Each program class corresponds to a specific on-chain program:
|
14
|
+
# - {Solace::Programs::SplToken} - SPL Token Program
|
15
|
+
# - {Solace::Programs::AssociatedTokenAccount} - Associated Token Account Program
|
16
|
+
#
|
17
|
+
# @example Using a program interface
|
18
|
+
# token_program = Solace::Programs::SplToken.new(connection)
|
19
|
+
# token_program.transfer(
|
20
|
+
# to:,
|
21
|
+
# from:,
|
22
|
+
# owner:,
|
23
|
+
# amount:
|
24
|
+
# )
|
25
|
+
#
|
26
|
+
# @see Solace::Programs::SplToken
|
27
|
+
# @see Solace::Programs::AssociatedTokenAccount
|
28
|
+
# @since 0.0.2
|
6
29
|
module Programs
|
7
30
|
# Base class for program-specific clients.
|
8
31
|
#
|