solace 0.1.4 → 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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solace/composers/associated_token_account_program_create_account_composer.rb +11 -10
  3. data/lib/solace/composers/associated_token_account_program_create_idempotent_account_composer.rb +2 -1
  4. data/lib/solace/composers/base.rb +1 -1
  5. data/lib/solace/composers/spl_token_program_close_account_composer.rb +3 -3
  6. data/lib/solace/composers/spl_token_program_initialize_mint_composer.rb +5 -5
  7. data/lib/solace/composers/spl_token_program_mint_to_composer.rb +4 -4
  8. data/lib/solace/composers/spl_token_program_transfer_checked_composer.rb +6 -6
  9. data/lib/solace/composers/spl_token_program_transfer_composer.rb +4 -4
  10. data/lib/solace/composers/system_program_create_account_composer.rb +5 -5
  11. data/lib/solace/composers/system_program_transfer_composer.rb +3 -3
  12. data/lib/solace/composers/token_2022_program_close_account_composer.rb +75 -0
  13. data/lib/solace/composers/token_2022_program_initialize_mint_composer.rb +93 -0
  14. data/lib/solace/composers/token_2022_program_mint_to_composer.rb +84 -0
  15. data/lib/solace/composers/token_2022_program_transfer_checked_composer.rb +109 -0
  16. data/lib/solace/composers/token_2022_program_transfer_composer.rb +86 -0
  17. data/lib/solace/connection.rb +29 -9
  18. data/lib/solace/constants.rb +8 -2
  19. data/lib/solace/errors/confirmation_timeout.rb +4 -4
  20. data/lib/solace/errors/rpc_error.rb +4 -4
  21. data/lib/solace/instructions/associated_token_account/create_account_instruction.rb +2 -1
  22. data/lib/solace/instructions/spl_token/close_account_instruction.rb +2 -2
  23. data/lib/solace/instructions/spl_token/initialize_account_instruction.rb +2 -2
  24. data/lib/solace/instructions/spl_token/initialize_mint_instruction.rb +2 -2
  25. data/lib/solace/instructions/spl_token/mint_to_instruction.rb +2 -2
  26. data/lib/solace/instructions/spl_token/transfer_checked_instruction.rb +3 -3
  27. data/lib/solace/instructions/spl_token/transfer_instruction.rb +2 -2
  28. data/lib/solace/instructions/system_program/create_account_instruction.rb +2 -2
  29. data/lib/solace/instructions/system_program/transfer_instruction.rb +2 -2
  30. data/lib/solace/instructions/token_2022/close_account_instruction.rb +50 -0
  31. data/lib/solace/instructions/token_2022/initialize_account_instruction.rb +62 -0
  32. data/lib/solace/instructions/token_2022/initialize_mint_instruction.rb +75 -0
  33. data/lib/solace/instructions/token_2022/mint_to_instruction.rb +59 -0
  34. data/lib/solace/instructions/token_2022/transfer_checked_instruction.rb +68 -0
  35. data/lib/solace/instructions/token_2022/transfer_instruction.rb +71 -0
  36. data/lib/solace/message.rb +5 -5
  37. data/lib/solace/programs/associated_token_account.rb +35 -17
  38. data/lib/solace/programs/spl_token.rb +18 -254
  39. data/lib/solace/programs/token_2022.rb +70 -0
  40. data/lib/solace/programs/token_program_interface.rb +312 -0
  41. data/lib/solace/serializers/address_lookup_table_deserializer.rb +2 -2
  42. data/lib/solace/serializers/base_deserializer.rb +1 -1
  43. data/lib/solace/serializers/instruction_deserializer.rb +2 -2
  44. data/lib/solace/serializers/message_deserializer.rb +3 -3
  45. data/lib/solace/serializers/transaction_deserializer.rb +1 -1
  46. data/lib/solace/tokens/token.rb +1 -1
  47. data/lib/solace/tokens.rb +2 -2
  48. data/lib/solace/transaction.rb +1 -1
  49. data/lib/solace/transaction_composer.rb +5 -5
  50. data/lib/solace/utils/account_context.rb +9 -9
  51. data/lib/solace/utils/codecs.rb +309 -49
  52. data/lib/solace/utils/rpc_client.rb +9 -9
  53. data/lib/solace/version.rb +1 -1
  54. data/lib/solace.rb +2 -0
  55. metadata +124 -9
  56. data/CHANGELOG +0 -226
  57. data/LICENSE +0 -21
  58. data/README.md +0 -518
