solace 0.0.2 → 0.0.5
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/CHANGELOG +57 -0
- data/LICENSE +21 -0
- data/README.md +142 -287
- data/lib/solace/address_lookup_table.rb +34 -18
- data/lib/solace/composers/base.rb +45 -0
- data/lib/solace/composers/spl_token_program_transfer_checked_composer.rb +113 -0
- data/lib/solace/composers/system_program_transfer_composer.rb +80 -0
- data/lib/solace/concerns/binary_serializable.rb +39 -0
- data/lib/solace/connection.rb +101 -44
- data/lib/solace/constants.rb +7 -14
- data/lib/solace/instruction.rb +30 -19
- data/lib/solace/instructions/associated_token_account/create_associated_token_account_instruction.rb +18 -3
- data/lib/solace/instructions/spl_token/initialize_account_instruction.rb +24 -3
- data/lib/solace/instructions/spl_token/initialize_mint_instruction.rb +18 -1
- data/lib/solace/instructions/spl_token/mint_to_instruction.rb +16 -3
- data/lib/solace/instructions/spl_token/transfer_checked_instruction.rb +76 -0
- data/lib/solace/instructions/spl_token/transfer_instruction.rb +15 -2
- data/lib/solace/instructions/system_program/create_account_instruction.rb +18 -3
- data/lib/solace/instructions/system_program/transfer_instruction.rb +58 -0
- data/lib/solace/keypair.rb +64 -31
- data/lib/solace/message.rb +22 -10
- data/lib/solace/programs/associated_token_account.rb +58 -11
- data/lib/solace/programs/base.rb +6 -0
- data/lib/solace/programs/spl_token.rb +52 -14
- data/lib/solace/public_key.rb +45 -20
- data/lib/solace/serializers/address_lookup_table_deserializer.rb +3 -5
- data/lib/solace/serializers/address_lookup_table_serializer.rb +7 -7
- data/lib/solace/serializers/base_deserializer.rb +29 -19
- data/lib/solace/serializers/base_serializer.rb +18 -9
- data/lib/solace/serializers/instruction_deserializer.rb +5 -7
- data/lib/solace/serializers/instruction_serializer.rb +4 -6
- data/lib/solace/serializers/message_deserializer.rb +3 -5
- data/lib/solace/serializers/message_serializer.rb +3 -5
- data/lib/solace/serializers/transaction_deserializer.rb +5 -7
- data/lib/solace/serializers/transaction_serializer.rb +5 -7
- data/lib/solace/transaction.rb +38 -23
- data/lib/solace/transaction_composer.rb +115 -0
- data/lib/solace/utils/account_context.rb +252 -0
- data/lib/solace/utils/codecs.rb +56 -128
- data/lib/solace/utils/curve25519_dalek.rb +9 -4
- data/lib/solace/utils/pda.rb +22 -24
- data/lib/solace/version.rb +2 -1
- data/lib/solace.rb +9 -7
- metadata +15 -12
- data/lib/solace/instructions/transfer_checked_instruction.rb +0 -58
- data/lib/solace/instructions/transfer_instruction.rb +0 -48
- data/lib/solace/serializable_record.rb +0 -26
- data/lib/solace/serializers/base.rb +0 -31
@@ -1,11 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# lib/solace/instructions/spl_token/initialize_account_instruction.rb
|
2
4
|
|
3
5
|
module Solace
|
4
6
|
module Instructions
|
5
7
|
module SplToken
|
6
|
-
#
|
8
|
+
# Instruction for initializing a new token account.
|
9
|
+
#
|
10
|
+
# This instruction is used to initialize a new token account for a given mint and owner. It
|
11
|
+
# is used in conjunction with the CreateAccount instruction to create and initialize a new
|
12
|
+
# token account. Note that the AssociatedTokenAccount::CreateAssociatedTokenAccountInstruction
|
13
|
+
# is a special "all-in-one" instruction that creates and initializes the account in a single
|
14
|
+
# instruction.
|
15
|
+
#
|
16
|
+
# @example Build an InitializeAccount instruction
|
17
|
+
# instruction = Solace::Instructions::SplToken::InitializeAccountInstruction.build(
|
18
|
+
# account_index: 0,
|
19
|
+
# mint_index: 1,
|
20
|
+
# owner_index: 2,
|
21
|
+
# rent_sysvar_index: 3,
|
22
|
+
# program_index: 4
|
23
|
+
# )
|
24
|
+
#
|
25
|
+
# @see Solace::Instructions::AssociatedTokenAccount::CreateAssociatedTokenAccountInstruction
|
26
|
+
# @see Solace::Instructions::SystemProgram::CreateAccountInstruction
|
27
|
+
# @since 0.0.2
|
7
28
|
class InitializeAccountInstruction
|
8
|
-
# @!
|
29
|
+
# @!attribute [Array<Integer>] INSTRUCTION_INDEX
|
9
30
|
# Instruction index for SPL Token Program's InitializeAccount instruction.
|
10
31
|
INSTRUCTION_INDEX = [1].freeze
|
11
32
|
|
@@ -43,4 +64,4 @@ module Solace
|
|
43
64
|
end
|
44
65
|
end
|
45
66
|
end
|
46
|
-
end
|
67
|
+
end
|
@@ -3,6 +3,23 @@
|
|
3
3
|
module Solace
|
4
4
|
module Instructions
|
5
5
|
module SplToken
|
6
|
+
# Instruction for initializing a new mint.
|
7
|
+
#
|
8
|
+
# This instruction is used to initialize a new mint for a given token. It is used in conjunction with the SystemProgram::CreateAccount
|
9
|
+
# instruction to create and initialize a new mint account.
|
10
|
+
#
|
11
|
+
# @example Build an InitializeMint instruction
|
12
|
+
# instruction = Solace::Instructions::SplToken::InitializeMintInstruction.build(
|
13
|
+
# decimals: 6,
|
14
|
+
# mint_authority: mint_authority.address,
|
15
|
+
# freeze_authority: freeze_authority.address,
|
16
|
+
# rent_sysvar_index: 2,
|
17
|
+
# mint_account_index: 1,
|
18
|
+
# program_index: 3
|
19
|
+
# )
|
20
|
+
#
|
21
|
+
# @see Solace::Instructions::SystemProgram::CreateAccountInstruction
|
22
|
+
# @since 0.0.2
|
6
23
|
class InitializeMintInstruction
|
7
24
|
# Instruction index for Initialize Mint
|
8
25
|
INSTRUCTION_INDEX = [0].freeze
|
@@ -49,7 +66,7 @@ module Solace
|
|
49
66
|
# @param decimals [Integer] Number of decimals for the token
|
50
67
|
# @param mint_authority [String] Public key of the mint authority
|
51
68
|
# @param freeze_authority [String, nil] Public key of the freeze authority
|
52
|
-
# @return [Array]
|
69
|
+
# @return [Array<u8>] The instruction data
|
53
70
|
def self.data(decimals, mint_authority, freeze_authority)
|
54
71
|
INSTRUCTION_INDEX +
|
55
72
|
[decimals] +
|
@@ -3,9 +3,22 @@
|
|
3
3
|
module Solace
|
4
4
|
module Instructions
|
5
5
|
module SplToken
|
6
|
-
#
|
6
|
+
# Instruction for minting tokens to a token account.
|
7
|
+
#
|
8
|
+
# This instruction is used to mint tokens to a token account for a given mint and owner.
|
9
|
+
#
|
10
|
+
# @example Build a MintTo instruction
|
11
|
+
# instruction = Solace::Instructions::SplToken::MintToInstruction.build(
|
12
|
+
# amount: 100,
|
13
|
+
# mint_index: 1,
|
14
|
+
# mint_authority_index: 2,
|
15
|
+
# destination_index: 3,
|
16
|
+
# program_index: 4
|
17
|
+
# )
|
18
|
+
#
|
19
|
+
# @since 0.0.2
|
7
20
|
class MintToInstruction
|
8
|
-
# @!
|
21
|
+
# @!attribute [Array<Integer>] INSTRUCTION_INDEX
|
9
22
|
# Instruction index for SPL Token Program's MintTo instruction.
|
10
23
|
INSTRUCTION_INDEX = [7].freeze
|
11
24
|
|
@@ -45,4 +58,4 @@ module Solace
|
|
45
58
|
end
|
46
59
|
end
|
47
60
|
end
|
48
|
-
end
|
61
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solace
|
4
|
+
module Instructions
|
5
|
+
module SplToken
|
6
|
+
# Instruction for transferring SPL tokens.
|
7
|
+
#
|
8
|
+
# This instruction is used to transfer SPL tokens from one token account to another while checking the decimals
|
9
|
+
# of the token to ensure the transfer amount is correct.
|
10
|
+
#
|
11
|
+
# @example Build a TransferChecked instruction
|
12
|
+
# instruction = Solace::Instructions::SplToken::TransferCheckedInstruction.build(
|
13
|
+
# amount: 100,
|
14
|
+
# decimals: 6,
|
15
|
+
# to_index: 1,
|
16
|
+
# from_index: 2,
|
17
|
+
# mint_index: 3,
|
18
|
+
# authority_index: 4,
|
19
|
+
# program_index: 5
|
20
|
+
# )
|
21
|
+
#
|
22
|
+
# @since 0.0.2
|
23
|
+
class TransferCheckedInstruction
|
24
|
+
# SPL Token Program instruction index for Transfer Checked
|
25
|
+
INSTRUCTION_INDEX = [12].freeze
|
26
|
+
|
27
|
+
# Builds a Solace::Instruction for transferring SPL tokens
|
28
|
+
#
|
29
|
+
# SPL Token Program transfer instruction layout:
|
30
|
+
# - 1 byte: instruction index (12 for transfer checked)
|
31
|
+
# - 8 bytes: amount (u64, little-endian)
|
32
|
+
# - 8 bytes: decimals (u64, little-endian)
|
33
|
+
#
|
34
|
+
# @param amount [Integer] Amount to transfer (in tokens, according to mint's decimals)
|
35
|
+
# @param decimals [Integer] Number of decimals for the token
|
36
|
+
# @param to_index [Integer] Index of the destination token account in the transaction's accounts
|
37
|
+
# @param from_index [Integer] Index of the source token account in the transaction's accounts
|
38
|
+
# @param mint_index [Integer] Index of the mint in the transaction's accounts
|
39
|
+
# @param authority_index [Integer] Index of the authority (owner) in the transaction's accounts
|
40
|
+
# @param program_index [Integer] Index of the SPL Token Program in the transaction's accounts (default: 3)
|
41
|
+
# @return [Solace::Instruction]
|
42
|
+
def self.build(
|
43
|
+
amount:,
|
44
|
+
decimals:,
|
45
|
+
to_index:,
|
46
|
+
from_index:,
|
47
|
+
mint_index:,
|
48
|
+
authority_index:,
|
49
|
+
program_index: 3
|
50
|
+
)
|
51
|
+
Solace::Instruction.new.tap do |ix|
|
52
|
+
ix.program_index = program_index
|
53
|
+
ix.accounts = [from_index, mint_index, to_index, authority_index]
|
54
|
+
ix.data = data(amount, decimals)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Instruction data for a token transfer instruction
|
59
|
+
#
|
60
|
+
# The BufferLayout is:
|
61
|
+
# - [Instruction Index (1 byte)]
|
62
|
+
# - [Amount (8 bytes little-endian u64)]
|
63
|
+
# - [Decimals (8 bytes little-endian u64)]
|
64
|
+
#
|
65
|
+
# @param amount [Integer] Amount to transfer
|
66
|
+
# @param decimals [Integer] Number of decimals for the token
|
67
|
+
# @return [Array] 1-byte instruction index + 8-byte amount + decimals
|
68
|
+
def self.data(amount, decimals)
|
69
|
+
INSTRUCTION_INDEX +
|
70
|
+
Solace::Utils::Codecs.encode_le_u64(amount).bytes +
|
71
|
+
[decimals]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -3,9 +3,22 @@
|
|
3
3
|
module Solace
|
4
4
|
module Instructions
|
5
5
|
module SplToken
|
6
|
-
#
|
6
|
+
# Instruction for transferring SPL tokens.
|
7
|
+
#
|
8
|
+
# This instruction is used to transfer SPL tokens from one token account to another.
|
9
|
+
#
|
10
|
+
# @example Build a Transfer instruction
|
11
|
+
# instruction = Solace::Instructions::SplToken::TransferInstruction.build(
|
12
|
+
# amount: 100,
|
13
|
+
# owner_index: 1,
|
14
|
+
# source_index: 2,
|
15
|
+
# destination_index: 3,
|
16
|
+
# program_index: 4
|
17
|
+
# )
|
18
|
+
#
|
19
|
+
# @since 0.0.2
|
7
20
|
class TransferInstruction
|
8
|
-
# @!
|
21
|
+
# @!attribute [Array<Integer>] INSTRUCTION_INDEX
|
9
22
|
# Instruction index for SPL Token Program's Transfer instruction.
|
10
23
|
INSTRUCTION_INDEX = [3].freeze
|
11
24
|
|
@@ -3,11 +3,25 @@
|
|
3
3
|
module Solace
|
4
4
|
module Instructions
|
5
5
|
module SystemProgram
|
6
|
+
# Instruction for creating a new account.
|
7
|
+
#
|
8
|
+
# This instruction is used to create a new account for a given program.
|
9
|
+
#
|
10
|
+
# @example Build a CreateAccount instruction
|
11
|
+
# instruction = Solace::Instructions::SystemProgram::CreateAccountInstruction.build(
|
12
|
+
# space: 1024,
|
13
|
+
# lamports: 1000,
|
14
|
+
# from_index: 0,
|
15
|
+
# new_account_index: 1,
|
16
|
+
# owner: owner.address,
|
17
|
+
# system_program_index: 2
|
18
|
+
# )
|
19
|
+
#
|
20
|
+
# @since 0.0.2
|
6
21
|
class CreateAccountInstruction
|
7
|
-
#
|
22
|
+
# @!attribute [Array<Integer>] INSTRUCTION_INDEX
|
8
23
|
# Instruction index for SystemProgram::CreateAccount
|
9
24
|
# This is the same across all Solana clusters
|
10
|
-
# @return [Array<Integer>]
|
11
25
|
INSTRUCTION_INDEX = [0, 0, 0, 0].freeze
|
12
26
|
|
13
27
|
# Builds a SystemProgram::CreateAccount instruction
|
@@ -22,9 +36,9 @@ module Solace
|
|
22
36
|
def self.build(
|
23
37
|
space:,
|
24
38
|
lamports:,
|
25
|
-
owner: Solace::Constants::SYSTEM_PROGRAM_ID,
|
26
39
|
from_index:,
|
27
40
|
new_account_index:,
|
41
|
+
owner: Solace::Constants::SYSTEM_PROGRAM_ID,
|
28
42
|
system_program_index: 2
|
29
43
|
)
|
30
44
|
Solace::Instruction.new.tap do |ix|
|
@@ -33,6 +47,7 @@ module Solace
|
|
33
47
|
ix.data = data(lamports, space, owner)
|
34
48
|
end
|
35
49
|
end
|
50
|
+
# rubocop:enable Metrics/ParameterLists
|
36
51
|
|
37
52
|
# Builds the data for a SystemProgram::CreateAccount instruction
|
38
53
|
#
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solace
|
4
|
+
module Instructions
|
5
|
+
module SystemProgram
|
6
|
+
# Instruction for transferring SOL.
|
7
|
+
#
|
8
|
+
# This instruction is used to transfer SOL from one account to another.
|
9
|
+
#
|
10
|
+
# @example Build a Transfer instruction
|
11
|
+
# instruction = Solace::Instructions::SystemProgram::TransferInstruction.build(
|
12
|
+
# lamports: 100,
|
13
|
+
# to_index: 1,
|
14
|
+
# from_index: 2,
|
15
|
+
# program_index: 3
|
16
|
+
# )
|
17
|
+
#
|
18
|
+
# @since 0.0.2
|
19
|
+
class TransferInstruction
|
20
|
+
# Instruction ID for System Transfer
|
21
|
+
INSTRUCTION_ID = [2, 0, 0, 0].freeze
|
22
|
+
|
23
|
+
# Builds a Solace::Instruction for transferring SOL
|
24
|
+
#
|
25
|
+
# @param lamports [Integer] Amount to transfer (in lamports)
|
26
|
+
# @param to_index [Integer] Index of the recipient in the transaction's accounts
|
27
|
+
# @param from_index [Integer] Index of the sender in the transaction's accounts
|
28
|
+
# @param program_index [Integer] Index of the program in the transaction's accounts (default: 2)
|
29
|
+
# @return [Solace::Instruction]
|
30
|
+
def self.build(
|
31
|
+
lamports:,
|
32
|
+
to_index:,
|
33
|
+
from_index:,
|
34
|
+
program_index: 2
|
35
|
+
)
|
36
|
+
Instruction.new.tap do |ix|
|
37
|
+
ix.program_index = program_index
|
38
|
+
ix.accounts = [from_index, to_index]
|
39
|
+
ix.data = data(lamports)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Instruction data for a transfer instruction
|
44
|
+
#
|
45
|
+
# The BufferLayout is:
|
46
|
+
# - [Instruction ID (4 bytes)]
|
47
|
+
# - [Amount (8 bytes little-endian u64)]
|
48
|
+
#
|
49
|
+
# @param lamports [Integer] Amount to transfer (in lamports)
|
50
|
+
# @return [Array] 4-byte instruction ID + 8-byte amount
|
51
|
+
def self.data(lamports)
|
52
|
+
INSTRUCTION_ID +
|
53
|
+
Utils::Codecs.encode_le_u64(lamports).bytes
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/solace/keypair.rb
CHANGED
@@ -3,38 +3,40 @@
|
|
3
3
|
require 'rbnacl'
|
4
4
|
require 'base58'
|
5
5
|
|
6
|
-
# =============================
|
7
|
-
# Keypair
|
8
|
-
# =============================
|
9
|
-
#
|
10
|
-
# Represents a Solana Ed25519 Keypair
|
11
6
|
module Solace
|
7
|
+
# Class representing a Solana Ed25519 Keypair
|
8
|
+
#
|
9
|
+
# This class provides utility methods for encoding, decoding, signing, and validating keypairs.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # Generate a new keypair
|
13
|
+
# keypair = Solace::Keypair.generate
|
14
|
+
#
|
15
|
+
# # Get the address of the pubkey
|
16
|
+
# keypair.address
|
17
|
+
#
|
18
|
+
# # Sign a message using the keypair
|
19
|
+
# keypair.sign("<any-message>")
|
20
|
+
#
|
21
|
+
# @since 0.0.1
|
12
22
|
class Keypair
|
13
|
-
#
|
14
|
-
# The length of a Solana secret key in bytes
|
15
|
-
#
|
16
|
-
# @return [Integer] The length of a secret key
|
23
|
+
# The length of a Solana secret key in bytes.
|
17
24
|
SECRET_LENGTH = 64
|
18
25
|
|
19
|
-
#
|
20
|
-
|
21
|
-
#
|
22
|
-
# @return [Integer] The length of a seed
|
23
|
-
SEED_LENGTH = RbNaCl::Signatures::Ed25519::SEEDBYTES
|
26
|
+
# The length of a Solana seed in bytes.
|
27
|
+
SEED_LENGTH = 32
|
24
28
|
|
25
|
-
#
|
26
|
-
# The RbNaCl signing key
|
29
|
+
# The full keypair bytes array
|
27
30
|
#
|
28
|
-
# @return [
|
29
|
-
SigningKey = RbNaCl::Signatures::Ed25519::SigningKey
|
30
|
-
|
31
|
-
# !@attribute [r] keypair_bytes
|
32
|
-
# @return [Array<Integer>] The keypair bytes
|
31
|
+
# @return [Array<u8>] The 64 bytes of the keypair
|
33
32
|
attr_reader :keypair_bytes
|
34
33
|
|
35
34
|
class << self
|
36
35
|
# Generate a new random keypair
|
37
36
|
#
|
37
|
+
# @example
|
38
|
+
# keypair = Solace::Keypair.generate
|
39
|
+
#
|
38
40
|
# @return [Keypair]
|
39
41
|
def generate
|
40
42
|
from_seed(RbNaCl::Random.random_bytes(SEED_LENGTH))
|
@@ -42,28 +44,40 @@ module Solace
|
|
42
44
|
|
43
45
|
# Create a keypair from a 32-byte seed
|
44
46
|
#
|
47
|
+
# @example
|
48
|
+
# keypair = Solace::Keypair.from_seed(seed)
|
49
|
+
#
|
45
50
|
# @param seed [String] 32-byte array
|
51
|
+
# @raise [ArgumentError] If the length of the seed isn't 32 bytes
|
46
52
|
# @return [Keypair]
|
47
53
|
def from_seed(seed)
|
48
54
|
raise ArgumentError, 'Seed must be 32 bytes' unless seed.length == SEED_LENGTH
|
49
55
|
|
50
|
-
new(SigningKey.new(seed).keypair_bytes.bytes)
|
56
|
+
new(RbNaCl::Signatures::Ed25519::SigningKey.new(seed).keypair_bytes.bytes)
|
51
57
|
end
|
52
58
|
|
53
59
|
# Create a keypair from a 64-byte secret key
|
54
60
|
#
|
61
|
+
# @example
|
62
|
+
# keypair = Solace::Keypair.from_secret_key(secret_key)
|
63
|
+
#
|
55
64
|
# @param secret_key [String] 64-byte array
|
65
|
+
# @raise [ArgumentError] If the length of the secret_key isn't 64 bytes
|
56
66
|
# @return [Keypair]
|
57
67
|
def from_secret_key(secret_key)
|
58
68
|
raise ArgumentError, 'Secret key must be 64 bytes' unless secret_key.length == SECRET_LENGTH
|
59
69
|
|
60
|
-
new(SigningKey.new(secret_key[0..31]).keypair_bytes.bytes)
|
70
|
+
new(RbNaCl::Signatures::Ed25519::SigningKey.new(secret_key[0..31]).keypair_bytes.bytes)
|
61
71
|
end
|
62
72
|
end
|
63
73
|
|
64
74
|
# Initialize a new keypair
|
65
75
|
#
|
76
|
+
# @example
|
77
|
+
# keypair = Solace::Keypair.new(bytes)
|
78
|
+
#
|
66
79
|
# @param keypair_bytes [Array<Integer>] The keypair bytes
|
80
|
+
# @raise [ArgumentError] If the length of the keypair_bytes isn't 64 bytes
|
67
81
|
# @return [Keypair] The new keypair object
|
68
82
|
def initialize(keypair_bytes)
|
69
83
|
raise ArgumentError, 'Keypair must be 64 bytes' unless keypair_bytes.length == SECRET_LENGTH
|
@@ -73,6 +87,9 @@ module Solace
|
|
73
87
|
|
74
88
|
# Returns the public key
|
75
89
|
#
|
90
|
+
# @example
|
91
|
+
# pubkey = keypair.public_key
|
92
|
+
#
|
76
93
|
# @return [PublicKey]
|
77
94
|
def public_key
|
78
95
|
@public_key ||= Solace::PublicKey.new(public_key_bytes)
|
@@ -80,16 +97,22 @@ module Solace
|
|
80
97
|
|
81
98
|
# Returns the signing key
|
82
99
|
#
|
100
|
+
# @example
|
101
|
+
# signing_key = instance.signing_key
|
102
|
+
#
|
83
103
|
# @return [RbNaCl::Signatures::Ed25519::SigningKey]
|
84
104
|
def signing_key
|
85
|
-
@signing_key ||= SigningKey.new(
|
105
|
+
@signing_key ||= RbNaCl::Signatures::Ed25519::SigningKey.new(private_key_bytes.pack('C*'))
|
86
106
|
end
|
87
107
|
|
88
108
|
# Returns the public key bytes
|
89
109
|
#
|
90
110
|
# The public key bytes are the last 32 bytes of the keypair
|
91
111
|
#
|
92
|
-
# @
|
112
|
+
# @example
|
113
|
+
# public_key_bytes = instance.public_key_bytes
|
114
|
+
#
|
115
|
+
# @return [Array<u8>] 32 bytes
|
93
116
|
def public_key_bytes
|
94
117
|
keypair_bytes[32..63]
|
95
118
|
end
|
@@ -98,12 +121,18 @@ module Solace
|
|
98
121
|
#
|
99
122
|
# The private key is the first 32 bytes of the keypair
|
100
123
|
#
|
101
|
-
# @
|
102
|
-
|
103
|
-
|
124
|
+
# @example
|
125
|
+
# private_key_bytes = instance.private_key_bytes
|
126
|
+
#
|
127
|
+
# @return [Array<u8>] 32 characters
|
128
|
+
def private_key_bytes
|
129
|
+
keypair_bytes[0..31]
|
104
130
|
end
|
105
131
|
|
106
|
-
# Returns the public key as a Base58 string
|
132
|
+
# Returns the public key address as a Base58 string
|
133
|
+
#
|
134
|
+
# @example
|
135
|
+
# pubkey_str = instance.address
|
107
136
|
#
|
108
137
|
# @return [String] Base58 encoded public key
|
109
138
|
def address
|
@@ -112,8 +141,12 @@ module Solace
|
|
112
141
|
|
113
142
|
# Signs a message (string or binary)
|
114
143
|
#
|
115
|
-
# @
|
116
|
-
#
|
144
|
+
# @example
|
145
|
+
# message = "An important message to be signed,"
|
146
|
+
# signature = instance.sign(message)
|
147
|
+
#
|
148
|
+
# @param message [String, Binary]
|
149
|
+
# @return [String] signature (binary string)
|
117
150
|
def sign(message)
|
118
151
|
signing_key.sign(message)
|
119
152
|
end
|
data/lib/solace/message.rb
CHANGED
@@ -1,18 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# =============================
|
4
|
-
# Message
|
5
|
-
# =============================
|
6
|
-
#
|
7
|
-
# Represents the message portion of a Solana transaction (legacy or versioned).
|
8
|
-
# Handles serialization and deserialization of message fields.
|
9
3
|
module Solace
|
10
|
-
|
11
|
-
|
4
|
+
# Solace::Message represents the message portion of a Solana transaction (legacy or versioned). It handles
|
5
|
+
# serialization and deserialization of message fields.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# message = Solace::Message.new(
|
9
|
+
# version: 0,
|
10
|
+
# header: [0, 0, 0],
|
11
|
+
# accounts: ['11111111111111111111111111111111'],
|
12
|
+
# recent_blockhash: '11111111111111111111111111111111',
|
13
|
+
# instructions: [],
|
14
|
+
# address_lookup_tables: []
|
15
|
+
# )
|
16
|
+
#
|
17
|
+
# @since 0.0.1
|
18
|
+
class Message
|
19
|
+
include Solace::Concerns::BinarySerializable
|
20
|
+
|
21
|
+
# @!attribute SERIALIZER
|
12
22
|
# @return [Solace::Serializers::MessageSerializer] The serializer for the message
|
13
23
|
SERIALIZER = Solace::Serializers::MessageSerializer
|
14
24
|
|
15
|
-
# @!
|
25
|
+
# @!attribute DESERIALIZER
|
16
26
|
# @return [Solace::Serializers::MessageDeserializer] The deserializer for the message
|
17
27
|
DESERIALIZER = Solace::Serializers::MessageDeserializer
|
18
28
|
|
@@ -46,7 +56,7 @@ module Solace
|
|
46
56
|
# @param accounts [Array<String>] Account public keys (base58)
|
47
57
|
# @param instructions [Array<Solace::Instruction>] Instructions in the message
|
48
58
|
# @param recent_blockhash [String] Recent blockhash (base58)
|
49
|
-
# @param header [Array<Integer>] Message header
|
59
|
+
# @param header [Array<Integer>] Message header
|
50
60
|
# @param address_lookup_tables [Array<Solace::AddressLookupTable>]
|
51
61
|
def initialize(
|
52
62
|
version: nil,
|
@@ -56,6 +66,8 @@ module Solace
|
|
56
66
|
header: [0, 0, 0],
|
57
67
|
address_lookup_tables: []
|
58
68
|
)
|
69
|
+
super()
|
70
|
+
|
59
71
|
@version = version
|
60
72
|
@header = header
|
61
73
|
@accounts = accounts
|
@@ -2,13 +2,33 @@
|
|
2
2
|
|
3
3
|
module Solace
|
4
4
|
module Programs
|
5
|
-
#
|
5
|
+
# Client for interacting with the Associated Token Account Program.
|
6
|
+
#
|
7
|
+
# This client provides methods for interacting with the Associated Token Account Program. It is a
|
8
|
+
# wrapper around the SPL Token Program and provides a more convenient interface for creating and
|
9
|
+
# managing associated token accounts.
|
10
|
+
#
|
11
|
+
# @example Create an associated token account
|
12
|
+
# # Initialize the program with a connection
|
13
|
+
# program = Solace::Programs::AssociatedTokenAccount.new(connection: connection)
|
14
|
+
#
|
15
|
+
# # Create an associated token account
|
16
|
+
# result = program.create_associated_token_account(
|
17
|
+
# payer: payer,
|
18
|
+
# owner: owner,
|
19
|
+
# mint: mint
|
20
|
+
# )
|
21
|
+
#
|
22
|
+
# # Wait for the transaction to be finalized
|
23
|
+
# @connection.wait_for_confirmed_signature('finalized') { result['result'] }
|
24
|
+
#
|
25
|
+
# @since 0.0.2
|
6
26
|
class AssociatedTokenAccount < Base
|
7
27
|
class << self
|
8
28
|
# Gets the address of an associated token account.
|
9
29
|
#
|
10
|
-
# @param owner [Solace::Keypair
|
11
|
-
# @param mint [Solace::Keypair
|
30
|
+
# @param owner [Solace::Keypair, Solace::PublicKey] The keypair of the owner.
|
31
|
+
# @param mint [Solace::Keypair, Solace::PublicKey] The keypair of the mint.
|
12
32
|
# @return [String] The address of the associated token account.
|
13
33
|
def get_address(owner:, mint:)
|
14
34
|
Solace::Utils::PDA.find_program_address(
|
@@ -26,16 +46,40 @@ module Solace
|
|
26
46
|
#
|
27
47
|
# @param connection [Solace::Connection] The connection to the Solana cluster.
|
28
48
|
def initialize(connection:)
|
29
|
-
super(connection
|
49
|
+
super(connection: connection, program_id: Solace::Constants::ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID)
|
30
50
|
end
|
31
51
|
|
32
52
|
# Alias method for get_address
|
33
|
-
#
|
34
|
-
# @
|
53
|
+
#
|
54
|
+
# @option options [Hash] A hash of options for the get_address class method
|
55
|
+
# @return [Array<String, Integer>] The address of the associated token account and the bump seed
|
35
56
|
def get_address(**options)
|
36
57
|
self.class.get_address(**options)
|
37
58
|
end
|
38
59
|
|
60
|
+
# Gets the address of an associated token account, creating it if it doesn't exist.
|
61
|
+
#
|
62
|
+
# @param payer [Solace::Keypair] The keypair that will pay for fees and rent.
|
63
|
+
# @param owner [Solace::Keypair, Solace::PublicKey] The keypair of the owner.
|
64
|
+
# @param mint [Solace::Keypair, Solace::PublicKey] The keypair of the mint.
|
65
|
+
# @param commitment [String] The commitment level for the get_account_info call.
|
66
|
+
# @return [String] The address of the associated token account
|
67
|
+
def get_or_create_address(payer:, owner:, mint:, commitment: 'confirmed')
|
68
|
+
ata_address, _bump = get_address(owner: owner, mint: mint)
|
69
|
+
|
70
|
+
account_info = @connection.get_account_info(ata_address)
|
71
|
+
|
72
|
+
return ata_address if account_info
|
73
|
+
|
74
|
+
response = create_associated_token_account(payer: payer, owner: owner, mint: mint)
|
75
|
+
|
76
|
+
raise 'Failed to create associated token account' unless response['result']
|
77
|
+
|
78
|
+
@connection.wait_for_confirmed_signature(commitment) { response['result'] }
|
79
|
+
|
80
|
+
ata_address
|
81
|
+
end
|
82
|
+
|
39
83
|
# Creates a new associated token account.
|
40
84
|
#
|
41
85
|
# @param options [Hash] Options for calling the prepare_create_associated_token_account method.
|
@@ -48,16 +92,18 @@ module Solace
|
|
48
92
|
|
49
93
|
# Prepares a new associated token account and returns the signed transaction.
|
50
94
|
#
|
51
|
-
# @param owner [Solace::Keypair
|
52
|
-
# @param mint [Solace::Keypair
|
95
|
+
# @param owner [Solace::Keypair, Solace::PublicKey] The keypair of the owner.
|
96
|
+
# @param mint [Solace::Keypair, Solace::PublicKey] The keypair of the mint.
|
53
97
|
# @param payer [Solace::Keypair] The keypair that will pay for fees and rent.
|
54
98
|
# @return [Solace::Transaction] The signed transaction.
|
99
|
+
#
|
100
|
+
# rubocop:disable Metrics/MethodLength
|
55
101
|
def prepare_create_associated_token_account(
|
102
|
+
payer:,
|
56
103
|
owner:,
|
57
|
-
mint
|
58
|
-
payer:
|
104
|
+
mint:
|
59
105
|
)
|
60
|
-
ata_address,
|
106
|
+
ata_address, = get_address(owner: owner, mint: mint)
|
61
107
|
|
62
108
|
accounts = [
|
63
109
|
payer.address,
|
@@ -91,6 +137,7 @@ module Solace
|
|
91
137
|
|
92
138
|
tx
|
93
139
|
end
|
140
|
+
# rubocop:enable Metrics/MethodLength
|
94
141
|
end
|
95
142
|
end
|
96
143
|
end
|
data/lib/solace/programs/base.rb
CHANGED
@@ -5,7 +5,13 @@
|
|
5
5
|
module Solace
|
6
6
|
module Programs
|
7
7
|
# Base class for program-specific clients.
|
8
|
+
#
|
8
9
|
# Provides a consistent interface for interacting with on-chain programs.
|
10
|
+
#
|
11
|
+
# @abstract
|
12
|
+
# @see Solace::Programs::SplToken
|
13
|
+
# @see Solace::Programs::AssociatedTokenAccount
|
14
|
+
# @since 0.0.2
|
9
15
|
class Base
|
10
16
|
attr_reader :connection, :program_id
|
11
17
|
|