solana-ruby-web3js 2.0.1 → 2.1.0

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: 83aeed228731c11fa62b87f4ab5761a6715754921effc58400764bbe43378409
4
- data.tar.gz: a0cd63b8a7998539304ce06ed69692e86361fece542033d63fab7383a692ebb3
3
+ metadata.gz: 731b11629fcf8aeccddb1041dd5380b72ca120dd3ad23fc8cf1884a963864a96
4
+ data.tar.gz: d2d42348b2eb8d58433aec922bdcb3bb1631ab119d52999d4d20d63ebcf545ff
5
5
  SHA512:
6
- metadata.gz: 29277d937c3201916bd0bd1eec7172621a4a83b2b21d5045afa5a285f4d757ba12de5f99031da0f0030e08e68adc4c7de1cb6a55301463cfb05f0b5e63072ffc
7
- data.tar.gz: 0b627b741396f666e92fe8b032d859e944c933eda6b8ac7da29201d7913f116195b0751bcc2247537ca3a2b461bff9d2999ac234669e56a2708efe39776d881d
6
+ metadata.gz: ace60d58b990d3364ff3397c0719a81089a5c73af584094ad4d1a673d55be52a9a6d60dab0db910b8f41ef4e01ce55b551ee0404b3aa075a12f1e4440ec96cbc
7
+ data.tar.gz: 9a26564405175ab409799becfeb8ea00d275689990b3319d379d6ae9df5d1c025d4ef925d21068664ce46a71f62a5abb07935b5732aa9eb5196addea4a36b5fa
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- solana-ruby-web3js (2.0.0beta1)
4
+ solana-ruby-web3js (2.0.1)
5
5
  base58 (~> 0.2.3)
6
6
  base64 (~> 0.2.0)
7
7
  ed25519
data/README.md CHANGED
@@ -404,3 +404,387 @@ To transfer SOL (the native cryptocurrency of the Solana blockchain) from one ac
404
404
  response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
405
405
  puts "Response: #{response}"
406
406
 
