solace 0.0.3 → 0.0.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +14 -0
  3. data/README.md +140 -285
  4. data/lib/solace/address_lookup_table.rb +34 -18
  5. data/lib/solace/composers/base.rb +16 -11
  6. data/lib/solace/composers/spl_token_program_transfer_checked_composer.rb +27 -1
  7. data/lib/solace/composers/system_program_transfer_composer.rb +22 -1
  8. data/lib/solace/concerns/binary_serializable.rb +39 -0
  9. data/lib/solace/connection.rb +69 -38
  10. data/lib/solace/constants.rb +7 -14
  11. data/lib/solace/instruction.rb +30 -19
  12. data/lib/solace/instructions/associated_token_account/create_associated_token_account_instruction.rb +18 -3
  13. data/lib/solace/instructions/spl_token/initialize_account_instruction.rb +24 -3
  14. data/lib/solace/instructions/spl_token/initialize_mint_instruction.rb +18 -1
  15. data/lib/solace/instructions/spl_token/mint_to_instruction.rb +16 -3
  16. data/lib/solace/instructions/spl_token/transfer_checked_instruction.rb +17 -1
  17. data/lib/solace/instructions/spl_token/transfer_instruction.rb +15 -2
  18. data/lib/solace/instructions/system_program/create_account_instruction.rb +18 -3
  19. data/lib/solace/instructions/system_program/transfer_instruction.rb +15 -7
  20. data/lib/solace/keypair.rb +64 -31
  21. data/lib/solace/message.rb +22 -10
  22. data/lib/solace/programs/associated_token_account.rb +45 -20
  23. data/lib/solace/programs/base.rb +6 -0
  24. data/lib/solace/programs/spl_token.rb +52 -14
  25. data/lib/solace/public_key.rb +58 -20
  26. data/lib/solace/serializers/address_lookup_table_deserializer.rb +3 -5
  27. data/lib/solace/serializers/address_lookup_table_serializer.rb +7 -7
  28. data/lib/solace/serializers/base_deserializer.rb +29 -19
  29. data/lib/solace/serializers/base_serializer.rb +18 -9
  30. data/lib/solace/serializers/instruction_deserializer.rb +5 -7
  31. data/lib/solace/serializers/instruction_serializer.rb +4 -6
  32. data/lib/solace/serializers/message_deserializer.rb +3 -5
  33. data/lib/solace/serializers/message_serializer.rb +3 -5
  34. data/lib/solace/serializers/transaction_deserializer.rb +5 -7
  35. data/lib/solace/serializers/transaction_serializer.rb +5 -7
  36. data/lib/solace/transaction.rb +38 -23
  37. data/lib/solace/transaction_composer.rb +47 -13
  38. data/lib/solace/utils/account_context.rb +64 -65
  39. data/lib/solace/utils/codecs.rb +56 -128
  40. data/lib/solace/utils/curve25519_dalek.rb +9 -4
  41. data/lib/solace/utils/pda.rb +22 -24
  42. data/lib/solace/version.rb +2 -1
  43. data/lib/solace.rb +4 -9
  44. metadata +7 -10
  45. data/lib/solace/instructions/base.rb +0 -21
  46. data/lib/solace/serializable_record.rb +0 -26
  47. data/lib/solace/serializers/base.rb +0 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73c15e6b362288fa1f3be0fd2793fcf43aff390deabe20f3264f22550cb67734
4
- data.tar.gz: 1b036900c1306c1af4f4c0887a625d6a633a7cf4276c79c1a8b61754d7ffe593
3
+ metadata.gz: d6a955af361ac7765d33c34560a09704730c8a394cd74e0bc17196d8cf3cb8eb
4
+ data.tar.gz: 3c86565b3f728bdd4b116dff1abc63125d187b2cc6d8b5fcb44c8444c2d15def
5
5
  SHA512:
