Module: Solace::Utils::Codecs

Extended by:
Codecs
Included in:
Codecs
Defined in:
lib/solace/squads_smart_accounts/codecs_extensions.rb

Overview

Extensions to Solace::Utils::Codecs for Anchor programs and Borsh types not covered by the base gem. Candidates for upstreaming to solace when the need is confirmed across other extension gems.

Instance Method Summary collapse

Instance Method Details

#decode_le_i64(stream) ⇒ Integer

Decodes an i64 from 8 little-endian bytes (two’s complement).

Parameters:

  • stream (IO, StringIO)

    The stream to read from.

Returns:

  • (Integer)

    Value in range -2**63..2**63-1.



180
181
182
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 180

def decode_le_i64(stream)
  stream.read(8).unpack1('q<')
end

#decode_le_u128(stream) ⇒ Integer

Decodes a u128 from 16 little-endian bytes (two u64 words, low word first).

Parameters:

  • stream (IO, StringIO)

    The stream to read from.

Returns:

  • (Integer)

    Value in range 0..2**128-1.



220
221
222
223
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 220

def decode_le_u128(stream)
  lo, hi = stream.read(16).unpack('Q<Q<')
  lo + (hi << 64)
end

#decode_le_u16(stream) ⇒ Integer

Decodes a u16 from 2 little-endian bytes.

Parameters:

  • stream (IO, StringIO)

    The stream to read from.

Returns:

  • (Integer)

    Value in range 0..65535.



204
205
206
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 204

def decode_le_u16(stream)
  stream.read(2).unpack1('S<')
end

#decode_le_u32(stream) ⇒ Integer

Decodes a u32 from 4 little-endian bytes.

Parameters:

  • stream (IO, StringIO)

    The stream to read from.

Returns:

  • (Integer)

    Value in range 0..4294967295.



212
213
214
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 212

def decode_le_u32(stream)
  stream.read(4).unpack1('L<')
end

#decode_option_pubkey(stream) ⇒ String?

Decodes an Option<publicKey> in Borsh format. None → nil, Some(key) → base58 pubkey.

Parameters:

  • stream (IO, StringIO)

    The stream to read from.

Returns:

  • (String, nil)

    Base58 public key or nil.



238
239
240
241
242
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 238

def decode_option_pubkey(stream)
  return nil if decode_u8(stream).zero?

  decode_pubkey(stream)
end

#decode_pubkey(stream) ⇒ String

Decodes a public key from 32 bytes.

Parameters:

  • stream (IO, StringIO)

    The stream to read from.

Returns:

  • (String)

    Base58 public key.



229
230
231
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 229

def decode_pubkey(stream)
  Solace::Utils::Codecs.bytes_to_base58(stream.read(32).bytes)
end

#decode_smart_account_signers(stream) ⇒ Array<SquadsSmartAccounts::SmartAccountSigner>

Decodes a Vec<SmartAccountSigner> in Borsh format. u32 length prefix followed by each signer’s 32-byte pubkey + 1-byte permission mask.

Parameters:

  • stream (IO, StringIO)

    The stream to read from.

Returns:



249
250
251
252
253
254
255
256
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 249

def (stream)
  Array.new(decode_le_u32(stream)) do
    SquadsSmartAccounts::SmartAccountSigner.new(
      pubkey:     decode_pubkey(stream),
      permission: decode_u8(stream)
    )
  end
end

#decode_u8(stream) ⇒ Integer

Decodes a u8 from 1 byte.

Parameters:

  • stream (IO, StringIO)

    The stream to read from.

Returns:

  • (Integer)

    Value in range 0..255.



196
197
198
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 196

def decode_u8(stream)
  stream.read(1).unpack1('C')
end

#decode_vec_pubkeys(stream) ⇒ Array<String>

Decodes a Vec<publicKey> in Borsh format.

Parameters:

  • stream (IO, StringIO)

    The stream to read from.

Returns:

  • (Array<String>)

    Base58 public keys.



188
189
190
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 188

