solana-ruby-web3js 2.0.0beta1 → 2.0.0beta2

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: 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