solana-ruby-web3js 2.0.0beta1 → 2.0.0beta2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37360e6f27ca521194022c29c3419d2dc06e5dcae0499af04892e3ca29299b0d
4
- data.tar.gz: c5748b0ddacfaa170e79aba9a16b883c64a05ac7f776f0589c3914a5ad418356
3
+ metadata.gz: 6bb6650de7a5beae14649fe9cfac20973923d0be4c4f74e9d1e8f373e70842b9
4
+ data.tar.gz: c3ad4316d61d4326327bb281a3eb64991011ae14d51a7974de6eaf9705d4ffa5
5
5
  SHA512:
6
- metadata.gz: 683573ae5898ae932dea765b65cc4d73136f198429920be4e923da76bfed3b515e941f96761238f42dd92cedadc7d28c03f43dc3357fb07451a4940b3a2e93e0
7
- data.tar.gz: e6c3b0e84760561c6b22290f3dab047cb041f9de7ed02d1a7cd88cc5ed285a6fb5c2ca97e7a719f709044c044b3c769aa0d0c612bb35b5894e0e70f1955e9c4e
6
+ metadata.gz: 94c8304f1d05d7cbd8ec22947d98ede21c1892b210ad5cdb43f3e6293f4c6ab288c8aa83b1ba6e40a28d08a191a32ba775966eeb370631d02112cac981309fb6
7
+ data.tar.gz: '0085b47b4f44786e0bd0af77827a12cbc191744a16aff61448cafff641a53efa798677ef51b3748966f76547b883fd767d3f48ffe5297f8519cc08eb1ee81e90'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- solana-ruby-web3js (1.0.1.beta3)
4
+ solana-ruby-web3js (2.0.0beta1)
5
5
  base58 (~> 0.2.3)
6
6
  base64 (~> 0.2.0)
7
7
  ed25519
data/README.md CHANGED
@@ -342,7 +342,7 @@ To transfer SOL (the native cryptocurrency of the Solana blockchain) from one ac
342
342
 
343
343
  - **Sender's Keypair:** Either generate a new keypair or provide the private key for an existing sender account. This keypair is used to sign the transaction.
344
344
  - **Receiver's Public Key:** Specify the public key of the destination account. You can generate a new keypair for the receiver or use an existing public key.
345
- - **Airdrop Functionality:** For Devnet or Testnet transactions, ensure that the sender's account is funded with sufficient lamports using the Solana airdrop feature.
345
+ - **Airdrop Functionality:** For Mainnet, Devnet, or Testnet transactions, ensure that the sender's account is funded with sufficient lamports using the Solana airdrop feature.
346
346
  - An initialized client to interact with the Solana blockchain.
347
347
 
348
348
  #### Example Usage:
@@ -364,7 +364,7 @@ To transfer SOL (the native cryptocurrency of the Solana blockchain) from one ac
364
364
  sender_pubkey = sender_keypair[:public_key]
365
365
 
366
366
 
367
- # Airdrop some lamports to the sender's account
367
+ # Airdrop some lamports to the sender's account when needed.
368
368
  lamports = 10 * 1_000_000_000
369
369
  sleep(1)
370
370
  result = client.request_airdrop(sender_pubkey, lamports)
@@ -374,7 +374,7 @@ To transfer SOL (the native cryptocurrency of the Solana blockchain) from one ac
374
374
 
375
375
  # Generate or use an existing receiver's public key
376
376
  # Option 1: Generate a new keypair for the receiver
377
- receiver_keypair = SolanaRuby::Keypair.generate # generate receiver keypair
377
+ receiver_keypair = SolanaRuby::Keypair.generate
378
378
  receiver_pubkey = receiver_keypair[:public_key]
379
379
  # Option 2: Use an existing public key
380
380
  # receiver_pubkey = 'InsertExistingPublicKeyHere'
@@ -385,7 +385,7 @@ To transfer SOL (the native cryptocurrency of the Solana blockchain) from one ac
385
385
  puts "Receiver's Public Key: #{receiver_keypair[:public_key]}"
386
386
 
387
387
  # Create a new transaction