407
+ ### Account Creation
408
+
409
+ The create_account helper allows creating a new account with specified parameters. This is commonly used to set up accounts for tokens, programs, or other allocations on the Solana blockchain.
410
+
411
+ #### Requirements:
412
+
413
+ - **Payer Public key**: The public key of the account funding the creation.
414
+ - **New Account Public Key**: The public key of the account to be created.
415
+ - **Lamports**: The amount of lamports to transfer to the new account.
416
+ - **Space**: The amount of space (in bytes) to allocate for the new account.
417
+ - **Recent Blockhash**: The latest blockhash for the transaction.
418
+ - **Program Id**: The program ID associated with the new account (default: System Program).
419
+
420
+ #### Example Usage:
421
+
422
+ require 'solana_ruby'
423
+
424
+ # Initialize the client (defaults to Mainnet(https://api.mainnet-beta.solana.com))
425
+ client = SolanaRuby::HttpClient.new('https://api.devnet.solana.com')
426
+
427
+ # Fetch the recent blockhash
428
+ recent_blockhash = client.get_latest_blockhash["blockhash"]
429
+
430
+ # Generate or fetch the sender/payer keypair
431
+ # Option 1: Generate a new keypair
432
+ sender_keypair = SolanaRuby::Keypair.generate
433
+ # Option 2: Use an existing private key
434
+ # sender_keypair = SolanaRuby::Keypair.from_private_key("InsertPrivateKeyHere")
435
+ sender_pubkey = sender_keypair[:public_key]
436
+
437
+ # Generate new account keypair
438
+ new_account = SolanaRuby::Keypair.generate
439
+ new_account_pubkey = new_account[:public_key]
440
+
441
+ # Parameters for account creation
442
+ lamports = 1_000_000_000
443
+ space = 165
444
+ program_id = SolanaRuby::TransactionHelper::SYSTEM_PROGRAM_ID
445
+
446
+ # Create the account creation transaction
447
+ transaction = SolanaRuby::TransactionHelper.create_account(
448
+ sender_pubkey,
449
+ new_account_pubkey,
450
+ lamports,
451
+ space,
452
+ recent_blockhash,
453
+ program_id
454
+ )
455
+
456
+ # Sign with both keypairs
457
+ transaction.sign([sender_keypair, new_account])
458
+
459
+ # Send the transaction
460
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
461
+
462
+ # Output transaction results
463
+ puts "Transaction Signature: #{response}"
464
+ puts "New account created with Public Key: #{new_account_pubkey}"
465
+
466
+ ### SPL Token Account Creation
467
+
468
+ The create_associated_token_account helper allows you to create an associated token account for a specific mint and owner. This is necessary when dealing with SPL tokens on the Solana blockchain.
469
+
470
+ #### Requirements:
471
+
472
+ - **Payer Public key**: The public key of the account funding the creation.
473
+ - **Mint Public Key**: The public key of the SPL token mint.
474
+ - **Owner Public Key**: The public key of the owner for whom the associated token account is being created.
475
+ - **Recent Blockhash**: The latest blockhash for the transaction.
476
+
477
+ #### Example Usage:
478
+
479
+ require 'solana_ruby'
480
+
481
+ # Initialize the Solana client (defaults to Mainnet: https://api.mainnet-beta.solana.com)
482
+ client = SolanaRuby::HttpClient.new('https://api.devnet.solana.com')
483
+
484
+ # Fetch the recent blockhash
485
+ recent_blockhash = client.get_latest_blockhash["blockhash"]
486
+
487
+ # Load the keypair for the payer
488
+ payer_keypair = SolanaRuby::Keypair.load_keypair('InsertYourJsonFilePathHere')
489
+ payer_pubkey = payer_keypair.public_key
490
+
491
+ # Generate or load the owner keypair
492
+ owner_keypair = SolanaRuby::Keypair.generate
493
+ owner_pubkey = owner_keypair.public_key
494
+
495
+ puts "Owner Public Key: #{owner_pubkey}"
496
+ puts "Owner Private Key: #{owner_keypair.private_key}"
497
+
498
+ # Define the mint public key for the SPL token
499
+ mint_pubkey = "InsertMintPublicKeyHere"
500
+
501
+ # Create the associated token account transaction
502
+ transaction = SolanaRuby::TransactionHelper.create_associated_token_account(
503
+ payer_pubkey,
504
+ mint_pubkey,
505
+ owner_pubkey,
506
+ recent_blockhash
507
+ )
508
+
509
+ # Sign the transaction
510
+ transaction.sign([payer_keypair])
511
+
512
+ # Send the transaction
513
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
514
+
515
+ # Output transaction results
516
+ puts "Transaction Signature: #{response}"
517
+
518
+ ### Close Account
519
+
520
+ The close_account helper allows you to close an associated token account on the Solana blockchain. Any remaining balance in the account is transferred to the specified destination account.
521
+
522
+ #### Requirements:
523
+
524
+ - **Account to Close**: The public key of the associated token account to be closed.
525
+ - **Destination Public Key**: The public key of the account receiving the remaining balance.
526
+ - **Owner Public Key**: The public key of the account owner who has permission to close the account.
527
+ - **Payer Public Key**: The public key of the account paying for the transaction fees.
528
+ - **Multi-Signers (Optional)**: An array of additional signer public keys if the account requires multiple signatures.
529
+ - **Recent Blockhash**: The latest blockhash for the transaction.
530
+
531
+ #### Example Usage:
532
+
533
+ require 'solana_ruby'
534
+
535
+ # Initialize the Solana client (defaults to Mainnet: https://api.mainnet-beta.solana.com)
536
+ client = SolanaRuby::HttpClient.new('https://api.devnet.solana.com')
537
+
538
+ # Fetch the recent blockhash
539
+ recent_blockhash = client.get_latest_blockhash["blockhash"]
540
+
541
+ # Load the keypairs
542
+ payer_keypair = SolanaRuby::Keypair.from_private_key("InsertPayerPrivateKeyHere")
543
+ owner_keypair = SolanaRuby::Keypair.from_private_key("InsertOwnerPrivateKeyHere")
544
+
545
+ payer_pubkey = payer_keypair[:public_key]
546
+ owner_pubkey = owner_keypair[:public_key]
547
+
548
+ # Define the associated token account to be closed and the destination account
549
+ account_to_close_pubkey = 'InsertAccountToClosePublicKeyHere' # Replace with the actual account to close
550
+ destination_pubkey = 'InsertDestinationPublicKeyHere' # Replace with the actual recipient address
551
+
552
+ # Multi-signers (if required)
553
+ # multi_signers = [SolanaRuby::Keypair.from_private_key("InsertAdditionalSignerPrivateKeyHere")]
554
+ multi_signers = []
555
+
556
+ # Extract public keys of multi-signers
557
+ multi_signer_pubkeys = multi_signers.map { |signer| signer[:public_key] }
558
+
559
+ # Create the close account transaction
560
+ transaction = SolanaRuby::TransactionHelper.close_account(
561
+ account_to_close_pubkey,
562
+ destination_pubkey,
563
+ owner_pubkey,
564
+ payer_pubkey,
565
+ multi_signer_pubkeys,
566
+ recent_blockhash
567
+ )
568
+
569
+ # Sign the transaction
570
+ transaction.sign([payer_keypair, owner_keypair])
571
+
572
+ # Send the transaction
573
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
574
+
575
+ # Output transaction results
576
+ puts "Transaction Signature: #{response}"
577
+ puts "Closed account: #{account_to_close_pubkey}, funds sent to: #{destination_pubkey}"
578
+
579
+ ### Get Associated Token Address
580
+
581
+ The get_associated_token_address helper fetches the associated token account for a given mint address and owner public key. This is essential when interacting with SPL tokens to determine where tokens are held.
582
+
583
+ #### Requirements:
584
+
585
+ - **Mint Address**: The public key of the SPL token mint.
586
+ - **Owner Public Key**: The public key of the token holder.
587
+
588
+ #### Example Usage:
589
+
590
+ require 'solana_ruby'
591
+
592
+ # Define mint address and owner public key
593
+ mint_address = 'InsertMintPublicKeyHere'
594
+ owner_pubkey = 'InsertOwnerPublicKeyHere'
595
+
596
+ # Fetch associated token address
597
+ associated_token_address = SolanaRuby::TransactionHelpers::TokenAccount.get_associated_token_address(
598
+ mint_address,
599
+ owner_pubkey
600
+ )
601
+
602
+ puts "Associated Token Address: #{associated_token_address}"
603
+
604
+ ### Mint SPL Tokens
605
+
606
+ The mint_spl_tokens helper allows you to mint new SPL tokens to a specified destination account. This is useful for token creators who need to distribute newly minted tokens.
607
+
608
+ #### Requirements:
609
+
610
+ - **Mint Account Public Key**: The public key of the mint account.
611
+ - **Destination Account Public Key**: The associated token account where the newly minted tokens will be sent.
612
+ - **Mint Authority Public Key**: The public key of the authority allowed to mint new tokens.
613
+ - **Amount**: The number of tokens to mint (in the smallest unit, based on token decimals).
614
+ - **Multi-Signers (Optional)**: Additional signer public keys if multi-signature authorization is required.
615
+ - **Recent Blockhash**: The latest blockhash for the transaction.
616
+
617
+ #### Example Usage:
618
+
619
+ require 'solana_ruby'
620
+
621
+ # Initialize the Solana client (defaults to Mainnet: https://api.mainnet-beta.solana.com)
622
+ client = SolanaRuby::HttpClient.new('https://api.devnet.solana.com')
623
+
624
+ # Fetch the recent blockhash
625
+ recent_blockhash = client.get_latest_blockhash["blockhash"]
626
+
627
+ # Define the mint account and recipient
628
+ mint_account = "InsertMintPublicKeyHere"
629
+ destination_account = "InsertDestinationPublicKeyHere"
630
+
631
+ # Load the mint authority keypair
632
+ mint_authority = SolanaRuby::Keypair.load_keypair('InsertYourJsonFilePathHere')
633
+
634
+ puts "Mint Authority Public Key: #{mint_authority[:public_key]}"
635
+
636
+ # Define the amount to mint (in smallest units)
637
+ amount = 1_000_000_00_00 # Adjust based on token decimals
638
+
639
+ # Multi-signers (if required)
640
+ multi_signers = [] # Example: [additional_signer_pubkey]
641
+
642
+ # Create the mint transaction
643
+ transaction = SolanaRuby::TransactionHelper.mint_spl_tokens(
644
+ mint_account,
645
+ destination_account,
646
+ mint_authority[:public_key],
647
+ amount,
648
+ recent_blockhash,
649
+ multi_signers
650
+ )
651
+
652
+ # Sign the transaction with the mint authority
653
+ transaction.sign([mint_authority])
654
+
655
+ # Send the transaction
656
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
657
+
658
+ # Output transaction results
659
+ puts "Transaction Signature: #{response}"
660
+ puts "Minted #{amount} tokens to: #{destination_account}"
661
+
662
+ ### Burn SPL Tokens
663
+
664
+ The burn_spl_tokens helper allows you to burn (destroy) a specified amount of SPL tokens from a token account. This is typically used to reduce the total supply of a token.
665
+
666
+ #### Requirements:
667
+
668
+ - **Token Account**: The associated token account holding the tokens to be burned..
669
+ - **Mint Address**: The mint address of the SPL token.
670
+ - **Owner**: The owner of the token account (must have authority to burn tokens).
671
+ - **Amount**: The number of tokens to burn (denominated in the smallest units).
672
+ - **Recent Blockhash**: The latest blockhash for the transaction.
673
+
674
+ #### Example Usage:
675
+
676
+ require 'solana_ruby'
677
+
678
+ # Initialize the Solana client (defaults to Mainnet: https://api.mainnet-beta.solana.com)
679
+ client = SolanaRuby::HttpClient.new('https://api.devnet.solana.com')
680
+
681
+ # Fetch the recent blockhash
682
+ recent_blockhash = client.get_latest_blockhash["blockhash"]
683
+
684
+ # Define token account and mint address
685
+ token_account = "InsertTokenAccountPublicKeyHere"
686
+ mint_address = "InsertMintPublicKeyHere"
687
+
688
+ # Load the mint authority keypair
689
+ mint_authority = SolanaRuby::Keypair.load_keypair('/path/to/id.json')
690
+ owner = mint_authority[:public_key]
691
+
692
+ # Define the amount to burn
693
+ amount = 500_000 # Tokens to burn in smallest units
694
+
695
+ # Create burn transaction
696
+ transaction = SolanaRuby::TransactionHelper.burn_spl_tokens(
697
+ token_account,
698
+ mint_address,
699
+ owner,
700
+ amount,
701
+ recent_blockhash
702
+ )
703
+
704
+ # Sign the transaction
705
+ transaction.sign([mint_authority])
706
+
707
+ # Send the transaction
708
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
709
+
710
+ # Output transaction results
711
+ puts "Transaction Signature: #{response}"
712
+
713
+ ### Transfer SPL Tokens
714
+
715
+ The new_spl_token_transaction helper allows you to transfer SPL tokens from one associated token account to another.
716
+
717
+ #### Requirements:
718
+
719
+ - **Sender's Token Account**: The associated token account holding the tokens to be transferred.
720
+ - **Mint Address**: The mint address of the SPL token.
721
+ - **Receiver's Token Account**: The associated token account of the recipient.
722
+ - **Fee Payer:**: The account responsible for transaction fees.
723
+ - **Amount**: The number of tokens to mint (in the smallest unit, based on token decimals).
724
+ - **Decimals**: The decimal precision of the SPL token (e.g., 9 for SOL-based tokens).
725
+ - **Recent Blockhash**: The latest blockhash for the transaction.
726
+ - **Multi-Signers (Optional)**: List of additional required signers (if applicable).
727
+
728
+ #### Example Usage:
729
+
730
+ require 'solana_ruby'
731
+
732
+ # Initialize the Solana client
733
+ client = SolanaRuby::HttpClient.new('http://127.0.0.1:8899')
734
+
735
+ # Fetch the recent blockhash
736
+ recent_blockhash = client.get_latest_blockhash["blockhash"]
737
+
738
+ # Load the fee payer's keypair
739
+ fee_payer = SolanaRuby::Keypair.from_private_key('InsertFeePayerPrivateKeyHere')
740
+ fee_payer_pubkey = fee_payer[:public_key]
741
+
742
+ # Define the SPL token mint address
743
+ mint_address = 'InsertMintPublicKeyHere'
744
+
745
+ # Define sender and receiver public keys
746
+ sender_pubkey = 'InsertSenderPublicKeyHere'
747
+ receiver_pubkey = 'InsertReceiverPublicKeyHere'
748
+
749
+ # Fetch the associated token accounts
750
+ senders_token_account = SolanaRuby::TransactionHelpers::TokenAccount.get_associated_token_address(mint_address, sender_pubkey)
751
+ receivers_token_account = SolanaRuby::TransactionHelpers::TokenAccount.get_associated_token_address(mint_address, receiver_pubkey)
752
+
753
+ puts "Sender's Token Account: #{senders_token_account}"
754
+ puts "Receiver's Token Account: #{receivers_token_account}"
755
+
756
+ # Define the transfer amount and decimals
757
+ transfer_lamports = 1_000_000 # Amount in smallest units
758
+ decimals = 9 # Adjust based on token precision
759
+
760
+ # Multi-signers (Optional, default is an empty array)
761
+ # multi_signers = [
762
+ # SolanaRuby::Keypair.from_private_key('InsertMultiSigner1PrivateKeyHere'),
763
+ # SolanaRuby::Keypair.from_private_key('InsertMultiSigner2PrivateKeyHere')
764
+ # ]
765
+ # multi_signer_pubkeys = multi_signers.map { |signer| signer[:public_key] }
766
+ multi_signers = []
767
+
768
+ # Create the transaction
769
+ transaction = SolanaRuby::TransactionHelper.new_spl_token_transaction(
770
+ senders_token_account,
771
+ mint_address,
772
+ receivers_token_account,
773
+ fee_payer_pubkey,
774
+ transfer_lamports,
775
+ decimals,
776
+ recent_blockhash,
777
+ multi_signer_pubkeys
778
+ )
779
+
780
+ # Sign the transaction (Only fee payer, unless multi-signers are provided)
781
+ transaction.sign([fee_payer] + multi_signers)
782
+
783
+ # Send the transaction
784
+ puts "Sending transaction..."
785
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
786
+
787
+ # Output transaction results
788
+ puts "Transaction Signature: #{response}"
789
+
790
+
@@ -0,0 +1,70 @@
1
+ module SolanaRuby
2
+ class Ed25519CurveChecker
3
+ # Constants for Ed25519
4
+ P = 2**255 - 19
5
+ ONE = 1
6
+
7
+ # Main function to check if a public key is on the Ed25519 curve
8
+ def self.on_curve?(public_key_bytes)
9
+ # Validate public key length
10
+ return false unless public_key_bytes.bytesize == 32 # Public key must be 32 bytes
11
+
12
+ begin
13
+ # Decode the y-coordinate from the public key
14
+ y = decode_y(public_key_bytes)
15
+
16
+ # Validate if y is a quadratic residue on the curve equation
17
+ y_squared = (y * y) % P
18
+ numerator = (y_squared - 1) % P
19
+ denominator = (D * y_squared + 1) % P
20
+
21
+ # Ensure denominator isn't zero to avoid invalid computation
22
+ return false if denominator.zero?
23
+
24
+ # Calculate x_squared = numerator * modular_inverse(denominator, P) mod P
25
+ x_squared = (numerator * modular_inverse(denominator, P)) % P
26
+
27
+ # Check if x_squared is a valid quadratic residue
28
+ quadratic_residue?(x_squared)
29
+ rescue StandardError => e
30
+ puts "Error during curve check: #{e.message}"
31
+ false
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # Decode the y-coordinate from the public key
38
+ def self.decode_y(public_key_bytes)
39
+ # Converts byte array directly to integer and maps it onto the curve's modulus
40
+ public_key_bytes.unpack1('H*').to_i(16) % P
41
+ end
42
+
43
+ # Determine if value is a quadratic residue modulo P
44
+ def self.quadratic_residue?(value)
45
+ # Quadratic residues satisfy value^((p - 1) / 2) mod P == 1
46
+ value.pow((P - 1) / 2, P) == 1
47
+ end
48
+
49
+ # Modular inverse using the Extended Euclidean Algorithm
50
+ def self.modular_inverse(value, mod_value)
51
+ t, new_t = 0, 1
52
+ r, new_r = mod_value, value
53
+
54
+ while new_r != 0
55
+ quotient = r / new_r
56
+ t, new_t = new_t, t - quotient * new_t
57
+ r, new_r = new_r, r - quotient * new_r
58
+ end
59
+
60
+ raise ArgumentError, 'Value has no modular inverse' if r > 1
61
+
62
+ t += mod_value if t.negative?
63
+ t % mod_value
64
+ end
65
+ end
66
+
67
+ # Calculate the Ed25519 constant D
68
+ # D = -121665 * modular_inverse(121666, P) mod P
69
+ D = (-121665 * Ed25519CurveChecker.modular_inverse(121666, Ed25519CurveChecker::P)) % Ed25519CurveChecker::P
70
+ end
@@ -6,16 +6,9 @@ module SolanaRuby
6
6
  # Generates a new Ed25519 keypair