6
- metadata.gz: 422a09d627bbf0e9bb59f3183f4a1ad34904a14996291555ff7c83717554c0915c4ba1d93c689b852cb9d9fab024cfd0e491c0443b332a6dc6f448028c48e000
7
- data.tar.gz: a185276e03d031c72c7a78b11db5fd3a9b1d1fa6388758b41c20fad66241aa14b44e5188caace7d0bffaf498c03834d4fe73461754834c3a33e412a13544bf1c
6
+ metadata.gz: 489042853cdc2ca68d2e35abab66c26bb1363e9ae31fa9816203b6c267d9083361a006cc73610467581ed179999317f0fefc0b09460497d1ac6f10dcb273b5c2
7
+ data.tar.gz: bc66a1d998abf224a30365e44ea026b034437cbdc3cf09092bf45147510bf010d8d97178047ee485f088255d86a928a58a752694aa813595e5622d6bd66d1310
data/CHANGELOG CHANGED
@@ -16,6 +16,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
16
16
  ### Fixed
17
17
  ```
18
18
 
19
+ ## [0.0.6] - 2025-08-07
20
+
21
+ ### Added
22
+ 1. Added `from_address` method to `Solace::PublicKey`.
23
+ 2. Change docs on most methods to include an `@example` section.
24
+
25
+ ### Changed
26
+ 1. Change `private_key` method on Keypair to `pivate_key_bytes`
27
+ 2. Change README to include a practical example of using composers.
28
+
29
+ ### Fixed
30
+ 1. Fix `encode_signatures` method in `Solace::Serializers::TransactionSerializer` to correctly count the number of signatures using the `num_required_signatures` field in the message.
31
+
32
+
19
33
  ## [0.0.3] - 2025-07-30
20
34
 
21
35
  ### Added
data/README.md CHANGED
@@ -1,17 +1,18 @@
1
1
  # Solace Ruby SDK Documentation
2
+ A Ruby SDK for the Solana blockchain.
2
3
 
3
4
  ## Overview
4
5
 
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
+ 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.
6
7
 
7
8
  ## Architecture
8
9
 
9
10
  The Solace SDK is organized into several key layers:
10
11
 
11
- ### 1. **Core Primitives** (Low-Level)
12
+ ### 1. **Core Classes** (Low-Level)
12
13
  - **Keypair/PublicKey**: Ed25519 cryptographic operations
13
14
  - **Connection**: RPC client for Solana nodes
14
- - **Transaction/Message/Instruction**: Transaction building blocks
15
+ - **Transaction/Message/Instruction/AddressLookupTable**: Transaction building blocks
15
16
  - **Serializers**: Binary serialization/deserialization system
16
17
 
17
18
  ### 2. **Instruction Builders** (Low-Level)
@@ -19,96 +20,32 @@ The Solace SDK is organized into several key layers:
19
20
  - Handle binary data encoding and account indexing
20
21
  - Located in `lib/solace/instructions/`
21
22
 
22
- ### 3. **Program Clients** (High-Level)
23
+ ### 3. **Composers** (High-Level)
24
+ - Convenient interfaces for composing transactions and instructions
25
+ - Handle account ordering and header calculations for transactions
26
+ - Located in `lib/solace/composers`
27
+
28
+ ### 3. **Programs** (High-Level)
23
29
  - Convenient interfaces for interacting with on-chain programs
24
30
  - Handle transaction assembly, signing, and submission
25
31
  - Located in `lib/solace/programs/`
26
32
 
27
- ### 4. **Utilities** (Supporting)
33
+ ### 4. **Utilities** (Support modules & classes)
28
34
  - **Codecs**: Base58/Base64 encoding, compact integers, little-endian encoding
29
35
  - **PDA**: Program Derived Address generation
30
36
  - **Curve25519**: Native curve operations via FFI
37
+ - **More...**: Checkout `lib/solace/utils`
31
38
 
32
39
  ## Core Components
33
40
 
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
41
  ### Transaction & Message
110
42
 
111
- Transactions contain a message and signatures. Messages contain instructions and metadata.
43
+ 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:
44
+
45
+ 1. Manually fill and order the accounts array
46
+ 2. Manually fill and order the instructions array
47
+ 3. Manually calculate the header
48
+ 4. ...did I forget to say manually?
112
49
 
113
50
  ```ruby
114
51
  # Create a message