@@ -24,23 +24,204 @@ module Solace
24
24
  # @see Solace::Keypair
25
25
  # @since 0.0.1
26
26
  module Utils
27
- # Module for encoding and decoding data
27
+ # Module for encoding and decoding data.
28
+ #
29
+ # The helpers are grouped by category: base64/base58 string encodings,
30
+ # fixed-width little-endian integers, the Solana compact-u16 (shortvec)
31
+ # varint, length-prefixed byte/pubkey collections, and optionals.
32
+ #
33
+ # Serialization formats referenced below:
34
+ # - "Borsh" — the Anchor serialization spec. Borsh encodes `bool` as a single
35
+ # 0/1 byte, `Vec<T>`/`bytes` with a u32 little-endian length prefix, and
36
+ # `Option<T>` as a 1-byte discriminant (0 = None, 1 = Some) followed by the
37
+ # value. Methods that produce these layouts say so explicitly.
38
+ # - "SmallVec" — a Solana/Anchor-program convention (e.g. Squads) that prefixes
39
+ # a collection with a u8 or u16 length instead of Borsh's u32. NOT Borsh.
40
+ # - "compact-u16" / "shortvec" — Solana's own variable-length integer used in
41
+ # the transaction wire format. NOT Borsh.
42
+ #
43
+ # `extend self` exposes every method both as a module method
44
+ # (Solace::Utils::Codecs.<method>) and as an instance method when the module is
45
+ # included into a composed encoder/decoder.
28
46
  #
29
47
  # @since 0.0.1
30
48
  module Codecs
49
+ extend self
50
+
51
+ # --- Base64 -----------------------------------------------------------
52
+
31
53
  # Creates a StringIO from a base64 string.
32
54
  #
33
55
  # @param base64 [String] The base64 string to decode
34
56
  # @return [StringIO] A StringIO object containing the decoded bytes
35
- def self.base64_to_bytestream(base64)
57
+ def base64_to_bytestream(base64)
36
58
  StringIO.new(Base64.decode64(base64))
37
59
  end
38
60
 