7
7
  def self.generate
8
8
  signing_key = RbNaCl::Signatures::Ed25519::SigningKey.generate
9
- public_key_bytes = signing_key.verify_key.to_bytes # Binary format for public key
10
9
  private_key_bytes = signing_key.to_bytes
11
- private_key_hex = private_key_bytes.unpack1('H*') # Hex format for private key
12
10
 
13
- # Convert public key binary to Base58 for readability and compatibility
14
- {
15
- public_key: Base58.binary_to_base58(public_key_bytes, :bitcoin),
16
- private_key: private_key_hex,
17
- full_private_key: Base58.binary_to_base58((private_key_bytes + public_key_bytes), :bitcoin)
18
- }
11
+ keys(signing_key, private_key_bytes)
19
12
  end
20
13
 
21
14
  # Restores a keypair from a private key in hex format
@@ -28,8 +21,39 @@ module SolanaRuby
28
21
  # Initialize signing key
29
22
  signing_key = RbNaCl::Signatures::Ed25519::SigningKey.new(private_key_bytes)
30
23
 
24
+ keys(signing_key, private_key_bytes)
25
+ end
26
+
27
+ # Load a keypair from a JSON file
28
+ def self.load_keypair(file_path)
29
+ # Parse the JSON file
30
+ keypair_data = JSON.parse(File.read(file_path))
31
+
32
+ # Ensure it contains exactly 64 bytes for Ed25519 (32 private + 32 public)
33
+ raise "Invalid keypair length: expected 64 bytes, got #{keypair_data.length}" unless keypair_data.length == 64
34
+
35
+ # Convert the array to a binary string
36
+ private_key_bytes = keypair_data[0, 32].pack('C*')
37
+ public_key_bytes = keypair_data[32, 32].pack('C*')
38
+
39
+ # Create the signing key
40
+ signing_key = RbNaCl::Signatures::Ed25519::SigningKey.new(private_key_bytes)
41
+
42
+ # Verify the public key matches
43
+ raise "Public key mismatch" unless signing_key.verify_key.to_bytes == public_key_bytes
44
+
45
+ keys(signing_key, private_key_bytes)
46
+ rescue JSON::ParserError => e
47
+ raise "Failed to parse JSON file: #{e.message}"
48
+ end
49
+
50
+
51
+ private
52
+
53
+ def self.keys(signing_key, private_key_bytes)
31
54
  # Extract public key in binary format