@@ -143,7 +80,11 @@ signature = connection.send_transaction(transaction.serialize)
143
80
 
144
81
  ### Instruction
145
82
 
146
- Instructions represent individual operations within a transaction.
83
+ 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:
84
+
85
+ 1. Manually fill and order the accounts indices array
86
+ 2. Manually specify the program index
87
+ 3. Manually specify the data
147
88
 
148
89
  ```ruby
149
90
  instruction = Solace::Instruction.new(
@@ -166,11 +107,9 @@ instruction.data # => [2, 0, 0, 0] + amount_bytes
166
107
 
167
108
  ## Low-Level Instruction Builders
168
109
 
169
- Instruction builders are service objects that create specific instruction types. They handle the binary encoding required by Solana programs.
110
+ 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.
170
111
 
171
- ### System Program Instructions
172
-
173
- #### Transfer Instruction
112
+ 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.
174
113
 
175
114
  ```ruby
176
115
  # Build a SOL transfer instruction
@@ -182,71 +121,33 @@ transfer_ix = Solace::Instructions::SystemProgram::TransferInstruction.build(
182
121
  )
183
122
  ```
184
123
 
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
124
+ Solace includes a number of these, and you can build your own as well.
216
125
 
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
- ```
126
+ - `Solace::Instructions::SystemProgram::TransferInstruction`
127
+ - `Solace::Instructions::SystemProgram::CreateAccountInstruction`
128
+ - `Solace::Instructions::SplToken::InitializeMintInstruction`
129
+ - `Solace::Instructions::SplToken::InitializeAccountInstruction`
130
+ - `Solace::Instructions::SplToken::MintToInstruction`
131
+ - `Solace::Instructions::SplToken::TransferInstruction`
132
+ - `Solace::Instructions::SplToken::TransferCheckedInstruction`
133
+ - `Solace::Instructions::AssociatedTokenAccount::CreateAssociatedTokenAccountInstruction`
240
134
 
241
135
  **Common Patterns:**
242
136
  - All builders use `.build()` class method
137
+ - All builders use `.data()` method to specify the instruction data
138
+ - All builders use named parameters and `_index` suffix for account indices
139
+ - All builders use a `program_index` parameter to specify the program index
243
140
  - Account indices reference the transaction's accounts array
244
141
  - Binary data encoding handled automatically
245
142
  - Instruction-specific data layouts documented in comments
246
143
 
247
- ## High-Level Program Methods
144
+ ## High-Level Program Classes
145
+
146
+ **WARNING: Programs will probably get deprecated in favor of composers in the future.**
147
+
148
+ 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.
248
149
 
249
- Program clients provide convenient interfaces for common operations, handling transaction assembly, signing, and submission.
150
+ For example, the `Solace::Programs::SplToken` class provides a high-level interface for interacting with the SPL Token Program.
250
151
 
251
152
  ### SPL Token Program
252
153
 
@@ -255,31 +156,34 @@ Program clients provide convenient interfaces for common operations, handling tr
255
156
  spl_token = Solace::Programs::SplToken.new(connection: connection)
256
157
 
257
158
  # Create a new token mint