39
- # Encodes a compact-u16 value in a compact form (shortvec)
61
+ # --- Base58 -----------------------------------------------------------
62
+
63
+ # Encodes a binary string in Base58 format.
64
+ #
65
+ # @param binary [String] The bytes to encode
66
+ # @return [String] The Base58 encoded string
67
+ def binary_to_base58(binary)
68
+ Base58.binary_to_base58(binary, :bitcoin)
69
+ end
70
+
71
+ # Decodes a Base58 string into a binary string
72
+ #
73
+ # @param string [String] The Base58 encoded string
74
+ # @return [String] The decoded binary string
75
+ def base58_to_binary(string)
76
+ base58_to_bytes(string).pack('C*')
77
+ end
78
+
79
+ # Encodes a byte array in Base58 format
80
+ #
81
+ # @param bytes [Array<Integer>] The bytes to encode
82
+ # @return [String] The Base58 encoded string
83
+ def bytes_to_base58(bytes)
84
+ binary_to_base58(bytes.pack('C*'))
85
+ end
86
+
87
+ # Decodes a Base58 string into a sequence of bytes
88
+ #
89
+ # @param string [String] The Base58 encoded string
90
+ # @return [Array<Integer>] The decoded bytes
91
+ def base58_to_bytes(string)
92
+ Base58.base58_to_binary(string, :bitcoin).bytes
93
+ end
94
+
95
+ # Checks if a string is a valid Base58 string
96
+ #
97
+ # @param string [String] The string to check
98
+ # @return [Boolean] True if the string is a valid Base58 string, false otherwise
99
+ def valid_base58?(string)
100
+ return false if string.nil? || string.empty?
101
+
102
+ Base58.decode(string)
103
+ true
104
+ rescue StandardError => _e
105
+ false
106
+ end
107
+
108
+ # --- Fixed-width little-endian integers -------------------------------
109
+
110
+ # Encodes a u8 as a single byte.
111
+ #
112
+ # @param byte [Integer] Value in range 0..255.
113
+ # @return [Array<Integer>] A single-element byte array.
114
+ def encode_u8(byte)
115
+ [byte]
116
+ end
117
+
118
+ # Decodes a u8 from 1 byte.
119
+ #
120
+ # @param stream [IO, StringIO] The stream to read from.
121
+ # @return [Integer] Value in range 0..255.
122
+ def decode_u8(stream)
123
+ stream.read(1).unpack1('C')
124
+ end
125
+
126
+ # Encodes a u16 as 2 little-endian bytes.
127
+ #
128
+ # @param u16 [Integer] Value in range 0..65535.
129
+ # @return [String] 2-byte little-endian binary string.
130
+ def encode_le_u16(u16)
131
+ [u16].pack('S<')
132
+ end
133
+
134
+ # Decodes a u16 from 2 little-endian bytes.
135
+ #
136
+ # @param stream [IO, StringIO] The stream to read from.
137
+ # @return [Integer] Value in range 0..65535.
138
+ def decode_le_u16(stream)
139
+ stream.read(2).unpack1('S<')
140
+ end
141
+
142
+ # Encodes a u32 as 4 little-endian bytes.
143
+ #
144
+ # @param u32 [Integer] Value in range 0..4294967295.
145
+ # @return [String] 4-byte little-endian binary string.
146
+ def encode_le_u32(u32)
147
+ [u32].pack('L<')
148
+ end
149
+
150
+ # Decodes a u32 from 4 little-endian bytes.
151
+ #
152
+ # @param stream [IO, StringIO] The stream to read from.
153
+ # @return [Integer] Value in range 0..4294967295.
154
+ def decode_le_u32(stream)
155
+ stream.read(4).unpack1('L<')
156
+ end
157
+
158
+ # Encodes a u64 value in little-endian format
159
+ #
160
+ # @param u64 [Integer] The u64 value to encode
161
+ # @return [String] The little-endian encoded u64 value
162
+ def encode_le_u64(u64)
163
+ [u64].pack('Q<') # 64-bit little-endian
164
+ end
165
+
166
+ # Decodes a little-endian u64 value from a sequence of bytes
167
+ #
168
+ # @param stream [IO, StringIO] The input to read bytes from.
169
+ # @return [Integer] The decoded u64 value
170
+ def decode_le_u64(stream)
171
+ stream.read(8).unpack1('Q<')
172
+ end
173
+
174
+ # Encodes a u128 as 16 little-endian bytes (two u64 words, low word first).
175
+ #
176
+ # @param u128 [Integer] Value in range 0..2**128-1.
177
+ # @return [String] 16-byte little-endian binary string.
178
+ def encode_le_u128(u128)
179
+ [u128 & 0xFFFFFFFFFFFFFFFF, u128 >> 64].pack('Q<Q<')
180
+ end
181
+
182
+ # Decodes a u128 from 16 little-endian bytes (two u64 words, low word first).
183
+ #
184
+ # @param stream [IO, StringIO] The stream to read from.
185
+ # @return [Integer] Value in range 0..2**128-1.
186
+ def decode_le_u128(stream)
187
+ lo, hi = stream.read(16).unpack('Q<Q<')
188
+ lo + (hi << 64)
189
+ end
190
+
191
+ # Encodes an i64 as 8 little-endian bytes (two's complement).
192
+ #
193
+ # @param i64 [Integer] Value in range -2**63..2**63-1.
194
+ # @return [String] 8-byte little-endian binary string.
195
+ def encode_le_i64(i64)
196
+ [i64].pack('q<')
197
+ end
198
+
199
+ # Decodes an i64 from 8 little-endian bytes (two's complement).
200
+ #
201
+ # @param stream [IO, StringIO] The stream to read from.
202
+ # @return [Integer] Value in range -2**63..2**63-1.
203
+ def decode_le_i64(stream)
204
+ stream.read(8).unpack1('q<')
205
+ end
206
+
207
+ # --- Boolean ----------------------------------------------------------
208
+
209
+ # Encodes a Borsh bool as a single byte: false → 0, true → 1.
210
+ #
211
+ # @param bool [Boolean] The value to encode.
212
+ # @return [Array<Integer>] A single-element byte array.
213
+ def encode_bool(bool)
214
+ [bool ? 1 : 0]
215
+ end
216
+
217
+ # --- compact-u16 (Solana shortvec varint) -----------------------------
218
+
219
+ # Encodes an integer as a compact-u16 (shortvec) varint. This is Solana's
220
+ # transaction wire-format length prefix, NOT Borsh.
40
221
  #