def decode_vec_pubkeys(stream)
  Array.new(decode_le_u32(stream)) { decode_pubkey(stream) }
end

#encode_bool(bool) ⇒ Array<Integer>

Encodes a Borsh bool as a single byte: false → 0, true → 1.

Parameters:

  • bool (Boolean)

    The value to encode.

Returns:

  • (Array<Integer>)

    A single-element byte array.



55
56
57
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 55

def encode_bool(bool)
  [bool ? 1 : 0]
end

#encode_bytes(bytes) ⇒ Array<Integer>

Encodes a Borsh bytes field: u32 LE length prefix + raw bytes.

Parameters:

  • bytes (Array<Integer>)

    The raw bytes.

Returns:

  • (Array<Integer>)


71
72
73
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 71

def encode_bytes(bytes)
  encode_le_u32(bytes.length).bytes + bytes
end

#encode_compiled_instructions(instructions) ⇒ Array<Integer>

Encodes a SmallVec<u8, CompiledInstruction> — the wire format the Squads program expects for synchronously executed inner instructions.

NOTE: this intentionally does NOT reuse Solace’s InstructionSerializer. That serializer produces the Solana transaction wire format, which uses compact-u16 (varint) length prefixes for the vec count, account indexes, and data. The Squads SmallVec format uses fixed-width prefixes instead: u8 for the vec count, u8 for the account indexes length, and u16 LE for the data length. The two encodings coincide for lengths < 128 (compact-u16 encodes those as a single byte) but diverge beyond that, so reusing the Solana format would corrupt larger instructions silently.

Each instruction is a Instruction whose program_index and accounts are indexes into the full remaining-accounts list (signers included). Layout per instruction: u8 program_id_index + SmallVec<u8,u8> account indexes + SmallVec<u16,u8> data.

Parameters:

  • instructions (Array<Solace::Instruction>)

Returns:

  • (Array<Integer>)


167
168
169
170
171
172
173
174
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 167

def encode_compiled_instructions(instructions)
  [instructions.length] +
    instructions.flat_map do |ix|
      [ix.program_index] +
        encode_smallvec_u8_bytes(ix.accounts) +
        encode_smallvec_u16_bytes(ix.data)
    end
end

#encode_le_i64(i64) ⇒ String

Encodes an i64 as 8 little-endian bytes (two’s complement).

Parameters:

  • i64 (Integer)

    Value in range -2**63..2**63-1.

Returns:

  • (String)

    8-byte little-endian binary string.



47
48
49
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 47

def encode_le_i64(i64)
  [i64].pack('q<')
end

#encode_le_u128(u128) ⇒ String

Encodes a u128 as 16 little-endian bytes (two u64 words, low word first).

Parameters:

  • u128 (Integer)

    Value in range 0..2**128-1.

Returns:

  • (String)

    16-byte little-endian binary string.



63
64
65
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 63

def encode_le_u128(u128)
  [u128 & 0xFFFFFFFFFFFFFFFF, u128 >> 64].pack('Q<Q<')
end

#encode_le_u16(u16) ⇒ String

Encodes a u16 as 2 little-endian bytes.

Parameters:

  • u16 (Integer)

    Value in range 0..65535.

Returns:

  • (String)

    2-byte little-endian binary string.



23
24
25
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 23

def encode_le_u16(u16)
  [u16].pack('S<')
end

#encode_le_u32(u32) ⇒ String

Encodes a u32 as 4 little-endian bytes.

Parameters:

  • u32 (Integer)

    Value in range 0..4294967295.

Returns:

  • (String)

    4-byte little-endian binary string.



39
40
41
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 39

def encode_le_u32(u32)
  [u32].pack('L<')
end

#encode_option_pubkey(pubkey) ⇒ Array<Integer>

Encodes an Option<publicKey> in Borsh format. None → [0], Some(key) → [1] + 32 bytes.

Parameters:

  • pubkey (String, nil)

    Base58 public key or nil.

Returns:

  • (Array<Integer>)


101
102
103
104
105
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 101

def encode_option_pubkey(pubkey)
  return [0] if pubkey.nil?

  [1] + encode_pubkey(pubkey)
