Class: Wallet::Wallet
- Inherits:
-
Object
- Object
- Wallet::Wallet
- Defined in:
- lib/wallet/wallet.rb
Overview
Represents an XRPL wallet, providing methods for signing and address derivation.
Instance Attribute Summary collapse
-
#algorithm ⇒ String
readonly
The algorithm used ('secp256k1' or 'ed25519').
-
#classic_address ⇒ String
readonly
The classic address.
-
#private_key ⇒ String
readonly
The private key as hex.
-
#public_key ⇒ String
readonly
The public key as hex.
-
#seed ⇒ String
readonly
The encoded seed.
Class Method Summary collapse
-
.from_entropy(entropy, algorithm = 'secp256k1') ⇒ Wallet
Creates a wallet from entropy.
-
.from_seed(seed, options = {}) ⇒ Wallet
Creates a wallet from a seed.
-
.generate(algorithm = 'secp256k1') ⇒ Wallet
Generates a new random wallet.
Instance Method Summary collapse
-
#get_x_address(tag: nil, test_network: false) ⇒ String
Derives the X-address for this wallet.
-
#initialize(public_key, private_key, seed: nil, classic_address: nil) ⇒ Wallet
constructor
Initializes a new Wallet instance.
-
#sign(transaction, multisign = false) ⇒ String, Hash
Signs a message (hex string) or transaction (Hash) with the wallet's private key.
-
#to_s ⇒ String
String representation of the wallet.
-
#verify(message, signature) ⇒ Boolean
Verifies a signature for a message.
-
#verify_transaction(signed_transaction) ⇒ Boolean
Verifies a signed transaction blob.
Constructor Details
#initialize(public_key, private_key, seed: nil, classic_address: nil) ⇒ Wallet
Initializes a new Wallet instance.
25 26 27 28 29 30 31 32 |
# File 'lib/wallet/wallet.rb', line 25 def initialize(public_key, private_key, seed: nil, classic_address: nil) @public_key = public_key @private_key = private_key @seed = seed @algorithm = public_key.start_with?('ED') ? 'ed25519' : 'secp256k1' @key_pairs = KeyPairs::KeyPairs.new @classic_address = classic_address || @key_pairs.derive_address(public_key) end |
Instance Attribute Details
#algorithm ⇒ String (readonly)
Returns The algorithm used ('secp256k1' or 'ed25519').
18 19 20 |
# File 'lib/wallet/wallet.rb', line 18 def algorithm @algorithm end |
#classic_address ⇒ String (readonly)
Returns The classic address.
16 17 18 |
# File 'lib/wallet/wallet.rb', line 16 def classic_address @classic_address end |
#private_key ⇒ String (readonly)
Returns The private key as hex.
12 13 14 |
# File 'lib/wallet/wallet.rb', line 12 def private_key @private_key end |
#public_key ⇒ String (readonly)
Returns The public key as hex.
10 11 12 |
# File 'lib/wallet/wallet.rb', line 10 def public_key @public_key end |
#seed ⇒ String (readonly)
Returns The encoded seed.
14 15 16 |
# File 'lib/wallet/wallet.rb', line 14 def seed @seed end |
Class Method Details
.from_entropy(entropy, algorithm = 'secp256k1') ⇒ Wallet
Creates a wallet from entropy.
57 58 59 60 61 |
# File 'lib/wallet/wallet.rb', line 57 def self.from_entropy(entropy, algorithm = 'secp256k1') kp = KeyPairs::KeyPairs.new seed = kp.generate_seed(entropy, algorithm) from_seed(seed) end |
Instance Method Details
#get_x_address(tag: nil, test_network: false) ⇒ String
Derives the X-address for this wallet.
169 170 171 172 |
# File 'lib/wallet/wallet.rb', line 169 def get_x_address(tag: nil, test_network: false) address_codec = AddressCodec::AddressCodec.new address_codec.classic_address_to_x_address(@classic_address, tag, test_network) end |
#sign(transaction, multisign = false) ⇒ String, Hash
Signs a message (hex string) or transaction (Hash) with the wallet's private key.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/wallet/wallet.rb', line 68 def sign(transaction, multisign = false) algorithm = @algorithm # Check if message is a Hash (transaction) if transaction.is_a?(::Hash) prefix = multisign ? BinaryCodec::HASH_PREFIX[:transaction_multi_sig] : BinaryCodec::HASH_PREFIX[:transaction_sig] # 1. Prepare the transaction for signing tx_to_sign = transaction.dup if multisign # For multisigning, we need the SigningPubKey to be empty, # and we need to add the Signers field later. # We also need to add the Account of the signer to the signing data. tx_to_sign['SigningPubKey'] = "" # The multisign signing data MUST include the account of the signer. else tx_to_sign['SigningPubKey'] = @public_key end # Ensure SigningPubKey is serialized as a 0-length blob if empty signing_data = BinaryCodec.signing_data(tx_to_sign, prefix, signing_fields_only: true) if multisign # Append the account ID of the signer to the signing data account_id = AddressCodec::AddressCodec.new.decode_account_id(@classic_address) signing_data += account_id end = bytes_to_hex(signing_data) # 2. Sign the message signature = @key_pairs.sign(, @private_key, algorithm) # 3. Create the signed transaction signed_tx = tx_to_sign.dup if multisign # For multisign=true, xrpl.js/PHP often returns a partially signed transaction # or an object containing the signature for a specific signer. # The PHP snippet expects a tx_blob. # Looking at the PHP snippet, it calls $wallet->sign($tx, true). # In XRPL, a multisigned transaction blob is usually the transaction # WITH the Signers array. signer = { "Signer" => { "Account" => @classic_address, "SigningPubKey" => @public_key, "TxnSignature" => signature } } signed_tx['Signers'] = [signer] signed_tx.delete('SigningPubKey') # Should be empty/not present in multisigned tx else signed_tx['TxnSignature'] = signature end # 4. Serialize the signed transaction tx_blob = BinaryCodec.json_to_binary(signed_tx) # 5. Generate the hash (transaction ID) # For transactions, the hash is SHA512Half of the serialized transaction with a prefix hash_prefix = [0x54, 0x58, 0x4E, 0x00].pack('C*') # 'TXN\0' hash = Digest::SHA512.digest(hash_prefix + [tx_blob].pack('H*'))[0...32].unpack1('H*').upcase return { 'tx_blob' => tx_blob, 'hash' => hash } end @key_pairs.sign(transaction, @private_key, algorithm) end |
#to_s ⇒ String
Returns String representation of the wallet.
175 176 177 |
# File 'lib/wallet/wallet.rb', line 175 def to_s "Wallet(address: #{@classic_address}, public_key: #{@public_key})" end |
#verify(message, signature) ⇒ Boolean
Verifies a signature for a message.
145 146 147 |
# File 'lib/wallet/wallet.rb', line 145 def verify(, signature) @key_pairs.verify(, signature, @public_key) end |
#verify_transaction(signed_transaction) ⇒ Boolean
Verifies a signed transaction blob.
152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/wallet/wallet.rb', line 152 def verify_transaction(signed_transaction) decoded = BinaryCodec.binary_to_json(signed_transaction) # The signing data is the transaction without the TxnSignature field, # prefixed by 0x53545800 (STX\0). tx_for_signing = decoded.dup signature = tx_for_signing.delete('TxnSignature') return false unless signature signing_data = BinaryCodec.signing_data(tx_for_signing) @key_pairs.verify(bytes_to_hex(signing_data), signature, @public_key) end |