41
222
  # @param u16 [Integer] The compact-u16 value to encode
42
223
  # @return [String] The compactly encoded compact-u16 value
43
- def self.encode_compact_u16(u16)
224
+ def encode_compact_u16(u16)
44
225
  out = []
45
226
 
46
227
  loop do
@@ -74,23 +255,23 @@ module Solace
74
255
  out.pack('C*')
75
256
  end
76
257
 
77
- # Decodes a compact-u16 (ShortVec) value from an IO-like object.
258
+ # Decodes a compact-u16 (shortvec) value from an IO-like object.
78
259
  #
79
260
  # Reads bytes one at a time, accumulating the result until the MSB is 0.
80
261
  #
81
262
  # @param stream [IO, StringIO] The input to read bytes from.
82
263
  # @return [Integer, Integer] The decoded value and the number of bytes read.
83
- def self.decode_compact_u16(stream)
84
- value = 0
85
- shift = 0
264
+ def decode_compact_u16(stream)
265
+ value = 0
266
+ shift = 0
86
267
  bytes_read = 0
87
268
 
88
269
  loop do
89
270
  byte = stream.read(1)
90
271
  raise EOFError, 'Unexpected end of input while decoding compact-u16' unless byte
91
272
 
92
- byte = byte.ord
93
- value |= (byte & 0x7F) << shift
273
+ byte = byte.ord
274
+ value |= (byte & 0x7F) << shift
94
275
  bytes_read += 1
95
276
  break if byte.nobits?(0x80)
96
277
 
@@ -100,65 +281,144 @@ module Solace
100
281
  [value, bytes_read]
101
282
  end
102
283
 
103
- # Encodes a u64 value in little-endian format
284
+ # --- Length-prefixed byte sequences -----------------------------------
285
+
286
+ # Encodes a Borsh bytes field / Vec<u8>: u32 LE length prefix + raw bytes.
104
287
  #
105
- # @param u64 [Integer] The u64 value to encode
106
- # @return [String] The little-endian encoded u64 value
107
- def self.encode_le_u64(u64)
108
- [u64].pack('Q<') # 64-bit little-endian
288
+ # @param bytes [Array<Integer>] The raw bytes.
289
+ # @return [Array<Integer>]
290
+ def encode_bytes(bytes)
291
+ encode_le_u32(bytes.length).bytes + bytes
109
292
  end
110
293
 
111
- # Decodes a little-endian u64 value from a sequence of bytes
294
+ # Decodes a Borsh bytes / Vec<u8> field: u32 LE length prefix + raw bytes.
112
295
  #
113
- # @param stream [IO, StringIO] The input to read bytes from.
114
- # @return [Integer] The decoded u64 value
115
- def self.decode_le_u64(stream)
116
- stream.read(8).unpack1('Q<')
296
+ # @param stream [IO, StringIO] The stream to read from.
297
+ # @return [String] The raw bytes as a binary string.
298
+ def decode_bytes(stream)
299
+ stream.read(decode_le_u32(stream))
117
300
  end
118
301
 
119
- # Encodes a sequence of bytes in Base58 format
302
+ # Encodes a SmallVec<u8, u8>: u8 length prefix + raw bytes. SmallVec is a
303
+ # Solana/Anchor-program convention, NOT Borsh (which would use a u32 prefix).
120
304
  #
121
- # @param binary [String] The bytes to encode
122
- # @return [String] The Base58 encoded string
123
- def self.binary_to_base58(binary)
124
- Base58.binary_to_base58(binary, :bitcoin)
305
+ # @param bytes [Array<Integer>] The raw bytes (max 255).
306
+ # @return [Array<Integer>]
307
+ def encode_smallvec_u8_bytes(bytes)
308
+ [bytes.length] + bytes
125
309
  end
126
310
 
127
- # Decodes a Base58 string into a binary string
311
+ # Encodes a SmallVec<u16, u8>: u16 LE length prefix + raw bytes. SmallVec is a
312
+ # Solana/Anchor-program convention, NOT Borsh (which would use a u32 prefix).
128
313
  #
