solana-ruby-web3js 1.0.1.beta3 → 1.0.1.beta4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 769dd8aff42953255243d337b811ab9bd61e27e19e6957d235e9e015300f925b
4
- data.tar.gz: e940aa048c15af34c5f06bf5de1db3716e8f68f1f83c41fe480a6de748082310
3
+ metadata.gz: 2ca6cbe9f7024efc46fc77b926caa77368c337d69f12b2d5bde3434cacd8be99
4
+ data.tar.gz: 7e4823b24785b3ec0d54f96f2a9b43b02cbdbedfe4732bf674249918b08beeab
5
5
  SHA512:
6
- metadata.gz: 7cd8eb6a1ff5a1c749cb1ded759323bd1a7a43dea78e6d19444f1d1e8dc77ca24f757c5fc53412431020f09960db0cef8f2bd519641a0bdc5790c4dc8e60a581
7
- data.tar.gz: d6c68d6c97ae798d5b79b4fcaae962ac3e34e7e2d28d61b80124b4725b3926803c49f20bd055bc7c6af9b46229558111a3ea0dae932d15750f726484a0c6b460
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.beta1)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolanaRuby
4
- VERSION = "1.0.1.beta3"
4
+ VERSION = "1.0.1.beta4"
5
5
  end
data/lib/solana_ruby.rb CHANGED
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "solana_ruby/version"
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.beta3
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-10-03 00:00:00.000000000 Z
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