32
55
  public_key_bytes = signing_key.verify_key.to_bytes
56
+ private_key_hex = private_key_bytes.unpack1('H*') # Hex format for private key
33
57
 
34
58
  # Return public key in Base58 format and private key in hex format
35
59
  {
@@ -0,0 +1,62 @@
1
+ require 'base58'
2
+ require 'openssl'
3
+
4
+ module SolanaRuby
5
+ class PublicKey
6
+ PUBLIC_KEY_LENGTH = 32
7
+
8
+ attr_reader :bn
9
+
10
+ def initialize(value)
11
+ case value
12
+ when PublicKey
13
+ @bn = value.bn
14
+ when String
15
+ decoded = decode_base58(value)
16
+ validate_length(decoded)
17
+ @bn = to_bn(decoded)
18
+ when Array
19
+ binary = value.pack('C*')
20
+ validate_length(binary)
21
+ @bn = to_bn(binary)
22
+ else
23
+ raise ArgumentError, "Unsupported input type: #{value.class}"
24
+ end
25
+ end
26
+
27
+ # Converts the public key to Base58
28
+ def to_base58
29
+ Base58.binary_to_base58(to_bytes, :bitcoin)
30
+ end
31
+
32
+ # Converts the public key to a binary string
33
+ def to_bytes
34
+ padded_bn = @bn.to_s(2) # Binary string from BigNum
35
+ if padded_bn.bytesize < PUBLIC_KEY_LENGTH
36
+ "\x00" * (PUBLIC_KEY_LENGTH - padded_bn.bytesize) + padded_bn
37
+ elsif padded_bn.bytesize > PUBLIC_KEY_LENGTH
38
+ raise "PublicKey byte length exceeds #{PUBLIC_KEY_LENGTH} bytes"
39
+ else
40
+ padded_bn
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def decode_base58(value)
47
+ Base58.base58_to_binary(value, :bitcoin)
48
+ rescue ArgumentError => e
49
+ raise ArgumentError, "Invalid Base58 encoding: #{e.message}"
50
+ end
51
+
52
+ def validate_length(data)
53
+ unless data.bytesize == PUBLIC_KEY_LENGTH
54
+ raise ArgumentError, "Invalid public key length: expected #{PUBLIC_KEY_LENGTH} bytes, got #{data.bytesize}"
55
+ end
56
+ end
57
+
58
+ def to_bn(input)
59
+ OpenSSL::BN.new(input, 2)
60
+ end
61
+ end
62
+ end
@@ -1,4 +1,5 @@
1
1
  Dir[File.join(__dir__, 'data_types', '*.rb')].each { |file| require file }
2
+ Dir[File.join(__dir__, 'transaction_helpers', '*.rb')].each { |file| require file }
2
3
 
3
4
  module SolanaRuby
4
5
  class Transaction
@@ -1,12 +1,13 @@
1
1
  module SolanaRuby
2
2
  class TransactionHelper
3
3
  require 'base58'
4
- require 'pry'
5
4
 
6
5
  # Constants for program IDs
7
6
  SYSTEM_PROGRAM_ID = '11111111111111111111111111111111'
8
7
  TOKEN_PROGRAM_ID = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
9
- ASSOCIATED_TOKEN_PROGRAM_ID = 'ATokenGP3evbxxpQ7bYPLNNaxD2c4bqtvWjpKbmz6HjH'
8
+ ASSOCIATED_TOKEN_PROGRAM_ID = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'
9
+ SYSVAR_RENT_ID = 'SysvarRent111111111111111111111111111111111'
10
+
10
11
 
11
12
  INSTRUCTION_LAYOUTS = {
12
13
  # Native SOL transfer
@@ -19,12 +20,32 @@ module SolanaRuby
19
20
  instruction: :uint8,
20
21
  amount: :uint64
21
22
  },
22
- # Create account layout
23
+ # Create account layout
23
24
  create_account: {
24
25
  instruction: :uint32,
25
26
  lamports: :uint64,
26
27
  space: :uint64,
27
28
  program_id: :blob32
29
+ },
30
+ # SPL token transfer_checked
31
+ spl_transfer_checked: {
32
+ instruction: :uint8,
33
+ amount: :uint64,
34
+ decimals: :uint8
35
+ },
36
+ # mint spl tokens
37
+ spl_mint_to: {
38
+ instruction: :uint8,
39
+ amount: :uint64
40
+ },
41
+ # burn spl tokens
42
+ spl_burn: {
43
+ instruction: :uint8,
44
+ amount: :uint64
45
+ },
46
+ # Close account layout (added here)
47
+ close_account: {
48
+ instruction: :uint8
28
49
  }
29
50
  }
30
51
 
@@ -41,18 +62,13 @@ module SolanaRuby
41
62
  }
42
63
  )
43
64
 
44
- # Construct the transaction instruction
45
- create_account_instruction = TransactionInstruction.new(
46
- keys: [
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
49
- ],
50
- program_id: program_id, # Use Solana's system program for account creation
51
- data: instruction_data # Encoded instruction data
52
- )
65
+ keys = [
66
+ { pubkey: from_pubkey, is_signer: true, is_writable: true }, # Funder's account
67
+ { pubkey: new_account_pubkey, is_signer: true, is_writable: true } # New account
68
+ ]
53
69
 
54
70
  # return instruction data
55
- create_account_instruction
71
+ create_instruction(keys, instruction_data, program_id)
56
72
  end