388
- transaction = SolanaRuby::TransactionHelper.new_sol_transaction(
388
+ transaction = SolanaRuby::TransactionHelper.sol_transfer(
389
389
  sender_pubkey,
390
390
  receiver_pubkey,
391
391
  transfer_lamports,
@@ -4,26 +4,26 @@ module SolanaRuby
4
4
  attr_reader :size
5
5
 
6
6
  BITS = {
7
- 8 => { directive: 'C*', size: 1 },
8
- 32 => { directive: 'L*', size: 4 },
9
- 64 => { directive: 'Q*', size: 8 }
7
+ 8 => { directive: 'C', size: 1 }, # 8-bit unsigned integer
8
+ 32 => { directive: 'L<', size: 4 }, # 32-bit little-endian unsigned integer
9
+ 64 => { directive: 'Q<', size: 8 } # 64-bit little-endian unsigned integer
10
10
  }
11
11
 
12
12
  def initialize(bits)
13
13
  @bits = bits
14
14
  type = BITS[@bits]
15
- raise "Can only fit #{BITS.keys}" unless type
15
+ raise "Unsupported size. Supported sizes: #{BITS.keys.join(', ')} bits" unless type
16
16
  @size = type[:size]
17
17
  @directive = type[:directive]
18
18
  end
19
19
 
20
- # Serialize the unsigned integer into bytes
20
+ # Serialize the unsigned integer into properly aligned bytes
21
21
  def serialize(obj)
22
22
  raise "Can only serialize integers" unless obj.is_a?(Integer)
23
- raise "Cannot serialize negative integers" if obj < 0
23
+ raise "Cannot serialize negative integers" if obj.negative?
24
24
 
25
25
  if obj >= 256**@size
26
- raise "Integer too large (does not fit in #{@size} bytes)"
26
+ raise "Integer too large to fit in #{@size} bytes"
27
27
  end
28
28
 
29
29
  [obj].pack(@directive).bytes
@@ -31,7 +31,7 @@ module SolanaRuby
31
31
 
32
32
  # Deserialize bytes into the unsigned integer
33
33
  def deserialize(bytes)
34
- raise "Invalid serialization (wrong size)" if bytes.size != @size
34
+ raise "Invalid serialization (expected #{@size} bytes, got #{bytes.size})" if bytes.size != @size
35
35
 
36
36
  bytes.pack('C*').unpack(@directive).first
37
37
  end
@@ -21,5 +21,9 @@ module SolanaRuby
21
21
  def blob1
22
22
  Blob.new(1)
23
23
  end
24
+
25
+ def blob32
26
+ Blob.new(32)
27
+ end
24
28
  end
25
29
  end
@@ -72,10 +72,10 @@ module SolanaRuby
72
72
  instructions.push(item)
73
73
  end
74
74
 
75
- def sign(keys)
76
- raise 'No signers' unless keys.any?
75
+ def sign(keypairs)
76
+ raise 'No signers' unless keypairs.any?
77
77
 
78
- keys = keys.uniq{ |k| key[:public_key] }
78
+ keys = keypairs.uniq { |kp| kp[:public_key] }
79
79
  @signatures = keys.map do |key|
80
80
  {
81
81
  signature: nil,
@@ -116,15 +116,17 @@ module SolanaRuby
116
116
  def compile_message
117
117
  check_for_errors
118
118
  fetch_message_data
119
- message = Message.new(
120
- header: {
121
- num_required_signatures: @num_required_signatures,
122
- num_readonly_signed_accounts: @num_readonly_signed_accounts,
123
- num_readonly_unsigned_accounts: @num_readonly_unsigned_accounts,
124
- },
125
- account_keys: @account_keys, recent_blockhash: recent_blockhash, instructions: @instructs
119
+
120
+ # add instruction structure
121
+ instructs = add_instructs
122
+
123
+ message_data = Message.new(
124
+ header: @header,
125
+ account_keys: @account_keys,
126
+ recent_blockhash: recent_blockhash,
127
+ instructions: instructs
126
128
  )
127
- message
129
+ message_data
128
130
  end
129
131
 
130
132
  def check_for_errors
@@ -170,11 +172,8 @@ module SolanaRuby
170
172
  # Split out signing from non-signing keys and count header values
171
173
  signed_keys = []
172
174
  unsigned_keys = []
173
- header_params = split_keys(unique_metas, signed_keys, unsigned_keys)
175
+ @header = split_keys(unique_metas, signed_keys, unsigned_keys)
174
176
  @account_keys = signed_keys + unsigned_keys
175
-
176
- # add instruction structure
177
- @instructs = add_instructs
178
177
  end
179
178
 
180
179
  def append_program_id(program_ids, account_metas)
@@ -247,19 +246,24 @@ module SolanaRuby
247
246
  end
248
247
 
249
248
  def split_keys(unique_metas, signed_keys, unsigned_keys)
250
- @num_required_signatures = 0
251
- @num_readonly_signed_accounts = 0
252
- @num_readonly_unsigned_accounts = 0
249
+ num_required_signatures = 0
250
+ num_readonly_signed_accounts = 0
251
+ num_readonly_unsigned_accounts = 0
253
252
  unique_metas.each do |meta|
254
253
  if meta[:is_signer]
255
254
  signed_keys.push(meta[:pubkey])
256
- @num_required_signatures += 1
257
- @num_readonly_signed_accounts += 1 if (!meta[:is_writable])
255
+ num_required_signatures += 1
256
+ num_readonly_signed_accounts += 1 if (!meta[:is_writable])
258
257
  else
259
258
  unsigned_keys.push(meta[:pubkey])
260
- @num_readonly_unsigned_accounts += 1 if (!meta[:is_writable])
259
+ num_readonly_unsigned_accounts += 1 if (!meta[:is_writable])
261
260
  end
262
261
  end
262
+ {
263
+ num_required_signatures: num_required_signatures,
264
+ num_readonly_signed_accounts: num_readonly_signed_accounts,
265
+ num_readonly_unsigned_accounts: num_readonly_unsigned_accounts,
266
+ }
263
267
  end
264
268
 
265
269
  def partial_sign(message, keys)
@@ -19,46 +19,59 @@ module SolanaRuby
19
19
  instruction: :uint8,
20
20
  amount: :uint64
21
21
  },
22
- # Create account layout
22
+ # Create account layout
23
23
  create_account: {
24
- instruction: :uint8,
24
+ instruction: :uint32,
25
25
  lamports: :uint64,
26
- space: :uint64
26
+ space: :uint64,
27
+ program_id: :blob32
27
28
  }
28
29
  }
29
30
 
30
31
  # Method to create a system account (e.g., for SPL token or SOL)
31
- def self.create_account(from_pubkey, new_account_pubkey, lamports, space, owner_pubkey = SYSTEM_PROGRAM_ID)
32
- instruction_data = encode_data(INSTRUCTION_LAYOUTS[:create_account], { instruction: 0, lamports: lamports, space: space })
32
+ def self.account_instruction(from_pubkey, new_account_pubkey, lamports, space, program_id)
33
+ # Encode the instruction data
34
+ instruction_data = encode_data(
35
+ INSTRUCTION_LAYOUTS[:create_account],
36
+ {
37
+ instruction: 0, # '0' corresponds to the Create Account instruction
38
+ lamports: lamports, # The amount of lamports to transfer to the new account
39
+ space: space, # Amount of space allocated for the account's data
40
+ program_id: Base58.base58_to_binary(program_id, :bitcoin).bytes # Convert public key to binary
41
+ }
42
+ )
43
+
44
+ # Construct the transaction instruction
33
45
  create_account_instruction = TransactionInstruction.new(
34
46
  keys: [
35
- { pubkey: from_pubkey, is_signer: true, is_writable: true },
36
- { pubkey: new_account_pubkey, is_signer: false, is_writable: true },
37
- { pubkey: owner_pubkey, is_signer: false, is_writable: false }
47
+ { pubkey: from_pubkey, is_signer: true, is_writable: true }, # Funder's account
48
+ { pubkey: new_account_pubkey, is_signer: true, is_writable: true } # New account
38
49
  ],
39
- program_id: owner_pubkey,
40
- data: instruction_data.bytes
50
+ program_id: program_id, # Use Solana's system program for account creation
51
+ data: instruction_data # Encoded instruction data
41
52
  )
53
+
54
+ # return instruction data
42
55
  create_account_instruction
43
56
  end
44
57
 
45
- def self.create_and_sign_transaction(from_pubkey, new_account_pubkey, lamports, space, recent_blockhash)
58
+
59
+ def self.create_account(from_pubkey, new_account_pubkey, lamports, space, recent_blockhash, program_id = SYSTEM_PROGRAM_ID)
46
60
  # Create the transaction
47
61
  transaction = Transaction.new
48
62
  transaction.set_fee_payer(from_pubkey)
49
63
  transaction.set_recent_blockhash(recent_blockhash)
50
64
 
51
65
  # Add the create account instruction to the transaction
52
- create_account_instruction = create_account(from_pubkey, new_account_pubkey, lamports, space)
53
- transaction.add_instruction(create_account_instruction)
54
-
55
- # You would then sign the transaction and send it as needed
56
- # Example: signing and sending the transaction
66
+ instruction = account_instruction(from_pubkey, new_account_pubkey, lamports, space, program_id)
67
+ transaction.add_instruction(instruction)
68
+
69
+ # return the transaction for signing
57
70
  transaction
58
71
  end
59
72
 
60
73
  # Method to create a SOL transfer instruction
61
- def self.transfer_sol_transaction(from_pubkey, to_pubkey, lamports)
74
+ def self.transfer_sol_instruction(from_pubkey, to_pubkey, lamports)
62
75
  fields = INSTRUCTION_LAYOUTS[:sol_transfer]
63
76
  data = encode_data(fields, { instruction: 2, lamports: lamports })
64
77
  TransactionInstruction.new(
@@ -72,11 +85,11 @@ module SolanaRuby
72
85
  end
73
86
 
74
87
  # Helper to create a new transaction for SOL transfer
75
- def self.new_sol_transaction(from_pubkey, to_pubkey, lamports, recent_blockhash)
88
+ def self.sol_transfer(from_pubkey, to_pubkey, lamports, recent_blockhash)
76
89
  transaction = Transaction.new
77
90
  transaction.set_fee_payer(from_pubkey)
78
91
  transaction.set_recent_blockhash(recent_blockhash)
79
- transfer_instruction = transfer_sol_transaction(from_pubkey, to_pubkey, lamports)
92
+ transfer_instruction = transfer_sol_instruction(from_pubkey, to_pubkey, lamports)
80
93
  transaction.add_instruction(transfer_instruction)
81
94
  transaction
82
95
  end
@@ -107,13 +120,14 @@ module SolanaRuby
107
120
  end
108
121
 
109
122
  # Method to create an associated token account for a given token mint
110
- def self.create_associated_token_account(from_pubkey, token_mint, owner_pubkey)
123
+ def self.create_associated_token_account(payer, mint, owner)
111
124
  data = [0, 0, 0, 0] # No data required for account creation
112
125
  create_account_instruction = TransactionInstruction.new(
113
126
  keys: [
114
- { pubkey: from_pubkey, is_signer: true, is_writable: true },
115
- { pubkey: owner_pubkey, is_signer: false, is_writable: true },
116
- { pubkey: token_mint, is_signer: false, is_writable: false },
127
+ { pubkey: payer, is_signer: true, is_writable: true },
128
+ { pubkey: associated_token, is_signer: false, is_writable: true },
129
+ { pubkey: owner, is_signer: false, is_writable: false },
130
+ { pubkey: mint, is_signer: false, is_writable: false },
117
131
  { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, is_signer: false, is_writable: false },
118
132
  { pubkey: SYSTEM_PROGRAM_ID, is_signer: false, is_writable: false }
119
133
  ],
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolanaRuby
4
- VERSION = "2.0.0beta1"
4
+ VERSION = "2.0.0beta2"
5
5
  end
@@ -3,30 +3,55 @@
3
3
  Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/*.rb')].each { |file| require file }
4
4
  Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/**/*.rb')].each { |file| require file }
5
5
 
6
- # Testing Script
7
-
6
+ # Initialize Solana client
8
7
  client = SolanaRuby::HttpClient.new('http://127.0.0.1:8899')
9
8
 
10
9
  # Fetch the recent blockhash
11
10
  recent_blockhash = client.get_latest_blockhash["blockhash"]
11
+ puts "Recent Blockhash: #{recent_blockhash}"
12
12
 
13
- # Generate a sender keypair and public key
14
- sender_keypair = SolanaRuby::Keypair.from_private_key("d22867a84ee1d91485a52c587793002dcaa7ce79a58bb605b3af2682099bb778")
13
+ # Sender keypair and public key
14
+ private_key = "d22867a84ee1d91485a52c587793002dcaa7ce79a58bb605b3af2682099bb778"
15
+ sender_keypair = SolanaRuby::Keypair.from_private_key(private_key)
15
16
  sender_pubkey = sender_keypair[:public_key]
16
- lamports = 1 * 1_000_000_000
17
- space = 165
18
- balance = client.get_balance(sender_pubkey)
19
- puts "sender account balance: #{balance}, wait for few seconds to update the balance in solana when the balance 0"
17
+ puts "Sender Public Key: #{sender_pubkey}"
20
18
 
19
+ # Check sender's account balance
20
+ balance = client.get_balance(sender_pubkey)
21
+ puts "Sender account balance: #{balance} lamports"
22
+ if balance == 0
23
+ puts "Balance is zero, waiting for balance update..."
24
+ sleep(10)
25
+ end
21
26
 
22
- # Generate a receiver keypair and public key
27
+ # new keypair and public key (new account)
23
28
  new_account = SolanaRuby::Keypair.generate
24
29
  new_account_pubkey = new_account[:public_key]
30
+ puts "New Account Public Key: #{new_account_pubkey}"
31
+
32
+ # Parameters for account creation
33
+ lamports = 1 * 1_000_000_000 # Lamports to transfer
34
+ space = 165 # Space allocation (bytes)
35
+ program_id = SolanaRuby::TransactionHelper::SYSTEM_PROGRAM_ID
36
+
37
+ # Create and sign the transaction
38
+ transaction = SolanaRuby::TransactionHelper.create_account(
39
+ sender_pubkey,
40
+ new_account_pubkey,
41
+ lamports,
42
+ space,
43
+ recent_blockhash,
44
+ program_id
45
+ )
46
+
47
+ # Sign transaction with both sender and new account keypairs
48
+ transaction.sign([sender_keypair, new_account])
49
+
50
+ # Send the transaction
51
+ puts "Sending transaction..."
52
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
25
53
 
26
- # create a transaction instruction
27
- transaction = SolanaRuby::TransactionHelper.create_and_sign_transaction(sender_pubkey, new_account_pubkey, lamports, space, recent_blockhash)
54
+ # Output transaction results
55
+ puts "Transaction Signature: #{response}"
56
+ puts "New account created successfully with Public Key: #{new_account_pubkey}"
28
57
 
29
- signed_transaction = transaction.sign([sender_keypair])
30
- sleep(5)
31
- response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
32
- puts "Response: #{response}"
@@ -1,3 +1,5 @@
1
+ Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/*.rb')].each { |file| require file }
2
+ Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/**/*.rb')].each { |file| require file }
1
3
  require 'pry'
2
4
 
3
5
  # SOL Transfer Testing Script
@@ -33,7 +35,7 @@ puts "Receiver's full private key: #{keypair[:full_private_key]}"
33
35
  puts "Receiver's Public Key: #{keypair[:public_key]}"
34
36
 
35
37
  # Create a new transaction
36
- transaction = SolanaRuby::TransactionHelper.new_sol_transaction(
38
+ transaction = SolanaRuby::TransactionHelper.sol_transfer(
37
39
  sender_pubkey,
38
40
  receiver_pubkey,
39
41
  transfer_lamports,
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: 2.0.0beta1
4
+ version: 2.0.0beta2
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-26 00:00:00.000000000 Z
11
+ date: 2024-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: websocket-client-simple