eth 0.5.7 → 0.5.9
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 +4 -4
- data/.github/workflows/codeql.yml +1 -1
- data/.github/workflows/docs.yml +2 -2
- data/.github/workflows/spec.yml +3 -3
- data/CHANGELOG.md +33 -0
- data/Gemfile +2 -2
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/abis/ens.json +422 -0
- data/eth.gemspec +2 -2
- data/lib/eth/abi/event.rb +1 -1
- data/lib/eth/abi/type.rb +46 -12
- data/lib/eth/abi.rb +72 -14
- data/lib/eth/address.rb +2 -2
- data/lib/eth/api.rb +1 -1
- data/lib/eth/chain.rb +19 -7
- data/lib/eth/client/http.rb +1 -1
- data/lib/eth/client/http_auth.rb +1 -1
- data/lib/eth/client/ipc.rb +1 -1
- data/lib/eth/client.rb +70 -58
- data/lib/eth/constant.rb +1 -1
- data/lib/eth/contract/event.rb +1 -1
- data/lib/eth/contract/function.rb +2 -2
- data/lib/eth/contract/function_input.rb +7 -2
- data/lib/eth/contract/function_output.rb +1 -1
- data/lib/eth/contract/initializer.rb +1 -1
- data/lib/eth/contract.rb +1 -1
- data/lib/eth/eip712.rb +2 -2
- data/lib/eth/ens/resolver.rb +77 -0
- data/lib/eth/key/decrypter.rb +1 -1
- data/lib/eth/key/encrypter.rb +1 -1
- data/lib/eth/key.rb +5 -5
- data/lib/eth/rlp/decoder.rb +2 -2
- data/lib/eth/rlp/encoder.rb +3 -3
- data/lib/eth/rlp/sedes/big_endian_int.rb +1 -1
- data/lib/eth/rlp/sedes/binary.rb +2 -2
- data/lib/eth/rlp/sedes/list.rb +5 -5
- data/lib/eth/rlp/sedes.rb +4 -4
- data/lib/eth/rlp.rb +1 -1
- data/lib/eth/signature.rb +4 -4
- data/lib/eth/solidity.rb +5 -3
- data/lib/eth/tx/eip1559.rb +3 -3
- data/lib/eth/tx/eip2930.rb +3 -3
- data/lib/eth/tx/legacy.rb +3 -3
- data/lib/eth/tx.rb +5 -5
- data/lib/eth/unit.rb +1 -1
- data/lib/eth/util.rb +14 -14
- data/lib/eth/version.rb +2 -2
- data/lib/eth.rb +2 -1
- metadata +7 -4
data/lib/eth/client.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -37,6 +37,9 @@ module Eth
|
|
37
37
|
# The default gas limit for the transaction, defaults to {Tx::DEFAULT_GAS_LIMIT}.
|
38
38
|
attr_accessor :gas_limit
|
39
39
|
|
40
|
+
# A custom error type if a contract interaction fails.
|
41
|
+
class ContractExecutionError < StandardError; end
|
42
|
+
|
40
43
|
# Creates a new RPC-Client, either by providing an HTTP/S host or
|
41
44
|
# an IPC path. Supports basic authentication with username and password.
|
42
45
|
#
|
@@ -106,8 +109,8 @@ module Eth
|
|
106
109
|
# See {#transfer} for params and overloads.
|
107
110
|
#
|
108
111
|
# @return [String] the transaction hash once it is mined.
|
109
|
-
def transfer_and_wait(destination, amount,
|
110
|
-
wait_for_tx(transfer(destination, amount,
|
112
|
+
def transfer_and_wait(destination, amount, **kwargs)
|
113
|
+
wait_for_tx(transfer(destination, amount, **kwargs))
|
111
114
|
end
|
112
115
|
|
113
116
|
# Simply transfer Ether to an account without any call data or
|
@@ -117,19 +120,24 @@ module Eth
|
|
117
120
|
# **Note**, that many remote providers (e.g., Infura) do not provide
|
118
121
|
# any accounts. Provide a `sender_key` if you experience issues.
|
119
122
|
#
|
120
|
-
# @
|
121
|
-
#
|
122
|
-
#
|
123
|
-
# @
|
123
|
+
# @overload transfer(destination, amount)
|
124
|
+
# @param destination [Eth::Address] the destination address.
|
125
|
+
# @param amount [Integer] the transfer amount in Wei.
|
126
|
+
# @overload transfer(destination, amount, **kwargs)
|
127
|
+
# @param destination [Eth::Address] the destination address.
|
128
|
+
# @param amount [Integer] the transfer amount in Wei.
|
129
|
+
# @param **sender_key [Eth::Key] the sender private key.
|
130
|
+
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
131
|
+
# @param **nonce [Integer] optional specific nonce for transaction.
|
124
132
|
# @return [String] the local transaction hash.
|
125
|
-
def transfer(destination, amount,
|
133
|
+
def transfer(destination, amount, **kwargs)
|
126
134
|
params = {
|
127
135
|
value: amount,
|
128
136
|
to: destination,
|
129
137
|
gas_limit: gas_limit,
|
130
138
|
chain_id: chain_id,
|
131
139
|
}
|
132
|
-
if legacy
|
140
|
+
if kwargs[:legacy]
|
133
141
|
params.merge!({
|
134
142
|
gas_price: max_fee_per_gas,
|
135
143
|
})
|
@@ -139,22 +147,22 @@ module Eth
|
|
139
147
|
max_gas_fee: max_fee_per_gas,
|
140
148
|
})
|
141
149
|
end
|
142
|
-
unless sender_key.nil?
|
150
|
+
unless kwargs[:sender_key].nil?
|
143
151
|
|
144
152
|
# use the provided key as sender and signer
|
145
153
|
params.merge!({
|
146
|
-
from: sender_key.address,
|
147
|
-
nonce: get_nonce(sender_key.address),
|
154
|
+
from: kwargs[:sender_key].address,
|
155
|
+
nonce: kwargs[:nonce] || get_nonce(kwargs[:sender_key].address),
|
148
156
|
})
|
149
157
|
tx = Eth::Tx.new(params)
|
150
|
-
tx.sign sender_key
|
158
|
+
tx.sign kwargs[:sender_key]
|
151
159
|
return eth_send_raw_transaction(tx.hex)["result"]
|
152
160
|
else
|
153
161
|
|
154
162
|
# use the default account as sender and external signer
|
155
163
|
params.merge!({
|
156
164
|
from: default_account,
|
157
|
-
nonce: get_nonce(default_account),
|
165
|
+
nonce: kwargs[:nonce] || get_nonce(default_account),
|
158
166
|
})
|
159
167
|
return eth_send_transaction(params)["result"]
|
160
168
|
end
|
@@ -189,6 +197,7 @@ module Eth
|
|
189
197
|
# @param **sender_key [Eth::Key] the sender private key.
|
190
198
|
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
191
199
|
# @param **gas_limit [Integer] optional gas limit override for deploying the contract.
|
200
|
+
# @param **nonce [Integer] optional specific nonce for transaction.
|
192
201
|
# @return [String] the transaction hash.
|
193
202
|
# @raise [ArgumentError] in case the contract does not have any source.
|
194
203
|
def deploy(contract, *args, **kwargs)
|
@@ -223,7 +232,7 @@ module Eth
|
|
223
232
|
# Uses the provided key as sender and signer
|
224
233
|
params.merge!({
|
225
234
|
from: kwargs[:sender_key].address,
|
226
|
-
nonce: get_nonce(kwargs[:sender_key].address),
|
235
|
+
nonce: kwargs[:nonce] || get_nonce(kwargs[:sender_key].address),
|
227
236
|
})
|
228
237
|
tx = Eth::Tx.new(params)
|
229
238
|
tx.sign kwargs[:sender_key]
|
@@ -232,7 +241,7 @@ module Eth
|
|
232
241
|
# Uses the default account as sender and external signer
|
233
242
|
params.merge!({
|
234
243
|
from: default_account,
|
235
|
-
nonce: get_nonce(default_account),
|
244
|
+
nonce: kwargs[:nonce] || get_nonce(default_account),
|
236
245
|
})
|
237
246
|
return eth_send_transaction(params)["result"]
|
238
247
|
end
|
@@ -288,6 +297,8 @@ module Eth
|
|
288
297
|
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
289
298
|
# @param **address [Eth::Address] contract address.
|
290
299
|
# @param **gas_limit [Integer] optional gas limit override for deploying the contract.
|
300
|
+
# @param **nonce [Integer] optional specific nonce for transaction.
|
301
|
+
# @param **tx_value [Integer] optional transaction value field filling.
|
291
302
|
# @return [Object] returns the result of the transaction.
|
292
303
|
def transact(contract, function, *args, **kwargs)
|
293
304
|
gas_limit = if kwargs[:gas_limit]
|
@@ -297,7 +308,7 @@ module Eth
|
|
297
308
|
end
|
298
309
|
fun = contract.functions.select { |func| func.name == function }[0]
|
299
310
|
params = {
|
300
|
-
value: 0,
|
311
|
+
value: kwargs[:tx_value] || 0,
|
301
312
|
gas_limit: gas_limit,
|
302
313
|
chain_id: chain_id,
|
303
314
|
to: kwargs[:address] || contract.address,
|
@@ -317,7 +328,7 @@ module Eth
|
|
317
328
|
# use the provided key as sender and signer
|
318
329
|
params.merge!({
|
319
330
|
from: kwargs[:sender_key].address,
|
320
|
-
nonce: get_nonce(kwargs[:sender_key].address),
|
331
|
+
nonce: kwargs[:nonce] || get_nonce(kwargs[:sender_key].address),
|
321
332
|
})
|
322
333
|
tx = Eth::Tx.new(params)
|
323
334
|
tx.sign kwargs[:sender_key]
|
@@ -326,7 +337,7 @@ module Eth
|
|
326
337
|
# use the default account as sender and external signer
|
327
338
|
params.merge!({
|
328
339
|
from: default_account,
|
329
|
-
nonce: get_nonce(default_account),
|
340
|
+
nonce: kwargs[:nonce] || get_nonce(default_account),
|
330
341
|
})
|
331
342
|
return eth_send_transaction(params)["result"]
|
332
343
|
end
|
@@ -337,9 +348,15 @@ module Eth
|
|
337
348
|
#
|
338
349
|
# See {#transact} for params and overloads.
|
339
350
|
#
|
351
|
+
# @raise [Client::ContractExecutionError] if the execution fails.
|
340
352
|
# @return [Object] returns the result of the transaction.
|
341
353
|
def transact_and_wait(contract, function, *args, **kwargs)
|
342
|
-
|
354
|
+
begin
|
355
|
+
hash = wait_for_tx(transact(contract, function, *args, **kwargs))
|
356
|
+
return hash if tx_succeeded? hash
|
357
|
+
rescue IOError => e
|
358
|
+
raise ContractExecutionError, e
|
359
|
+
end
|
343
360
|
end
|
344
361
|
|
345
362
|
# Provides an interface to call `isValidSignature` as per EIP-1271 on a given
|
@@ -354,9 +371,9 @@ module Eth
|
|
354
371
|
# @raise [ArgumentError] in case the contract cannot be called yet.
|
355
372
|
def is_valid_signature(contract, hash, signature, magic = "1626ba7e")
|
356
373
|
raise ArgumentError, "Contract not deployed yet." if contract.address.nil?
|
357
|
-
hash = Util.hex_to_bin hash if Util.
|
358
|
-
signature = Util.hex_to_bin signature if Util.
|
359
|
-
magic = Util.hex_to_bin magic if Util.
|
374
|
+
hash = Util.hex_to_bin hash if Util.hex? hash
|
375
|
+
signature = Util.hex_to_bin signature if Util.hex? signature
|
376
|
+
magic = Util.hex_to_bin magic if Util.hex? magic
|
360
377
|
result = call(contract, "isValidSignature", hash, signature)
|
361
378
|
return result === magic
|
362
379
|
end
|
@@ -369,15 +386,24 @@ module Eth
|
|
369
386
|
@id = 0
|
370
387
|
end
|
371
388
|
|
372
|
-
#
|
389
|
+
# Checks whether a transaction is mined or not.
|
373
390
|
#
|
374
391
|
# @param hash [String] the transaction hash.
|
375
392
|
# @return [Boolean] true if included in a block.
|
376
|
-
def
|
393
|
+
def tx_mined?(hash)
|
377
394
|
mined_tx = eth_get_transaction_by_hash hash
|
378
395
|
!mined_tx.nil? && !mined_tx["result"].nil? && !mined_tx["result"]["blockNumber"].nil?
|
379
396
|
end
|
380
397
|
|
398
|
+
# Checks whether a contract transaction succeeded or not.
|
399
|
+
#
|
400
|
+
# @param hash [String] the transaction hash.
|
401
|
+
# @return [Boolean] true if status is success.
|
402
|
+
def tx_succeeded?(hash)
|
403
|
+
tx_receipt = eth_get_transaction_receipt(hash)
|
404
|
+
!tx_receipt.nil? && !tx_receipt["result"].nil? && tx_receipt["result"]["status"] == "0x1"
|
405
|
+
end
|
406
|
+
|
381
407
|
# Waits for an transaction to be mined by the connected chain.
|
382
408
|
#
|
383
409
|
# @param hash [String] the transaction hash.
|
@@ -389,7 +415,7 @@ module Eth
|
|
389
415
|
retry_rate = 0.1
|
390
416
|
loop do
|
391
417
|
raise Timeout::Error if ((Time.now - start_time) > timeout)
|
392
|
-
return hash if
|
418
|
+
return hash if tx_mined? hash
|
393
419
|
sleep retry_rate
|
394
420
|
end
|
395
421
|
end
|
@@ -406,39 +432,14 @@ module Eth
|
|
406
432
|
private
|
407
433
|
|
408
434
|
# Non-transactional function call called from call().
|
435
|
+
# @see https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call
|
409
436
|
def call_raw(contract, func, *args, **kwargs)
|
410
|
-
gas_limit = if kwargs[:gas_limit]
|
411
|
-
kwargs[:gas_limit]
|
412
|
-
else
|
413
|
-
Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
|
414
|
-
end
|
415
437
|
params = {
|
416
|
-
gas_limit: gas_limit,
|
417
|
-
chain_id: chain_id,
|
418
438
|
data: call_payload(func, args),
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
if kwargs[:legacy]
|
424
|
-
params.merge!({
|
425
|
-
gas_price: max_fee_per_gas,
|
426
|
-
})
|
427
|
-
else
|
428
|
-
params.merge!({
|
429
|
-
priority_fee: max_priority_fee_per_gas,
|
430
|
-
max_gas_fee: max_fee_per_gas,
|
431
|
-
})
|
432
|
-
end
|
433
|
-
unless kwargs[:sender_key].nil?
|
434
|
-
# Uses the provided key as sender and signer
|
435
|
-
params.merge!({
|
436
|
-
from: kwargs[:sender_key].address,
|
437
|
-
nonce: get_nonce(kwargs[:sender_key].address),
|
438
|
-
})
|
439
|
-
tx = Eth::Tx.new(params)
|
440
|
-
tx.sign kwargs[:sender_key]
|
441
|
-
end
|
439
|
+
to: kwargs[:address] || contract.address,
|
440
|
+
from: kwargs[:from],
|
441
|
+
}.compact
|
442
|
+
|
442
443
|
raw_result = eth_call(params)["result"]
|
443
444
|
types = func.outputs.map { |i| i.type }
|
444
445
|
return nil if raw_result == "0x"
|
@@ -447,7 +448,7 @@ module Eth
|
|
447
448
|
|
448
449
|
# Encodes function call payloads.
|
449
450
|
def call_payload(fun, args)
|
450
|
-
types = fun.inputs.map
|
451
|
+
types = fun.inputs.map(&:parsed_type)
|
451
452
|
encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
|
452
453
|
Util.prefix_hex(fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str))
|
453
454
|
end
|
@@ -477,17 +478,28 @@ module Eth
|
|
477
478
|
@id += 1
|
478
479
|
end
|
479
480
|
|
481
|
+
# expects Hash object
|
482
|
+
def camelize!(params)
|
483
|
+
params.transform_keys! do |k|
|
484
|
+
k = k.to_s.split(/_/).map(&:capitalize).join
|
485
|
+
k[0] = k[0].downcase
|
486
|
+
k.to_sym
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
480
490
|
# Recursively marshals all request parameters.
|
481
491
|
def marshal(params)
|
492
|
+
params = params.dup
|
482
493
|
if params.is_a? Array
|
483
494
|
return params.map! { |param| marshal(param) }
|
484
495
|
elsif params.is_a? Hash
|
496
|
+
params = camelize!(params)
|
485
497
|
return params.transform_values! { |param| marshal(param) }
|
486
498
|
elsif params.is_a? Numeric
|
487
499
|
return Util.prefix_hex "#{params.to_i.to_s(16)}"
|
488
500
|
elsif params.is_a? Address
|
489
501
|
return params.to_s
|
490
|
-
elsif Util.
|
502
|
+
elsif Util.hex? params
|
491
503
|
return Util.prefix_hex params
|
492
504
|
else
|
493
505
|
return params
|
data/lib/eth/constant.rb
CHANGED
data/lib/eth/contract/event.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -43,7 +43,7 @@ module Eth
|
|
43
43
|
# @param inputs [Array<Eth::Contract::FunctionInput>] function input class list.
|
44
44
|
# @return [String] function string.
|
45
45
|
def self.calc_signature(name, inputs)
|
46
|
-
"#{name}(#{inputs.
|
46
|
+
"#{name}(#{inputs.map { |x| x.parsed_type.to_s }.join(",")})"
|
47
47
|
end
|
48
48
|
|
49
49
|
# Encodes a function signature.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -26,7 +26,7 @@ module Eth
|
|
26
26
|
# @param data [Hash] contract abi data.
|
27
27
|
def initialize(data)
|
28
28
|
@raw_type = data["type"]
|
29
|
-
@type = Eth::Abi::Type.parse(data["type"])
|
29
|
+
@type = Eth::Abi::Type.parse(data["type"], data["components"])
|
30
30
|
@name = data["name"]
|
31
31
|
end
|
32
32
|
|
@@ -34,5 +34,10 @@ module Eth
|
|
34
34
|
def type
|
35
35
|
@type.base_type + @type.sub_type + @type.dimensions.map { |dimension| "[#{dimension > 0 ? dimension : ""}]" }.join("")
|
36
36
|
end
|
37
|
+
|
38
|
+
# Returns parsed types.
|
39
|
+
def parsed_type
|
40
|
+
@type
|
41
|
+
end
|
37
42
|
end
|
38
43
|
end
|
data/lib/eth/contract.rb
CHANGED
data/lib/eth/eip712.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -149,7 +149,7 @@ module Eth
|
|
149
149
|
# @return [Array] the data in the data structure we want to hash.
|
150
150
|
# @raise [TypedDataError] if the data fails validation.
|
151
151
|
def enforce_typed_data(data)
|
152
|
-
data = JSON.parse data if Util.
|
152
|
+
data = JSON.parse data if Util.hex? data
|
153
153
|
raise TypedDataError, "Data is missing, try again with data." if data.nil? or data.empty?
|
154
154
|
raise TypedDataError, "Data types are missing." if data[:types].nil? or data[:types].empty?
|
155
155
|
raise TypedDataError, "Data primaryType is missing." if data[:primaryType].nil? or data[:primaryType].empty?
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Copyright (c) 2016-2023 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
|
+
# -*- encoding : ascii-8bit -*-
|
16
|
+
|
17
|
+
# Provides the {Eth} module.
|
18
|
+
module Eth
|
19
|
+
# Provides ENS specific functionality
|
20
|
+
# ref: https://ens.domains
|
21
|
+
module Ens
|
22
|
+
|
23
|
+
# Utility class for resolving ENS names to Ethereum addresses
|
24
|
+
class Resolver
|
25
|
+
|
26
|
+
# The default address for ENS, which applies to most chains
|
27
|
+
DEFAULT_ADDRESS = "0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e".freeze
|
28
|
+
|
29
|
+
# Create an instance of the ENS Resolver
|
30
|
+
#
|
31
|
+
# @param client [Eth::Client] The client instance
|
32
|
+
# @param address [String] The address of the ENS contract
|
33
|
+
def initialize(client, address = DEFAULT_ADDRESS)
|
34
|
+
@client = client
|
35
|
+
@contract = Eth::Contract.from_abi(
|
36
|
+
name: "ENS",
|
37
|
+
address: address,
|
38
|
+
abi: JSON.parse(File.read(File.join(File.dirname(__FILE__), "../../../abis/ens.json"))),
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Resolve an ENS name to an address
|
43
|
+
#
|
44
|
+
# @param ens_name [String] The ENS name, eg: fancy.eth
|
45
|
+
# @return [String] The owner address of the name, as a hex string
|
46
|
+
def resolve(ens_name)
|
47
|
+
@client.call(@contract, "owner", namehash(ens_name))
|
48
|
+
end
|
49
|
+
|
50
|
+
# Generate node for the given domain name
|
51
|
+
# See: https://docs.ens.domains/contract-api-reference/name-processing
|
52
|
+
#
|
53
|
+
# @param ens_name [String] The ENS name, eg: fancy.eth
|
54
|
+
# @return [String] The node as a hex string
|
55
|
+
def namehash(ens_name)
|
56
|
+
node = ("0" * 64)
|
57
|
+
name = normalize(ens_name)
|
58
|
+
name.split(".").reverse.each do |label|
|
59
|
+
hash = Digest::Keccak.new(256).hexdigest(label)
|
60
|
+
node = Digest::Keccak.new(256).hexdigest([node + hash].pack("H*"))
|
61
|
+
end
|
62
|
+
"0x#{node}"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Normalize a string as specified by http://unicode.org/reports/tr46/
|
66
|
+
#
|
67
|
+
# @param input [String] The input string
|
68
|
+
# @return [String] The normalized output string
|
69
|
+
def normalize(input)
|
70
|
+
# TODO: This is fairly complicated, and there doesn't seem to be a ruby
|
71
|
+
# library which can handle it perfectly.
|
72
|
+
# https://www.unicode.org/reports/tr46/tr46-27.html
|
73
|
+
input.downcase
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/eth/key/decrypter.rb
CHANGED
data/lib/eth/key/encrypter.rb
CHANGED
data/lib/eth/key.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -51,7 +51,7 @@ module Eth
|
|
51
51
|
unless priv.nil?
|
52
52
|
|
53
53
|
# Converts hex private keys to binary strings.
|
54
|
-
priv = Util.hex_to_bin priv if Util.
|
54
|
+
priv = Util.hex_to_bin priv if Util.hex? priv
|
55
55
|
|
56
56
|
# Creates a keypair from existing private key data.
|
57
57
|
key = ctx.key_pair_from_private_key priv
|
@@ -74,10 +74,10 @@ module Eth
|
|
74
74
|
compact, recovery_id = context.sign_recoverable(@private_key, blob).compact
|
75
75
|
signature = compact.bytes
|
76
76
|
v = Chain.to_v recovery_id, chain_id
|
77
|
-
|
77
|
+
leading_zero = true
|
78
78
|
[v].pack("N").unpack("C*").each do |byte|
|
79
|
-
|
80
|
-
signature.append byte unless
|
79
|
+
leading_zero = false if byte > 0 and leading_zero
|
80
|
+
signature.append byte unless leading_zero and byte === 0
|
81
81
|
end
|
82
82
|
Util.bin_to_hex signature.pack "c*"
|
83
83
|
end
|
data/lib/eth/rlp/decoder.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -31,7 +31,7 @@ module Eth
|
|
31
31
|
# @raise [Eth::Rlp::DecodingError] if the input string does not end after
|
32
32
|
# the root item.
|
33
33
|
def perform(rlp)
|
34
|
-
rlp = Util.hex_to_bin rlp if Util.
|
34
|
+
rlp = Util.hex_to_bin rlp if Util.hex? rlp
|
35
35
|
rlp = Util.str_to_bytes rlp
|
36
36
|
begin
|
37
37
|
item, next_start = consume_item rlp, 0
|
data/lib/eth/rlp/encoder.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -41,8 +41,8 @@ module Eth
|
|
41
41
|
# Encodes the raw item.
|
42
42
|
def encode_raw(item)
|
43
43
|
return item if item.instance_of? Rlp::Data
|
44
|
-
return encode_primitive item if Util.
|
45
|
-
return encode_list item if Util.
|
44
|
+
return encode_primitive item if Util.primitive? item
|
45
|
+
return encode_list item if Util.list? item
|
46
46
|
raise EncodingError "Cannot encode object of type #{item.class.name}"
|
47
47
|
end
|
48
48
|
|
data/lib/eth/rlp/sedes/binary.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -78,7 +78,7 @@ module Eth
|
|
78
78
|
# @raise [DeserializationError] if provided serial is of wrong type.
|
79
79
|
# @raise [DeserializationError] if provided serial is of wrong length.
|
80
80
|
def deserialize(serial)
|
81
|
-
raise DeserializationError, "Objects of type #{serial.class} cannot be deserialized" unless Util.
|
81
|
+
raise DeserializationError, "Objects of type #{serial.class} cannot be deserialized" unless Util.primitive? serial
|
82
82
|
raise DeserializationError, "#{serial.class} has invalid length" unless valid_length? serial.size
|
83
83
|
serial
|
84
84
|
end
|
data/lib/eth/rlp/sedes/list.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -34,9 +34,9 @@ module Eth
|
|
34
34
|
super()
|
35
35
|
@strict = strict
|
36
36
|
elements.each do |e|
|
37
|
-
if Sedes.
|
37
|
+
if Sedes.sedes?(e)
|
38
38
|
push e
|
39
|
-
elsif Util.
|
39
|
+
elsif Util.list?(e)
|
40
40
|
push List.new(elements: e)
|
41
41
|
else
|
42
42
|
raise TypeError, "Instances of List must only contain sedes objects or nested sequences thereof."
|
@@ -51,7 +51,7 @@ module Eth
|
|
51
51
|
# @raise [SerializationError] if provided array is not a sequence.
|
52
52
|
# @raise [SerializationError] if provided array is of wrong length.
|
53
53
|
def serialize(obj)
|
54
|
-
raise SerializationError, "Can only serialize sequences" unless Util.
|
54
|
+
raise SerializationError, "Can only serialize sequences" unless Util.list?(obj)
|
55
55
|
raise SerializationError, "List has wrong length" if (@strict && self.size != obj.size) || self.size < obj.size
|
56
56
|
result = []
|
57
57
|
obj.zip(self).each_with_index do |(element, sedes), i|
|
@@ -67,7 +67,7 @@ module Eth
|
|
67
67
|
# @raise [DeserializationError] if provided serial is not a sequence.
|
68
68
|
# @raise [DeserializationError] if provided serial is of wrong length.
|
69
69
|
def deserialize(serial)
|
70
|
-
raise DeserializationError, "Can only deserialize sequences" unless Util.
|
70
|
+
raise DeserializationError, "Can only deserialize sequences" unless Util.list?(serial)
|
71
71
|
raise DeserializationError, "List has wrong length" if @strict && serial.size != self.size
|
72
72
|
result = []
|
73
73
|
len = [serial.size, self.size].min
|
data/lib/eth/rlp/sedes.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -39,10 +39,10 @@ module Eth
|
|
39
39
|
# @param obj [Object] the Ruby object for which to find a sedes object.
|
40
40
|
# @raise [TypeError] if no appropriate sedes could be found.
|
41
41
|
def infer(obj)
|
42
|
-
return obj.class if
|
42
|
+
return obj.class if sedes? obj.class
|
43
43
|
return big_endian_int if obj.is_a?(Integer) && obj >= 0
|
44
44
|
return binary if Binary.valid_type? obj
|
45
|
-
return List.new(elements: obj.map { |item| infer item }) if Util.
|
45
|
+
return List.new(elements: obj.map { |item| infer item }) if Util.list? obj
|
46
46
|
raise TypeError, "Did not find sedes handling type #{obj.class.name}"
|
47
47
|
end
|
48
48
|
|
@@ -50,7 +50,7 @@ module Eth
|
|
50
50
|
#
|
51
51
|
# @param obj [Object] the object to check.
|
52
52
|
# @return [Boolean] true if it's serializable and deserializable.
|
53
|
-
def
|
53
|
+
def sedes?(obj)
|
54
54
|
obj.respond_to?(:serialize) && obj.respond_to?(:deserialize)
|
55
55
|
end
|
56
56
|
|
data/lib/eth/rlp.rb
CHANGED
data/lib/eth/signature.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2016-
|
1
|
+
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -48,7 +48,7 @@ module Eth
|
|
48
48
|
# @return [String, String, String] the `r`, `s`, and `v` values.
|
49
49
|
# @raise [SignatureError] if signature is of unknown size.
|
50
50
|
def dissect(signature)
|
51
|
-
signature = Util.bin_to_hex signature unless Util.
|
51
|
+
signature = Util.bin_to_hex signature unless Util.hex? signature
|
52
52
|
signature = Util.remove_hex_prefix signature
|
53
53
|
if signature.size < 130
|
54
54
|
raise SignatureError, "Unknown signature length #{signature.size}!"
|
@@ -70,7 +70,7 @@ module Eth
|
|
70
70
|
context = Secp256k1::Context.new
|
71
71
|
r, s, v = dissect signature
|
72
72
|
v = v.to_i(16)
|
73
|
-
if !Chain.
|
73
|
+
if !Chain.ledger? v and !Chain.legacy? v
|
74
74
|
min_v = 2 * chain_id + 35
|
75
75
|
raise SignatureError, "Invalid signature v byte #{v} for chain ID #{chain_id}!" if v < min_v
|
76
76
|
end
|
@@ -126,7 +126,7 @@ module Eth
|
|
126
126
|
|
127
127
|
# recover message from personal_sign
|
128
128
|
recovered_key = personal_recover blob, signature, chain_id
|
129
|
-
elsif blob.instance_of? String and (Util.
|
129
|
+
elsif blob.instance_of? String and (Util.hex? blob or blob.encoding == Encoding::ASCII_8BIT)
|
130
130
|
|
131
131
|
# if nothing else, recover from arbitrary signature
|
132
132
|
recovered_key = recover blob, signature, chain_id
|