258
- signature = spl_token.create_mint(
159
+ response = spl_token.create_mint(
259
160
  payer: payer_keypair,
260
161
  decimals: 6,
261
162
  mint_authority: authority_keypair,
262
163
  freeze_authority: freeze_keypair, # Optional
263
164
  mint_keypair: mint_keypair # Optional, generates if not provided
264
165
  )
166
+ connection.wait_for_confirmed_signature { response['result'] }
265
167
 
266
168
  # Mint tokens to an account
267
- signature = spl_token.mint_to(
169
+ response = spl_token.mint_to(
268
170
  payer: payer_keypair,
269
171
  mint: mint_keypair,
270
172
  destination: token_account_address,
271
173
  amount: 1_000_000,
272
174
  mint_authority: authority_keypair
273
175
  )
176
+ connection.wait_for_confirmed_signature { response['result'] }
274
177
 
275
178
  # Transfer tokens
276
- signature = spl_token.transfer(
179
+ response = spl_token.transfer(
277
180
  payer: payer_keypair,
278
181
  source: source_token_account,
279
182
  destination: dest_token_account,
280
183
  amount: 500_000,
281
184
  owner: owner_keypair
282
185
  )
186
+ connection.wait_for_confirmed_signature { response['result'] }
283
187
  ```
284
188
 
285
189
  **Key Features:**
@@ -291,7 +195,7 @@ signature = spl_token.transfer(
291
195
 
292
196
  ### Prepare Methods
293
197
 
294
- For more control, use "prepare" methods that return signed transactions without sending:
198
+ For more control, use "prepare" methods that return signed transactions without sending it on the program:
295
199
 
296
200
  ```ruby
297
201
  # Prepare transaction without sending
@@ -308,54 +212,6 @@ puts transaction.serialize # Base64 transaction
308
212
  signature = connection.send_transaction(transaction.serialize)
309
213
  ```
310
214
 
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
215
  ## Utility Modules
360
216
 
361
217
  ### Codecs
@@ -387,9 +243,6 @@ seeds = ['metadata', mint_address, 'edition']
387
243
  program_id = 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'
388
244
 
389
245
  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
246
  ```
394
247
 
395
248
  **Key Features:**
@@ -407,6 +260,8 @@ on_curve = Solace::Utils::Curve25519Dalek.on_curve?(32_byte_point)
407
260
 
408
261
  ## Constants
409
262
 
263
+ **WARNING: Constants will probably get deprecated in favor of config file that developers can use to define their own constants with required values.**
264
+
410
265
  Common Solana program IDs are defined in `Solace::Constants`:
411
266
 
412
267
  ```ruby
@@ -417,6 +272,79 @@ Solace::Constants::SYSVAR_RENT_PROGRAM_ID # 'SysvarRent11111111111
417
272
  Solace::Constants::MEMO_PROGRAM_ID # 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr'
418
273
  ```
419
274
 
275
+ ## Composers
276
+
277
+ 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.
278
+
279
+ ```ruby
280
+ # Initialize a transaction composer
281
+ composer = Solace::TransactionComposer.new(connection: connection)
282
+
283
+ # Add an instruction composer
284
+ composer.add_instruction(
285
+ Solace::Composers::SystemProgramTransferComposer.new(
286
+ to: 'pubkey1',
287
+ from: 'pubkey2',
288
+ lamports: 100
289
+ )
290
+ )
291
+
292
+ # Add another instruction composer
293
+ composer.add_instruction(
294
+ Solace::Composers::SplTokenProgramTransferCheckedComposer.new(
295
+ from: 'pubkey4',
296
+ to: 'pubkey5',
297
+ mint: 'pubkey6',
298
+ authority: 'pubkey7',
299
+ amount: 1_000_000,
300
+ decimals: 6
301
+ )
302
+ )
303
+
304
+ # Set the fee payer
305
+ composer.set_fee_payer('pubkey8')
306
+
307
+ # Compose the transaction
308
+ tx = composer.compose_transaction
309
+
310
+ # Sign the transaction with all required signers
311
+ tx.sign(*any_required_signers)
312
+ ```
313
+
314
+ 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.
315
+
316
+ ```ruby
317
+ class MyProgramComposer < Solace::Composers::Base
318
+ # All keyword arguments are passed to the constructor and available
319
+ # as a `params` hash.
320
+ #
321
+ # The setup_accounts method is called automatically by the transaction composer
322
+ # during compilation and should be used to add accounts to the account_context
323
+ # with the appropriate access permissions. Conditional logic is fine here given
324
+ # and available params to determine the access permissions.
325
+ def setup_accounts
326
+ account_context.add_writable_signer(params[:from])
327
+ account_context.add_writable_nonsigner(params[:to])
328
+ account_context.add_readonly_nonsigner(params[:program])
329
+ end
330
+
331
+ # The build_instruction method is called automatically by the transaction composer
332
+ # during compilation and should be used to build the instruction using an instruction builder.
333
+ #
334
+ # The passed context to the build_instruction method provides the indices of all accounts
335
+ # that were added to the account_context in the setup_accounts method. These are accessible
336
+ # by the index_of method of the context using the account address as a parameter.
337
+ def build_instruction(context)
338
+ Solace::Instructions::MyProgram::MyInstruction.build(
339
+ data: params[:data],
340
+ from_index: context.index_of(params[:from]),
341
+ to_index: context.index_of(params[:to]),
342
+ program_index: context.index_of(params[:program])
343
+ )
344
+ end
345
+ end
346
+ ```
347
+
420
348
  ## Practical Examples
421
349
 
422
350
  ### Complete SOL Transfer
@@ -425,12 +353,15 @@ Solace::Constants::MEMO_PROGRAM_ID # 'MemoSq4gqABAXKb96qnH8
425
353
  require 'solace'
426
354
 
427
355
  # Setup
428
- connection = Solace::Connection.new('https://api.devnet.solana.com')
429
356
  payer = Solace::Keypair.generate
430
357
  recipient = Solace::Keypair.generate
431
358
 
359
+ # Create connection
360
+ connection = Solace::Connection.new('https://api.devnet.solana.com')
361
+
432
362
  # Fund payer (devnet only)
433
- connection.request_airdrop(payer.address, 1_000_000_000)
363
+ response = connection.request_airdrop(payer.address, 1_000_000_000)
364
+ connection.wait_for_confirmed_signature('finalized') { response['result'] }
434
365
 
435
366
  # Build transfer instruction
436
367
  transfer_ix = Solace::Instructions::SystemProgram::TransferInstruction.build(
@@ -455,9 +386,9 @@ message = Solace::Message.new(
455
386
  # Sign and send
456
387
  transaction = Solace::Transaction.new(message: message)
457
388
  transaction.sign(payer)
458
- signature = connection.send_transaction(transaction.serialize)
459
389
 
460
- puts "Transaction: #{signature}"
390
+ response = connection.send_transaction(transaction.serialize)
391
+ puts "Transaction: #{response['result']}"
461
392
  ```
462
393
 
463
394
  ### Complete Token Mint Creation
@@ -466,16 +397,19 @@ puts "Transaction: #{signature}"
466
397
  require 'solace'
467
398
 
468
399
  # Setup
469
- connection = Solace::Connection.new('https://api.devnet.solana.com')
470
400
  payer = Solace::Keypair.generate
471
401
  mint_keypair = Solace::Keypair.generate
472
402
 
403
+ # Create connection
404
+ connection = Solace::Connection.new('https://api.devnet.solana.com')
405
+
473
406
  # Fund payer
474
- connection.request_airdrop(payer.address, 1_000_000_000)
407
+ response = connection.request_airdrop(payer.address, 1_000_000_000)
408
+ connection.wait_for_confirmed_signature('finalized') { response['result'] }
475
409
 
476
410
  # High-level approach
477
- spl_token = Solace::Programs::SplToken.new(connection: connection)
478
- signature = spl_token.create_mint(
411
+ program = Solace::Programs::SplToken.new(connection: connection)
412
+ signature = program.create_mint(
479
413
  payer: payer,
480
414
  decimals: 6,
481
415
  mint_authority: payer,
@@ -487,49 +421,6 @@ puts "Mint created: #{mint_keypair.address}"
487
421
  puts "Transaction: #{signature}"
488
422
  ```
489
423
 
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
424
  ## Design Patterns
534
425
 
535
426
  ### Service Objects
@@ -539,43 +430,6 @@ Instruction builders follow the service object pattern:
539
430
  - Consistent `.build()` interface
540
431
  - Separate `.data()` methods for instruction data
541
432
 
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
433
  ## Testing Support
580
434
 
581
435
  The SDK includes comprehensive test utilities:
@@ -597,6 +451,7 @@ connection.wait_for_confirmed_signature { response['result'] }
597
451
  ## Dependencies
598
452
 
599
453
  - **base58**: Base58 encoding/decoding
454
+ - **base64**: Base64 encoding/decoding
600
455
  - **rbnacl**: Ed25519 cryptography
601
456
  - **ffi**: Foreign Function Interface for native libraries
602
457
  - **json**: JSON parsing for RPC