Class: Klay::Tx::Legacy
- Inherits:
-
Object
- Object
- Klay::Tx::Legacy
- Defined in:
- lib/klay/tx/legacy.rb
Overview
Provides legacy support for transactions on blockchains that do not implement EIP-1559, EIP-2718, or EIP-2930.
Instance Attribute Summary collapse
-
#amount ⇒ Object
readonly
The transaction amount in Wei.
-
#chain_id ⇒ Object
readonly
The EIP-155 chain ID field.
-
#destination ⇒ Object
readonly
The recipient address.
-
#gas_limit ⇒ Object
readonly
The gas limit for the transaction.
-
#gas_price ⇒ Object
readonly
The gas price for the transaction in Wei.
-
#payload ⇒ Object
readonly
The transaction data payload.
-
#sender ⇒ Object
readonly
The sender address.
-
#signature_r ⇒ Object
readonly
The signature
r
value. -
#signature_s ⇒ Object
readonly
The signature
s
value. -
#signature_v ⇒ Object
readonly
The signature
v
byte. -
#signer_nonce ⇒ Object
readonly
The transaction nonce provided by the signer.
-
#type ⇒ Object
readonly
The transaction type.
Instance Method Summary collapse
-
#decode(hex) ⇒ Klay::Tx::Legacy
Decodes a raw transaction hex into an Legacy transaction object.
-
#encoded ⇒ String
Encodes a raw transaction object.
-
#hash ⇒ String
Gets the transaction hash.
-
#hex ⇒ String
Gets the encoded, raw transaction hex.
-
#initialize(params, chain_id = Chain::CYPRESS) ⇒ Legacy
constructor
Create a legacy transaction object that can be prepared for signature and broadcast.
-
#sign(key) ⇒ String
Sign the transaction with a given key.
-
#unsigned_copy(tx) ⇒ Klay::Tx::Legacy
Creates an unsigned copy of a transaction.
-
#unsigned_encoded ⇒ String
Encodes the unsigned transaction object, required for signing.
-
#unsigned_hash ⇒ String
Gets the sign-hash required to sign a raw transaction.
Constructor Details
#initialize(params, chain_id = Chain::CYPRESS) ⇒ Legacy
Create a legacy transaction object that can be prepared for signature and broadcast. Should not be used unless there is no EIP-1559 support.
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 |
# File 'lib/klay/tx/legacy.rb', line 76 def initialize(params, chain_id = Chain::CYPRESS) fields = { v: chain_id, r: 0, s: 0 }.merge params # populate optional fields with serializable empty values fields[:value] = Tx.sanitize_amount fields[:value] fields[:from] = Tx.sanitize_address fields[:from] fields[:to] = Tx.sanitize_address fields[:to] fields[:data] = Tx.sanitize_data fields[:data] # ensure sane values for all mandatory fields fields = Tx.validate_legacy_params fields # ensure gas limit is not too low minimum_cost = Tx.estimate_intrinsic_gas fields[:data] raise ParameterError, "Transaction gas limit is too low, try #{minimum_cost}!" if fields[:gas_limit].to_i < minimum_cost # populate class attributes @signer_nonce = fields[:nonce].to_i @gas_price = fields[:gas_price].to_i @gas_limit = fields[:gas_limit].to_i @sender = fields[:from].to_s @destination = fields[:to].to_s @amount = fields[:value].to_i @payload = fields[:data] # the signature v is set to the chain id for unsigned transactions @signature_v = fields[:v] @chain_id = chain_id # the signature fields are empty for unsigned transactions. @signature_r = fields[:r] @signature_s = fields[:s] # last but not least, set the type. @type = TYPE_LEGACY end |
Instance Attribute Details
#amount ⇒ Object (readonly)
The transaction amount in Wei.
38 39 40 |
# File 'lib/klay/tx/legacy.rb', line 38 def amount @amount end |
#chain_id ⇒ Object (readonly)
The EIP-155 chain ID field. Ref: https://eips.ethereum.org/EIPS/eip-155
54 55 56 |
# File 'lib/klay/tx/legacy.rb', line 54 def chain_id @chain_id end |
#destination ⇒ Object (readonly)
The recipient address.
35 36 37 |
# File 'lib/klay/tx/legacy.rb', line 35 def destination @destination end |
#gas_limit ⇒ Object (readonly)
The gas limit for the transaction.
32 33 34 |
# File 'lib/klay/tx/legacy.rb', line 32 def gas_limit @gas_limit end |
#gas_price ⇒ Object (readonly)
The gas price for the transaction in Wei.
29 30 31 |
# File 'lib/klay/tx/legacy.rb', line 29 def gas_price @gas_price end |
#payload ⇒ Object (readonly)
The transaction data payload.
41 42 43 |
# File 'lib/klay/tx/legacy.rb', line 41 def payload @payload end |
#sender ⇒ Object (readonly)
The sender address.
57 58 59 |
# File 'lib/klay/tx/legacy.rb', line 57 def sender @sender end |
#signature_r ⇒ Object (readonly)
The signature r
value.
47 48 49 |
# File 'lib/klay/tx/legacy.rb', line 47 def signature_r @signature_r end |
#signature_s ⇒ Object (readonly)
The signature s
value.
50 51 52 |
# File 'lib/klay/tx/legacy.rb', line 50 def signature_s @signature_s end |
#signature_v ⇒ Object (readonly)
The signature v
byte.
44 45 46 |
# File 'lib/klay/tx/legacy.rb', line 44 def signature_v @signature_v end |
#signer_nonce ⇒ Object (readonly)
The transaction nonce provided by the signer.
26 27 28 |
# File 'lib/klay/tx/legacy.rb', line 26 def signer_nonce @signer_nonce end |
#type ⇒ Object (readonly)
The transaction type.
60 61 62 |
# File 'lib/klay/tx/legacy.rb', line 60 def type @type end |
Instance Method Details
#decode(hex) ⇒ Klay::Tx::Legacy
Decodes a raw transaction hex into an Klay::Tx::Legacy transaction object.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/klay/tx/legacy.rb', line 122 def decode(hex) bin = Util.hex_to_bin hex tx = Rlp.decode bin # decoded transactions always have 9 fields, even if they are empty or zero raise ParameterError, "Transaction missing fields!" if tx.size < 9 # populate the 9 fields nonce = Util.deserialize_big_endian_to_int tx[0] gas_price = Util.deserialize_big_endian_to_int tx[1] gas_limit = Util.deserialize_big_endian_to_int tx[2] to = Util.bin_to_hex tx[3] value = Util.deserialize_big_endian_to_int tx[4] data = tx[5] v = Util.bin_to_hex tx[6] r = Util.bin_to_hex tx[7] s = Util.bin_to_hex tx[8] # try to recover the chain id from v chain_id = Chain.to_chain_id Util.deserialize_big_endian_to_int tx[6] # populate class attributes @signer_nonce = nonce.to_i @gas_price = gas_price.to_i @gas_limit = gas_limit.to_i @destination = to.to_s @amount = value.to_i @payload = data @chain_id = chain_id # allows us to force-setting a signature if the transaction is signed already _set_signature(v, r, s) unless chain_id.nil? # recover sender address public_key = Signature.recover(unsigned_hash, "#{r}#{s}#{v}", chain_id) address = Util.public_key_to_address(public_key).to_s @sender = Tx.sanitize_address address else # keep the 'from' field blank @sender = Tx.sanitize_address nil end # last but not least, set the type. @type = TYPE_LEGACY end |
#encoded ⇒ String
Encodes a raw transaction object.
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/klay/tx/legacy.rb', line 231 def encoded unless Tx.is_signed? self raise Signature::SignatureError, "Transaction is not signed!" end tx_data = [] tx_data.push Util.serialize_int_to_big_endian @signer_nonce tx_data.push Util.serialize_int_to_big_endian @gas_price tx_data.push Util.serialize_int_to_big_endian @gas_limit tx_data.push Util.hex_to_bin @destination tx_data.push Util.serialize_int_to_big_endian @amount tx_data.push Rlp::Sedes.binary.serialize @payload tx_data.push Util.serialize_int_to_big_endian @signature_v tx_data.push Util.serialize_int_to_big_endian @signature_r tx_data.push Util.serialize_int_to_big_endian @signature_s Rlp.encode tx_data end |
#hash ⇒ String
Gets the transaction hash.
258 259 260 |
# File 'lib/klay/tx/legacy.rb', line 258 def hash Util.bin_to_hex Util.keccak256 encoded end |
#hex ⇒ String
Gets the encoded, raw transaction hex.
251 252 253 |
# File 'lib/klay/tx/legacy.rb', line 251 def hex Util.bin_to_hex encoded end |
#sign(key) ⇒ String
Sign the transaction with a given key.
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/klay/tx/legacy.rb', line 206 def sign(key) if Tx.is_signed? self raise Signature::SignatureError, "Transaction is already signed!" end # ensure the sender address matches the given key unless @sender.nil? or sender.empty? signer_address = Tx.sanitize_address key.address.to_s from_address = Tx.sanitize_address @sender raise Signature::SignatureError, "Signer does not match sender" unless signer_address == from_address end # sign a keccak hash of the unsigned, encoded transaction signature = key.sign(unsigned_hash, @chain_id) r, s, v = Signature.dissect signature @signature_v = v @signature_r = r @signature_s = s return hash end |
#unsigned_copy(tx) ⇒ Klay::Tx::Legacy
Creates an unsigned copy of a transaction.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/klay/tx/legacy.rb', line 176 def unsigned_copy(tx) # not checking transaction validity unless it's of a different class raise TransactionTypeError, "Cannot copy transaction of different type!" unless tx.instance_of? Tx::Legacy # populate class attributes @signer_nonce = tx.signer_nonce @gas_price = tx.gas_price @gas_limit = tx.gas_limit @destination = tx.destination @amount = tx.amount @payload = tx.payload @chain_id = tx.chain_id # force-set signature to unsigned _set_signature(tx.chain_id, 0, 0) # keep the 'from' field blank @sender = Tx.sanitize_address nil # last but not least, set the type. @type = TYPE_LEGACY end |
#unsigned_encoded ⇒ String
Encodes the unsigned transaction object, required for signing.
265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/klay/tx/legacy.rb', line 265 def unsigned_encoded tx_data = [] tx_data.push Util.serialize_int_to_big_endian @signer_nonce tx_data.push Util.serialize_int_to_big_endian @gas_price tx_data.push Util.serialize_int_to_big_endian @gas_limit tx_data.push Util.hex_to_bin @destination tx_data.push Util.serialize_int_to_big_endian @amount tx_data.push Rlp::Sedes.binary.serialize @payload tx_data.push Util.serialize_int_to_big_endian @chain_id tx_data.push Util.serialize_int_to_big_endian 0 tx_data.push Util.serialize_int_to_big_endian 0 Rlp.encode tx_data end |