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
data/lib/solace/utils/pda.rb
CHANGED
@@ -5,27 +5,34 @@ require 'digest'
|
|
5
5
|
|
6
6
|
module Solace
|
7
7
|
module Utils
|
8
|
+
# Module for generating program addresses
|
9
|
+
#
|
10
|
+
# This module provides methods for generating program addresses from seeds and program IDs. It interfaces
|
11
|
+
# with the Curve25519 Dalek library to check if a point is on the curve. It also provides a method for
|
12
|
+
# converting seeds to bytes and a method for checking if a string looks like a base58 address.
|
13
|
+
#
|
14
|
+
# @see Solace::Utils::Curve25519Dalek
|
15
|
+
# @since 0.0.1
|
8
16
|
module PDA
|
9
|
-
#
|
10
|
-
# An error raised when an invalid PDA is generated
|
11
|
-
#
|
12
|
-
# @return [StandardError]
|
17
|
+
# InvalidPDAError is an error raised when an invalid PDA is generated
|
13
18
|
class InvalidPDAError < StandardError; end
|
14
19
|
|
15
|
-
# !@
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# @return [String]
|
20
|
+
# !@attribute PDA_MARKER
|
21
|
+
# PDA_MARKER is the marker used in PDA calculations
|
19
22
|
PDA_MARKER = 'ProgramDerivedAddress'
|
20
23
|
|
21
|
-
# !@
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# @return [Integer]
|
24
|
+
# !@attribute MAX_BUMP_SEED
|
25
|
+
# The maximum seed value for PDA calculations
|
25
26
|
MAX_BUMP_SEED = 255
|
26
27
|
|
27
28
|
# Finds a valid program address by trying different seeds
|
28
29
|
#
|
30
|
+
# @example Find a PDA with bump seed
|
31
|
+
# seeds = ['metadata', mint_address, 'edition']
|
32
|
+
# program_id = 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'
|
33
|
+
#
|
34
|
+
# address, bump = Solace::Utils::PDA.find_program_address(seeds, program_id)
|
35
|
+
#
|
29
36
|
# @param seeds [Array] The seeds to use in the calculation
|
30
37
|
# @param program_id [String] The program ID to use in the calculation
|
31
38
|
# @return [Array] The program address and bump seed
|
@@ -68,17 +75,9 @@ module Solace
|
|
68
75
|
def self.seed_to_bytes(seed)
|
69
76
|
case seed
|
70
77
|
when String
|
71
|
-
|
72
|
-
Solace::Utils::Codecs.base58_to_bytes(seed)
|
73
|
-
else
|
74
|
-
seed.bytes
|
75
|
-
end
|
78
|
+
looks_like_base58_address?(seed) ? Solace::Utils::Codecs.base58_to_bytes(seed) : seed.bytes
|
76
79
|
when Integer
|
77
|
-
|
78
|
-
[seed]
|
79
|
-
else
|
80
|
-
seed.digits(256)
|
81
|
-
end
|
80
|
+
seed.between?(0, 255) ? [seed] : seed.digits(256)
|
82
81
|
when Array
|
83
82
|
seed
|
84
83
|
else
|
@@ -91,8 +90,7 @@ module Solace
|
|
91
90
|
# @param string [String] The string to check
|
92
91
|
# @return [Boolean] True if the string looks like a base58 address, false otherwise
|
93
92
|
def self.looks_like_base58_address?(string)
|
94
|
-
string.length
|
95
|
-
string.length <= 44 &&
|
93
|
+
string.length.between?(32, 44) &&
|
96
94
|
Solace::Utils::Codecs.valid_base58?(string)
|
97
95
|
end
|
98
96
|
end
|
data/lib/solace/version.rb
CHANGED
data/lib/solace.rb
CHANGED
@@ -8,17 +8,14 @@ require_relative 'solace/constants'
|
|
8
8
|
require_relative 'solace/connection'
|
9
9
|
require_relative 'solace/utils/codecs'
|
10
10
|
require_relative 'solace/utils/pda'
|
11
|
+
require_relative 'solace/utils/account_context'
|
11
12
|
require_relative 'solace/utils/curve25519_dalek'
|
12
13
|
require_relative 'solace/concerns/binary_serializable'
|
13
14
|
|
14
15
|
# ✨ Serializers
|
15
|
-
require_relative 'solace/serializers/base'
|
16
16
|
require_relative 'solace/serializers/base_serializer'
|
17
17
|
require_relative 'solace/serializers/base_deserializer'
|
18
18
|
|
19
|
-
# Base classes
|
20
|
-
require_relative 'solace/serializable_record'
|
21
|
-
|
22
19
|
# 🧬 Primitives
|
23
20
|
require_relative 'solace/keypair'
|
24
21
|
require_relative 'solace/public_key'
|
@@ -26,14 +23,19 @@ require_relative 'solace/transaction'
|
|
26
23
|
require_relative 'solace/message'
|
27
24
|
require_relative 'solace/instruction'
|
28
25
|
require_relative 'solace/address_lookup_table'
|
26
|
+
require_relative 'solace/transaction_composer'
|
27
|
+
|
28
|
+
# 📦 Composers (Builders)
|
29
|
+
#
|
30
|
+
# Glob require all instructions
|
31
|
+
Dir[File.join(__dir__, 'solace/composers', '**', '*.rb')].each { |file| require file }
|
29
32
|
|
30
33
|
# 📦 Instructions (Builders)
|
31
|
-
#
|
34
|
+
#
|
32
35
|
# Glob require all instructions
|
33
|
-
Dir[File.join(__dir__, 'solace/instructions', '**', '*.rb')].
|
36
|
+
Dir[File.join(__dir__, 'solace/instructions', '**', '*.rb')].each { |file| require file }
|
34
37
|
|
35
38
|
# 📦 Programs
|
36
39
|
require_relative 'solace/programs/base'
|
37
40
|
require_relative 'solace/programs/spl_token'
|
38
41
|
require_relative 'solace/programs/associated_token_account'
|
39
|
-
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Scholl
|
@@ -52,38 +52,38 @@ dependencies:
|
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '7.0'
|
54
54
|
- !ruby/object:Gem::Dependency
|
55
|
-
name:
|
55
|
+
name: minitest
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '
|
60
|
+
version: '5.0'
|
61
61
|
type: :development
|
62
62
|
prerelease: false
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: '
|
67
|
+
version: '5.0'
|
68
68
|
- !ruby/object:Gem::Dependency
|
69
|
-
name:
|
69
|
+
name: rake
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: '
|
74
|
+
version: '13.0'
|
75
75
|
type: :development
|
76
76
|
prerelease: false
|
77
77
|
version_requirements: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
81
|
+
version: '13.0'
|
82
82
|
description: A Ruby library for working with Solana blockchain. Provides both low-level
|
83
83
|
instruction builders and high-level program clients for interacting with Solana
|
84
84
|
programs.
|
85
85
|
email:
|
86
|
-
-
|
86
|
+
- sebscholl@gmail.com
|
87
87
|
executables: []
|
88
88
|
extensions: []
|
89
89
|
extra_rdoc_files: []
|
@@ -93,6 +93,9 @@ files:
|
|
93
93
|
- README.md
|
94
94
|
- lib/solace.rb
|
95
95
|
- lib/solace/address_lookup_table.rb
|
96
|
+
- lib/solace/composers/base.rb
|
97
|
+
- lib/solace/composers/spl_token_program_transfer_checked_composer.rb
|
98
|
+
- lib/solace/composers/system_program_transfer_composer.rb
|
96
99
|
- lib/solace/concerns/binary_serializable.rb
|
97
100
|
- lib/solace/connection.rb
|
98
101
|
- lib/solace/constants.rb
|
@@ -101,20 +104,18 @@ files:
|
|
101
104
|
- lib/solace/instructions/spl_token/initialize_account_instruction.rb
|
102
105
|
- lib/solace/instructions/spl_token/initialize_mint_instruction.rb
|
103
106
|
- lib/solace/instructions/spl_token/mint_to_instruction.rb
|
107
|
+
- lib/solace/instructions/spl_token/transfer_checked_instruction.rb
|
104
108
|
- lib/solace/instructions/spl_token/transfer_instruction.rb
|
105
109
|
- lib/solace/instructions/system_program/create_account_instruction.rb
|
106
|
-
- lib/solace/instructions/
|
107
|
-
- lib/solace/instructions/transfer_instruction.rb
|
110
|
+
- lib/solace/instructions/system_program/transfer_instruction.rb
|
108
111
|
- lib/solace/keypair.rb
|
109
112
|
- lib/solace/message.rb
|
110
113
|
- lib/solace/programs/associated_token_account.rb
|
111
114
|
- lib/solace/programs/base.rb
|
112
115
|
- lib/solace/programs/spl_token.rb
|
113
116
|
- lib/solace/public_key.rb
|
114
|
-
- lib/solace/serializable_record.rb
|
115
117
|
- lib/solace/serializers/address_lookup_table_deserializer.rb
|
116
118
|
- lib/solace/serializers/address_lookup_table_serializer.rb
|
117
|
-
- lib/solace/serializers/base.rb
|
118
119
|
- lib/solace/serializers/base_deserializer.rb
|
119
120
|
- lib/solace/serializers/base_serializer.rb
|
120
121
|
- lib/solace/serializers/instruction_deserializer.rb
|
@@ -124,6 +125,8 @@ files:
|
|
124
125
|
- lib/solace/serializers/transaction_deserializer.rb
|
125
126
|
- lib/solace/serializers/transaction_serializer.rb
|
126
127
|
- lib/solace/transaction.rb
|
128
|
+
- lib/solace/transaction_composer.rb
|
129
|
+
- lib/solace/utils/account_context.rb
|
127
130
|
- lib/solace/utils/codecs.rb
|
128
131
|
- lib/solace/utils/curve25519_dalek.rb
|
129
132
|
- lib/solace/utils/libcurve25519_dalek-linux/libcurve25519_dalek.so
|
@@ -1,58 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Solace
|
4
|
-
module Instructions
|
5
|
-
# Service object for building an SPL Token Program transfer instruction
|
6
|
-
class TransferCheckedInstruction
|
7
|
-
# SPL Token Program instruction index for Transfer Checked
|
8
|
-
INSTRUCTION_INDEX = [12].freeze
|
9
|
-
|
10
|
-
# Builds a Solace::Instruction for transferring SPL tokens
|
11
|
-
#
|
12
|
-
# SPL Token Program transfer instruction layout:
|
13
|
-
# - 1 byte: instruction index (12 for transfer checked)
|
14
|
-
# - 8 bytes: amount (u64, little-endian)
|
15
|
-
# - 8 bytes: decimals (u64, little-endian)
|
16
|
-
#
|
17
|
-
# @param amount [Integer] Amount to transfer (in tokens, according to mint's decimals)
|
18
|
-
# @param decimals [Integer] Number of decimals for the token
|
19
|
-
# @param to_index [Integer] Index of the destination token account in the transaction's accounts
|
20
|
-
# @param from_index [Integer] Index of the source token account in the transaction's accounts
|
21
|
-
# @param mint_index [Integer] Index of the mint in the transaction's accounts
|
22
|
-
# @param authority_index [Integer] Index of the authority (owner) in the transaction's accounts
|
23
|
-
# @param program_index [Integer] Index of the SPL Token Program in the transaction's accounts (default: 3)
|
24
|
-
# @return [Solace::Instruction]
|
25
|
-
def self.build(
|
26
|
-
amount:,
|
27
|
-
decimals:,
|
28
|
-
to_index:,
|
29
|
-
from_index:,
|
30
|
-
mint_index:,
|
31
|
-
authority_index:,
|
32
|
-
program_index: 3
|
33
|
-
)
|
34
|
-
Solace::Instruction.new.tap do |ix|
|
35
|
-
ix.program_index = program_index
|
36
|
-
ix.accounts = [from_index, mint_index, to_index, authority_index]
|
37
|
-
ix.data = data(amount, decimals)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Instruction data for a token transfer instruction
|
42
|
-
#
|
43
|
-
# The BufferLayout is:
|
44
|
-
# - [Instruction Index (1 byte)]
|
45
|
-
# - [Amount (8 bytes little-endian u64)]
|
46
|
-
# - [Decimals (8 bytes little-endian u64)]
|
47
|
-
#
|
48
|
-
# @param amount [Integer] Amount to transfer
|
49
|
-
# @param decimals [Integer] Number of decimals for the token
|
50
|
-
# @return [Array] 1-byte instruction index + 8-byte amount + decimals
|
51
|
-
def self.data(amount, decimals)
|
52
|
-
INSTRUCTION_INDEX +
|
53
|
-
Solace::Utils::Codecs.encode_le_u64(amount).bytes +
|
54
|
-
[decimals]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Solace
|
4
|
-
module Instructions
|
5
|
-
# Service object for building a System Program transfer instruction
|
6
|
-
class TransferInstruction
|
7
|
-
# Instruction ID for System Transfer
|
8
|
-
INSTRUCTION_ID = [2, 0, 0, 0].freeze
|
9
|
-
|
10
|
-
# Builds a Solace::Instruction for transferring SOL
|
11
|
-
#
|
12
|
-
# System Program transfer instruction layout:
|
13
|
-
# - 4 bytes: instruction index (0 for transfer)
|
14
|
-
# - 8 bytes: amount (u64, little-endian)
|
15
|
-
#
|
16
|
-
# @param lamports [Integer] Amount to transfer (in lamports)
|
17
|
-
# @param to_index [Integer] Index of the recipient in the transaction's accounts
|
18
|
-
# @param from_index [Integer] Index of the sender in the transaction's accounts
|
19
|
-
# @param program_index [Integer] Index of the program in the transaction's accounts (default: 2)
|
20
|
-
# @return [Solace::Instruction]
|
21
|
-
def self.build(
|
22
|
-
lamports:,
|
23
|
-
to_index:,
|
24
|
-
from_index:,
|
25
|
-
program_index: 2
|
26
|
-
)
|
27
|
-
Solace::Instruction.new.tap do |ix|
|
28
|
-
ix.program_index = program_index
|
29
|
-
ix.accounts = [from_index, to_index]
|
30
|
-
ix.data = data(lamports)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# Instruction data for a transfer instruction
|
35
|
-
#
|
36
|
-
# The BufferLayout is:
|
37
|
-
# - [Instruction ID (4 bytes)]
|
38
|
-
# - [Amount (8 bytes little-endian u64)]
|
39
|
-
#
|
40
|
-
# @param lamports [Integer] Amount to transfer (in lamports)
|
41
|
-
# @return [Array] 4-byte instruction ID + 8-byte amount
|
42
|
-
def self.data(lamports)
|
43
|
-
INSTRUCTION_ID +
|
44
|
-
Solace::Utils::Codecs.encode_le_u64(lamports).bytes
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Solace
|
4
|
-
class SerializableRecord
|
5
|
-
include Solace::Concerns::BinarySerializable
|
6
|
-
|
7
|
-
# Parse instruction from io stream
|
8
|
-
#
|
9
|
-
# @param io [IO or StringIO] The input to read bytes from.
|
10
|
-
# @return [Solace::Instruction] Parsed instruction object
|
11
|
-
def self.deserialize(io)
|
12
|
-
self::DESERIALIZER.call(io)
|
13
|
-
rescue NameError => e
|
14
|
-
raise "DESERIALIZER must be defined: #{e.message}"
|
15
|
-
end
|
16
|
-
|
17
|
-
# Serializes the transaction to a binary format
|
18
|
-
#
|
19
|
-
# @return [String] The serialized transaction (binary)
|
20
|
-
def serialize
|
21
|
-
self.class::SERIALIZER.call(self)
|
22
|
-
rescue NameError => e
|
23
|
-
raise "SERIALIZER must be defined: #{e.message}"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Solace
|
4
|
-
module Serializers
|
5
|
-
class Base
|
6
|
-
include Solace::Utils
|
7
|
-
|
8
|
-
# Proxy method to call the serializer and create a new instance
|
9
|
-
#
|
10
|
-
# @return [String] The serialized record (base64)
|
11
|
-
def self.call(*args, **kwargs)
|
12
|
-
new(*args, **kwargs).call
|
13
|
-
end
|
14
|
-
|
15
|
-
# Serializes the record
|
16
|
-
#
|
17
|
-
# @return [String] The serialized record (base64)
|
18
|
-
def call
|
19
|
-
bin = self.class::STEPS
|
20
|
-
.map { |m| send(m) }
|
21
|
-
.flatten
|
22
|
-
.compact
|
23
|
-
.pack('C*')
|
24
|
-
|
25
|
-
Base64.strict_encode64(bin)
|
26
|
-
rescue NameError => e
|
27
|
-
raise "STEPS must be defined: #{e.message}"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|