klay 0.0.1

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.
@@ -0,0 +1,296 @@
1
+ # Copyright (c) 2016-2022 The Ruby-Eth Contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Provides the {Eth} module.
16
+ module Klay
17
+
18
+ # Provides the `Tx` module supporting various transaction types.
19
+ module Tx
20
+
21
+ # Provides legacy support for transactions on blockchains that do not
22
+ # implement EIP-1559, EIP-2718, or EIP-2930.
23
+ class Legacy
24
+
25
+ # The transaction nonce provided by the signer.
26
+ attr_reader :signer_nonce
27
+
28
+ # The gas price for the transaction in Wei.
29
+ attr_reader :gas_price
30
+
31
+ # The gas limit for the transaction.
32
+ attr_reader :gas_limit
33
+
34
+ # The recipient address.
35
+ attr_reader :destination
36
+
37
+ # The transaction amount in Wei.
38
+ attr_reader :amount
39
+
40
+ # The transaction data payload.
41
+ attr_reader :payload
42
+
43
+ # The signature `v` byte.
44
+ attr_reader :signature_v
45
+
46
+ # The signature `r` value.
47
+ attr_reader :signature_r
48
+
49
+ # The signature `s` value.
50
+ attr_reader :signature_s
51
+
52
+ # The EIP-155 chain ID field.
53
+ # Ref: https://eips.ethereum.org/EIPS/eip-155
54
+ attr_reader :chain_id
55
+
56
+ # The sender address.
57
+ attr_reader :sender
58
+
59
+ # The transaction type.
60
+ attr_reader :type
61
+
62
+ # Create a legacy transaction object that can be prepared for
63
+ # signature and broadcast. Should not be used unless there is
64
+ # no EIP-1559 support.
65
+ #
66
+ # @param params [Hash] all necessary transaction fields.
67
+ # @option params [Integer] :nonce the signer nonce.
68
+ # @option params [Integer] :gas_price the gas price.
69
+ # @option params [Integer] :gas_limit the gas limit.
70
+ # @option params [Eth::Address] :from the sender address.
71
+ # @option params [Eth::Address] :to the reciever address.
72
+ # @option params [Integer] :value the transaction value.
73
+ # @option params [String] :data the transaction data payload.
74
+ # @param chain_id [Integer] the EIP-155 Chain ID.
75
+ # @raise [ParameterError] if gas limit is too low.
76
+ def initialize(params, chain_id = Chain::CYPRESS)
77
+ fields = { v: chain_id, r: 0, s: 0 }.merge params
78
+
79
+ # populate optional fields with serializable empty values
80
+ fields[:value] = Tx.sanitize_amount fields[:value]
81
+ fields[:from] = Tx.sanitize_address fields[:from]
82
+ fields[:to] = Tx.sanitize_address fields[:to]
83
+ fields[:data] = Tx.sanitize_data fields[:data]
84
+
85
+ # ensure sane values for all mandatory fields
86
+ fields = Tx.validate_legacy_params fields
87
+
88
+ # ensure gas limit is not too low
89
+ minimum_cost = Tx.estimate_intrinsic_gas fields[:data]
90
+ raise ParameterError, "Transaction gas limit is too low, try #{minimum_cost}!" if fields[:gas_limit].to_i < minimum_cost
91
+
92
+ # populate class attributes
93
+ @signer_nonce = fields[:nonce].to_i
94
+ @gas_price = fields[:gas_price].to_i
95
+ @gas_limit = fields[:gas_limit].to_i
96
+ @sender = fields[:from].to_s
97
+ @destination = fields[:to].to_s
98
+ @amount = fields[:value].to_i
99
+ @payload = fields[:data]
100
+
101
+ # the signature v is set to the chain id for unsigned transactions
102
+ @signature_v = fields[:v]
103
+ @chain_id = chain_id
104
+
105
+ # the signature fields are empty for unsigned transactions.
106
+ @signature_r = fields[:r]
107
+ @signature_s = fields[:s]
108
+
109
+ # last but not least, set the type.
110
+ @type = TYPE_LEGACY
111
+ end
112
+
113
+ # overloads the constructor for decoding raw transactions and creating unsigned copies
114
+ konstructor :decode, :unsigned_copy
115
+
116
+ # Decodes a raw transaction hex into an {Eth::Tx::Legacy}
117
+ # transaction object.
118
+ #
119
+ # @param hex [String] the raw transaction hex-string.
120
+ # @return [Eth::Tx::Legacy] transaction object.
121
+ # @raise [ParameterError] if transaction misses fields.
122
+ def decode(hex)
123
+ bin = Util.hex_to_bin hex
124
+ tx = Rlp.decode bin
125
+
126
+ # decoded transactions always have 9 fields, even if they are empty or zero
127
+ raise ParameterError, "Transaction missing fields!" if tx.size < 9
128
+
129
+ # populate the 9 fields
130
+ nonce = Util.deserialize_big_endian_to_int tx[0]
131
+ gas_price = Util.deserialize_big_endian_to_int tx[1]
132
+ gas_limit = Util.deserialize_big_endian_to_int tx[2]
133
+ to = Util.bin_to_hex tx[3]
134
+ value = Util.deserialize_big_endian_to_int tx[4]
135
+ data = tx[5]
136
+ v = Util.bin_to_hex tx[6]
137
+ r = Util.bin_to_hex tx[7]
138
+ s = Util.bin_to_hex tx[8]
139
+
140
+ # try to recover the chain id from v
141
+ chain_id = Chain.to_chain_id Util.deserialize_big_endian_to_int tx[6]
142
+
143
+ # populate class attributes
144
+ @signer_nonce = nonce.to_i
145
+ @gas_price = gas_price.to_i
146
+ @gas_limit = gas_limit.to_i
147
+ @destination = to.to_s
148
+ @amount = value.to_i
149
+ @payload = data
150
+ @chain_id = chain_id
151
+
152
+ # allows us to force-setting a signature if the transaction is signed already
153
+ _set_signature(v, r, s)
154
+
155
+ unless chain_id.nil?
156
+
157
+ # recover sender address
158
+ public_key = Signature.recover(unsigned_hash, "#{r}#{s}#{v}", chain_id)
159
+ address = Util.public_key_to_address(public_key).to_s
160
+ @sender = Tx.sanitize_address address
161
+ else
162
+
163
+ # keep the 'from' field blank
164
+ @sender = Tx.sanitize_address nil
165
+ end
166
+
167
+ # last but not least, set the type.
168
+ @type = TYPE_LEGACY
169
+ end
170
+
171
+ # Creates an unsigned copy of a transaction.
172
+ #
173
+ # @param tx [Eth::Tx::Legacy] an legacy transaction object.
174
+ # @return [Eth::Tx::Legacy] an unsigned transaction object.
175
+ # @raise [TransactionTypeError] if transaction type does not match.
176
+ def unsigned_copy(tx)
177
+
178
+ # not checking transaction validity unless it's of a different class
179
+ raise TransactionTypeError, "Cannot copy transaction of different type!" unless tx.instance_of? Tx::Legacy
180
+
181
+ # populate class attributes
182
+ @signer_nonce = tx.signer_nonce
183
+ @gas_price = tx.gas_price
184
+ @gas_limit = tx.gas_limit
185
+ @destination = tx.destination
186
+ @amount = tx.amount
187
+ @payload = tx.payload
188
+ @chain_id = tx.chain_id
189
+
190
+ # force-set signature to unsigned
191
+ _set_signature(tx.chain_id, 0, 0)
192
+
193
+ # keep the 'from' field blank
194
+ @sender = Tx.sanitize_address nil
195
+
196
+ # last but not least, set the type.
197
+ @type = TYPE_LEGACY
198
+ end
199
+
200
+ # Sign the transaction with a given key.
201
+ #
202
+ # @param key [Eth::Key] the key-pair to use for signing.
203
+ # @return [String] a transaction hash.
204
+ # @raise [Signature::SignatureError] if transaction is already signed.
205
+ # @raise [Signature::SignatureError] if sender address does not match signing key.
206
+ def sign(key)
207
+ if Tx.is_signed? self
208
+ raise Signature::SignatureError, "Transaction is already signed!"
209
+ end
210
+
211
+ # ensure the sender address matches the given key
212
+ unless @sender.nil? or sender.empty?
213
+ signer_address = Tx.sanitize_address key.address.to_s
214
+ from_address = Tx.sanitize_address @sender
215
+ raise Signature::SignatureError, "Signer does not match sender" unless signer_address == from_address
216
+ end
217
+
218
+ # sign a keccak hash of the unsigned, encoded transaction
219
+ signature = key.sign(unsigned_hash, @chain_id)
220
+ r, s, v = Signature.dissect signature
221
+ @signature_v = v
222
+ @signature_r = r
223
+ @signature_s = s
224
+ return hash
225
+ end
226
+
227
+ # Encodes a raw transaction object.
228
+ #
229
+ # @return [String] a raw, RLP-encoded legacy transaction.
230
+ # @raise [Signature::SignatureError] if the transaction is not yet signed.
231
+ def encoded
232
+ unless Tx.is_signed? self
233
+ raise Signature::SignatureError, "Transaction is not signed!"
234
+ end
235
+ tx_data = []
236
+ tx_data.push Util.serialize_int_to_big_endian @signer_nonce
237
+ tx_data.push Util.serialize_int_to_big_endian @gas_price
238
+ tx_data.push Util.serialize_int_to_big_endian @gas_limit
239
+ tx_data.push Util.hex_to_bin @destination
240
+ tx_data.push Util.serialize_int_to_big_endian @amount
241
+ tx_data.push Rlp::Sedes.binary.serialize @payload
242
+ tx_data.push Util.serialize_int_to_big_endian @signature_v
243
+ tx_data.push Util.serialize_int_to_big_endian @signature_r
244
+ tx_data.push Util.serialize_int_to_big_endian @signature_s
245
+ Rlp.encode tx_data
246
+ end
247
+
248
+ # Gets the encoded, raw transaction hex.
249
+ #
250
+ # @return [String] the raw transaction hex.
251
+ def hex
252
+ Util.bin_to_hex encoded
253
+ end
254
+
255
+ # Gets the transaction hash.
256
+ #
257
+ # @return [String] the transaction hash.
258
+ def hash
259
+ Util.bin_to_hex Util.keccak256 encoded
260
+ end
261
+
262
+ # Encodes the unsigned transaction object, required for signing.
263
+ #
264
+ # @return [String] an RLP-encoded, unsigned transaction.
265
+ def unsigned_encoded
266
+ tx_data = []
267
+ tx_data.push Util.serialize_int_to_big_endian @signer_nonce
268
+ tx_data.push Util.serialize_int_to_big_endian @gas_price
269
+ tx_data.push Util.serialize_int_to_big_endian @gas_limit
270
+ tx_data.push Util.hex_to_bin @destination
271
+ tx_data.push Util.serialize_int_to_big_endian @amount
272
+ tx_data.push Rlp::Sedes.binary.serialize @payload
273
+ tx_data.push Util.serialize_int_to_big_endian @chain_id
274
+ tx_data.push Util.serialize_int_to_big_endian 0
275
+ tx_data.push Util.serialize_int_to_big_endian 0
276
+ Rlp.encode tx_data
277
+ end
278
+
279
+ # Gets the sign-hash required to sign a raw transaction.
280
+ #
281
+ # @return [String] a Keccak-256 hash of an unsigned transaction.
282
+ def unsigned_hash
283
+ Util.keccak256 unsigned_encoded
284
+ end
285
+
286
+ private
287
+
288
+ # Force-sets an existing signature of a decoded transaction.
289
+ def _set_signature(v, r, s)
290
+ @signature_v = v
291
+ @signature_r = r
292
+ @signature_s = s
293
+ end
294
+ end
295
+ end
296
+ end
data/lib/klay/tx.rb ADDED
@@ -0,0 +1,327 @@
1
+ # Copyright (c) 2016-2022 The Ruby-Eth Contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "konstructor"
16
+
17
+ require "klay/chain"
18
+ require "klay/tx/eip1559"
19
+ require "klay/tx/eip2930"
20
+ require "klay/tx/legacy"
21
+ require "klay/unit"
22
+
23
+ # Provides the {Eth} module.
24
+ module Klay
25
+
26
+ # Provides the `Tx` module supporting various transaction types.
27
+ module Tx
28
+ extend self
29
+
30
+ # Provides a special transaction error if transaction type is unknown.
31
+ class TransactionTypeError < TypeError; end
32
+
33
+ # Provides an decoder error if transaction cannot be decoded.
34
+ class DecoderError < StandardError; end
35
+
36
+ # Provides a parameter error if parameter types are invalid.
37
+ class ParameterError < TypeError; end
38
+
39
+ # The minimum transaction gas limit required for a value transfer.
40
+ DEFAULT_GAS_LIMIT = 21_000.freeze
41
+
42
+ # The "default" transaction gas price of 20 GWei. Do not use.
43
+ DEFAULT_GAS_PRICE = (20 * Unit::GWEI).freeze
44
+
45
+ # The calldata gas cost of a non-zero byte as per EIP-2028.
46
+ COST_NON_ZERO_BYTE = 16.freeze
47
+
48
+ # The calldata gas cost of a zero byte.
49
+ COST_ZERO_BYTE = 4.freeze
50
+
51
+ # The access list gas cost of a storage key as per EIP-2930.
52
+ COST_STORAGE_KEY = 1_900.freeze
53
+
54
+ # The access list gas cost of an address as per EIP-2930.
55
+ COST_ADDRESS = 2_400.freeze
56
+
57
+ # The maximum transaction gas limit is bound by the block gas limit.
58
+ BLOCK_GAS_LIMIT = 25_000_000.freeze
59
+
60
+ # The legacy transaction type is 0.
61
+ TYPE_LEGACY = 0x00.freeze
62
+
63
+ # The EIP-2930 transaction type is 1.
64
+ TYPE_2930 = 0x01.freeze
65
+
66
+ # The EIP-1559 transaction type is 2.
67
+ TYPE_1559 = 0x02.freeze
68
+
69
+ # The zero byte is 0x00.
70
+ ZERO_BYTE = "\x00".freeze
71
+
72
+ # Creates a new transaction of any type for given parameters and chain ID.
73
+ # Required parameters are (optional in brackets):
74
+ # - EIP-1559: chain_id, nonce, priority_fee, max_gas_fee, gas_limit(, from, to,
75
+ # value, data, access_list)
76
+ # - EIP-2930: chain_id, nonce, gas_price, gas_limit, access_list(, from, to,
77
+ # value, data)
78
+ # - Legacy: nonce, gas_price, gas_lmit(, from, to, value, data)
79
+ #
80
+ # @param params [Hash] all necessary transaction fields.
81
+ # @param chain_id [Integer] the EIP-155 Chain ID (legacy transactions only).
82
+ def new(params, chain_id = Chain::CYPRESS)
83
+
84
+ # if we deal with max gas fee parameter, attempt EIP-1559
85
+ unless params[:max_gas_fee].nil?
86
+ params[:chain_id] = chain_id if params[:chain_id].nil?
87
+ return Tx::Eip1559.new params
88
+ end
89
+
90
+ # if we deal with access list parameter, attempt EIP-2930
91
+ unless params[:access_list].nil?
92
+ params[:chain_id] = chain_id if params[:chain_id].nil?
93
+ return Tx::Eip2930.new params
94
+ end
95
+
96
+ # if nothing else, go with legacy transactions
97
+ chain_id = params[:chain_id] if !params[:chain_id].nil? and params[:chain_id] != chain_id
98
+ return Tx::Legacy.new params, chain_id
99
+ end
100
+
101
+ # Decodes a transaction hex of any known type (2, 1, or legacy).
102
+ #
103
+ # @param hex [String] the raw transaction hex-string.
104
+ # @return [Eth::Tx] transaction payload.
105
+ # @raise [TransactionTypeError] if the transaction type is unknown.
106
+ def decode(hex)
107
+ hex = Util.remove_hex_prefix hex
108
+ type = hex[0, 2].to_i(16)
109
+ case type
110
+ when TYPE_1559
111
+
112
+ # EIP-1559 transaction (type 2)
113
+ return Tx::Eip1559.decode hex
114
+ when TYPE_2930
115
+
116
+ # EIP-2930 transaction (type 1)
117
+ return Tx::Eip2930.decode hex
118
+ else
119
+
120
+ # Legacy transaction if first byte is RLP (>= 192)
121
+ if type >= 0xc0
122
+ return Tx::Legacy.decode hex
123
+ else
124
+ raise TransactionTypeError, "Cannot decode unknown transaction type #{type}!"
125
+ end
126
+ end
127
+ end
128
+
129
+ # Creates an unsigned copy of any transaction object.
130
+ #
131
+ # @param tx [Eth::Tx] any transaction payload.
132
+ # @return [Eth::Tx] an unsigned transaction payload of the same type.
133
+ # @raise [TransactionTypeError] if the transaction type is unknown.
134
+ def unsigned_copy(tx)
135
+ case tx.type
136
+ when TYPE_1559
137
+
138
+ # EIP-1559 transaction (type 2)
139
+ return Tx::Eip1559.unsigned_copy tx
140
+ when TYPE_2930
141
+
142
+ # EIP-2930 transaction (type 1)
143
+ return Tx::Eip2930.unsigned_copy tx
144
+ when TYPE_LEGACY
145
+
146
+ # Legacy transaction ("type 0")
147
+ return Tx::Legacy.unsigned_copy tx
148
+ end
149
+ raise TransactionTypeError, "Cannot copy unknown transaction type #{tx.type}!"
150
+ end
151
+
152
+ # Estimates intrinsic gas for provided call data (EIP-2028) and
153
+ # access lists (EIP-2930).
154
+ #
155
+ # @param data [String] the call data.
156
+ # @param list [Array] the access list.
157
+ # @return [Integer] the estimated intrinsic gas cost.
158
+ def estimate_intrinsic_gas(data = "", list = [])
159
+ gas = DEFAULT_GAS_LIMIT
160
+ unless data.nil? or data.empty?
161
+ data = Util.hex_to_bin data if Util.is_hex? data
162
+
163
+ # count zero bytes
164
+ zero = data.count ZERO_BYTE
165
+ gas += zero * COST_ZERO_BYTE
166
+
167
+ # count non-zero bytes
168
+ none = data.size - zero
169
+ gas += none * COST_NON_ZERO_BYTE
170
+ end
171
+ unless list.nil? or list.empty?
172
+ list.each do |entry|
173
+
174
+ # count addresses
175
+ gas += COST_ADDRESS
176
+
177
+ entry.last.each do |key|
178
+
179
+ # count storage keys
180
+ gas += COST_STORAGE_KEY
181
+ end
182
+ end
183
+ end
184
+ return gas
185
+ end
186
+
187
+ # Validates the common type-2 transaction fields such as nonce, priority
188
+ # fee, max gas fee, gas limit, amount, and access list.
189
+ #
190
+ # @param fields [Hash] the transaction fields.
191
+ # @return [Hash] the validated transaction fields.
192
+ # @raise [ParameterError] if nonce is an invalid integer.
193
+ # @raise [ParameterError] if priority fee is invalid.
194
+ # @raise [ParameterError] if max gas fee is invalid.
195
+ # @raise [ParameterError] if gas limit is invalid.
196
+ # @raise [ParameterError] if amount is invalid.
197
+ # @raise [ParameterError] if access list is invalid.
198
+ def validate_params(fields)
199
+ if fields[:nonce].nil? or fields[:nonce] < 0
200
+ raise ParameterError, "Invalid signer nonce #{fields[:nonce]}!"
201
+ end
202
+ if fields[:priority_fee].nil? or fields[:priority_fee] < 0
203
+ raise ParameterError, "Invalid gas priority fee #{fields[:priority_fee]}!"
204
+ end
205
+ if fields[:max_gas_fee].nil? or fields[:max_gas_fee] < 0
206
+ raise ParameterError, "Invalid max gas fee #{fields[:max_gas_fee]}!"
207
+ end
208
+ if fields[:gas_limit].nil? or fields[:gas_limit] < DEFAULT_GAS_LIMIT or fields[:gas_limit] > BLOCK_GAS_LIMIT
209
+ raise ParameterError, "Invalid gas limit #{fields[:gas_limit]}!"
210
+ end
211
+ unless fields[:value] >= 0
212
+ raise ParameterError, "Invalid transaction value #{fields[:value]}!"
213
+ end
214
+ unless fields[:access_list].nil? or fields[:access_list].is_a? Array
215
+ raise ParameterError, "Invalid access list #{fields[:access_list]}!"
216
+ end
217
+ return fields
218
+ end
219
+
220
+ # Validates the common legacy transaction fields such as nonce, gas
221
+ # price, gas limit, amount, and access list.
222
+ #
223
+ # @param fields [Hash] the transaction fields.
224
+ # @return [Hash] the validated transaction fields.
225
+ # @raise [ParameterError] if nonce is an invalid integer.
226
+ # @raise [ParameterError] if gas price is invalid.
227
+ # @raise [ParameterError] if gas limit is invalid.
228
+ # @raise [ParameterError] if amount is invalid.
229
+ # @raise [ParameterError] if access list is invalid.
230
+ def validate_legacy_params(fields)
231
+ if fields[:nonce].nil? or fields[:nonce] < 0
232
+ raise ParameterError, "Invalid signer nonce #{fields[:nonce]}!"
233
+ end
234
+ if fields[:gas_price].nil? or fields[:gas_price] < 0
235
+ raise ParameterError, "Invalid gas price #{fields[:gas_price]}!"
236
+ end
237
+ if fields[:gas_limit].nil? or fields[:gas_limit] < DEFAULT_GAS_LIMIT or fields[:gas_limit] > BLOCK_GAS_LIMIT
238
+ raise ParameterError, "Invalid gas limit #{fields[:gas_limit]}!"
239
+ end
240
+ unless fields[:value] >= 0
241
+ raise ParameterError, "Invalid transaction value #{fields[:value]}!"
242
+ end
243
+ unless fields[:access_list].nil? or fields[:access_list].is_a? Array
244
+ raise ParameterError, "Invalid access list #{fields[:access_list]}!"
245
+ end
246
+ return fields
247
+ end
248
+
249
+ # Populates the transaction chain id field with a serializable default
250
+ # value (1) in case it is undefined.
251
+ #
252
+ # @param id [Integer] the transaction chain id.
253
+ # @return [Integer] the sanitized transaction chain id.
254
+ def sanitize_chain(id)
255
+ id = Chain::CYPRESS if id.nil?
256
+ return id
257
+ end
258
+
259
+ # Populates the transaction destination address with a serializable
260
+ # empty value in case it is undefined; also ensures the address is
261
+ # checksummed but not prefixed for consistency.
262
+ #
263
+ # @param addr [String] the transaction destination address.
264
+ # @return [String] the sanitized transaction destination address.
265
+ def sanitize_address(addr)
266
+ addr = "" if addr.nil?
267
+ if addr.is_a? String and !addr.empty?
268
+ addr = Address.new(addr).to_s
269
+ addr = Util.remove_hex_prefix addr
270
+ end
271
+ return addr
272
+ end
273
+
274
+ # Populates the transaction value field with a serializable empty value
275
+ # in case it is undefined.
276
+ #
277
+ # @param val [Integer] the transaction value.
278
+ # @return [Integer] the sanitized transaction value.
279
+ def sanitize_amount(val)
280
+ val = 0 if val.nil?
281
+ return val
282
+ end
283
+
284
+ # Populates the transaction payload field with a serializable empty value
285
+ # in case it is undefined; also ensures the data is binary not hex.
286
+ #
287
+ # @param data [String] the transaction payload data.
288
+ # @return [String] the sanitized transaction payload data.
289
+ def sanitize_data(data)
290
+ data = "" if data.nil?
291
+
292
+ # ensure payload to be binary if it's hex, otherwise we'll treat it raw
293
+ data = Util.hex_to_bin data if Util.is_hex? data
294
+ return data
295
+ end
296
+
297
+ # Populates the transaction access list field with a serializable empty
298
+ # array in case it is undefined; also ensures the nested data is binary
299
+ # not hex.
300
+ #
301
+ # @param list [Array] the transaction access list.
302
+ # @return [Array] the sanitized transaction access list.
303
+ def sanitize_list(list)
304
+ list = [] if list.nil?
305
+ list.each_with_index do |value, index|
306
+ if value.is_a? Array
307
+
308
+ # recursively check the entire array
309
+ list[index] = sanitize_list value
310
+ elsif Util.is_hex? value
311
+
312
+ # only modify if we find a hex value
313
+ list[index] = Util.hex_to_bin value
314
+ end
315
+ end
316
+ return list
317
+ end
318
+
319
+ # Allows to check wether a transaction is signed already.
320
+ #
321
+ # @return [Bool] true if transaction is already signed.
322
+ def is_signed?(tx)
323
+ !tx.signature_r.nil? and tx.signature_r != 0 and
324
+ !tx.signature_s.nil? and tx.signature_s != 0
325
+ end
326
+ end
327
+ end
data/lib/klay/unit.rb ADDED
@@ -0,0 +1,49 @@
1
+ # Copyright (c) 2016-2022 The Ruby-Eth Contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "bigdecimal"
16
+
17
+ # Provides the {Eth} module.
18
+ module Klay
19
+
20
+ # Provides constants for common Ethereum units.
21
+ module Unit
22
+ extend self
23
+
24
+ # Ethereum unit 1 wei := 0.000000000000000001 Ether.
25
+ WEI = BigDecimal("1e0").freeze
26
+
27
+ # Ethereum unit 1 babbage := 0.000000000000001 Ether or 1_000 wei.
28
+ BABBAGE = BigDecimal("1e3").freeze
29
+
30
+ # Ethereum unit 1 lovelace := 0.000000000001 Ether or 1_000_000 wei.
31
+ LOVELACE = BigDecimal("1e6").freeze
32
+
33
+ # Ethereum unit 1 shannon := 0.000000001 Ether or 1_000_000_000 wei.
34
+ SHANNON = BigDecimal("1e9").freeze
35
+
36
+ # Ethereum unit 1 szabo := 0.000_001 Ether or 1_000_000_000_000 wei.
37
+ SZABO = BigDecimal("1e12").freeze
38
+
39
+ # Ethereum unit 1 finney := 0.001 Ether or 1_000_000_000_000_000 wei.
40
+ FINNEY = BigDecimal("1e15").freeze
41
+
42
+ # Ethereum unit 1 Ether := 1_000_000_000_000_000_000 wei.
43
+ ETHER = BigDecimal("1e18").freeze
44
+
45
+ # Ethereum unit 1 Gwei := 0.000000001 Ether or 1_000_000_000 wei.
46
+ # Same as shannon, but more commonly used (billion wei).
47
+ GWEI = SHANNON.freeze
48
+ end
49
+ end