57
73
 
58
74
 
@@ -70,18 +86,50 @@ module SolanaRuby
70
86
  transaction
71
87
  end
72
88
 
89
+ # Method to create a close account instruction
90
+ def self.close_account_instruction( account_to_close, destination, owner, payer, multi_signers)
91
+ # Encode the instruction data
92
+ instruction_data = encode_data(
93
+ INSTRUCTION_LAYOUTS[:close_account],
94
+ { instruction: 9 } # Close account instruction number is 9
95
+ )
96
+
97
+ signer = multi_signers.empty? ? payer : multi_signers
98
+ # Set up the keys for the close account instruction
99
+ keys = SolanaRuby::TransactionHelpers::TokenAccount.add_signers(
100
+ [{ pubkey: account_to_close, is_signer: false, is_writable: true },
101
+ { pubkey: destination, is_signer: false, is_writable: true }],
102
+ owner, signer)
103
+
104
+ # Return the instruction
105
+ create_instruction(keys, instruction_data)
106
+ end
107
+
108
+ # Method to close an account (helper)
109
+ def self.close_account(account_to_close, destination, owner, payer, multi_signers, recent_blockhash)
110
+ # Create the transaction
111
+ transaction = Transaction.new
112
+ transaction.set_fee_payer(payer)
113
+ transaction.set_recent_blockhash(recent_blockhash)
114
+
115
+ # Add the close account instruction to the transaction
116
+ instruction = close_account_instruction(account_to_close, destination, owner, payer, multi_signers)
117
+ transaction.add_instruction(instruction)
118
+
119
+ # Return the transaction for signing
120
+ transaction
121
+ end
122
+
73
123
  # Method to create a SOL transfer instruction
74
124
  def self.transfer_sol_instruction(from_pubkey, to_pubkey, lamports)
75
125
  fields = INSTRUCTION_LAYOUTS[:sol_transfer]
76
126
  data = encode_data(fields, { instruction: 2, lamports: lamports })
77
- TransactionInstruction.new(
78
- keys: [
127
+ keys = [
79
128
  { pubkey: from_pubkey, is_signer: true, is_writable: true },
80
129
  { pubkey: to_pubkey, is_signer: false, is_writable: true }
81
- ],
82
- program_id: SYSTEM_PROGRAM_ID,
83
- data: data
84
- )
130
+ ]
131
+
132
+ create_instruction(keys, data, SYSTEM_PROGRAM_ID)
85
133
  end
86
134
 
87
135
  # Helper to create a new transaction for SOL transfer
@@ -95,46 +143,117 @@ module SolanaRuby
95
143
  end
96
144
 
97
145
  # Method to create an SPL token transfer instruction
98
- def self.transfer_spl_token(source, destination, owner, amount)
99
- fields = INSTRUCTION_LAYOUTS[:spl_transfer]
100
- data = encode_data(fields, { instruction: 3, amount: amount }) # Instruction type 3: Transfer tokens
101
- TransactionInstruction.new(
102
- keys: [
103
- { pubkey: source, is_signer: false, is_writable: true },
104
- { pubkey: destination, is_signer: false, is_writable: true },
105
- { pubkey: owner, is_signer: true, is_writable: false }
106
- ],
107
- program_id: TOKEN_PROGRAM_ID,
108
- data: data
109
- )
146
+ def self.transfer_spl_token(source, token, destination, owner, amount, decimals, multi_signers)
147
+ fields = INSTRUCTION_LAYOUTS[:spl_transfer_checked]
148
+ data = encode_data(fields, { instruction: 12, amount: amount, decimals: decimals }) # Instruction type 3: Transfer tokens
149
+ keys = SolanaRuby::TransactionHelpers::TokenAccount.add_signers(
150
+ [{ pubkey: source, is_signer: false, is_writable: true },
151
+ { pubkey: token, is_signer: false, is_writable: false },
152
+ { pubkey: destination, is_signer: false, is_writable: true }],
153
+ owner, multi_signers)
154
+
155
+ create_instruction(keys, data)
110
156
  end
111
157
 
112
158
  # Helper to create a new transaction for SPL token transfer
113
- def self.new_spl_token_transaction(source, destination, owner, amount, recent_blockhash)
159
+ def self.new_spl_token_transaction(source, mint, destination, owner, amount, decimals, recent_blockhash, multi_signers=[])
114
160
  transaction = Transaction.new
115
161
  transaction.set_fee_payer(owner)
116
162
  transaction.set_recent_blockhash(recent_blockhash)
117
- transfer_instruction = transfer_spl_token(source, destination, owner, amount)
163
+ transfer_instruction = transfer_spl_token(source, mint, destination, owner, amount, decimals, multi_signers)
118
164
  transaction.add_instruction(transfer_instruction)
119
165
  transaction
120
166
  end
121
167
 
122
- # Method to create an associated token account for a given token mint
123
- def self.create_associated_token_account(payer, mint, owner)
124
- data = [0, 0, 0, 0] # No data required for account creation
168
+ # Method to create an associated token account
169
+ def self.create_associated_token_account(payer, mint, owner, recent_blockhash, program_id = SYSTEM_PROGRAM_ID)
170
+ transaction = Transaction.new
171
+ transaction.set_fee_payer(payer) # Payer funds the transaction
172
+ transaction.set_recent_blockhash(recent_blockhash)
173
+
174
+ # Derive the associated token account address
175
+ associated_token_account_pubkey = SolanaRuby::TransactionHelpers::TokenAccount.get_associated_token_address(mint, owner)
176
+ puts "associated_token_account_pubkey: #{associated_token_account_pubkey}"
177
+
178
+
179
+ # Create the associated token account instruction
125
180
  create_account_instruction = TransactionInstruction.new(
126
181
  keys: [
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 },
131
- { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, is_signer: false, is_writable: false },
132
- { pubkey: SYSTEM_PROGRAM_ID, is_signer: false, is_writable: false }
182
+ { pubkey: payer, is_signer: true, is_writable: true }, # Payer account
183
+ { pubkey: associated_token_account_pubkey, is_signer: false, is_writable: true }, # New ATA
184
+ { pubkey: owner, is_signer: false, is_writable: false }, # Owner of the ATA
185
+ { pubkey: mint, is_signer: false, is_writable: false }, # Token mint
186
+ { pubkey: SYSTEM_PROGRAM_ID, is_signer: false, is_writable: false }, # System program
187
+ { pubkey: TOKEN_PROGRAM_ID, is_signer: false, is_writable: false }, # Token program
188
+ { pubkey: SYSVAR_RENT_ID, is_signer: false, is_writable: false }
133
189
  ],
134
190
  program_id: ASSOCIATED_TOKEN_PROGRAM_ID,
135
- data: data
191
+ data: [] # No data required for creating an associated token account
136
192
  )
