eth 0.5.8 → 0.5.10
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/spec.yml +2 -1
- data/CHANGELOG.md +32 -0
- data/CODE_OF_CONDUCT.md +122 -0
- data/CONTRIBUTING.md +61 -0
- data/LICENSE.txt +1 -1
- data/README.md +6 -2
- data/SECURITY.md +24 -0
- data/abi/ens_registry.json +436 -0
- data/abi/ens_resolver.json +885 -0
- 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 +118 -16
- 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/coin_type.rb +50 -0
- data/lib/eth/ens/resolver.rb +68 -24
- data/lib/eth/ens.rb +28 -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 -2
- metadata +9 -3
- data/abis/ens.json +0 -422
data/lib/eth/abi/event.rb
CHANGED
data/lib/eth/abi/type.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.
|
@@ -35,18 +35,28 @@ module Eth
|
|
35
35
|
# The dimension attribute, e.g., `[10]` for an array of size 10.
|
36
36
|
attr :dimensions
|
37
37
|
|
38
|
+
# The components of a tuple type.
|
39
|
+
attr :components
|
40
|
+
|
41
|
+
# The name of tuple component.
|
42
|
+
attr :name
|
43
|
+
|
38
44
|
# Create a new Type object for base types, sub types, and dimensions.
|
39
45
|
# Should not be used; use {Type.parse} instead.
|
40
46
|
#
|
41
47
|
# @param base_type [String] the base-type attribute.
|
42
48
|
# @param sub_type [String] the sub-type attribute.
|
43
49
|
# @param dimensions [Array] the dimension attribute.
|
50
|
+
# @param components [Array] the components attribute.
|
51
|
+
# @param component_name [String] the tuple component's name.
|
44
52
|
# @return [Eth::Abi::Type] an ABI type object.
|
45
|
-
def initialize(base_type, sub_type, dimensions)
|
53
|
+
def initialize(base_type, sub_type, dimensions, components = nil, component_name = nil)
|
46
54
|
sub_type = sub_type.to_s
|
47
55
|
@base_type = base_type
|
48
56
|
@sub_type = sub_type
|
49
57
|
@dimensions = dimensions
|
58
|
+
@components = components
|
59
|
+
@name = component_name
|
50
60
|
end
|
51
61
|
|
52
62
|
# Converts the self.parse method into a constructor.
|
@@ -56,9 +66,12 @@ module Eth
|
|
56
66
|
# Creates a new Type upon success (using konstructor).
|
57
67
|
#
|
58
68
|
# @param type [String] a common Solidity type.
|
69
|
+
# @param components [Array] the components attribute.
|
70
|
+
# @param component_name [String] the tuple component's name.
|
59
71
|
# @return [Eth::Abi::Type] a parsed Type object.
|
60
72
|
# @raise [ParseError] if it fails to parse the type.
|
61
|
-
def parse(type)
|
73
|
+
def parse(type, components = nil, component_name = nil)
|
74
|
+
return type if type.is_a?(Type)
|
62
75
|
_, base_type, sub_type, dimension = /([a-z]*)([0-9]*x?[0-9]*)((\[[0-9]*\])*)/.match(type).to_a
|
63
76
|
|
64
77
|
# type dimension can only be numeric
|
@@ -73,6 +86,8 @@ module Eth
|
|
73
86
|
@base_type = base_type
|
74
87
|
@sub_type = sub_type
|
75
88
|
@dimensions = dims.map { |x| x[1...-1].to_i }
|
89
|
+
@components = components.map { |component| Eth::Abi::Type.parse(component["type"], component.dig("components"), component.dig("name")) } unless components.nil?
|
90
|
+
@name = component_name
|
76
91
|
end
|
77
92
|
|
78
93
|
# Creates a new uint256 type used for size.
|
@@ -98,15 +113,13 @@ module Eth
|
|
98
113
|
def size
|
99
114
|
s = nil
|
100
115
|
if dimensions.empty?
|
101
|
-
|
116
|
+
if !(["string", "bytes", "tuple"].include?(base_type) and sub_type.empty?)
|
102
117
|
s = 32
|
118
|
+
elsif base_type == "tuple" && components.none?(&:dynamic?)
|
119
|
+
s = components.sum(&:size)
|
103
120
|
end
|
104
|
-
|
105
|
-
|
106
|
-
unless nested_sub.is_dynamic?
|
107
|
-
s = dimensions.last * nested_sub.size
|
108
|
-
end
|
109
|
-
end
|
121
|
+
elsif dimensions.last != 0 && !nested_sub.dynamic?
|
122
|
+
s = dimensions.last * nested_sub.size
|
110
123
|
end
|
111
124
|
@size ||= s
|
112
125
|
end
|
@@ -114,7 +127,7 @@ module Eth
|
|
114
127
|
# Helpes to determine whether array is of dynamic size.
|
115
128
|
#
|
116
129
|
# @return [Boolean] true if array is of dynamic size.
|
117
|
-
def
|
130
|
+
def dynamic?
|
118
131
|
size.nil?
|
119
132
|
end
|
120
133
|
|
@@ -122,7 +135,24 @@ module Eth
|
|
122
135
|
#
|
123
136
|
# @return [Eth::Abi::Type] nested sub-type.
|
124
137
|
def nested_sub
|
125
|
-
@nested_sub ||= self.class.new(base_type, sub_type, dimensions[0...-1])
|
138
|
+
@nested_sub ||= self.class.new(base_type, sub_type, dimensions[0...-1], components, name)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Allows exporting the type as string.
|
142
|
+
#
|
143
|
+
# @return [String] the type string.
|
144
|
+
def to_s
|
145
|
+
if base_type == "tuple"
|
146
|
+
"(" + components.map(&:to_s).join(",") + ")" + (dimensions.size > 0 ? dimensions.map { |x| "[#{x == 0 ? "" : x}]" }.join : "")
|
147
|
+
elsif dimensions.empty?
|
148
|
+
if %w[string bytes].include?(base_type) && sub_type.empty?
|
149
|
+
base_type
|
150
|
+
else
|
151
|
+
"#{base_type}#{sub_type}"
|
152
|
+
end
|
153
|
+
else
|
154
|
+
"#{base_type}#{sub_type}#{dimensions.map { |x| "[#{x == 0 ? "" : x}]" }.join}"
|
155
|
+
end
|
126
156
|
end
|
127
157
|
|
128
158
|
private
|
@@ -138,6 +168,10 @@ module Eth
|
|
138
168
|
|
139
169
|
# bytes can be no longer than 32 bytes
|
140
170
|
raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub_type.empty? || sub_type.to_i <= 32
|
171
|
+
when "tuple"
|
172
|
+
|
173
|
+
# tuples can not have any suffix
|
174
|
+
raise ParseError, "Tuple type must have no suffix or numerical suffix" unless sub_type.empty?
|
141
175
|
when "uint", "int"
|
142
176
|
|
143
177
|
# integers must have a numerical suffix
|
data/lib/eth/abi.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.
|
@@ -45,7 +45,7 @@ module Eth
|
|
45
45
|
def encode(types, args)
|
46
46
|
|
47
47
|
# parse all types
|
48
|
-
parsed_types = types.map { |t| Type.parse(t) }
|
48
|
+
parsed_types = types.map { |t| Type === t ? t : Type.parse(t) }
|
49
49
|
|
50
50
|
# prepare the "head"
|
51
51
|
head_size = (0...args.size)
|
@@ -55,7 +55,7 @@ module Eth
|
|
55
55
|
|
56
56
|
# encode types and arguments
|
57
57
|
args.each_with_index do |arg, i|
|
58
|
-
if parsed_types[i].
|
58
|
+
if parsed_types[i].dynamic?
|
59
59
|
head += encode_type Type.size_type, head_size + tail.size
|
60
60
|
tail += encode_type parsed_types[i], arg
|
61
61
|
else
|
@@ -81,12 +81,16 @@ module Eth
|
|
81
81
|
size = encode_type Type.size_type, arg.size
|
82
82
|
padding = Constant::BYTE_ZERO * (Util.ceil32(arg.size) - arg.size)
|
83
83
|
return "#{size}#{arg}#{padding}"
|
84
|
-
elsif type.
|
85
|
-
|
84
|
+
elsif type.base_type == "tuple" && type.dimensions.size == 1 && type.dimensions[0] != 0
|
85
|
+
result = ""
|
86
|
+
result += encode_struct_offsets(type.nested_sub, arg)
|
87
|
+
result += arg.map { |x| encode_type(type.nested_sub, x) }.join
|
88
|
+
result
|
89
|
+
elsif type.dynamic? && arg.is_a?(Array)
|
86
90
|
|
87
91
|
# encodes dynamic-sized arrays
|
88
92
|
head, tail = "", ""
|
89
|
-
head += encode_type
|
93
|
+
head += encode_type(Type.size_type, arg.size)
|
90
94
|
nested_sub = type.nested_sub
|
91
95
|
nested_sub_size = type.nested_sub.size
|
92
96
|
|
@@ -102,8 +106,10 @@ module Eth
|
|
102
106
|
offset += total_bytes_length + 32
|
103
107
|
end
|
104
108
|
|
105
|
-
head += encode_type
|
109
|
+
head += encode_type(Type.size_type, offset)
|
106
110
|
end
|
111
|
+
elsif nested_sub.base_type == "tuple" && nested_sub.dynamic?
|
112
|
+
head += encode_struct_offsets(nested_sub, arg)
|
107
113
|
end
|
108
114
|
|
109
115
|
arg.size.times do |i|
|
@@ -145,6 +151,8 @@ module Eth
|
|
145
151
|
return encode_fixed arg, type
|
146
152
|
when "string", "bytes"
|
147
153
|
return encode_bytes arg, type
|
154
|
+
when "tuple"
|
155
|
+
return encode_tuple arg, type
|
148
156
|
when "hash"
|
149
157
|
return encode_hash arg, type
|
150
158
|
when "address"
|
@@ -163,7 +171,7 @@ module Eth
|
|
163
171
|
def decode(types, data)
|
164
172
|
|
165
173
|
# accept hex abi but decode it first
|
166
|
-
data = Util.hex_to_bin data if Util.
|
174
|
+
data = Util.hex_to_bin data if Util.hex? data
|
167
175
|
|
168
176
|
# parse all types
|
169
177
|
parsed_types = types.map { |t| Type.parse(t) }
|
@@ -173,7 +181,7 @@ module Eth
|
|
173
181
|
start_positions = [nil] * types.size + [data.size]
|
174
182
|
pos = 0
|
175
183
|
parsed_types.each_with_index do |t, i|
|
176
|
-
if t.
|
184
|
+
if t.dynamic?
|
177
185
|
|
178
186
|
# record start position for dynamic type
|
179
187
|
start_positions[i] = Util.deserialize_big_endian_to_int(data[pos, 32])
|
@@ -201,7 +209,7 @@ module Eth
|
|
201
209
|
|
202
210
|
# add dynamic types
|
203
211
|
parsed_types.each_with_index do |t, i|
|
204
|
-
if t.
|
212
|
+
if t.dynamic?
|
205
213
|
offset, next_offset = start_positions[i, 2]
|
206
214
|
outputs[i] = data[offset...next_offset]
|
207
215
|
end
|
@@ -225,12 +233,12 @@ module Eth
|
|
225
233
|
|
226
234
|
# decoded strings and bytes
|
227
235
|
return data[0, l]
|
228
|
-
elsif type.
|
236
|
+
elsif type.dynamic?
|
229
237
|
l = Util.deserialize_big_endian_to_int arg[0, 32]
|
230
238
|
nested_sub = type.nested_sub
|
231
239
|
|
232
240
|
# ref https://github.com/ethereum/tests/issues/691
|
233
|
-
raise NotImplementedError, "Decoding dynamic arrays with nested dynamic sub-types is not implemented for ABI." if nested_sub.
|
241
|
+
raise NotImplementedError, "Decoding dynamic arrays with nested dynamic sub-types is not implemented for ABI." if nested_sub.dynamic?
|
234
242
|
|
235
243
|
# decoded dynamic-sized arrays
|
236
244
|
return (0...l).map { |i| decode_type(nested_sub, arg[32 + nested_sub.size * i, nested_sub.size]) }
|
@@ -381,6 +389,56 @@ module Eth
|
|
381
389
|
end
|
382
390
|
end
|
383
391
|
|
392
|
+
# Properly encodes tuples.
|
393
|
+
def encode_tuple(arg, type)
|
394
|
+
raise EncodingError, "Expecting Hash: #{arg}" unless arg.instance_of? Hash
|
395
|
+
raise EncodingError, "Expecting #{type.components.size} elements: #{arg}" unless arg.size == type.components.size
|
396
|
+
|
397
|
+
static_size = 0
|
398
|
+
type.components.each_with_index do |component, i|
|
399
|
+
if type.components[i].dynamic?
|
400
|
+
static_size += 32
|
401
|
+
else
|
402
|
+
static_size += Util.ceil32(type.components[i].size || 0)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
dynamic_offset = static_size
|
407
|
+
offsets_and_static_values = []
|
408
|
+
dynamic_values = []
|
409
|
+
|
410
|
+
type.components.each_with_index do |component, i|
|
411
|
+
component_type = type.components[i]
|
412
|
+
if component_type.dynamic?
|
413
|
+
offsets_and_static_values << encode_type(Type.size_type, dynamic_offset)
|
414
|
+
dynamic_value = encode_type(component_type, arg.is_a?(Array) ? arg[i] : arg[component_type.name])
|
415
|
+
dynamic_values << dynamic_value
|
416
|
+
dynamic_offset += dynamic_value.size
|
417
|
+
else
|
418
|
+
offsets_and_static_values << encode_type(component_type, arg.is_a?(Array) ? arg[i] : arg[component_type.name])
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
offsets_and_static_values.join + dynamic_values.join
|
423
|
+
end
|
424
|
+
|
425
|
+
# Properly encode struct offsets.
|
426
|
+
def encode_struct_offsets(type, arg)
|
427
|
+
result = ""
|
428
|
+
offset = arg.size
|
429
|
+
tails_encoding = arg.map { |a| encode_type(type, a) }
|
430
|
+
arg.size.times do |i|
|
431
|
+
if i == 0
|
432
|
+
offset *= 32
|
433
|
+
else
|
434
|
+
offset += tails_encoding[i - 1].size
|
435
|
+
end
|
436
|
+
offset_string = encode_type(Type.size_type, offset)
|
437
|
+
result += offset_string
|
438
|
+
end
|
439
|
+
result
|
440
|
+
end
|
441
|
+
|
384
442
|
# Properly encodes hash-strings.
|
385
443
|
def encode_hash(arg, type)
|
386
444
|
size = type.sub_type.to_i
|
@@ -428,8 +486,8 @@ module Eth
|
|
428
486
|
# The ABI encoder needs to be able to determine between a hex `"123"`
|
429
487
|
# and a binary `"123"` string.
|
430
488
|
def handle_hex_string(arg, type)
|
431
|
-
if Util.
|
432
|
-
(arg.size === type.sub_type.to_i * 2 and Util.
|
489
|
+
if Util.prefixed? arg or
|
490
|
+
(arg.size === type.sub_type.to_i * 2 and Util.hex? arg)
|
433
491
|
|
434
492
|
# There is no way telling whether a string is hex or binary with certainty
|
435
493
|
# in Ruby. Therefore, we assume a `0x` prefix to indicate a hex string.
|
data/lib/eth/address.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.
|
@@ -29,7 +29,7 @@ module Eth
|
|
29
29
|
#
|
30
30
|
# @param address [String] hex string representing an ethereum address.
|
31
31
|
def initialize(address)
|
32
|
-
unless Util.
|
32
|
+
unless Util.hex? address
|
33
33
|
raise CheckSumError, "Unknown address type #{address}!"
|
34
34
|
end
|
35
35
|
@address = Util.prefix_hex address
|
data/lib/eth/api.rb
CHANGED
data/lib/eth/chain.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.
|
@@ -38,12 +38,18 @@ module Eth
|
|
38
38
|
# Chain ID for POA Network mainnet.
|
39
39
|
POA_NET = 99.freeze
|
40
40
|
|
41
|
-
# Chain ID for Gnosis
|
41
|
+
# Chain ID for xDAI mainnet (now Gnosis Chain).
|
42
42
|
XDAI = 100.freeze
|
43
43
|
|
44
|
-
# Chain ID for
|
44
|
+
# Chain ID for Gnosis mainnet (formerly xDAI).
|
45
|
+
GNOSIS = XDAI.freeze
|
46
|
+
|
47
|
+
# Chain ID for the Matic mainnet (now Polygon).
|
45
48
|
MATIC = 137.freeze
|
46
49
|
|
50
|
+
# Chain ID for the Polygon mainnet (formerly Matic).
|
51
|
+
POLYGON = MATIC.freeze
|
52
|
+
|
47
53
|
# Chain ID for Arbitrum mainnet.
|
48
54
|
ARBITRUM = 42161.freeze
|
49
55
|
|
@@ -86,9 +92,15 @@ module Eth
|
|
86
92
|
# Chain ID for Arbitrum Rinkeby testnet.
|
87
93
|
RINKEBY_ARBITRUM = 421611.freeze
|
88
94
|
|
95
|
+
# Chain ID for Arbitrum Goerli testnet.
|
96
|
+
GOERLI_ARBITRUM = 421613.freeze
|
97
|
+
|
89
98
|
# Chain ID for Sepolia testnet.
|
90
99
|
SEPOLIA = 11155111.freeze
|
91
100
|
|
101
|
+
# Chain ID for Holesovice testnet.
|
102
|
+
HOLESOVICE = 11166111.freeze
|
103
|
+
|
92
104
|
# Chain ID for the geth private network preset.
|
93
105
|
PRIVATE_GETH = 1337.freeze
|
94
106
|
|
@@ -97,7 +109,7 @@ module Eth
|
|
97
109
|
#
|
98
110
|
# @param v [Integer] the signature's `v` value.
|
99
111
|
# @return [Boolean] true if ledger's legacy value.
|
100
|
-
def
|
112
|
+
def ledger?(v)
|
101
113
|
[0, 1].include? v
|
102
114
|
end
|
103
115
|
|
@@ -106,7 +118,7 @@ module Eth
|
|
106
118
|
#
|
107
119
|
# @param v [Integer] the signature's `v` value.
|
108
120
|
# @return [Boolean] true if legacy value.
|
109
|
-
def
|
121
|
+
def legacy?(v)
|
110
122
|
[27, 28].include? v
|
111
123
|
end
|
112
124
|
|
@@ -120,11 +132,11 @@ module Eth
|
|
120
132
|
def to_recovery_id(v, chain_id = ETHEREUM)
|
121
133
|
e = 0 + 2 * chain_id + 35
|
122
134
|
i = 1 + 2 * chain_id + 35
|
123
|
-
if
|
135
|
+
if ledger? v
|
124
136
|
|
125
137
|
# some wallets are using a `v` of 0 or 1 (ledger)
|
126
138
|
return v
|
127
|
-
elsif
|
139
|
+
elsif legacy? v
|
128
140
|
|
129
141
|
# this is the pre-EIP-155 legacy case
|
130
142
|
return v - 27
|
data/lib/eth/client/http.rb
CHANGED
data/lib/eth/client/http_auth.rb
CHANGED
data/lib/eth/client/ipc.rb
CHANGED