solace 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG +0 -0
- data/LICENSE +0 -0
- data/README.md +661 -0
- data/lib/solace/address_lookup_table.rb +50 -0
- data/lib/solace/concerns/binary_serializable.rb +30 -0
- data/lib/solace/connection.rb +187 -0
- data/lib/solace/constants.rb +52 -0
- data/lib/solace/instruction.rb +38 -0
- data/lib/solace/instructions/associated_token_account/create_associated_token_account_instruction.rb +68 -0
- data/lib/solace/instructions/spl_token/initialize_account_instruction.rb +46 -0
- data/lib/solace/instructions/spl_token/initialize_mint_instruction.rb +68 -0
- data/lib/solace/instructions/spl_token/mint_to_instruction.rb +48 -0
- data/lib/solace/instructions/spl_token/transfer_instruction.rb +48 -0
- data/lib/solace/instructions/system_program/create_account_instruction.rb +58 -0
- data/lib/solace/instructions/transfer_checked_instruction.rb +58 -0
- data/lib/solace/instructions/transfer_instruction.rb +48 -0
- data/lib/solace/keypair.rb +121 -0
- data/lib/solace/message.rb +95 -0
- data/lib/solace/programs/associated_token_account.rb +96 -0
- data/lib/solace/programs/base.rb +22 -0
- data/lib/solace/programs/spl_token.rb +187 -0
- data/lib/solace/public_key.rb +74 -0
- data/lib/solace/serializable_record.rb +26 -0
- data/lib/solace/serializers/address_lookup_table_deserializer.rb +62 -0
- data/lib/solace/serializers/address_lookup_table_serializer.rb +54 -0
- data/lib/solace/serializers/base.rb +31 -0
- data/lib/solace/serializers/base_deserializer.rb +56 -0
- data/lib/solace/serializers/base_serializer.rb +52 -0
- data/lib/solace/serializers/instruction_deserializer.rb +62 -0
- data/lib/solace/serializers/instruction_serializer.rb +54 -0
- data/lib/solace/serializers/message_deserializer.rb +116 -0
- data/lib/solace/serializers/message_serializer.rb +95 -0
- data/lib/solace/serializers/transaction_deserializer.rb +49 -0
- data/lib/solace/serializers/transaction_serializer.rb +60 -0
- data/lib/solace/transaction.rb +98 -0
- data/lib/solace/utils/codecs.rb +220 -0
- data/lib/solace/utils/curve25519_dalek.rb +59 -0
- data/lib/solace/utils/libcurve25519_dalek-linux/libcurve25519_dalek.so +0 -0
- data/lib/solace/utils/libcurve25519_dalek-macos/libcurve25519_dalek.dylib +0 -0
- data/lib/solace/utils/libcurve25519_dalek-windows/curve25519_dalek.dll +0 -0
- data/lib/solace/utils/pda.rb +100 -0
- data/lib/solace/version.rb +5 -0
- data/lib/solace.rb +39 -0
- metadata +165 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 78ff45cbaff80411dfec8433e478a0b7a97caea5fb97ae6b8159e2ea7fa409fc
|
4
|
+
data.tar.gz: 13c025072948cc13dfc61d0d7c431df5ae4af90bcca76e239d1fff6cb0033d4f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6d7dfe812cbe1a44275a6a62d36555cdf666e838d1ed37777efc9072bd91605ac4e0a8fca931a29405c387944c3bcef5c949022c21af762dfba09e7e6ab2530d
|
7
|
+
data.tar.gz: 181f9c5eb217ad0499b76f6e0052e3f9131d46c12c76583f8a3b1ad05d10274347158512e490656ed41c0c44a07b7645648b0e89b956de8691bf2b4916eebdd6
|
data/CHANGELOG
ADDED
File without changes
|
data/LICENSE
ADDED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1,661 @@
|
|
1
|
+
# Solace Ruby SDK Documentation
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
**Solace** is a comprehensive Ruby SDK for interacting with the Solana blockchain. It provides both low-level building blocks and high-level abstractions for creating, signing, and sending Solana transactions. The library follows Ruby conventions while maintaining compatibility with Solana's binary protocols.
|
6
|
+
|
7
|
+
## Architecture
|
8
|
+
|
9
|
+
The Solace SDK is organized into several key layers:
|
10
|
+
|
11
|
+
### 1. **Core Primitives** (Low-Level)
|
12
|
+
- **Keypair/PublicKey**: Ed25519 cryptographic operations
|
13
|
+
- **Connection**: RPC client for Solana nodes
|
14
|
+
- **Transaction/Message/Instruction**: Transaction building blocks
|
15
|
+
- **Serializers**: Binary serialization/deserialization system
|
16
|
+
|
17
|
+
### 2. **Instruction Builders** (Low-Level)
|
18
|
+
- Service objects that build specific instruction types
|
19
|
+
- Handle binary data encoding and account indexing
|
20
|
+
- Located in `lib/solace/instructions/`
|
21
|
+
|
22
|
+
### 3. **Program Clients** (High-Level)
|
23
|
+
- Convenient interfaces for interacting with on-chain programs
|
24
|
+
- Handle transaction assembly, signing, and submission
|
25
|
+
- Located in `lib/solace/programs/`
|
26
|
+
|
27
|
+
### 4. **Utilities** (Supporting)
|
28
|
+
- **Codecs**: Base58/Base64 encoding, compact integers, little-endian encoding
|
29
|
+
- **PDA**: Program Derived Address generation
|
30
|
+
- **Curve25519**: Native curve operations via FFI
|
31
|
+
|
32
|
+
## Core Components
|
33
|
+
|
34
|
+
### Keypair
|
35
|
+
|
36
|
+
The `Solace::Keypair` class represents Ed25519 keypairs for signing transactions.
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
# Generate a new random keypair
|
40
|
+
keypair = Solace::Keypair.generate
|
41
|
+
|
42
|
+
# Create from seed (32 bytes)
|
43
|
+
seed = SecureRandom.random_bytes(32)
|
44
|
+
keypair = Solace::Keypair.from_seed(seed)
|
45
|
+
|
46
|
+
# Create from secret key (64 bytes)
|
47
|
+
keypair = Solace::Keypair.from_secret_key(secret_key_bytes)
|
48
|
+
|
49
|
+
# Usage
|
50
|
+
puts keypair.address # Base58 public key
|
51
|
+
signature = keypair.sign(message) # Sign binary data
|
52
|
+
```
|
53
|
+
|
54
|
+
**Key Features:**
|
55
|
+
- Ed25519 signature support via RbNaCl
|
56
|
+
- Base58 address encoding
|
57
|
+
- Secure random generation
|
58
|
+
- Compatible with Solana's key format
|
59
|
+
|
60
|
+
### PublicKey
|
61
|
+
|
62
|
+
The `Solace::PublicKey` class represents Solana public keys with utility methods.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
# Create from bytes
|
66
|
+
pubkey = Solace::PublicKey.new(32_byte_array)
|
67
|
+
|
68
|
+
# Usage
|
69
|
+
puts pubkey.to_base58 # Base58 representation
|
70
|
+
puts pubkey.to_s # Same as to_base58
|
71
|
+
bytes = pubkey.to_bytes # Get raw bytes
|
72
|
+
```
|
73
|
+
|
74
|
+
**Key Features:**
|
75
|
+
- 32-byte Ed25519 public keys
|
76
|
+
- Base58 encoding/decoding
|
77
|
+
- PDA (Program Derived Address) support via mixin
|
78
|
+
- Equality comparison
|
79
|
+
|
80
|
+
### Connection
|
81
|
+
|
82
|
+
The `Solace::Connection` class provides RPC communication with Solana nodes.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
# Connect to local validator (default = http://localhost:8899)
|
86
|
+
connection = Solace::Connection.new
|
87
|
+
|
88
|
+
# Connect to devnet or other RPC nodes
|
89
|
+
connection = Solace::Connection.new('https://api.devnet.solana.com')
|
90
|
+
|
91
|
+
# RPC methods
|
92
|
+
balance = connection.get_balance(pubkey)
|
93
|
+
blockhash = connection.get_latest_blockhash
|
94
|
+
account_info = connection.get_account_info(pubkey)
|
95
|
+
signature = connection.send_transaction(transaction)
|
96
|
+
|
97
|
+
# Airdrop (devnet/testnet only)
|
98
|
+
response = connection.request_airdrop(pubkey, 1_000_000_000) # 1 SOL
|
99
|
+
connection.wait_for_confirmed_signature { response['result'] }
|
100
|
+
```
|
101
|
+
|
102
|
+
**Key Features:**
|
103
|
+
- JSON-RPC 2.0 client
|
104
|
+
- Automatic request ID generation
|
105
|
+
- Built-in error handling
|
106
|
+
- Support for all major RPC methods
|
107
|
+
- Transaction confirmation waiting
|
108
|
+
|
109
|
+
### Transaction & Message
|
110
|
+
|
111
|
+
Transactions contain a message and signatures. Messages contain instructions and metadata.
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
# Create a message
|
115
|
+
message = Solace::Message.new(
|
116
|
+
header: [
|
117
|
+
1, # required_signatures
|
118
|
+
0, # readonly_signed
|
119
|
+
1 # readonly_unsigned
|
120
|
+
],
|
121
|
+
accounts: [
|
122
|
+
payer.address,
|
123
|
+
recipient.address,
|
124
|
+
system_program_id
|
125
|
+
],
|
126
|
+
instructions: [transfer_instruction],
|
127
|
+
recent_blockhash: connection.get_latest_blockhash,
|
128
|
+
)
|
129
|
+
|
130
|
+
# Create and sign transaction
|
131
|
+
transaction = Solace::Transaction.new(message: message)
|
132
|
+
transaction.sign(payer_keypair)
|
133
|
+
|
134
|
+
# Send transaction
|
135
|
+
signature = connection.send_transaction(transaction.serialize)
|
136
|
+
```
|
137
|
+
|
138
|
+
**Key Features:**
|
139
|
+
- Legacy and versioned transaction support
|
140
|
+
- Automatic signature management
|
141
|
+
- Binary serialization/deserialization
|
142
|
+
- Address lookup table support (versioned)
|
143
|
+
|
144
|
+
### Instruction
|
145
|
+
|
146
|
+
Instructions represent individual operations within a transaction.
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
instruction = Solace::Instruction.new(
|
150
|
+
program_index: 2, # Index in accounts array
|
151
|
+
accounts: [0, 1], # Account indices
|
152
|
+
data: [2, 0, 0, 0] + amount_bytes # Instruction data
|
153
|
+
)
|
154
|
+
|
155
|
+
# All instructions have accessor methods for program_index, accounts, and data
|
156
|
+
instruction.program_index # => 2
|
157
|
+
instruction.accounts # => [0, 1]
|
158
|
+
instruction.data # => [2, 0, 0, 0] + amount_bytes
|
159
|
+
```
|
160
|
+
|
161
|
+
**Key Features:**
|
162
|
+
- Program index referencing
|
163
|
+
- Account index arrays
|
164
|
+
- Binary data payload
|
165
|
+
- Serializable format
|
166
|
+
|
167
|
+
## Low-Level Instruction Builders
|
168
|
+
|
169
|
+
Instruction builders are service objects that create specific instruction types. They handle the binary encoding required by Solana programs.
|
170
|
+
|
171
|
+
### System Program Instructions
|
172
|
+
|
173
|
+
#### Transfer Instruction
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
# Build a SOL transfer instruction
|
177
|
+
transfer_ix = Solace::Instructions::TransferInstruction.build(
|
178
|
+
lamports: 1_000_000, # 0.001 SOL
|
179
|
+
from_index: 0, # Sender account index
|
180
|
+
to_index: 1, # Recipient account index
|
181
|
+
program_index: 2 # System program index
|
182
|
+
)
|
183
|
+
```
|
184
|
+
|
185
|
+
#### Create Account Instruction
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
# Build account creation instruction
|
189
|
+
create_ix = Solace::Instructions::SystemProgram::CreateAccountInstruction.build(
|
190
|
+
from_index: 0, # Payer account index
|
191
|
+
new_account_index: 1, # New account index
|
192
|
+
system_program_index: 2, # System program index
|
193
|
+
lamports: rent_lamports, # Rent-exempt amount
|
194
|
+
space: 165, # Account data size
|
195
|
+
owner: token_program_id # Owning program
|
196
|
+
)
|
197
|
+
```
|
198
|
+
|
199
|
+
### SPL Token Instructions
|
200
|
+
|
201
|
+
#### Initialize Mint Instruction
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
# Initialize a new token mint
|
205
|
+
init_mint_ix = Solace::Instructions::SplToken::InitializeMintInstruction.build(
|
206
|
+
mint_account_index: 1, # Mint account index
|
207
|
+
rent_sysvar_index: 2, # Rent sysvar index
|
208
|
+
program_index: 3, # Token program index
|
209
|
+
decimals: 6, # Token decimals
|
210
|
+
mint_authority: authority_pubkey,
|
211
|
+
freeze_authority: freeze_pubkey # Optional
|
212
|
+
)
|
213
|
+
```
|
214
|
+
|
215
|
+
#### Mint To Instruction
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
# Mint tokens to an account
|
219
|
+
mint_to_ix = Solace::Instructions::SplToken::MintToInstruction.build(
|
220
|
+
amount: 1_000_000, # Amount to mint
|
221
|
+
mint_index: 0, # Mint account index
|
222
|
+
destination_index: 1, # Destination token account
|
223
|
+
mint_authority_index: 2, # Mint authority index
|
224
|
+
program_index: 3 # Token program index
|
225
|
+
)
|
226
|
+
```
|
227
|
+
|
228
|
+
#### Transfer Instruction
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
# Transfer tokens between accounts
|
232
|
+
transfer_ix = Solace::Instructions::SplToken::TransferInstruction.build(
|
233
|
+
amount: 500_000, # Amount to transfer
|
234
|
+
source_index: 0, # Source token account
|
235
|
+
destination_index: 1, # Destination token account
|
236
|
+
owner_index: 2, # Owner/authority index
|
237
|
+
program_index: 3 # Token program index
|
238
|
+
)
|
239
|
+
```
|
240
|
+
|
241
|
+
**Common Patterns:**
|
242
|
+
- All builders use `.build()` class method
|
243
|
+
- Account indices reference the transaction's accounts array
|
244
|
+
- Binary data encoding handled automatically
|
245
|
+
- Instruction-specific data layouts documented in comments
|
246
|
+
|
247
|
+
## High-Level Program Methods
|
248
|
+
|
249
|
+
Program clients provide convenient interfaces for common operations, handling transaction assembly, signing, and submission.
|
250
|
+
|
251
|
+
### SPL Token Program
|
252
|
+
|
253
|
+
```ruby
|
254
|
+
# Initialize program client
|
255
|
+
spl_token = Solace::Programs::SplToken.new(connection: connection)
|
256
|
+
|
257
|
+
# Create a new token mint
|
258
|
+
signature = spl_token.create_mint(
|
259
|
+
payer: payer_keypair,
|
260
|
+
decimals: 6,
|
261
|
+
mint_authority: authority_keypair,
|
262
|
+
freeze_authority: freeze_keypair, # Optional
|
263
|
+
mint_keypair: mint_keypair # Optional, generates if not provided
|
264
|
+
)
|
265
|
+
|
266
|
+
# Mint tokens to an account
|
267
|
+
signature = spl_token.mint_to(
|
268
|
+
payer: payer_keypair,
|
269
|
+
mint: mint_keypair,
|
270
|
+
destination: token_account_address,
|
271
|
+
amount: 1_000_000,
|
272
|
+
mint_authority: authority_keypair
|
273
|
+
)
|
274
|
+
|
275
|
+
# Transfer tokens
|
276
|
+
signature = spl_token.transfer(
|
277
|
+
payer: payer_keypair,
|
278
|
+
source: source_token_account,
|
279
|
+
destination: dest_token_account,
|
280
|
+
amount: 500_000,
|
281
|
+
owner: owner_keypair
|
282
|
+
)
|
283
|
+
```
|
284
|
+
|
285
|
+
**Key Features:**
|
286
|
+
- Automatic transaction assembly
|
287
|
+
- Built-in signing and submission
|
288
|
+
- Error handling and validation
|
289
|
+
- Sensible defaults for common operations
|
290
|
+
- Returns transaction signatures
|
291
|
+
|
292
|
+
### Prepare Methods
|
293
|
+
|
294
|
+
For more control, use "prepare" methods that return signed transactions without sending:
|
295
|
+
|
296
|
+
```ruby
|
297
|
+
# Prepare transaction without sending
|
298
|
+
transaction = spl_token.prepare_create_mint(
|
299
|
+
payer: payer_keypair,
|
300
|
+
decimals: 6,
|
301
|
+
mint_authority: authority_keypair,
|
302
|
+
freeze_authority: nil,
|
303
|
+
mint_keypair: mint_keypair
|
304
|
+
)
|
305
|
+
|
306
|
+
# Inspect or modify transaction before sending
|
307
|
+
puts transaction.serialize # Base64 transaction
|
308
|
+
signature = connection.send_transaction(transaction.serialize)
|
309
|
+
```
|
310
|
+
|
311
|
+
## Serialization System
|
312
|
+
|
313
|
+
Solace uses a serialization system for converting Ruby objects to/from Solana's binary format.
|
314
|
+
|
315
|
+
### SerializableRecord Base Class
|
316
|
+
|
317
|
+
```ruby
|
318
|
+
class Transaction < Solace::SerializableRecord
|
319
|
+
SERIALIZER = Solace::Serializers::TransactionSerializer
|
320
|
+
DESERIALIZER = Solace::Serializers::TransactionDeserializer
|
321
|
+
|
322
|
+
# Automatic serialization
|
323
|
+
def serialize
|
324
|
+
self.class::SERIALIZER.call(self)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Automatic deserialization
|
328
|
+
def self.deserialize(io)
|
329
|
+
self::DESERIALIZER.call(io)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
```
|
333
|
+
|
334
|
+
### Serializer Pattern
|
335
|
+
|
336
|
+
```ruby
|
337
|
+
class TransactionSerializer < Solace::Serializers::Base
|
338
|
+
STEPS = %i[
|
339
|
+
serialize_signatures
|
340
|
+
serialize_message
|
341
|
+
].freeze
|
342
|
+
|
343
|
+
def serialize_signatures
|
344
|
+
# Convert signatures to binary format
|
345
|
+
end
|
346
|
+
|
347
|
+
def serialize_message
|
348
|
+
# Serialize message component
|
349
|
+
end
|
350
|
+
end
|
351
|
+
```
|
352
|
+
|
353
|
+
**Key Features:**
|
354
|
+
- Step-based serialization process
|
355
|
+
- Automatic Base64 encoding
|
356
|
+
- Consistent error handling
|
357
|
+
- Reversible serialization/deserialization
|
358
|
+
|
359
|
+
## Utility Modules
|
360
|
+
|
361
|
+
### Codecs
|
362
|
+
|
363
|
+
The `Solace::Utils::Codecs` module provides encoding/decoding utilities for Solana data types.
|
364
|
+
|
365
|
+
```ruby
|
366
|
+
# Base58 operations
|
367
|
+
base58_string = Solace::Utils::Codecs.bytes_to_base58(bytes)
|
368
|
+
bytes = Solace::Utils::Codecs.base58_to_bytes(base58_string)
|
369
|
+
|
370
|
+
# Compact u16 encoding (ShortVec)
|
371
|
+
encoded = Solace::Utils::Codecs.encode_compact_u16(1234)
|
372
|
+
value, bytes_read = Solace::Utils::Codecs.decode_compact_u16(io)
|
373
|
+
|
374
|
+
# Little-endian u64
|
375
|
+
encoded = Solace::Utils::Codecs.encode_le_u64(amount)
|
376
|
+
value = Solace::Utils::Codecs.decode_le_u64(io)
|
377
|
+
|
378
|
+
# Base64 to IO stream
|
379
|
+
io = Solace::Utils::Codecs.base64_to_bytestream(base64_string)
|
380
|
+
```
|
381
|
+
|
382
|
+
### Program Derived Addresses (PDA)
|
383
|
+
|
384
|
+
```ruby
|
385
|
+
# Find PDA with bump seed
|
386
|
+
seeds = ['metadata', mint_address, 'edition']
|
387
|
+
program_id = 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'
|
388
|
+
|
389
|
+
address, bump = Solace::Utils::PDA.find_program_address(seeds, program_id)
|
390
|
+
|
391
|
+
# Create PDA directly
|
392
|
+
address = Solace::Utils::PDA.create_program_address(seeds + [bump], program_id)
|
393
|
+
```
|
394
|
+
|
395
|
+
**Key Features:**
|
396
|
+
- Automatic bump seed finding
|
397
|
+
- Multiple seed type support (String, Integer, Array)
|
398
|
+
- Base58 address detection
|
399
|
+
- SHA256 hashing with curve validation
|
400
|
+
|
401
|
+
### Curve25519 Operations
|
402
|
+
|
403
|
+
```ruby
|
404
|
+
# Check if point is on curve (used in PDA validation)
|
405
|
+
on_curve = Solace::Utils::Curve25519Dalek.on_curve?(32_byte_point)
|
406
|
+
```
|
407
|
+
|
408
|
+
## Constants
|
409
|
+
|
410
|
+
Common Solana program IDs are defined in `Solace::Constants`:
|
411
|
+
|
412
|
+
```ruby
|
413
|
+
Solace::Constants::SYSTEM_PROGRAM_ID # '11111111111111111111111111111111'
|
414
|
+
Solace::Constants::TOKEN_PROGRAM_ID # 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
|
415
|
+
Solace::Constants::ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID # 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'
|
416
|
+
Solace::Constants::SYSVAR_RENT_PROGRAM_ID # 'SysvarRent111111111111111111111111111111111'
|
417
|
+
Solace::Constants::MEMO_PROGRAM_ID # 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr'
|
418
|
+
```
|
419
|
+
|
420
|
+
## Practical Examples
|
421
|
+
|
422
|
+
### Complete SOL Transfer
|
423
|
+
|
424
|
+
```ruby
|
425
|
+
require 'solace'
|
426
|
+
|
427
|
+
# Setup
|
428
|
+
connection = Solace::Connection.new('https://api.devnet.solana.com')
|
429
|
+
payer = Solace::Keypair.generate
|
430
|
+
recipient = Solace::Keypair.generate
|
431
|
+
|
432
|
+
# Fund payer (devnet only)
|
433
|
+
connection.request_airdrop(payer.address, 1_000_000_000)
|
434
|
+
|
435
|
+
# Build transfer instruction
|
436
|
+
transfer_ix = Solace::Instructions::TransferInstruction.build(
|
437
|
+
lamports: 100_000_000, # 0.1 SOL
|
438
|
+
from_index: 0,
|
439
|
+
to_index: 1,
|
440
|
+
program_index: 2
|
441
|
+
)
|
442
|
+
|
443
|
+
# Create message
|
444
|
+
message = Solace::Message.new(
|
445
|
+
accounts: [
|
446
|
+
payer.address,
|
447
|
+
recipient.address,
|
448
|
+
Solace::Constants::SYSTEM_PROGRAM_ID
|
449
|
+
],
|
450
|
+
instructions: [transfer_ix],
|
451
|
+
recent_blockhash: connection.get_latest_blockhash,
|
452
|
+
header: [1, 0, 1]
|
453
|
+
)
|
454
|
+
|
455
|
+
# Sign and send
|
456
|
+
transaction = Solace::Transaction.new(message: message)
|
457
|
+
transaction.sign(payer)
|
458
|
+
signature = connection.send_transaction(transaction.serialize)
|
459
|
+
|
460
|
+
puts "Transaction: #{signature}"
|
461
|
+
```
|
462
|
+
|
463
|
+
### Complete Token Mint Creation
|
464
|
+
|
465
|
+
```ruby
|
466
|
+
require 'solace'
|
467
|
+
|
468
|
+
# Setup
|
469
|
+
connection = Solace::Connection.new('https://api.devnet.solana.com')
|
470
|
+
payer = Solace::Keypair.generate
|
471
|
+
mint_keypair = Solace::Keypair.generate
|
472
|
+
|
473
|
+
# Fund payer
|
474
|
+
connection.request_airdrop(payer.address, 1_000_000_000)
|
475
|
+
|
476
|
+
# High-level approach
|
477
|
+
spl_token = Solace::Programs::SplToken.new(connection: connection)
|
478
|
+
signature = spl_token.create_mint(
|
479
|
+
payer: payer,
|
480
|
+
decimals: 6,
|
481
|
+
mint_authority: payer,
|
482
|
+
freeze_authority: nil,
|
483
|
+
mint_keypair: mint_keypair
|
484
|
+
)
|
485
|
+
|
486
|
+
puts "Mint created: #{mint_keypair.address}"
|
487
|
+
puts "Transaction: #{signature}"
|
488
|
+
```
|
489
|
+
|
490
|
+
### Manual Transaction Building
|
491
|
+
|
492
|
+
```ruby
|
493
|
+
# Low-level approach for maximum control
|
494
|
+
rent_lamports = connection.get_minimum_lamports_for_rent_exemption(82)
|
495
|
+
|
496
|
+
# Build instructions
|
497
|
+
create_account_ix = Solace::Instructions::SystemProgram::CreateAccountInstruction.build(
|
498
|
+
from_index: 0,
|
499
|
+
new_account_index: 1,
|
500
|
+
system_program_index: 4,
|
501
|
+
lamports: rent_lamports,
|
502
|
+
space: 82,
|
503
|
+
owner: Solace::Constants::TOKEN_PROGRAM_ID
|
504
|
+
)
|
505
|
+
|
506
|
+
initialize_mint_ix = Solace::Instructions::SplToken::InitializeMintInstruction.build(
|
507
|
+
mint_account_index: 1,
|
508
|
+
rent_sysvar_index: 2,
|
509
|
+
program_index: 3,
|
510
|
+
decimals: 6,
|
511
|
+
mint_authority: payer.address
|
512
|
+
)
|
513
|
+
|
514
|
+
# Assemble transaction
|
515
|
+
message = Solace::Message.new(
|
516
|
+
accounts: [
|
517
|
+
payer.address,
|
518
|
+
mint_keypair.address,
|
519
|
+
Solace::Constants::SYSVAR_RENT_PROGRAM_ID,
|
520
|
+
Solace::Constants::TOKEN_PROGRAM_ID,
|
521
|
+
Solace::Constants::SYSTEM_PROGRAM_ID
|
522
|
+
],
|
523
|
+
instructions: [create_account_ix, initialize_mint_ix],
|
524
|
+
recent_blockhash: connection.get_latest_blockhash,
|
525
|
+
header: [2, 0, 3] # 2 signers, 0 readonly signed, 3 readonly unsigned
|
526
|
+
)
|
527
|
+
|
528
|
+
transaction = Solace::Transaction.new(message: message)
|
529
|
+
transaction.sign(payer, mint_keypair)
|
530
|
+
signature = connection.send_transaction(transaction.serialize)
|
531
|
+
```
|
532
|
+
|
533
|
+
## Design Patterns
|
534
|
+
|
535
|
+
### Service Objects
|
536
|
+
Instruction builders follow the service object pattern:
|
537
|
+
- Single responsibility (build one instruction type)
|
538
|
+
- Class methods for stateless operations
|
539
|
+
- Consistent `.build()` interface
|
540
|
+
- Separate `.data()` methods for instruction data
|
541
|
+
|
542
|
+
### Serializable Records
|
543
|
+
Core data structures inherit from `SerializableRecord`:
|
544
|
+
- Automatic serialization/deserialization
|
545
|
+
- Consistent binary format handling
|
546
|
+
- SERIALIZER/DESERIALIZER constants pattern
|
547
|
+
|
548
|
+
### Mixin Modules
|
549
|
+
Shared functionality via mixins:
|
550
|
+
- `BinarySerializable` for serialization support
|
551
|
+
- `PDA` for Program Derived Address operations
|
552
|
+
- `Utils` modules for common operations
|
553
|
+
|
554
|
+
### Builder Pattern
|
555
|
+
High-level program methods use builder pattern:
|
556
|
+
- Fluent interfaces with keyword arguments
|
557
|
+
- Sensible defaults for optional parameters
|
558
|
+
- Automatic transaction assembly and signing
|
559
|
+
|
560
|
+
## Error Handling
|
561
|
+
|
562
|
+
The SDK provides comprehensive error handling:
|
563
|
+
|
564
|
+
```ruby
|
565
|
+
begin
|
566
|
+
signature = connection.send_transaction(transaction.serialize)
|
567
|
+
rescue StandardError => e
|
568
|
+
puts "Transaction failed: #{e.message}"
|
569
|
+
end
|
570
|
+
|
571
|
+
# PDA validation
|
572
|
+
begin
|
573
|
+
address = Solace::Utils::PDA.create_program_address(seeds, program_id)
|
574
|
+
rescue Solace::Utils::PDA::InvalidPDAError => e
|
575
|
+
puts "Invalid PDA: #{e.message}"
|
576
|
+
end
|
577
|
+
```
|
578
|
+
|
579
|
+
## Testing Support
|
580
|
+
|
581
|
+
The SDK includes comprehensive test utilities:
|
582
|
+
|
583
|
+
```ruby
|
584
|
+
# Test fixtures for keypairs
|
585
|
+
bob = Fixtures.load_keypair('bob')
|
586
|
+
alice = Fixtures.load_keypair('anna')
|
587
|
+
|
588
|
+
# Automatic funding in test environment
|
589
|
+
response = connection.request_airdrop(keypair.address, 10_000_000_000)
|
590
|
+
connection.wait_for_confirmed_signature { response['result'] }
|
591
|
+
|
592
|
+
# Transaction confirmation helpers
|
593
|
+
response = connection.send_transaction(transaction.serialize)
|
594
|
+
connection.wait_for_confirmed_signature { response['result'] }
|
595
|
+
```
|
596
|
+
|
597
|
+
## Dependencies
|
598
|
+
|
599
|
+
- **base58**: Base58 encoding/decoding
|
600
|
+
- **rbnacl**: Ed25519 cryptography
|
601
|
+
- **ffi**: Foreign Function Interface for native libraries
|
602
|
+
- **json**: JSON parsing for RPC
|
603
|
+
- **net/http**: HTTP client for RPC calls
|
604
|
+
|
605
|
+
## Current Limitations
|
606
|
+
|
607
|
+
### High-Impact/Foundational Next Steps
|
608
|
+
|
609
|
+
1. **Associated Token Account Program**
|
610
|
+
- Implement: close_associated_token_account, and helpers for derivation.
|
611
|
+
- Rationale: Required for user wallets and token UX. **Most SPL Token operations depend on ATAs to be useful in real-world workflows.**
|
612
|
+
|
613
|
+
2. **Full SPL Token Program Coverage** _(depends on ATA support)_
|
614
|
+
- Implement: mint_to, burn, close_account, set_authority, freeze/thaw, approve/revoke, etc.
|
615
|
+
- Rationale: Most dApps and DeFi protocols rely on SPL tokens. **For practical use, SPL Token instructions should leverage ATA helpers.**
|
616
|
+
|
617
|
+
3. **Account Data Parsing**
|
618
|
+
- Implement: Decoders for token accounts, mint accounts, stake accounts, etc.
|
619
|
+
- Rationale: Needed to read on-chain state.
|
620
|
+
|
621
|
+
4. **Transaction Simulation**
|
622
|
+
- Implement: `simulateTransaction` RPC endpoint.
|
623
|
+
- Rationale: Allows dry-run and error debugging.
|
624
|
+
|
625
|
+
5. **Error Decoding**
|
626
|
+
- Implement: Map program error codes to readable errors.
|
627
|
+
- Rationale: Improves DX and debugging.
|
628
|
+
|
629
|
+
---
|
630
|
+
|
631
|
+
### Medium-Impact
|
632
|
+
|
633
|
+
6. **Address Lookup Table Support**
|
634
|
+
- Implement: Create, extend, use ALT in transactions.
|
635
|
+
- Rationale: Needed for scalable DeFi/protocols.
|
636
|
+
|
637
|
+
7. **Stake Program**
|
638
|
+
- Implement: delegate, deactivate, withdraw, split, merge.
|
639
|
+
- Rationale: For validators, staking dApps.
|
640
|
+
|
641
|
+
8. **Websocket/Event Subscription**
|
642
|
+
- Implement: Account/slot/transaction subscriptions.
|
643
|
+
- Rationale: For real-time apps and bots.
|
644
|
+
|
645
|
+
9. **Utility Functions**
|
646
|
+
- base58/base64 encode/decode, lamports/SOL conversions, etc.
|
647
|
+
|
648
|
+
10. **Advanced Transaction Features**
|
649
|
+
- Durable nonce, versioned transactions, partial signing.
|
650
|
+
|
651
|
+
---
|
652
|
+
|
653
|
+
### Low-Impact/Advanced
|
654
|
+
|
655
|
+
- Governance program
|
656
|
+
- Anchor IDL/Anchor-style program support
|
657
|
+
- Program deployment (BPF loader)
|
658
|
+
|
659
|
+
## Conclusion
|
660
|
+
|
661
|
+
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.
|