137
- create_account_instruction
193
+
194
+ # Add the instruction to the transaction
195
+ transaction.add_instruction(create_account_instruction)
196
+ transaction
197
+ end
198
+
199
+ # Method to create a mint instruction for SPL tokens
200
+ def self.mint_spl_token(mint, destination, mint_authority, amount, multi_signers = [])
201
+ fields = INSTRUCTION_LAYOUTS[:spl_mint_to]
202
+ data = encode_data(fields, { instruction: 7, amount: amount }) # Instruction type 7: Mint to
203
+ keys = SolanaRuby::TransactionHelpers::TokenAccount.add_signers(
204
+ [{ pubkey: mint, is_signer: false, is_writable: true },
205
+ { pubkey: destination, is_signer: false, is_writable: true }],
206
+ mint_authority, multi_signers)
207
+
208
+ create_instruction(keys, data)
209
+ end
210
+
211
+ # Helper to create a transaction for minting SPL tokens
212
+ def self.mint_spl_tokens(mint, destination, mint_authority, amount, recent_blockhash, multi_signers = [])
213
+ transaction = Transaction.new
214
+ transaction.set_fee_payer(mint_authority)
215
+ transaction.set_recent_blockhash(recent_blockhash)
216
+ mint_instruction = mint_spl_token(mint, destination, mint_authority, amount, multi_signers)
217
+ transaction.add_instruction(mint_instruction)
218
+ transaction
219
+ end
220
+
221
+ # Method to create a burn instruction for SPL tokens
222
+ def self.burn_spl_token(token_account, mint, mint_authority, amount, multi_signers = [])
223
+ # Define the fields for the burn instruction
224
+ fields = INSTRUCTION_LAYOUTS[:spl_burn]
225
+
226
+ # Encode the instruction data
227
+ data = encode_data(fields, { instruction: 8, amount: amount }) # Instruction type 8: Burn
228
+
229
+ keys = SolanaRuby::TransactionHelpers::TokenAccount.add_signers(
230
+ [
231
+ { pubkey: token_account, is_signer: false, is_writable: true }, # Token account holding tokens to burn
232
+ { pubkey: mint, is_signer: false, is_writable: true } # Mint address
233
+ ], mint_authority, multi_signers)
234
+
235
+ # Return the transaction instruction
236
+ create_instruction(keys, data)
237
+ end
238
+
239
+ # Helper to create a transaction for burning SPL tokens
240
+ def self.burn_spl_tokens(token_account, mint, owner, amount, recent_blockhash, multi_signers = [])
241
+ # Create a new transaction
242
+ transaction = Transaction.new
243
+ transaction.set_fee_payer(owner)
244
+ transaction.set_recent_blockhash(recent_blockhash)
245
+
246
+ # Add the burn instruction to the transaction
247
+ burn_instruction = burn_spl_token(token_account, mint, owner, amount, multi_signers)
248
+ transaction.add_instruction(burn_instruction)
249
+
250
+ # Return the transaction for signing
251
+ transaction
252
+ end
253
+
254
+ # Derive the associated token account address
255
+ def self.get_associated_token_address(mint, owner, program_id)
256
+ SolanaRuby::TransactionHelpers::TokenAccount.get_associated_token_address(mint, owner, program_id)
138
257
  end
139
258
 
140
259
  # Utility to encode data using predefined layouts
@@ -148,5 +267,13 @@ module SolanaRuby
148
267
  layout = SolanaRuby::DataTypes::Layout.new(fields)
149
268
  layout.deserialize(data)
150
269
  end
270
+
271
+ def self.create_instruction(keys, data, token_program_id = TOKEN_PROGRAM_ID)
272
+ TransactionInstruction.new(
273
+ keys: keys,
274
+ program_id: token_program_id,
275
+ data: data
276
+ )
277
+ end
151
278
  end
152
279
  end
@@ -0,0 +1,73 @@
1
+ module SolanaRuby
2
+ module TransactionHelpers
3
+ class TokenAccount
4
+ # Associated Token Program ID
5
+ ASSOCIATED_TOKEN_PROGRAM_ID = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'.freeze
6
+
7
+ # Token Program ID
8
+ TOKEN_PROGRAM_ID = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'.freeze
9
+
10
+ def self.get_associated_token_address(mint, payer)
11
+ mint_bytes = Base58.base58_to_binary(mint, :bitcoin)
12
+ payer_bytes = Base58.base58_to_binary(payer, :bitcoin)
13
+ associated_program_bytes = Base58.base58_to_binary(ASSOCIATED_TOKEN_PROGRAM_ID, :bitcoin)
14
+
15
+ # Derive associated token account PDA
16
+ seeds = [
17
+ payer_bytes,
18
+ Base58.base58_to_binary(TOKEN_PROGRAM_ID, :bitcoin),
19
+ mint_bytes
20
+ ]
21
+
22
+ # Attempt to find the first valid off-curve PDA
23
+ associated_token_account_pubkey = find_program_address(seeds, associated_program_bytes)
24
+
25
+ # Return the computed Base58 PDA string
26
+ Base58.binary_to_base58(associated_token_account_pubkey, :bitcoin)
27
+ end
28
+
29
+ def self.add_signers(keys, owner_or_authority, multi_signers)
30
+ if multi_signers.is_a?(Array) && multi_signers.any?
31
+ keys.push({ pubkey: owner_or_authority, is_signer: false, is_writable: false })
32
+ multi_signers.each do |signer|
33
+ pubkey = signer.is_a?(String) ? signer : signer.public_key
34
+ keys.push({ pubkey: pubkey, is_signer: true, is_writable: false })
35
+ end
36
+ else
37
+ keys.push({ pubkey: owner_or_authority, is_signer: true, is_writable: false })
38
+ end
39
+ keys
40
+ end
41
+
42
+ private
43
+
44
+ def self.find_program_address(seeds, program_id)
45
+ nonce = 255
46
+ loop do
47
+ # Combine the current nonce with the seeds
48
+ seeds_with_nonce = seeds + [[nonce].pack('C*')]
49
+ hashed_buffer = hash_seeds(seeds_with_nonce, program_id)
50
+
51
+ # Debugging: Log every generated address for inspection
52
+ puts "Testing nonce #{nonce}: #{Base58.binary_to_base58(hashed_buffer, :bitcoin)}"
53
+
54
+ # Check if it's valid and off-curve
55
+ if !SolanaRuby::Ed25519CurveChecker.on_curve?(hashed_buffer)
56
+ puts "Found valid PDA with nonce #{nonce}: #{Base58.binary_to_base58(hashed_buffer, :bitcoin)}"
57
+ return hashed_buffer
58
+ end
59
+
60
+ # Decrement nonce safely
61
+ nonce -= 1
62
+ raise "Unable to find a valid PDA address off the curve" if nonce < 0
63
+ end
64
+ end
65
+
66
+ def self.hash_seeds(seeds, program_id)
67
+ # Combine seeds and program ID with the PDA derivation logic
68
+ buffer = seeds.flatten.join + program_id + "ProgramDerivedAddress"
69
+ RbNaCl::Hash.sha256(buffer)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolanaRuby
4
- VERSION = "2.0.1"
4
+ VERSION = "2.1.0"
5
5
  end
data/lib/solana_ruby.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  Dir[File.join(__dir__, 'solana_ruby', '*.rb')].each { |file| require file }
4
4
  # Dir["solana_ruby/*.rb"].each { |f| require_relative f.delete(".rb") }
5
- require 'pry'
6
5
  module SolanaRuby
7
6
  class Error < StandardError; end