129
- # @param string [String] The Base58 encoded string
130
- # @return [String] The decoded binary string
131
- def self.base58_to_binary(string)
132
- base58_to_bytes(string).pack('C*')
314
+ # @param bytes [Array<Integer>] The raw bytes (max 65535).
315
+ # @return [Array<Integer>]
316
+ def encode_smallvec_u16_bytes(bytes)
317
+ encode_le_u16(bytes.length).bytes + bytes
133
318
  end
134
319
 
135
- # Encodes a sequence of bytes in Base58 format
320
+ # --- Public keys ------------------------------------------------------
321
+
322
+ # Encodes a public key as 32 raw bytes (a Solana primitive, not a Borsh
323
+ # type). Accepts any representation that resolves to a base58 string via
324
+ # #to_s (String, Keypair, PublicKey).
136
325
  #
137
- # @param bytes [String] The bytes to encode
138
- # @return [String] The Base58 encoded string
139
- def self.bytes_to_base58(bytes)
140
- binary_to_base58(bytes.pack('C*'))
326
+ # @param pubkey [#to_s] The public key in any representation.
327
+ # @return [Array<Integer>] 32 bytes.
328
+ def encode_pubkey(pubkey)
329
+ base58_to_bytes(pubkey.to_s)
141
330
  end
142
331
 
143
- # Decodes a Base58 string into a sequence of bytes
332
+ # Decodes a public key from 32 bytes.
144
333
  #
145
- # @param string [String] The Base58 encoded string
146
- # @return [String] The decoded bytes
147
- def self.base58_to_bytes(string)
148
- Base58.base58_to_binary(string, :bitcoin).bytes
334
+ # @param stream [IO, StringIO] The stream to read from.
335
+ # @return [String] Base58 public key.
336
+ def decode_pubkey(stream)
337
+ bytes_to_base58(stream.read(32).bytes)
149
338
  end
150
339
 
151
- # Checks if a string is a valid Base58 string
340
+ # Encodes a Borsh Vec<publicKey>: u32 LE count prefix followed by each
341
+ # 32-byte pubkey.
152
342
  #
153
- # @param string [String] The string to check
154
- # @return [Boolean] True if the string is a valid Base58 string, false otherwise
155
- def self.valid_base58?(string)
156
- return false if string.nil? || string.empty?
343
+ # @param pubkeys [Array<#to_s>] The public keys in any representation.
344
+ # @return [Array<Integer>]
345
+ def encode_vec_pubkeys(pubkeys)
346
+ encode_le_u32(pubkeys.length).bytes +
347
+ pubkeys.flat_map { |pubkey| encode_pubkey(pubkey) }
348
+ end
157
349
 
158
- Base58.decode(string)
159
- true
160
- rescue StandardError => _e
161
- false
350
+ # Decodes a Borsh Vec<publicKey>: u32 LE count prefix followed by each
351
+ # 32-byte pubkey.
352
+ #
353
+ # @param stream [IO, StringIO] The stream to read from.
354
+ # @return [Array<String>] Base58 public keys.
355
+ def decode_vec_pubkeys(stream)
356
+ Array.new(decode_le_u32(stream)) { decode_pubkey(stream) }
357
+ end
358
+
359
+ # Encodes a SmallVec<u8, Pubkey>: u8 count prefix followed by each 32-byte
360
+ # pubkey. SmallVec is a Solana convention (NOT Borsh); used by the
361
+ # transaction message header's account_keys (distinct from
362
+ # encode_vec_pubkeys, which uses Borsh's u32 count).
363
+ #
364
+ # @param pubkeys [Array<#to_s>] The public keys in any representation (max 255).
365
+ # @return [Array<Integer>]
366
+ def encode_smallvec_u8_pubkeys(pubkeys)
367
+ [pubkeys.length] + pubkeys.flat_map { |pubkey| encode_pubkey(pubkey) }
368
+ end
369
+
370
+ # --- Optionals (Borsh Option<T>) --------------------------------------
371
+
372
+ # Encodes a Borsh Option<publicKey>: None → [0], Some(key) → [1] + 32 bytes.
373
+ #
374
+ # @param pubkey [#to_s, nil] Base58 public key or nil.
375
+ # @return [Array<Integer>]
376
+ def encode_option_pubkey(pubkey)
377
+ return [0] if pubkey.nil?
378
+
379
+ [1] + encode_pubkey(pubkey)
380
+ end
381
+
382
+ # Decodes a Borsh Option<publicKey>: None → nil, Some(key) → base58 pubkey.
383
+ #
384
+ # @param stream [IO, StringIO] The stream to read from.
385
+ # @return [String, nil] Base58 public key or nil.
386
+ def decode_option_pubkey(stream)
387
+ return nil if decode_u8(stream).zero?
388
+
389
+ decode_pubkey(stream)
390
+ end
391
+
392
+ # Encodes a Borsh Option<i64>: None → [0], Some(i64) → [1] + 8 LE bytes.
393
+ #
394
+ # @param i64 [Integer, nil]
395
+ # @return [Array<Integer>]
396
+ def encode_option_i64(i64)
397
+ return [0] if i64.nil?
398
+
399
+ [1] + encode_le_i64(i64).bytes
400
+ end
401
+
402
+ # Decodes a Borsh Option<i64>: None → nil, Some(i64) → integer.
403
+ #
404
+ # @param stream [IO, StringIO] The stream to read from.
405
+ # @return [Integer, nil]
406
+ def decode_option_i64(stream)
407
+ return nil if decode_u8(stream).zero?
408
+
409
+ decode_le_i64(stream)
410
+ end
411
+
412
+ # Encodes a Borsh Option<String>:
413
+ # None → [0], Some(str) → [1] + u32 LE length + UTF-8 bytes.
414
+ #
415
+ # @param str [String, nil]
416
+ # @return [Array<Integer>]
417
+ def encode_option_string(str)
418
+ return [0] if str.nil?
419
+
420
+ bytes = str.encode('UTF-8').bytes
421
+ [1] + encode_le_u32(bytes.length).bytes + bytes
162
422
  end
