Module: Klay::Tx
- Extended by:
- Tx
- Included in:
- Tx
- Defined in:
- lib/klay/tx.rb,
lib/klay/tx/legacy.rb,
lib/klay/tx/eip1559.rb,
lib/klay/tx/eip2930.rb
Overview
Provides the Tx
module supporting various transaction types.
Defined Under Namespace
Classes: DecoderError, Eip1559, Eip2930, Legacy, ParameterError, TransactionTypeError
Constant Summary collapse
- DEFAULT_GAS_LIMIT =
The minimum transaction gas limit required for a value transfer.
21_000.freeze
- DEFAULT_GAS_PRICE =
The "default" transaction gas price of 25 GPeb.
(25 * Unit::GPEB).freeze
- COST_NON_ZERO_BYTE =
The calldata gas cost of a non-zero byte as per EIP-2028.
16.freeze
- COST_ZERO_BYTE =
The calldata gas cost of a zero byte.
4.freeze
- COST_STORAGE_KEY =
The access list gas cost of a storage key as per EIP-2930.
1_900.freeze
- COST_ADDRESS =
The access list gas cost of an address as per EIP-2930.
2_400.freeze
- BLOCK_GAS_LIMIT =
The maximum transaction gas limit is bound by the block gas limit.
25_000_000.freeze
- TYPE_LEGACY =
The legacy transaction type is 0.
0x00.freeze
- TYPE_2930 =
The EIP-2930 transaction type is 1.
0x01.freeze
- TYPE_1559 =
The EIP-1559 transaction type is 2.
0x02.freeze
- ZERO_BYTE =
The zero byte is 0x00.
"\x00".freeze
Class Method Summary collapse
-
.decode(hex) ⇒ Klay::Tx
Decodes a transaction hex of any known type (2, 1, or legacy).
-
.estimate_intrinsic_gas(data = "", list = []) ⇒ Integer
Estimates intrinsic gas for provided call data (EIP-2028) and access lists (EIP-2930).
-
.is_signed?(tx) ⇒ Bool
Allows to check wether a transaction is signed already.
-
.new(params, chain_id = Chain::CYPRESS) ⇒ Object
Creates a new transaction of any type for given parameters and chain ID.
-
.sanitize_address(addr) ⇒ String
Populates the transaction destination address with a serializable empty value in case it is undefined; also ensures the address is checksummed but not prefixed for consistency.
-
.sanitize_amount(val) ⇒ Integer
Populates the transaction value field with a serializable empty value in case it is undefined.
-
.sanitize_chain(id) ⇒ Integer
Populates the transaction chain id field with a serializable default value (1) in case it is undefined.
-
.sanitize_data(data) ⇒ String
Populates the transaction payload field with a serializable empty value in case it is undefined; also ensures the data is binary not hex.
-
.sanitize_list(list) ⇒ Array
Populates the transaction access list field with a serializable empty array in case it is undefined; also ensures the nested data is binary not hex.
-
.unsigned_copy(tx) ⇒ Klay::Tx
Creates an unsigned copy of any transaction object.
-
.validate_legacy_params(fields) ⇒ Hash
Validates the common legacy transaction fields such as nonce, gas price, gas limit, amount, and access list.
-
.validate_params(fields) ⇒ Hash
Validates the common type-2 transaction fields such as nonce, priority fee, max gas fee, gas limit, amount, and access list.
Instance Method Summary collapse
-
#decode(hex) ⇒ Klay::Tx
Decodes a transaction hex of any known type (2, 1, or legacy).
-
#estimate_intrinsic_gas(data = "", list = []) ⇒ Integer
Estimates intrinsic gas for provided call data (EIP-2028) and access lists (EIP-2930).
-
#is_signed?(tx) ⇒ Bool
Allows to check wether a transaction is signed already.
-
#new(params, chain_id = Chain::CYPRESS) ⇒ Object
Creates a new transaction of any type for given parameters and chain ID.
-
#sanitize_address(addr) ⇒ String
Populates the transaction destination address with a serializable empty value in case it is undefined; also ensures the address is checksummed but not prefixed for consistency.
-
#sanitize_amount(val) ⇒ Integer
Populates the transaction value field with a serializable empty value in case it is undefined.
-
#sanitize_chain(id) ⇒ Integer
Populates the transaction chain id field with a serializable default value (1) in case it is undefined.
-
#sanitize_data(data) ⇒ String
Populates the transaction payload field with a serializable empty value in case it is undefined; also ensures the data is binary not hex.
-
#sanitize_list(list) ⇒ Array
Populates the transaction access list field with a serializable empty array in case it is undefined; also ensures the nested data is binary not hex.
-
#unsigned_copy(tx) ⇒ Klay::Tx
Creates an unsigned copy of any transaction object.
-
#validate_legacy_params(fields) ⇒ Hash
Validates the common legacy transaction fields such as nonce, gas price, gas limit, amount, and access list.
-
#validate_params(fields) ⇒ Hash
Validates the common type-2 transaction fields such as nonce, priority fee, max gas fee, gas limit, amount, and access list.
Class Method Details
.decode(hex) ⇒ Klay::Tx
Decodes a transaction hex of any known type (2, 1, or legacy).
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/klay/tx.rb', line 106 def decode(hex) hex = Util.remove_hex_prefix hex type = hex[0, 2].to_i(16) case type when TYPE_1559 # EIP-1559 transaction (type 2) return Tx::Eip1559.decode hex when TYPE_2930 # EIP-2930 transaction (type 1) return Tx::Eip2930.decode hex else # Legacy transaction if first byte is RLP (>= 192) if type >= 0xc0 return Tx::Legacy.decode hex else raise TransactionTypeError, "Cannot decode unknown transaction type #{type}!" end end end |
.estimate_intrinsic_gas(data = "", list = []) ⇒ Integer
Estimates intrinsic gas for provided call data (EIP-2028) and access lists (EIP-2930).
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/klay/tx.rb', line 158 def estimate_intrinsic_gas(data = "", list = []) gas = DEFAULT_GAS_LIMIT unless data.nil? or data.empty? data = Util.hex_to_bin data if Util.is_hex? data # count zero bytes zero = data.count ZERO_BYTE gas += zero * COST_ZERO_BYTE # count non-zero bytes none = data.size - zero gas += none * COST_NON_ZERO_BYTE end unless list.nil? or list.empty? list.each do |entry| # count addresses gas += COST_ADDRESS entry.last.each do |key| # count storage keys gas += COST_STORAGE_KEY end end end return gas end |
.is_signed?(tx) ⇒ Bool
Allows to check wether a transaction is signed already.
322 323 324 325 |
# File 'lib/klay/tx.rb', line 322 def is_signed?(tx) !tx.signature_r.nil? and tx.signature_r != 0 and !tx.signature_s.nil? and tx.signature_s != 0 end |
.new(params, chain_id = Chain::CYPRESS) ⇒ Object
Creates a new transaction of any type for given parameters and chain ID. Required parameters are (optional in brackets):
- EIP-1559: chain_id, nonce, priority_fee, max_gas_fee, gas_limit(, from, to, value, data, access_list)
- EIP-2930: chain_id, nonce, gas_price, gas_limit, access_list(, from, to, value, data)
- Legacy: nonce, gas_price, gas_lmit(, from, to, value, data)
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/klay/tx.rb', line 82 def new(params, chain_id = Chain::CYPRESS) # if we deal with max gas fee parameter, attempt EIP-1559 unless params[:max_gas_fee].nil? params[:chain_id] = chain_id if params[:chain_id].nil? return Tx::Eip1559.new params end # if we deal with access list parameter, attempt EIP-2930 unless params[:access_list].nil? params[:chain_id] = chain_id if params[:chain_id].nil? return Tx::Eip2930.new params end # if nothing else, go with legacy transactions chain_id = params[:chain_id] if !params[:chain_id].nil? and params[:chain_id] != chain_id return Tx::Legacy.new params, chain_id end |
.sanitize_address(addr) ⇒ String
Populates the transaction destination address with a serializable empty value in case it is undefined; also ensures the address is checksummed but not prefixed for consistency.
265 266 267 268 269 270 271 272 |
# File 'lib/klay/tx.rb', line 265 def sanitize_address(addr) addr = "" if addr.nil? if addr.is_a? String and !addr.empty? addr = Address.new(addr).to_s addr = Util.remove_hex_prefix addr end return addr end |
.sanitize_amount(val) ⇒ Integer
Populates the transaction value field with a serializable empty value in case it is undefined.
279 280 281 282 |
# File 'lib/klay/tx.rb', line 279 def sanitize_amount(val) val = 0 if val.nil? return val end |
.sanitize_chain(id) ⇒ Integer
Populates the transaction chain id field with a serializable default value (1) in case it is undefined.
254 255 256 257 |
# File 'lib/klay/tx.rb', line 254 def sanitize_chain(id) id = Chain::CYPRESS if id.nil? return id end |
.sanitize_data(data) ⇒ String
Populates the transaction payload field with a serializable empty value in case it is undefined; also ensures the data is binary not hex.
289 290 291 292 293 294 295 |
# File 'lib/klay/tx.rb', line 289 def sanitize_data(data) data = "" if data.nil? # ensure payload to be binary if it's hex, otherwise we'll treat it raw data = Util.hex_to_bin data if Util.is_hex? data return data end |
.sanitize_list(list) ⇒ Array
Populates the transaction access list field with a serializable empty array in case it is undefined; also ensures the nested data is binary not hex.
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/klay/tx.rb', line 303 def sanitize_list(list) list = [] if list.nil? list.each_with_index do |value, index| if value.is_a? Array # recursively check the entire array list[index] = sanitize_list value elsif Util.is_hex? value # only modify if we find a hex value list[index] = Util.hex_to_bin value end end return list end |
.unsigned_copy(tx) ⇒ Klay::Tx
Creates an unsigned copy of any transaction object.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/klay/tx.rb', line 134 def unsigned_copy(tx) case tx.type when TYPE_1559 # EIP-1559 transaction (type 2) return Tx::Eip1559.unsigned_copy tx when TYPE_2930 # EIP-2930 transaction (type 1) return Tx::Eip2930.unsigned_copy tx when TYPE_LEGACY # Legacy transaction ("type 0") return Tx::Legacy.unsigned_copy tx end raise TransactionTypeError, "Cannot copy unknown transaction type #{tx.type}!" end |
.validate_legacy_params(fields) ⇒ Hash
Validates the common legacy transaction fields such as nonce, gas price, gas limit, amount, and access list.
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/klay/tx.rb', line 230 def validate_legacy_params(fields) if fields[:nonce].nil? or fields[:nonce] < 0 raise ParameterError, "Invalid signer nonce #{fields[:nonce]}!" end if fields[:gas_price].nil? or fields[:gas_price] < 0 raise ParameterError, "Invalid gas price #{fields[:gas_price]}!" end if fields[:gas_limit].nil? or fields[:gas_limit] < DEFAULT_GAS_LIMIT or fields[:gas_limit] > BLOCK_GAS_LIMIT raise ParameterError, "Invalid gas limit #{fields[:gas_limit]}!" end unless fields[:value] >= 0 raise ParameterError, "Invalid transaction value #{fields[:value]}!" end unless fields[:access_list].nil? or fields[:access_list].is_a? Array raise ParameterError, "Invalid access list #{fields[:access_list]}!" end return fields end |
.validate_params(fields) ⇒ Hash
Validates the common type-2 transaction fields such as nonce, priority fee, max gas fee, gas limit, amount, and access list.
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/klay/tx.rb', line 198 def validate_params(fields) if fields[:nonce].nil? or fields[:nonce] < 0 raise ParameterError, "Invalid signer nonce #{fields[:nonce]}!" end if fields[:priority_fee].nil? or fields[:priority_fee] < 0 raise ParameterError, "Invalid gas priority fee #{fields[:priority_fee]}!" end if fields[:max_gas_fee].nil? or fields[:max_gas_fee] < 0 raise ParameterError, "Invalid max gas fee #{fields[:max_gas_fee]}!" end if fields[:gas_limit].nil? or fields[:gas_limit] < DEFAULT_GAS_LIMIT or fields[:gas_limit] > BLOCK_GAS_LIMIT raise ParameterError, "Invalid gas limit #{fields[:gas_limit]}!" end unless fields[:value] >= 0 raise ParameterError, "Invalid transaction value #{fields[:value]}!" end unless fields[:access_list].nil? or fields[:access_list].is_a? Array raise ParameterError, "Invalid access list #{fields[:access_list]}!" end return fields end |
Instance Method Details
#decode(hex) ⇒ Klay::Tx
Decodes a transaction hex of any known type (2, 1, or legacy).
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/klay/tx.rb', line 106 def decode(hex) hex = Util.remove_hex_prefix hex type = hex[0, 2].to_i(16) case type when TYPE_1559 # EIP-1559 transaction (type 2) return Tx::Eip1559.decode hex when TYPE_2930 # EIP-2930 transaction (type 1) return Tx::Eip2930.decode hex else # Legacy transaction if first byte is RLP (>= 192) if type >= 0xc0 return Tx::Legacy.decode hex else raise TransactionTypeError, "Cannot decode unknown transaction type #{type}!" end end end |
#estimate_intrinsic_gas(data = "", list = []) ⇒ Integer
Estimates intrinsic gas for provided call data (EIP-2028) and access lists (EIP-2930).
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/klay/tx.rb', line 158 def estimate_intrinsic_gas(data = "", list = []) gas = DEFAULT_GAS_LIMIT unless data.nil? or data.empty? data = Util.hex_to_bin data if Util.is_hex? data # count zero bytes zero = data.count ZERO_BYTE gas += zero * COST_ZERO_BYTE # count non-zero bytes none = data.size - zero gas += none * COST_NON_ZERO_BYTE end unless list.nil? or list.empty? list.each do |entry| # count addresses gas += COST_ADDRESS entry.last.each do |key| # count storage keys gas += COST_STORAGE_KEY end end end return gas end |
#is_signed?(tx) ⇒ Bool
Allows to check wether a transaction is signed already.
322 323 324 325 |
# File 'lib/klay/tx.rb', line 322 def is_signed?(tx) !tx.signature_r.nil? and tx.signature_r != 0 and !tx.signature_s.nil? and tx.signature_s != 0 end |
#new(params, chain_id = Chain::CYPRESS) ⇒ Object
Creates a new transaction of any type for given parameters and chain ID. Required parameters are (optional in brackets):
- EIP-1559: chain_id, nonce, priority_fee, max_gas_fee, gas_limit(, from, to, value, data, access_list)
- EIP-2930: chain_id, nonce, gas_price, gas_limit, access_list(, from, to, value, data)
- Legacy: nonce, gas_price, gas_lmit(, from, to, value, data)
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/klay/tx.rb', line 82 def new(params, chain_id = Chain::CYPRESS) # if we deal with max gas fee parameter, attempt EIP-1559 unless params[:max_gas_fee].nil? params[:chain_id] = chain_id if params[:chain_id].nil? return Tx::Eip1559.new params end # if we deal with access list parameter, attempt EIP-2930 unless params[:access_list].nil? params[:chain_id] = chain_id if params[:chain_id].nil? return Tx::Eip2930.new params end # if nothing else, go with legacy transactions chain_id = params[:chain_id] if !params[:chain_id].nil? and params[:chain_id] != chain_id return Tx::Legacy.new params, chain_id end |
#sanitize_address(addr) ⇒ String
Populates the transaction destination address with a serializable empty value in case it is undefined; also ensures the address is checksummed but not prefixed for consistency.
265 266 267 268 269 270 271 272 |
# File 'lib/klay/tx.rb', line 265 def sanitize_address(addr) addr = "" if addr.nil? if addr.is_a? String and !addr.empty? addr = Address.new(addr).to_s addr = Util.remove_hex_prefix addr end return addr end |
#sanitize_amount(val) ⇒ Integer
Populates the transaction value field with a serializable empty value in case it is undefined.
279 280 281 282 |
# File 'lib/klay/tx.rb', line 279 def sanitize_amount(val) val = 0 if val.nil? return val end |
#sanitize_chain(id) ⇒ Integer
Populates the transaction chain id field with a serializable default value (1) in case it is undefined.
254 255 256 257 |
# File 'lib/klay/tx.rb', line 254 def sanitize_chain(id) id = Chain::CYPRESS if id.nil? return id end |
#sanitize_data(data) ⇒ String
Populates the transaction payload field with a serializable empty value in case it is undefined; also ensures the data is binary not hex.
289 290 291 292 293 294 295 |
# File 'lib/klay/tx.rb', line 289 def sanitize_data(data) data = "" if data.nil? # ensure payload to be binary if it's hex, otherwise we'll treat it raw data = Util.hex_to_bin data if Util.is_hex? data return data end |
#sanitize_list(list) ⇒ Array
Populates the transaction access list field with a serializable empty array in case it is undefined; also ensures the nested data is binary not hex.
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/klay/tx.rb', line 303 def sanitize_list(list) list = [] if list.nil? list.each_with_index do |value, index| if value.is_a? Array # recursively check the entire array list[index] = sanitize_list value elsif Util.is_hex? value # only modify if we find a hex value list[index] = Util.hex_to_bin value end end return list end |
#unsigned_copy(tx) ⇒ Klay::Tx
Creates an unsigned copy of any transaction object.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/klay/tx.rb', line 134 def unsigned_copy(tx) case tx.type when TYPE_1559 # EIP-1559 transaction (type 2) return Tx::Eip1559.unsigned_copy tx when TYPE_2930 # EIP-2930 transaction (type 1) return Tx::Eip2930.unsigned_copy tx when TYPE_LEGACY # Legacy transaction ("type 0") return Tx::Legacy.unsigned_copy tx end raise TransactionTypeError, "Cannot copy unknown transaction type #{tx.type}!" end |
#validate_legacy_params(fields) ⇒ Hash
Validates the common legacy transaction fields such as nonce, gas price, gas limit, amount, and access list.
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/klay/tx.rb', line 230 def validate_legacy_params(fields) if fields[:nonce].nil? or fields[:nonce] < 0 raise ParameterError, "Invalid signer nonce #{fields[:nonce]}!" end if fields[:gas_price].nil? or fields[:gas_price] < 0 raise ParameterError, "Invalid gas price #{fields[:gas_price]}!" end if fields[:gas_limit].nil? or fields[:gas_limit] < DEFAULT_GAS_LIMIT or fields[:gas_limit] > BLOCK_GAS_LIMIT raise ParameterError, "Invalid gas limit #{fields[:gas_limit]}!" end unless fields[:value] >= 0 raise ParameterError, "Invalid transaction value #{fields[:value]}!" end unless fields[:access_list].nil? or fields[:access_list].is_a? Array raise ParameterError, "Invalid access list #{fields[:access_list]}!" end return fields end |
#validate_params(fields) ⇒ Hash
Validates the common type-2 transaction fields such as nonce, priority fee, max gas fee, gas limit, amount, and access list.
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/klay/tx.rb', line 198 def validate_params(fields) if fields[:nonce].nil? or fields[:nonce] < 0 raise ParameterError, "Invalid signer nonce #{fields[:nonce]}!" end if fields[:priority_fee].nil? or fields[:priority_fee] < 0 raise ParameterError, "Invalid gas priority fee #{fields[:priority_fee]}!" end if fields[:max_gas_fee].nil? or fields[:max_gas_fee] < 0 raise ParameterError, "Invalid max gas fee #{fields[:max_gas_fee]}!" end if fields[:gas_limit].nil? or fields[:gas_limit] < DEFAULT_GAS_LIMIT or fields[:gas_limit] > BLOCK_GAS_LIMIT raise ParameterError, "Invalid gas limit #{fields[:gas_limit]}!" end unless fields[:value] >= 0 raise ParameterError, "Invalid transaction value #{fields[:value]}!" end unless fields[:access_list].nil? or fields[:access_list].is_a? Array raise ParameterError, "Invalid access list #{fields[:access_list]}!" end return fields end |