8
7
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/*.rb')].each { |file| require file }
4
+ Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/**/*.rb')].each { |file| require file }
5
+
6
+ # SOL Transfer Testing Script
7
+
8
+ # Initialize the Solana client
9
+ client = SolanaRuby::HttpClient.new('http://127.0.0.1:8899')
10
+
11
+ # Fetch the recent blockhash
12
+ recent_blockhash = client.get_latest_blockhash["blockhash"]
13
+ token_account = "C2wY5TKnj52S4s9yRUTNqitRe5gmFokSCoppJS6t63aa"
14
+ mint_address = "5FQhi6Kq3CKDaB3bus21ZqcL7wyeZNR18otFGoDfrZXU"
15
+ mint_authority = SolanaRuby::Keypair.load_keypair('/Users/chinaputtaiahbellamkonda/.config/solana/id.json')
16
+ owner = mint_authority[:public_key]
17
+ amount = 500_000 # Number of tokens to burn
18
+
19
+ transaction = SolanaRuby::TransactionHelper.burn_spl_tokens(
20
+ token_account,
21
+ mint_address,
22
+ owner,
23
+ amount,
24
+ recent_blockhash
25
+ )
26
+
27
+ # Sign and send the transaction
28
+ resp = transaction.sign([mint_authority])
29
+
30
+ puts "signature: #{resp}"
31
+
32
+ # Send the transaction
33
+ puts "Sending transaction..."
34
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
35
+
36
+ # Output transaction results
37
+ puts "Transaction Signature: #{response}"
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ require 'pry'
3
+
4
+ Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/*.rb')].each { |file| require file }
5
+ Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/**/*.rb')].each { |file| require file }
6
+
7
+ # SOL Transfer Testing Script
8
+
9
+ # Initialize the Solana client
10
+ client = SolanaRuby::HttpClient.new('http://127.0.0.1:8899')
11
+
12
+ # Fetch the recent blockhash
13
+ recent_blockhash = client.get_latest_blockhash["blockhash"]
14
+
15
+ # Assuming you already have the following public keys
16
+ payer = SolanaRuby::Keypair.from_private_key('7bcd98e0be17a23f5adbb199d614f5df28e2491ca9856a7efc276245d9d22f26')
17
+ payer_pubkey = payer[:public_key]
18
+ owner = SolanaRuby::Keypair.from_private_key('7bcd98e0be17a23f5adbb199d614f5df28e2491ca9856a7efc276245d9d22f26')
19
+ account_to_close_pubkey = 'bnKvAbZzNjF123Wa9g4yQNva5adLqj2fLNfipZ2KgP6' # associated token account closing address
20
+ destination_pubkey = 'DCm6PCsdRoEXzHUdHxXnJTP65gYSPK5p8h9Cui3quiQQ' # associated token account receiving address
21
+
22
+ # Create the transaction to close the account
23
+ transaction = SolanaRuby::TransactionHelper.close_account(
24
+ account_to_close_pubkey,
25
+ destination_pubkey,
26
+ owner[:public_key],
27
+ payer_pubkey,
28
+ [],
29
+ recent_blockhash
30
+ )
31
+
32
+ resp = transaction.sign([payer, owner])
33
+
34
+ puts "signature: #{resp}"
35
+
36
+ # Send the transaction
37
+ puts "Sending transaction..."
38
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
39
+
40
+ # Output transaction results
41
+ puts "Transaction Signature: #{response}"
42
+
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
-
2
+ # require 'pry'
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
 
@@ -11,8 +11,9 @@ recent_blockhash = client.get_latest_blockhash["blockhash"]
11
11
  puts "Recent Blockhash: #{recent_blockhash}"
12
12
 
13
13
  # Sender keypair and public key
14
- private_key = "d22867a84ee1d91485a52c587793002dcaa7ce79a58bb605b3af2682099bb778"
15
- sender_keypair = SolanaRuby::Keypair.from_private_key(private_key)
14
+ # private_key = "d22867a84ee1d91485a52c587793002dcaa7ce79a58bb605b3af2682099bb778"
15
+ # sender_keypair = SolanaRuby::Keypair.from_private_key(private_key)
16
+ sender_keypair = SolanaRuby::Keypair.load_keypair('/Users/chinaputtaiahbellamkonda/.config/solana/id.json')
16
17
  sender_pubkey = sender_keypair[:public_key]
17
18
  puts "Sender Public Key: #{sender_pubkey}"
18
19
 
@@ -28,6 +29,8 @@ end
28
29
  new_account = SolanaRuby::Keypair.generate
29
30
  new_account_pubkey = new_account[:public_key]
30
31
  puts "New Account Public Key: #{new_account_pubkey}"
32
+ puts "New Account Private Key: #{new_account[:private_key]}"
33
+ puts "New Account Full Private Key: #{new_account[:full_private_key]}"
31
34
 
32
35
  # Parameters for account creation
33
36
  lamports = 1 * 1_000_000_000 # Lamports to transfer
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/*.rb')].each { |file| require file }
4
+ Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/**/*.rb')].each { |file| require file }
5
+
6
+ # SOL Transfer Testing Script
7
+
8
+ # Initialize the Solana client
9
+ client = SolanaRuby::HttpClient.new('http://127.0.0.1:8899')
10
+
11
+ # Fetch the recent blockhash
12
+ recent_blockhash = client.get_latest_blockhash["blockhash"]
13
+
14
+ payer = SolanaRuby::Keypair.load_keypair('/Users/chinaputtaiahbellamkonda/.config/solana/id.json')
15
+ payer_pubkey = payer[:public_key]
16
+
17
+ # Generate a sender keypair and public key
18
+ owner = SolanaRuby::Keypair.generate
19
+ # owner = SolanaRuby::Keypair.from_private_key("4b9a36383e12d13581c37a50c38a00d91ae0e80f3ce25de852ea61f499102a33")
20
+ owner_pubkey = owner[:public_key]
21
+ puts "owner public key: #{owner_pubkey}"
22
+ puts "owner private key: #{owner[:private_key]}"
23
+ puts "owner full private key: #{owner[:full_private_key]}"
24
+
25
+ # Airdrop some lamports to the sender's account
26
+ # lamports = 10 * 1_000_000_000
27
+ # sleep(1)
28
+ # result = client.request_airdrop(payer_pubkey, lamports)
29
+ # puts "Solana Balance #{lamports} lamports added sucessfully for the public key: #{payer_pubkey}"
30
+ # sleep(10)
31
+
32
+
33
+ mint_pubkey = "InsertMintPublicKeyHere"
34
+ program_id = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
35
+ puts "payer public key: #{payer_pubkey}"
36
+
37
+ # associated_token_address = SolanaRuby::TransactionHelpers::TokenAccount.get_associated_token_address(mint_pubkey, payer_pubkey, program_id)
38
+
39
+ # puts "Associated Token Address: #{associated_token_address}"
40
+
41
+ transaction = SolanaRuby::TransactionHelper.create_associated_token_account(payer_pubkey, mint_pubkey, owner_pubkey, recent_blockhash)
42
+
43
+ resp = transaction.sign([payer])
44
+
45
+ puts "signature: #{resp}"
46
+
47
+ # Send the transaction
48
+ puts "Sending transaction..."
49
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
50
+
51
+ # Output transaction results
52
+ puts "Transaction Signature: #{response}"
53
+
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/*.rb')].each { |file| require file }
4
+ Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/**/*.rb')].each { |file| require file }
5
+
6
+ # SOL Transfer Testing Script
7
+
8
+ # Initialize the Solana client
9
+ client = SolanaRuby::HttpClient.new('http://127.0.0.1:8899')
10
+
11
+ # Fetch the recent blockhash
12
+ recent_blockhash = client.get_latest_blockhash["blockhash"]
13
+
14
+ # Example parameters
15
+ mint_account = "2DoNkK31X9HH5MXY6pBeb3RDZ1ZDK7wgXrcvnyipXNvf"
16
+ destination_account = "DCm6PCsdRoEXzHUdHxXnJTP65gYSPK5p8h9Cui3quiQQ"
17
+ mint_authority = SolanaRuby::Keypair.load_keypair('/Users/chinaputtaiahbellamkonda/.config/solana/id.json')
18
+ puts "Full private key: #{mint_authority[:full_private_key]}"
19
+ puts "Private key: #{mint_authority[:private_key]}"
20
+ puts "Public key: #{mint_authority[:public_key]}"
21
+ amount = 1_000_000_00_00 # Amount to mint in smallest units
22
+ multi_signers = [] # If multi-signature is used, include public keys here
23
+
24
+ # Create a mint transaction
25
+ transaction = SolanaRuby::TransactionHelper.mint_spl_tokens(
26
+ mint_account,
27
+ destination_account,
28
+ mint_authority[:public_key],
29
+ amount,
30
+ recent_blockhash,
31
+ multi_signers
32
+ )
33
+
34
+ resp = transaction.sign([mint_authority])
35
+
36
+ puts "signature: #{resp}"
37
+
38
+ # Send the transaction
39
+ puts "Sending transaction..."
40
+ response = client.send_transaction(transaction.to_base64, { encoding: 'base64' })
41
+
42
+ # Output transaction results
43
+ puts "Transaction Signature: #{response}"
@@ -1,6 +1,6 @@
1
1
  Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/*.rb')].each { |file| require file }
2
2
  Dir[File.join(File.dirname(__dir__), 'lib/solana_ruby/**/*.rb')].each { |file| require file }
