solana-ruby-web3js 1.0.1.beta3 → 1.0.1.beta4
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/.DS_Store +0 -0
- data/Gemfile.lock +7 -1
- data/lib/solana_ruby/keypair.rb +39 -0
- data/lib/solana_ruby/transaction.rb +108 -0
- data/lib/solana_ruby/transaction_helper.rb +29 -0
- data/lib/solana_ruby/transaction_instruction.rb +42 -0
- data/lib/solana_ruby/version.rb +1 -1
- data/lib/solana_ruby.rb +2 -4
- metadata +34 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ca6cbe9f7024efc46fc77b926caa77368c337d69f12b2d5bde3434cacd8be99
|
4
|
+
data.tar.gz: 7e4823b24785b3ec0d54f96f2a9b43b02cbdbedfe4732bf674249918b08beeab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d75c69661f9bd7353c9251d8cb7615785d5233d7832a1e596c02997a42b1f07dbfb9600abb45ea2b04dfc8d80ddbe2167e91e2504c436ca27e99ec30a4679f2
|
7
|
+
data.tar.gz: e4784c227e3e24fd2bcaf79734b42602540c39c8ed4338fc5a53d740b2077aedeb76e7bb62c84d7cf4bc54c5a044281293d02adfd92fc487483d428ab03c1ea5
|
data/.DS_Store
CHANGED
Binary file
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
solana-ruby-web3js (1.0.1.
|
4
|
+
solana-ruby-web3js (1.0.1.beta3)
|
5
5
|
base58 (~> 0.2.3)
|
6
6
|
base64 (~> 0.2.0)
|
7
|
+
ed25519
|
8
|
+
rbnacl (~> 6.0)
|
7
9
|
websocket-client-simple (~> 0.8.0)
|
8
10
|
|
9
11
|
GEM
|
@@ -64,6 +66,8 @@ GEM
|
|
64
66
|
ed25519 (1.3.0)
|
65
67
|
erubi (1.13.0)
|
66
68
|
event_emitter (0.2.6)
|
69
|
+
ffi (1.17.0)
|
70
|
+
ffi (1.17.0-arm64-darwin)
|
67
71
|
flay (2.13.3)
|
68
72
|
erubi (~> 1.10)
|
69
73
|
path_expander (~> 1.0)
|
@@ -93,6 +97,8 @@ GEM
|
|
93
97
|
public_suffix (6.0.1)
|
94
98
|
racc (1.8.1)
|
95
99
|
rainbow (3.1.1)
|
100
|
+
rbnacl (6.0.1)
|
101
|
+
ffi
|
96
102
|
reek (6.3.0)
|
97
103
|
dry-schema (~> 1.13.0)
|
98
104
|
parser (~> 3.3.0)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SolanaRuby
|
2
|
+
class Keypair
|
3
|
+
require 'rbnacl'
|
4
|
+
require 'base58'
|
5
|
+
|
6
|
+
# Generates a new Ed25519 keypair
|
7
|
+
def self.generate
|
8
|
+
signing_key = RbNaCl::Signatures::Ed25519::SigningKey.generate
|
9
|
+
public_key_bytes = signing_key.verify_key.to_bytes # Binary format for public key
|
10
|
+
private_key_hex = signing_key.to_bytes.unpack1('H*') # Hex format for private key
|
11
|
+
|
12
|
+
# Convert public key binary to Base58 for readability and compatibility
|
13
|
+
{
|
14
|
+
public_key: Base58.binary_to_base58(public_key_bytes),
|
15
|
+
private_key: private_key_hex
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Restores a keypair from a private key in hex format
|
20
|
+
def self.from_private_key(private_key_hex)
|
21
|
+
raise ArgumentError, "Invalid private key length" unless private_key_hex.size == 64
|
22
|
+
|
23
|
+
# Convert hex private key to binary format for signing key
|
24
|
+
private_key_bytes = [private_key_hex].pack('H*')
|
25
|
+
|
26
|
+
# Initialize signing key
|
27
|
+
signing_key = RbNaCl::Signatures::Ed25519::SigningKey.new(private_key_bytes)
|
28
|
+
|
29
|
+
# Extract public key in binary format
|
30
|
+
public_key_bytes = signing_key.verify_key.to_bytes
|
31
|
+
|
32
|
+
# Return public key in Base58 format and private key in hex format
|
33
|
+
{
|
34
|
+
public_key: Base58.binary_to_base58(public_key_bytes),
|
35
|
+
private_key: private_key_hex
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module SolanaRuby
|
2
|
+
class Transaction
|
3
|
+
require 'rbnacl'
|
4
|
+
|
5
|
+
attr_accessor :instructions, :signatures, :fee_payer, :recent_blockhash
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@instructions = []
|
9
|
+
@signatures = []
|
10
|
+
@fee_payer = nil
|
11
|
+
@recent_blockhash = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_instruction(instruction)
|
15
|
+
@instructions << instruction
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_fee_payer(pubkey)
|
19
|
+
puts "Setting fee payer: #{pubkey.inspect}" # Debugging output
|
20
|
+
unless Base58.valid?(pubkey)
|
21
|
+
raise "Invalid Base58 public key for fee payer: #{pubkey.inspect}"
|
22
|
+
end
|
23
|
+
@fee_payer = pubkey # Store as-is since Base58 gem can handle encoding/decoding
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_recent_blockhash(blockhash)
|
27
|
+
raise "Invalid Base58 blockhash" unless Base58.valid?(blockhash)
|
28
|
+
@recent_blockhash = blockhash # Store as-is for similar reasons
|
29
|
+
end
|
30
|
+
|
31
|
+
def serialize
|
32
|
+
raise "Recent blockhash not set" if @recent_blockhash.nil?
|
33
|
+
raise "Fee payer not set" if @fee_payer.nil?
|
34
|
+
|
35
|
+
transaction_data = []
|
36
|
+
transaction_data << Base58.base58_to_binary(@recent_blockhash) # Convert as needed here
|
37
|
+
transaction_data << Base58.base58_to_binary(@fee_payer)
|
38
|
+
transaction_data << [@instructions.length].pack("C")
|
39
|
+
|
40
|
+
@instructions.each do |instruction|
|
41
|
+
serialized_instruction = instruction.serialize
|
42
|
+
raise "Instruction serialization failed" if serialized_instruction.nil?
|
43
|
+
transaction_data << serialized_instruction
|
44
|
+
end
|
45
|
+
|
46
|
+
serialized = transaction_data.join
|
47
|
+
puts "Serialized Transaction Data: #{serialized.bytes.inspect}" # Debugging output
|
48
|
+
|
49
|
+
serialized
|
50
|
+
end
|
51
|
+
|
52
|
+
def sign(private_key_hex)
|
53
|
+
private_key_bytes = [private_key_hex].pack('H*')
|
54
|
+
signing_key = RbNaCl::Signatures::Ed25519::SigningKey.new(private_key_bytes)
|
55
|
+
|
56
|
+
message = serialize_message
|
57
|
+
signature = signing_key.sign(message)
|
58
|
+
|
59
|
+
@signatures << signature # Store as binary
|
60
|
+
Base58.binary_to_base58(signature) # Convert to Base58 for external use
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def serialize_message
|
66
|
+
accounts = collect_accounts
|
67
|
+
|
68
|
+
message_data = []
|
69
|
+
message_data << Base58.base58_to_binary(@recent_blockhash)
|
70
|
+
message_data << [accounts.length].pack("C")
|
71
|
+
|
72
|
+
accounts.each do |account|
|
73
|
+
message_data << account
|
74
|
+
end
|
75
|
+
|
76
|
+
message_data << [@instructions.length].pack("C")
|
77
|
+
|
78
|
+
@instructions.each do |instruction|
|
79
|
+
message_data << instruction.serialize
|
80
|
+
end
|
81
|
+
|
82
|
+
message_data.join
|
83
|
+
end
|
84
|
+
|
85
|
+
def collect_accounts
|
86
|
+
accounts = []
|
87
|
+
accounts << Base58.base58_to_binary(@fee_payer) if @fee_payer
|
88
|
+
|
89
|
+
@instructions.each do |instruction|
|
90
|
+
instruction.keys.each do |key_meta|
|
91
|
+
pubkey_binary = Base58.base58_to_binary(key_meta[:pubkey])
|
92
|
+
accounts << pubkey_binary unless accounts.include?(pubkey_binary)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
accounts.uniq
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class Base58
|
102
|
+
ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.freeze
|
103
|
+
|
104
|
+
# Checks if a string contains only valid Base58 characters
|
105
|
+
def self.valid?(base58_str)
|
106
|
+
base58_str.chars.all? { |char| ALPHABET.include?(char) }
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SolanaRuby
|
2
|
+
class TransactionHelper
|
3
|
+
require 'base58'
|
4
|
+
PROGRAM_ID = '11111111111111111111111111111111'
|
5
|
+
|
6
|
+
def self.create_transfer(from_pubkey, to_pubkey, lamports, program_id = PROGRAM_ID)
|
7
|
+
transfer_instruction = TransactionInstruction.new(
|
8
|
+
keys: [
|
9
|
+
{ pubkey: from_pubkey, is_signer: true, is_writable: true },
|
10
|
+
{ pubkey: to_pubkey, is_signer: false, is_writable: true }
|
11
|
+
],
|
12
|
+
program_id: program_id,
|
13
|
+
data: [2, lamports].pack('CQ<') # Instruction type 2 (transfer) + lamports (u64)
|
14
|
+
)
|
15
|
+
transfer_instruction
|
16
|
+
end
|
17
|
+
|
18
|
+
# Helper to construct a new transaction
|
19
|
+
def self.new_transaction(from_pubkey, to_pubkey, lamports, recent_blockhash, program_id = PROGRAM_ID)
|
20
|
+
transaction = Transaction.new
|
21
|
+
transaction.set_fee_payer(from_pubkey)
|
22
|
+
transaction.set_recent_blockhash(recent_blockhash)
|
23
|
+
|
24
|
+
transfer_instruction = create_transfer(from_pubkey, to_pubkey, lamports, program_id)
|
25
|
+
transaction.add_instruction(transfer_instruction)
|
26
|
+
transaction
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module SolanaRuby
|
2
|
+
class TransactionInstruction
|
3
|
+
require 'base58'
|
4
|
+
|
5
|
+
attr_accessor :keys, :program_id, :data
|
6
|
+
|
7
|
+
def initialize(keys:, program_id:, data:)
|
8
|
+
@keys = keys # Array of account metadata hashes
|
9
|
+
@program_id = program_id # Program ID in Base58
|
10
|
+
@data = data # Binary data for the instruction
|
11
|
+
end
|
12
|
+
|
13
|
+
def serialize
|
14
|
+
serialized_instruction = ""
|
15
|
+
|
16
|
+
# Convert and serialize the program ID from Base58 to binary
|
17
|
+
program_id_binary = Base58.base58_to_binary(@program_id)
|
18
|
+
serialized_instruction << program_id_binary
|
19
|
+
|
20
|
+
# Serialize the number of keys
|
21
|
+
serialized_instruction << [@keys.length].pack("C")
|
22
|
+
|
23
|
+
# Serialize each key (pubkey in binary, is_signer, is_writable flags)
|
24
|
+
@keys.each do |key_meta|
|
25
|
+
# Convert public key to binary and serialize it
|
26
|
+
pubkey_binary = Base58.base58_to_binary(key_meta[:pubkey])
|
27
|
+
serialized_instruction << pubkey_binary
|
28
|
+
|
29
|
+
# Serialize meta flags (is_signer and is_writable)
|
30
|
+
meta_flags = (key_meta[:is_signer] ? 1 : 0) | (key_meta[:is_writable] ? 2 : 0)
|
31
|
+
serialized_instruction << [meta_flags].pack("C")
|
32
|
+
end
|
33
|
+
|
34
|
+
# Serialize data length (encoded as a single byte, can adjust with C, S, and L accordingly if data is larger)
|
35
|
+
serialized_instruction << [@data.length].pack("C")
|
36
|
+
|
37
|
+
# Serialize the actual data in binary format
|
38
|
+
serialized_instruction << @data
|
39
|
+
serialized_instruction
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/solana_ruby/version.rb
CHANGED
data/lib/solana_ruby.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require_relative "solana_ruby/http_client"
|
5
|
-
require_relative "solana_ruby/web_socket_client"
|
3
|
+
Dir[File.join(__dir__, 'solana_ruby', '*.rb')].each { |file| require file }
|
6
4
|
# Dir["solana_ruby/*.rb"].each { |f| require_relative f.delete(".rb") }
|
7
|
-
|
5
|
+
require 'pry'
|
8
6
|
module SolanaRuby
|
9
7
|
class Error < StandardError; end
|
10
8
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solana-ruby-web3js
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.1.
|
4
|
+
version: 1.0.1.beta4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- BuildSquad
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: websocket-client-simple
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.2.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rbnacl
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '6.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '6.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ed25519
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: brakeman
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -211,6 +239,10 @@ files:
|
|
211
239
|
- lib/solana_ruby/http_methods/slot_methods.rb
|
212
240
|
- lib/solana_ruby/http_methods/token_methods.rb
|
213
241
|
- lib/solana_ruby/http_methods/transaction_methods.rb
|
242
|
+
- lib/solana_ruby/keypair.rb
|
243
|
+
- lib/solana_ruby/transaction.rb
|
244
|
+
- lib/solana_ruby/transaction_helper.rb
|
245
|
+
- lib/solana_ruby/transaction_instruction.rb
|
214
246
|
- lib/solana_ruby/version.rb
|
215
247
|
- lib/solana_ruby/web_socket_client.rb
|
216
248
|
- lib/solana_ruby/web_socket_handlers.rb
|