solace 0.1.5 → 0.1.6
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/lib/solace/composers/associated_token_account_program_create_account_composer.rb +6 -6
- data/lib/solace/composers/associated_token_account_program_create_idempotent_account_composer.rb +2 -1
- data/lib/solace/composers/base.rb +1 -1
- data/lib/solace/composers/spl_token_program_close_account_composer.rb +3 -3
- data/lib/solace/composers/spl_token_program_initialize_mint_composer.rb +5 -5
- data/lib/solace/composers/spl_token_program_mint_to_composer.rb +4 -4
- data/lib/solace/composers/spl_token_program_transfer_checked_composer.rb +6 -6
- data/lib/solace/composers/spl_token_program_transfer_composer.rb +4 -4
- data/lib/solace/composers/system_program_create_account_composer.rb +5 -5
- data/lib/solace/composers/system_program_transfer_composer.rb +3 -3
- data/lib/solace/composers/token_2022_program_close_account_composer.rb +3 -3
- data/lib/solace/composers/token_2022_program_initialize_mint_composer.rb +5 -5
- data/lib/solace/composers/token_2022_program_mint_to_composer.rb +4 -4
- data/lib/solace/composers/token_2022_program_transfer_checked_composer.rb +6 -6
- data/lib/solace/composers/token_2022_program_transfer_composer.rb +4 -4
- data/lib/solace/connection.rb +5 -5
- data/lib/solace/errors/confirmation_timeout.rb +4 -4
- data/lib/solace/errors/rpc_error.rb +4 -4
- data/lib/solace/instructions/associated_token_account/create_account_instruction.rb +2 -1
- data/lib/solace/instructions/spl_token/close_account_instruction.rb +2 -2
- data/lib/solace/instructions/spl_token/initialize_account_instruction.rb +2 -2
- data/lib/solace/instructions/spl_token/initialize_mint_instruction.rb +2 -2
- data/lib/solace/instructions/spl_token/mint_to_instruction.rb +2 -2
- data/lib/solace/instructions/spl_token/transfer_checked_instruction.rb +2 -2
- data/lib/solace/instructions/spl_token/transfer_instruction.rb +2 -2
- data/lib/solace/instructions/system_program/create_account_instruction.rb +2 -2
- data/lib/solace/instructions/system_program/transfer_instruction.rb +2 -2
- data/lib/solace/instructions/token_2022/close_account_instruction.rb +2 -2
- data/lib/solace/instructions/token_2022/initialize_account_instruction.rb +2 -2
- data/lib/solace/instructions/token_2022/initialize_mint_instruction.rb +2 -2
- data/lib/solace/instructions/token_2022/mint_to_instruction.rb +2 -2
- data/lib/solace/instructions/token_2022/transfer_checked_instruction.rb +2 -2
- data/lib/solace/instructions/token_2022/transfer_instruction.rb +2 -2
- data/lib/solace/message.rb +5 -5
- data/lib/solace/programs/associated_token_account.rb +10 -9
- data/lib/solace/programs/token_program_interface.rb +18 -18
- data/lib/solace/serializers/address_lookup_table_deserializer.rb +2 -2
- data/lib/solace/serializers/base_deserializer.rb +1 -1
- data/lib/solace/serializers/instruction_deserializer.rb +2 -2
- data/lib/solace/serializers/message_deserializer.rb +3 -3
- data/lib/solace/serializers/transaction_deserializer.rb +1 -1
- data/lib/solace/tokens/token.rb +1 -1
- data/lib/solace/tokens.rb +2 -2
- data/lib/solace/transaction.rb +1 -1
- data/lib/solace/transaction_composer.rb +5 -5
- data/lib/solace/utils/account_context.rb +9 -9
- data/lib/solace/utils/codecs.rb +309 -49
- data/lib/solace/utils/rpc_client.rb +9 -9
- data/lib/solace/version.rb +1 -1
- metadata +111 -9
- data/CHANGELOG +0 -243
- data/LICENSE +0 -21
- data/README.md +0 -578
data/README.md
DELETED
|
@@ -1,578 +0,0 @@
|
|
|
1
|
-
# Solace Ruby SDK Documentation
|
|
2
|
-
|
|
3
|
-
A Ruby SDK for the Solana blockchain.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
Solace is a comprehensive Ruby SDK for interacting with the Solana blockchain. It provides both low-level building blocks and high-level abstractions for composing, signing, and sending Solana transactions. The library aims to follow Ruby conventions while maintaining compatibility with Solana's binary protocols.
|
|
8
|
-
|
|
9
|
-
## Architecture
|
|
10
|
-
|
|
11
|
-
The Solace SDK is organized into several key layers:
|
|
12
|
-
|
|
13
|
-
### 1. **Core Classes** (Low-Level)
|
|
14
|
-
- **Keypair, PublicKey**: Ed25519 cryptographic operations
|
|
15
|
-
- **Connection**: RPC client for Solana nodes
|
|
16
|
-
- **Transaction, Message, Instruction, AddressLookupTable**: Transaction building blocks
|
|
17
|
-
- **Serializers**: Binary serialization/deserialization system
|
|
18
|
-
|
|
19
|
-
### 2. **Instruction Builders** (Low-Level)
|
|
20
|
-
- Service objects that build specific instruction types
|
|
21
|
-
- Handle binary data encoding and account indexing
|
|
22
|
-
- Located in `lib/solace/instructions/`
|
|
23
|
-
|
|
24
|
-
### 3. **Composers** (High-Level)
|
|
25
|
-
- Convenient interfaces for composing transactions and instructions
|
|
26
|
-
- Handle account ordering and header calculations for transactions
|
|
27
|
-
- Located in `lib/solace/composers`
|
|
28
|
-
|
|
29
|
-
### 3. **Programs** (High-Level)
|
|
30
|
-
- Convenient interfaces for interacting with on-chain programs
|
|
31
|
-
- Handle transaction assembly, signing, and submission
|
|
32
|
-
- Located in `lib/solace/programs/`
|
|
33
|
-
|
|
34
|
-
### 4. **Utilities** (Support modules & classes)
|
|
35
|
-
- **Codecs**: Base58/Base64 encoding, compact integers, little-endian encoding
|
|
36
|
-
- **PDA**: Program Derived Address generation
|
|
37
|
-
- **Curve25519**: Native curve operations via FFI
|
|
38
|
-
- **Token**: Classes for loading and accessing token data
|
|
39
|
-
- **More...**: Checkout `lib/solace/utils`
|
|
40
|
-
|
|
41
|
-
## Core Components
|
|
42
|
-
|
|
43
|
-
### Transaction & Message
|
|
44
|
-
|
|
45
|
-
Transactions contain a message and signatures. Messages contain instructions and metadata. This core class is as simple as possible and provide the lowest level of abstraction for building and sending transactions. A developer is expected to:
|
|
46
|
-
|
|
47
|
-
1. Manually fill and order the accounts array
|
|
48
|
-
2. Manually fill and order the instructions array
|
|
49
|
-
3. Manually calculate the header
|
|
50
|
-
4. ...did I forget to say manually?
|
|
51
|
-
|
|
52
|
-
```ruby
|
|
53
|
-
# Create a message
|
|
54
|
-
message = Solace::Message.new(
|
|
55
|
-
header: [
|
|
56
|
-
1, # required_signatures
|
|
57
|
-
0, # readonly_signed
|
|
58
|
-
1 # readonly_unsigned
|
|
59
|
-
],
|
|
60
|
-
accounts: [
|
|
61
|
-
payer.address,
|
|
62
|
-
recipient.address,
|
|
63
|
-
system_program_id
|
|
64
|
-
],
|
|
65
|
-
instructions: [transfer_instruction],
|
|
66
|
-
recent_blockhash: connection.get_latest_blockhash[0],
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
# Create and sign transaction
|
|
70
|
-
transaction = Solace::Transaction.new(message: message)
|
|
71
|
-
transaction.sign(payer_keypair)
|
|
72
|
-
|
|
73
|
-
# Send transaction
|
|
74
|
-
signature = connection.send_transaction(transaction.serialize)
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
**Key Features:**
|
|
78
|
-
- Legacy and versioned transaction support
|
|
79
|
-
- Automatic signature management
|
|
80
|
-
- Binary serialization/deserialization
|
|
81
|
-
- Address lookup table support (versioned)
|
|
82
|
-
|
|
83
|
-
### Instruction
|
|
84
|
-
|
|
85
|
-
Instructions represent individual operations within a transaction. Like messages, instructions are as simple as possible and provide the lowest level of abstraction for building and sending transactions. A developer is expected to:
|
|
86
|
-
|
|
87
|
-
1. Manually fill and order the accounts indices array
|
|
88
|
-
2. Manually specify the program index
|
|
89
|
-
3. Manually specify the data
|
|
90
|
-
|
|
91
|
-
```ruby
|
|
92
|
-
instruction = Solace::Instruction.new(
|
|
93
|
-
program_index: 2, # Index in accounts array
|
|
94
|
-
accounts: [0, 1], # Account indices
|
|
95
|
-
data: [2, 0, 0, 0] + amount_bytes # Instruction data
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
# All instructions have accessor methods for program_index, accounts, and data
|
|
99
|
-
instruction.program_index # => 2
|
|
100
|
-
instruction.accounts # => [0, 1]
|
|
101
|
-
instruction.data # => [2, 0, 0, 0] + amount_bytes
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
**Key Features:**
|
|
105
|
-
- Program index referencing
|
|
106
|
-
- Account index arrays
|
|
107
|
-
- Binary data payload
|
|
108
|
-
- Serializable format
|
|
109
|
-
|
|
110
|
-
## Low-Level Instruction Builders
|
|
111
|
-
|
|
112
|
-
Given that the low-level instruction class is fully available, it's easy to build higher-level instruction builders that wrap the low-level instruction class. These builders are service objects that create specific instruction types. They handle the binary encoding required by Solana programs.
|
|
113
|
-
|
|
114
|
-
For example, the SystemProgram::TransferInstruction builder is a service object that creates and returns a Solace::Instruction object with the correct program index, accounts indices, and data for a System Program solana transfer.
|
|
115
|
-
|
|
116
|
-
```ruby
|
|
117
|
-
# Build a SOL transfer instruction
|
|
118
|
-
transfer_ix = Solace::Instructions::SystemProgram::TransferInstruction.build(
|
|
119
|
-
lamports: 1_000_000, # 0.001 SOL
|
|
120
|
-
from_index: 0, # Sender account index
|
|
121
|
-
to_index: 1, # Recipient account index
|
|
122
|
-
program_index: 2 # System program index
|
|
123
|
-
)
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Solace includes a number of these, and you can build your own as well.
|
|
127
|
-
|
|
128
|
-
- `Solace::Instructions::SystemProgram::TransferInstruction`
|
|
129
|
-
- `Solace::Instructions::SystemProgram::CreateAccountInstruction`
|
|
130
|
-
- `Solace::Instructions::SplToken::InitializeMintInstruction`
|
|
131
|
-
- `Solace::Instructions::SplToken::InitializeAccountInstruction`
|
|
132
|
-
- `Solace::Instructions::SplToken::MintToInstruction`
|
|
133
|
-
- `Solace::Instructions::SplToken::TransferInstruction`
|
|
134
|
-
- `Solace::Instructions::SplToken::TransferCheckedInstruction`
|
|
135
|
-
- `Solace::Instructions::AssociatedTokenAccount::CreateAssociatedTokenAccountInstruction`
|
|
136
|
-
|
|
137
|
-
**Common Patterns:**
|
|
138
|
-
- All builders use `.build()` class method
|
|
139
|
-
- All builders use `.data()` method to specify the instruction data
|
|
140
|
-
- All builders use named parameters and `_index` suffix for account indices
|
|
141
|
-
- All builders use a `program_index` parameter to specify the program index
|
|
142
|
-
- Account indices reference the transaction's accounts array
|
|
143
|
-
- Binary data encoding handled automatically
|
|
144
|
-
- Instruction-specific data layouts documented in comments
|
|
145
|
-
|
|
146
|
-
## High-Level Program Classes
|
|
147
|
-
|
|
148
|
-
**WARNING: Programs will probably get deprecated in favor of composers in the future.**
|
|
149
|
-
|
|
150
|
-
Now that we have the mid-level instruction builders, we can create high-level program classes that provide convenient interfaces for common operations, handling transaction assembly, signing, and submission.
|
|
151
|
-
|
|
152
|
-
For example, the `Solace::Programs::SplToken` class provides a high-level interface for interacting with the SPL Token Program.
|
|
153
|
-
|
|
154
|
-
### SPL Token Program
|
|
155
|
-
|
|
156
|
-
```ruby
|
|
157
|
-
# Initialize program client
|
|
158
|
-
spl_token = Solace::Programs::SplToken.new(connection: connection)
|
|
159
|
-
|
|
160
|
-
# Create a new token mint
|
|
161
|
-
response = spl_token.create_mint(
|
|
162
|
-
payer: payer_keypair,
|
|
163
|
-
decimals: 6,
|
|
164
|
-
mint_authority: authority_keypair,
|
|
165
|
-
freeze_authority: freeze_keypair, # Optional
|
|
166
|
-
mint_keypair: mint_keypair # Optional, generates if not provided
|
|
167
|
-
)
|
|
168
|
-
connection.wait_for_confirmed_signature { response['result'] }
|
|
169
|
-
|
|
170
|
-
# Mint tokens to an account
|
|
171
|
-
response = spl_token.mint_to(
|
|
172
|
-
payer: payer_keypair,
|
|
173
|
-
mint: mint_keypair,
|
|
174
|
-
destination: token_account_address,
|
|
175
|
-
amount: 1_000_000,
|
|
176
|
-
mint_authority: authority_keypair
|
|
177
|
-
)
|
|
178
|
-
connection.wait_for_confirmed_signature { response['result'] }
|
|
179
|
-
|
|
180
|
-
# Transfer tokens
|
|
181
|
-
response = spl_token.transfer(
|
|
182
|
-
payer: payer_keypair,
|
|
183
|
-
source: source_token_account,
|
|
184
|
-
destination: dest_token_account,
|
|
185
|
-
amount: 500_000,
|
|
186
|
-
owner: owner_keypair
|
|
187
|
-
)
|
|
188
|
-
connection.wait_for_confirmed_signature { response['result'] }
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
**Key Features:**
|
|
192
|
-
- Automatic transaction assembly
|
|
193
|
-
- Built-in signing and submission
|
|
194
|
-
- Error handling and validation
|
|
195
|
-
- Sensible defaults for common operations
|
|
196
|
-
- Returns transaction signatures
|
|
197
|
-
|
|
198
|
-
### Prepare Methods
|
|
199
|
-
|
|
200
|
-
For more control, use "prepare" methods that return signed transactions without sending it on the program:
|
|
201
|
-
|
|
202
|
-
```ruby
|
|
203
|
-
# Prepare transaction without sending
|
|
204
|
-
transaction = spl_token.compose_create_mint(
|
|
205
|
-
payer: payer_keypair,
|
|
206
|
-
decimals: 6,
|
|
207
|
-
mint_authority: authority_keypair,
|
|
208
|
-
freeze_authority: nil,
|
|
209
|
-
mint_keypair: mint_keypair
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
# Inspect or modify transaction before sending
|
|
213
|
-
puts transaction.serialize # Base64 transaction
|
|
214
|
-
signature = connection.send_transaction(transaction.serialize)
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## Utility Modules
|
|
218
|
-
|
|
219
|
-
### Codecs
|
|
220
|
-
|
|
221
|
-
The `Solace::Utils::Codecs` module provides encoding/decoding utilities for Solana data types.
|
|
222
|
-
|
|
223
|
-
```ruby
|
|
224
|
-
# Base58 operations
|
|
225
|
-
base58_string = Solace::Utils::Codecs.bytes_to_base58(bytes)
|
|
226
|
-
bytes = Solace::Utils::Codecs.base58_to_bytes(base58_string)
|
|
227
|
-
|
|
228
|
-
# Compact u16 encoding (ShortVec)
|
|
229
|
-
encoded = Solace::Utils::Codecs.encode_compact_u16(1234)
|
|
230
|
-
value, bytes_read = Solace::Utils::Codecs.decode_compact_u16(io)
|
|
231
|
-
|
|
232
|
-
# Little-endian u64
|
|
233
|
-
encoded = Solace::Utils::Codecs.encode_le_u64(amount)
|
|
234
|
-
value = Solace::Utils::Codecs.decode_le_u64(io)
|
|
235
|
-
|
|
236
|
-
# Base64 to IO stream
|
|
237
|
-
io = Solace::Utils::Codecs.base64_to_bytestream(base64_string)
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Program Derived Addresses (PDA)
|
|
241
|
-
|
|
242
|
-
```ruby
|
|
243
|
-
# Find PDA with bump seed
|
|
244
|
-
seeds = ['metadata', mint_address, 'edition']
|
|
245
|
-
program_id = 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'
|
|
246
|
-
|
|
247
|
-
address, bump = Solace::Utils::PDA.find_program_address(seeds, program_id)
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
**Key Features:**
|
|
251
|
-
- Automatic bump seed finding
|
|
252
|
-
- Multiple seed type support (String, Integer, Array)
|
|
253
|
-
- Base58 address detection
|
|
254
|
-
- SHA256 hashing with curve validation
|
|
255
|
-
|
|
256
|
-
### Curve25519 Operations
|
|
257
|
-
|
|
258
|
-
```ruby
|
|
259
|
-
# Check if point is on curve (used in PDA validation)
|
|
260
|
-
on_curve = Solace::Utils::Curve25519Dalek.on_curve?(32_byte_point)
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
## Constants
|
|
264
|
-
|
|
265
|
-
**WARNING: Constants will probably get deprecated in favor of config file that developers can use to define their own constants with required values.**
|
|
266
|
-
|
|
267
|
-
Common Solana program IDs are defined in `Solace::Constants`:
|
|
268
|
-
|
|
269
|
-
```ruby
|
|
270
|
-
Solace::Constants::SYSTEM_PROGRAM_ID # '11111111111111111111111111111111'
|
|
271
|
-
Solace::Constants::TOKEN_PROGRAM_ID # 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
|
|
272
|
-
Solace::Constants::ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID # 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'
|
|
273
|
-
Solace::Constants::SYSVAR_RENT_PROGRAM_ID # 'SysvarRent111111111111111111111111111111111'
|
|
274
|
-
Solace::Constants::MEMO_PROGRAM_ID # 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr'
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
## Composers
|
|
278
|
-
|
|
279
|
-
Composers are used to build transactions from multiple instructions. They handle all the low-level details of transaction assembly, such as account ordering, header calculation, and fee payer selection.
|
|
280
|
-
|
|
281
|
-
```ruby
|
|
282
|
-
# Initialize a transaction composer
|
|
283
|
-
composer = Solace::TransactionComposer.new(connection: connection)
|
|
284
|
-
|
|
285
|
-
# Add an instruction composer
|
|
286
|
-
composer.add_instruction(
|
|
287
|
-
Solace::Composers::SystemProgramTransferComposer.new(
|
|
288
|
-
to: 'pubkey1',
|
|
289
|
-
from: 'pubkey2',
|
|
290
|
-
lamports: 100
|
|
291
|
-
)
|
|
292
|
-
)
|
|
293
|
-
|
|
294
|
-
# Add another instruction composer
|
|
295
|
-
composer.add_instruction(
|
|
296
|
-
Solace::Composers::SplTokenProgramTransferCheckedComposer.new(
|
|
297
|
-
from: 'pubkey4',
|
|
298
|
-
to: 'pubkey5',
|
|
299
|
-
mint: 'pubkey6',
|
|
300
|
-
authority: 'pubkey7',
|
|
301
|
-
amount: 1_000_000,
|
|
302
|
-
decimals: 6
|
|
303
|
-
)
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
# Set the fee payer
|
|
307
|
-
composer.set_fee_payer('pubkey8')
|
|
308
|
-
|
|
309
|
-
# Compose the transaction
|
|
310
|
-
tx = composer.compose_transaction
|
|
311
|
-
|
|
312
|
-
# Sign the transaction with all required signers
|
|
313
|
-
tx.sign(*any_required_signers)
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
Composers are intended to be extended by developers with custom instruction composers to interface with their own programs. Simply inherit from `Solace::Composers::Base` and implement the required methods.
|
|
317
|
-
|
|
318
|
-
```ruby
|
|
319
|
-
class MyProgramComposer < Solace::Composers::Base
|
|
320
|
-
# All keyword arguments are passed to the constructor and available
|
|
321
|
-
# as a `params` hash.
|
|
322
|
-
#
|
|
323
|
-
# The setup_accounts method is called automatically by the transaction composer
|
|
324
|
-
# during compilation and should be used to add accounts to the account_context
|
|
325
|
-
# with the appropriate access permissions. Conditional logic is fine here given
|
|
326
|
-
# and available params to determine the access permissions.
|
|
327
|
-
def setup_accounts
|
|
328
|
-
account_context.add_writable_signer(params[:from])
|
|
329
|
-
account_context.add_writable_nonsigner(params[:to])
|
|
330
|
-
account_context.add_readonly_nonsigner(params[:program])
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
# The build_instruction method is called automatically by the transaction composer
|
|
334
|
-
# during compilation and should be used to build the instruction using an instruction builder.
|
|
335
|
-
#
|
|
336
|
-
# The passed context to the build_instruction method provides the indices of all accounts
|
|
337
|
-
# that were added to the account_context in the setup_accounts method. These are accessible
|
|
338
|
-
# by the index_of method of the context using the account address as a parameter.
|
|
339
|
-
def build_instruction(context)
|
|
340
|
-
Solace::Instructions::MyProgram::MyInstruction.build(
|
|
341
|
-
data: params[:data],
|
|
342
|
-
from_index: context.index_of(params[:from]),
|
|
343
|
-
to_index: context.index_of(params[:to]),
|
|
344
|
-
program_index: context.index_of(params[:program])
|
|
345
|
-
)
|
|
346
|
-
end
|
|
347
|
-
end
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
## Practical Examples
|
|
351
|
-
|
|
352
|
-
### Complete SOL Transfer
|
|
353
|
-
|
|
354
|
-
```ruby
|
|
355
|
-
require 'solace'
|
|
356
|
-
|
|
357
|
-
# Setup
|
|
358
|
-
payer = Solace::Keypair.generate
|
|
359
|
-
recipient = Solace::Keypair.generate
|
|
360
|
-
|
|
361
|
-
# Create connection
|
|
362
|
-
connection = Solace::Connection.new('https://api.devnet.solana.com')
|
|
363
|
-
|
|
364
|
-
# Fund payer (devnet only)
|
|
365
|
-
response = connection.request_airdrop(payer.address, 1_000_000_000)
|
|
366
|
-
connection.wait_for_confirmed_signature('finalized') { response['result'] }
|
|
367
|
-
|
|
368
|
-
# Build transfer instruction
|
|
369
|
-
transfer_ix = Solace::Instructions::SystemProgram::TransferInstruction.build(
|
|
370
|
-
lamports: 100_000_000, # 0.1 SOL
|
|
371
|
-
from_index: 0,
|
|
372
|
-
to_index: 1,
|
|
373
|
-
program_index: 2
|
|
374
|
-
)
|
|
375
|
-
|
|
376
|
-
# Create message
|
|
377
|
-
message = Solace::Message.new(
|
|
378
|
-
accounts: [
|
|
379
|
-
payer.address,
|
|
380
|
-
recipient.address,
|
|
381
|
-
Solace::Constants::SYSTEM_PROGRAM_ID
|
|
382
|
-
],
|
|
383
|
-
instructions: [transfer_ix],
|
|
384
|
-
recent_blockhash: connection.get_latest_blockhash,
|
|
385
|
-
header: [1, 0, 1]
|
|
386
|
-
)
|
|
387
|
-
|
|
388
|
-
# Sign and send
|
|
389
|
-
transaction = Solace::Transaction.new(message: message)
|
|
390
|
-
transaction.sign(payer)
|
|
391
|
-
|
|
392
|
-
response = connection.send_transaction(transaction.serialize)
|
|
393
|
-
puts "Transaction: #{response['result']}"
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
### Complete Token Mint Creation
|
|
397
|
-
|
|
398
|
-
```ruby
|
|
399
|
-
require 'solace'
|
|
400
|
-
|
|
401
|
-
# Setup
|
|
402
|
-
payer = Solace::Keypair.generate
|
|
403
|
-
mint_keypair = Solace::Keypair.generate
|
|
404
|
-
|
|
405
|
-
# Create connection
|
|
406
|
-
connection = Solace::Connection.new('https://api.devnet.solana.com')
|
|
407
|
-
|
|
408
|
-
# Fund payer
|
|
409
|
-
response = connection.request_airdrop(payer.address, 1_000_000_000)
|
|
410
|
-
connection.wait_for_confirmed_signature('finalized') { response['result'] }
|
|
411
|
-
|
|
412
|
-
# High-level approach
|
|
413
|
-
program = Solace::Programs::SplToken.new(connection: connection)
|
|
414
|
-
signature = program.create_mint(
|
|
415
|
-
payer: payer,
|
|
416
|
-
decimals: 6,
|
|
417
|
-
mint_authority: payer,
|
|
418
|
-
freeze_authority: nil,
|
|
419
|
-
mint_keypair: mint_keypair
|
|
420
|
-
)
|
|
421
|
-
|
|
422
|
-
puts "Mint created: #{mint_keypair.address}"
|
|
423
|
-
puts "Transaction: #{signature}"
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
## Design Patterns
|
|
427
|
-
|
|
428
|
-
### Service Objects
|
|
429
|
-
Instruction builders follow the service object pattern:
|
|
430
|
-
- Single responsibility (build one instruction type)
|
|
431
|
-
- Class methods for stateless operations
|
|
432
|
-
- Consistent `.build()` interface
|
|
433
|
-
- Separate `.data()` methods for instruction data
|
|
434
|
-
|
|
435
|
-
## Testing Support
|
|
436
|
-
|
|
437
|
-
The SDK includes comprehensive test utilities:
|
|
438
|
-
|
|
439
|
-
```ruby
|
|
440
|
-
# Test fixtures for keypairs
|
|
441
|
-
bob = Fixtures.load_keypair('bob')
|
|
442
|
-
alice = Fixtures.load_keypair('anna')
|
|
443
|
-
|
|
444
|
-
# Automatic funding in test environment
|
|
445
|
-
response = connection.request_airdrop(keypair.address, 10_000_000_000)
|
|
446
|
-
connection.wait_for_confirmed_signature { response['result'] }
|
|
447
|
-
|
|
448
|
-
# Transaction confirmation helpers
|
|
449
|
-
response = connection.send_transaction(transaction.serialize)
|
|
450
|
-
connection.wait_for_confirmed_signature { response['result'] }
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
## Development
|
|
454
|
-
|
|
455
|
-
### Prerequisites
|
|
456
|
-
|
|
457
|
-
- **Ruby** (matching `.ruby-version` / `Gemfile.lock`) and **Bundler**
|
|
458
|
-
- **Solana CLI**, which provides `solana-test-validator` and `solana-keygen`. Install with:
|
|
459
|
-
```bash
|
|
460
|
-
sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"
|
|
461
|
-
```
|
|
462
|
-
Then add the installer's PATH line to your shell profile (the installer prints the exact `export PATH=...` to use).
|
|
463
|
-
|
|
464
|
-
### One-time setup
|
|
465
|
-
|
|
466
|
-
```bash
|
|
467
|
-
# Install Ruby dependencies
|
|
468
|
-
bundle install
|
|
469
|
-
|
|
470
|
-
# Generate the seven keypair fixtures the test suite expects.
|
|
471
|
-
# test/fixtures/ is gitignored — each developer generates their own.
|
|
472
|
-
mkdir -p test/fixtures
|
|
473
|
-
for name in bob anna payer mint mint-2022 mint-authority fee-collector; do
|
|
474
|
-
solana-keygen new --no-bip39-passphrase --silent --force -o "test/fixtures/${name}.json"
|
|
475
|
-
done
|
|
476
|
-
|
|
477
|
-
# Bootstrap the local validator: airdrops SOL to the fixture accounts,
|
|
478
|
-
# creates their ATAs, and creates the test mint. Spins up a
|
|
479
|
-
# solana-test-validator on the side; ledger state persists in ./test-ledger.
|
|
480
|
-
bundle exec rake bootstrap
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
If you ever need a clean slate, delete `test-ledger/` and re-run `rake bootstrap`.
|
|
484
|
-
|
|
485
|
-
### Running the tests
|
|
486
|
-
|
|
487
|
-
```bash
|
|
488
|
-
bundle exec rake test
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
`rake test` spawns `solana-test-validator` automatically (re-using `./test-ledger`) and tears it down on exit. You can also run a single file:
|
|
492
|
-
|
|
493
|
-
```bash
|
|
494
|
-
bundle exec rake test test/solace/programs/spl_token_test.rb
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
To exercise the longer end-to-end flows in `test/usecases/`:
|
|
498
|
-
|
|
499
|
-
```bash
|
|
500
|
-
bundle exec rake usecases # all usecases
|
|
501
|
-
bundle exec rake usecases token_mint # a specific one
|
|
502
|
-
```
|
|
503
|
-
|
|
504
|
-
### Building & installing the gem locally
|
|
505
|
-
|
|
506
|
-
```bash
|
|
507
|
-
bundle exec rake build # produces builds/solace-<version>.gem
|
|
508
|
-
bundle exec rake install # builds and `gem install`s it locally
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
The native curve25519 library is shipped pre-compiled in `lib/solace/utils/`. You only need `rake compile` (which invokes `cargo`) if you're modifying `ext/curve25519_dalek` — that target cross-builds for every supported platform and requires the corresponding Rust toolchains.
|
|
512
|
-
|
|
513
|
-
## Dependencies
|
|
514
|
-
|
|
515
|
-
- **base58**: Base58 encoding/decoding
|
|
516
|
-
- **base64**: Base64 encoding/decoding
|
|
517
|
-
- **rbnacl**: Ed25519 cryptography
|
|
518
|
-
- **ffi**: Foreign Function Interface for native libraries
|
|
519
|
-
- **json**: JSON parsing for RPC
|
|
520
|
-
- **net/http**: HTTP client for RPC calls
|
|
521
|
-
|
|
522
|
-
## Current Limitations
|
|
523
|
-
|
|
524
|
-
### High-Impact/Foundational Next Steps
|
|
525
|
-
|
|
526
|
-
1. **Associated Token Account Program**
|
|
527
|
-
- Implement: close_associated_token_account, and helpers for derivation.
|
|
528
|
-
- Rationale: Required for user wallets and token UX. **Most SPL Token operations depend on ATAs to be useful in real-world workflows.**
|
|
529
|
-
|
|
530
|
-
2. **Full SPL Token Program Coverage** _(depends on ATA support)_
|
|
531
|
-
- Implement: mint_to, burn, close_account, set_authority, freeze/thaw, approve/revoke, etc.
|
|
532
|
-
- Rationale: Most dApps and DeFi protocols rely on SPL tokens. **For practical use, SPL Token instructions should leverage ATA helpers.**
|
|
533
|
-
|
|
534
|
-
3. **Account Data Parsing**
|
|
535
|
-
- Implement: Decoders for token accounts, mint accounts, stake accounts, etc.
|
|
536
|
-
- Rationale: Needed to read on-chain state.
|
|
537
|
-
|
|
538
|
-
4. **Transaction Simulation**
|
|
539
|
-
- Implement: `simulateTransaction` RPC endpoint.
|
|
540
|
-
- Rationale: Allows dry-run and error debugging.
|
|
541
|
-
|
|
542
|
-
5. **Error Decoding**
|
|
543
|
-
- Implement: Map program error codes to readable errors.
|
|
544
|
-
- Rationale: Improves DX and debugging.
|
|
545
|
-
|
|
546
|
-
---
|
|
547
|
-
|
|
548
|
-
### Medium-Impact
|
|
549
|
-
|
|
550
|
-
6. **Address Lookup Table Support**
|
|
551
|
-
- Implement: Create, extend, use ALT in transactions.
|
|
552
|
-
- Rationale: Needed for scalable DeFi/protocols.
|
|
553
|
-
|
|
554
|
-
7. **Stake Program**
|
|
555
|
-
- Implement: delegate, deactivate, withdraw, split, merge.
|
|
556
|
-
- Rationale: For validators, staking dApps.
|
|
557
|
-
|
|
558
|
-
8. **Websocket/Event Subscription**
|
|
559
|
-
- Implement: Account/slot/transaction subscriptions.
|
|
560
|
-
- Rationale: For real-time apps and bots.
|
|
561
|
-
|
|
562
|
-
9. **Utility Functions**
|
|
563
|
-
- base58/base64 encode/decode, lamports/SOL conversions, etc.
|
|
564
|
-
|
|
565
|
-
10. **Advanced Transaction Features**
|
|
566
|
-
- Durable nonce, versioned transactions, partial signing.
|
|
567
|
-
|
|
568
|
-
---
|
|
569
|
-
|
|
570
|
-
### Low-Impact/Advanced
|
|
571
|
-
|
|
572
|
-
- Governance program
|
|
573
|
-
- Anchor IDL/Anchor-style program support
|
|
574
|
-
- Program deployment (BPF loader)
|
|
575
|
-
|
|
576
|
-
## Conclusion
|
|
577
|
-
|
|
578
|
-
Solace provides a comprehensive, Ruby-idiomatic interface to the Solana blockchain. Its layered architecture allows developers to choose the appropriate level of abstraction for their needs, from low-level instruction building to high-level program interactions. The consistent patterns and thorough documentation make it accessible to Ruby developers while maintaining the power and flexibility needed for complex Solana applications.
|