3
- require 'pry'
3
+ # require 'pry'
4
4
 
5
5
  # SOL Transfer Testing Script
6
6
 
@@ -13,7 +13,7 @@ client = SolanaRuby::HttpClient.new('http://127.0.0.1:8899')
13
13
  recent_blockhash = client.get_latest_blockhash["blockhash"]
14
14
 
15
15
  # Generate a sender keypair and public key
16
- fee_payer = SolanaRuby::Keypair.from_private_key("d22867a84ee1d91485a52c587793002dcaa7ce79a58bb605b3af2682099bb778")
16
+ fee_payer = SolanaRuby::Keypair.from_private_key('e06f61b73aa625690ef97ed3704e8dc22bc835092e94cc9ae5650b516f26c91a')
17
17
  fee_payer_pubkey = fee_payer[:public_key]
18
18
  lamports = 10 * 1_000_000_000
19
19
  space = 165
@@ -24,22 +24,26 @@ puts "sender account balance: #{balance}, wait for few seconds to update the bal
24
24
 
25
25
 
26
26
  # # Generate a receiver keypair and public key
27
- keypair = SolanaRuby::Keypair.generate
27
+ keypair = SolanaRuby::Keypair.from_private_key('f7173083807e1692e844aa2ec515eca18d016fc5e4468be75be20f6093de6641')
28
28
  receiver_pubkey = keypair[:public_key]
29
- transfer_lamports = 1 * 1_000_000
30
- # puts "Payer's full private key: #{sender_keypair[:full_private_key]}"
31
- # # puts "Receiver's full private key: #{keypair[:full_private_key]}"
32
- # # puts "Receiver's Public Key: #{keypair[:public_key]}"
33
- mint_address = '9BvJGQC5FkLJzUC2TmYpi1iU8n9vt2388GLT5zvu8S1G'
34
- token_program_id = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
29
+ transfer_lamports = 1_000_000
30
+ mint_address = 'GDAWgGT42CqgaMds81JFVoqyJ4WBvfQsHAshPggAfXCM'
31
+
32
+ senders_token_account = SolanaRuby::TransactionHelpers::TokenAccount.get_associated_token_address(mint_address, fee_payer_pubkey)
33
+ receivers_token_account = SolanaRuby::TransactionHelpers::TokenAccount.get_associated_token_address(mint_address, receiver_pubkey)
34
+ puts "senders_token_account: #{senders_token_account}"
35
+ puts "receivers_token_account: #{receivers_token_account}"
35
36
 
36
37
  # Create a new transaction
37
38
  transaction = SolanaRuby::TransactionHelper.new_spl_token_transaction(
38
- "9BvJGQC5FkLJzUC2TmYpi1iU8n9vt2388GLT5zvu8S1G",
39
- receiver_pubkey,
39
+ senders_token_account,
40
+ mint_address,
41
+ receivers_token_account,
40
42
  fee_payer_pubkey,
41
43
  transfer_lamports,
42
- recent_blockhash
44
+ 9,
45
+ recent_blockhash,
46
+ []
43
47
  )
44
48
  # # Get the sender's private key (ensure it's a string)
45
49
  private_key = fee_payer[:private_key]
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.1
4
+ version: 2.1.0
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-28 00:00:00.000000000 Z
11
+ date: 2025-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: websocket-client-simple
@@ -235,6 +235,7 @@ files:
235
235
  - lib/solana_ruby/data_types/near_int64.rb
236
236
  - lib/solana_ruby/data_types/sequence.rb
237
237
  - lib/solana_ruby/data_types/unsigned_int.rb
238
+ - lib/solana_ruby/ed25519_curve_checker.rb
238
239
  - lib/solana_ruby/http_client.rb
239
240
  - lib/solana_ruby/http_methods/account_methods.rb
240
241
  - lib/solana_ruby/http_methods/basic_methods.rb
@@ -247,8 +248,10 @@ files:
247
248
  - lib/solana_ruby/http_methods/transaction_methods.rb
248
249
  - lib/solana_ruby/keypair.rb
249
250
  - lib/solana_ruby/message.rb
251
+ - lib/solana_ruby/public_key.rb
250
252
  - lib/solana_ruby/transaction.rb
251
253
  - lib/solana_ruby/transaction_helper.rb
254
+ - lib/solana_ruby/transaction_helpers/token_account.rb
252
255
  - lib/solana_ruby/transaction_instruction.rb
253
256
  - lib/solana_ruby/utils.rb
254
257
  - lib/solana_ruby/version.rb
@@ -259,7 +262,11 @@ files:
259
262
  - lib/solana_ruby/web_socket_methods/root_methods.rb
260
263
  - lib/solana_ruby/web_socket_methods/signature_methods.rb
261
264
  - lib/solana_ruby/web_socket_methods/slot_methods.rb
265
+ - transaction_testing/burn_spl_tokens.rb
266
+ - transaction_testing/close_acccount.rb
262
267
  - transaction_testing/create_account.rb
268
+ - transaction_testing/create_spl_token_account.rb
269
+ - transaction_testing/mint_spl_tokens.rb
263
270
  - transaction_testing/sol_transfer.rb
264
271
  - transaction_testing/spl_token_transfer.rb
265
272
  homepage: https://github.com/Build-Squad/solana-ruby
@@ -284,7 +291,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
284
291
  - !ruby/object:Gem::Version
285
292
  version: '0'
286
293
  requirements: []
287
- rubygems_version: 3.5.23
294
+ rubygems_version: 3.5.20
288
295
  signing_key:
289
296
  specification_version: 4
290
297
  summary: Solana Ruby SDK