solana-ruby-web3js 1.0.1.beta2 → 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: b4523cc4b31deed37187c1f16585843ad9cb30fb65fa6e1ffd623f40a77cba0b
4
- data.tar.gz: 95b7f14f5202f681d19e8ce09c466660d583fd84a4fb82213b77c1eff633164e
3
+ metadata.gz: 2ca6cbe9f7024efc46fc77b926caa77368c337d69f12b2d5bde3434cacd8be99
4
+ data.tar.gz: 7e4823b24785b3ec0d54f96f2a9b43b02cbdbedfe4732bf674249918b08beeab
5
5
  SHA512:
6
- metadata.gz: f5e042632802df702a40a514f7fae3d0c2c5d3d3d6cbe563e94f5a8d5b8be2e9bb8b61b0da2cec398f3c9d9f71247162f281e31770d2559d41a9ed85596142eb
7
- data.tar.gz: be74a999f1eebc3eb4cded2b4d594aa9a90dca57589af40ce360636efe3cb150317e948ab8b9f95eba8485846a56dde9405d65465615e34ad5c246da8c84e90e
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)
data/README.md CHANGED
@@ -67,33 +67,86 @@ For a more detailed overview of Solana's available RPC methods, visit the offici
67
67
 
68
68
  ### Options Parameter
69
69
 
70
- The options parameter is a hash that can include the following fields:
70
+ The options parameter is a hash that can include the following fields and more, allowing for customized responses:
71
71
 
72
- commitment: Specifies the level of commitment desired when querying state.
72
+ - **commitment**: Specifies the level of commitment desired when querying state. Options include:
73
73
 
74
- Options include:
74
+ - 'finalized': Query the most recent block confirmed by supermajority of the cluster.
75
+ - 'confirmed': Query the most recent block that has been voted on by supermajority of the cluster.
76
+ - 'processed': Query the most recent block regardless of cluster voting.
75
77
 
76
- 'finalized': Query the most recent block confirmed by supermajority of the cluster.
77
- 'confirmed': Query the most recent block that has been voted on by supermajority of the cluster.
78
- 'processed': Query the most recent block regardless of cluster voting.
78
+ - **encoding**: Defines the format of the returned account data. Possible values include:
79
79
 
80
- encoding: Defines the format of the returned account data. Possible values include:
80
+ - 'jsonParsed': Returns data in a JSON-parsed format.
81
+ - 'base64': Returns raw account data in Base64 encoding.
82
+ - 'base64+zstd': Returns compressed Base64 data.
81
83
 
82
- 'jsonParsed': Returns data in a JSON-parsed format.
83
- 'base64': Returns raw account data in Base64 encoding.
84
- 'base64+zstd': Returns compressed Base64 data.
84
+ - **epoch**: Specify the epoch when querying for certain information like epoch details.
85
+
86
+ - **skipPreflight**: If true, skip the preflight transaction verification. Preflight ensures that a transaction is valid before sending it to the network, but skipping this can result in faster submission.
87
+
88
+ - **maxRetries**: Specify how many times to retry sending a transaction before giving up.
89
+
90
+ - **recentBlockhash**: Provide a custom recent blockhash for a transaction if not relying on the default.
85
91
 
86
92
  By providing options, you can control the nature of the returned data and the reliability of the query.
87
93
 
88
94
  ### Filters Parameter
89
95
 
90
- The filters parameter allows you to specify conditions for querying token accounts. Some common filter types include:
96
+ The filters parameter allows you to specify conditions when querying accounts and other resources. Here are some common filters:
97
+
98
+ #### Token Accounts by Owner
99
+
100
+ # Replace 'owner_pubkey' with the owner's public key
101
+ owner_pubkey = 'Fg6PaFpoGXkYsidMpWxTWqSKJf6KJkUxX92cnv7WMd2J'
102
+
103
+ # Query for token accounts owned by this public key
104
+ filters = [{ mint: 'TokenMintPublicKey' }]
105
+
106
+ result = client.get_token_accounts_by_owner(owner_pubkey, filters)
107
+
108
+ puts result
109
+
110
+ #### Account Filters
111
+
112
+ You can use the filters parameter to apply conditions for certain queries, such as fetching token accounts by a specific owner or a specific token program. Below are examples of filters that can be used in different queries.
113
+
114
+ #### Mint Filter
115
+
116
+ - Filter accounts by a specific token mint.
117
+
118
+ ``filters = [{ mint: 'TokenMintPublicKey' }]``
119
+
120
+ ``result = client.get_token_accounts_by_owner(owner_pubkey, filters)``
121
+
122
+ #### Program Filter
123
+
124
+ - Filter accounts associated with a particular program, such as the token program.
125
+
126
+ ``filters = [{ programId: 'TokenProgramPublicKey' }]``
127
+
128
+ ``result = client.get_token_accounts_by_owner(owner_pubkey, filters)``
129
+
130
+ #### Data Size Filter
131
+
132
+ - Filter accounts by the exact size of the account data.
133
+
134
+ ``filters = [{ dataSize: 165 }]``
135
+
136
+ ``result = client.get_program_accounts('ProgramPublicKey', filters)``
137
+
138
+ #### Memcmp Filter
139
+
140
+ - Filter by matching a specific slice of bytes at a given offset in account data.
91
141
 
92
- # Mint Filter: Filter by a specific token mint. This retrieves accounts holding tokens of that mint.
93
- filters = { mint: 'TokenMintPublicKey' }
142
+ ``filters = [{
143
+ memcmp: {
144
+ offset: 0,
145
+ bytes: 'Base58EncodedBytes'
146
+ }
147
+ }]``
94
148
 
95
- # Program Filter: Filter by a specific program (e.g., the token program).
96
- filters = { programId: 'TokenProgramPublicKey' }
149
+ ``result = client.get_program_accounts('ProgramPublicKey', filters)``
97
150
 
98
151
  ## WebSocket Methods
99
152
 
@@ -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.beta2"
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.beta2
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