163
423
  end
164
424
  end
@@ -35,7 +35,7 @@ module Solace
35
35
  open_timeout:,
36
36
  read_timeout:
37
37
  )
38
- @url = url
38
+ @url = url
39
39
  @open_timeout = open_timeout
40
40
  @read_timeout = read_timeout
41
41
  end
@@ -52,7 +52,7 @@ module Solace
52
52
  # Solace::Errors::ConfirmationTimeout
53
53
  # ]
54
54
  def rpc_request(method, params = [])
55
- request = build_rpc_request(method, params)
55
+ request = build_rpc_request(method, params)
56
56
  response = perform_http_request(*request)
57
57
  handle_rpc_response(response)
58
58
  end
@@ -67,10 +67,10 @@ module Solace
67
67
  def build_rpc_request(method, params)
68
68
  uri = URI(url)
69
69
 
70
- req = Net::HTTP::Post.new(uri)
71
- req['Accept'] = 'application/json'
70
+ req = Net::HTTP::Post.new(uri)
71
+ req['Accept'] = 'application/json'
72
72
  req['Content-Type'] = 'application/json'
73
- req.body = build_request_body(method, params)
73
+ req.body = build_request_body(method, params)
74
74
 
75
75
  [uri, req]
76
76
  end
@@ -83,9 +83,9 @@ module Solace
83
83
  def build_request_body(method, params)
84
84
  {
85
85
  jsonrpc: '2.0',
86
- id: SecureRandom.uuid,
87
- method: method,
88
- params: params
86
+ id: SecureRandom.uuid,
87
+ method: method,
88
+ params: params
89
89
  }.to_json
90
90
  end
91
91
 
@@ -99,7 +99,7 @@ module Solace
99
99
  Net::HTTP.start(
100
100
  uri.hostname,
101
101
  uri.port,
102
- use_ssl: uri.scheme == 'https',
102
+ use_ssl: uri.scheme == 'https',
103
103
  open_timeout: open_timeout,
104
104
  read_timeout: read_timeout
105
105
  ) do |http|
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Solace
4
4
  # Latest version of the Solace gem.
5
- VERSION = '0.1.4'
5
+ VERSION = '0.1.6'
6
6
  end
data/lib/solace.rb CHANGED
@@ -68,5 +68,7 @@ Dir[File.join(__dir__, 'solace/composers', '**', '*.rb')].each { |file| require
68
68
  Dir[File.join(__dir__, 'solace/instructions', '**', '*.rb')].each { |file| require file }
69
69
 
70
70
  # Programs
71
+ require_relative 'solace/programs/token_program_interface'
71
72
  require_relative 'solace/programs/spl_token'
73
+ require_relative 'solace/programs/token_2022'
72
74
  require_relative 'solace/programs/associated_token_account'