end

#encode_option_string(str) ⇒ Array<Integer>

Encodes an Option<String> in Borsh format. None → [0], Some(str) → [1] + u32 length + UTF-8 bytes.

Parameters:

  • str (String, nil)

Returns:

  • (Array<Integer>)


80
81
82
83
84
85
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 80

def encode_option_string(str)
  return [0] if str.nil?

  bytes = str.encode('UTF-8').bytes
  [1] + encode_le_u32(bytes.length).bytes + bytes
end

#encode_pubkey(pubkey) ⇒ Array<Integer>

Encodes a public key as 32 bytes. Accepts any representation that resolves to a base58 string via #to_s (String, Keypair, PublicKey).

Parameters:

  • pubkey (#to_s)

    The public key in any representation.

Returns:

  • (Array<Integer>)

    32 bytes.



92
93
94
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 92

def encode_pubkey(pubkey)
  Solace::Utils::Codecs.base58_to_bytes(pubkey.to_s)
end

#encode_settings_actions(actions) ⇒ Array<Integer>

Encodes a Vec<SettingsAction> in Borsh format. u32 LE count prefix followed by each action’s variant index + field bytes.

Parameters:

Returns:

  • (Array<Integer>)


144
145
146
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 144

def encode_settings_actions(actions)
  encode_le_u32(actions.length).bytes + actions.flat_map(&:serialize)
end

#encode_smallvec_u16_bytes(bytes) ⇒ Array<Integer>

Encodes a SmallVec<u16, u8>: u16 LE length prefix + raw bytes.

Parameters:

  • bytes (Array<Integer>)

    The raw bytes (max 65535).

Returns:

  • (Array<Integer>)


31
32
33
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 31

def encode_smallvec_u16_bytes(bytes)
  encode_le_u16(bytes.length).bytes + bytes
end

#encode_smallvec_u8_bytes(bytes) ⇒ Array<Integer>

Encodes a SmallVec<u8, u8>: u8 length prefix + raw bytes.

Parameters:

  • bytes (Array<Integer>)

    The raw bytes (max 255).

Returns:

  • (Array<Integer>)


15
16
17
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 15

def encode_smallvec_u8_bytes(bytes)
  [bytes.length] + bytes
end

#encode_smallvec_u8_pubkeys(pubkeys) ⇒ Array<Integer>

Encodes a SmallVec<u8, Pubkey>: u8 count prefix followed by each 32-byte pubkey. Used by the transaction message header’s account_keys (distinct from encode_vec_pubkeys, which uses a u32 count).

Parameters:

  • pubkeys (Array<#to_s>)

    The public keys in any representation (max 255).

Returns:

  • (Array<Integer>)


123
124
125
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 123

def encode_smallvec_u8_pubkeys(pubkeys)
  [pubkeys.length] + pubkeys.flat_map { |pubkey| encode_pubkey(pubkey) }
end

#encode_smart_account_signers(signers) ⇒ Array<Integer>

Encodes a Vec<SmartAccountSigner> in Borsh format. u32 length prefix followed by each signer’s 32-byte pubkey + 1-byte permission mask.

Parameters:

Returns:

  • (Array<Integer>)


132
133
134
135
136
137
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 132

def (signers)
  encode_le_u32(signers.length).bytes +
    signers.flat_map do |signer|
      encode_pubkey(signer.pubkey) + [signer.permission]
    end
end

#encode_vec_pubkeys(pubkeys) ⇒ Array<Integer>

Encodes a Vec<publicKey> in Borsh format. u32 LE count prefix followed by each 32-byte pubkey.

Parameters:

  • pubkeys (Array<#to_s>)

    The public keys in any representation.

Returns:

  • (Array<Integer>)


112
113
114
115
# File 'lib/solace/squads_smart_accounts/codecs_extensions.rb', line 112

def encode_vec_pubkeys(pubkeys)
  encode_le_u32(pubkeys.length).bytes +
    pubkeys.flat_map { |pubkey| encode_pubkey(pubkey) }
end