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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/spec.yml +2 -1
  3. data/CHANGELOG.md +32 -0
  4. data/CODE_OF_CONDUCT.md +122 -0
  5. data/CONTRIBUTING.md +61 -0
  6. data/LICENSE.txt +1 -1
  7. data/README.md +6 -2
  8. data/SECURITY.md +24 -0
  9. data/abi/ens_registry.json +436 -0
  10. data/abi/ens_resolver.json +885 -0
  11. data/lib/eth/abi/event.rb +1 -1
  12. data/lib/eth/abi/type.rb +46 -12
  13. data/lib/eth/abi.rb +72 -14
  14. data/lib/eth/address.rb +2 -2
  15. data/lib/eth/api.rb +1 -1
  16. data/lib/eth/chain.rb +19 -7
  17. data/lib/eth/client/http.rb +1 -1
  18. data/lib/eth/client/http_auth.rb +1 -1
  19. data/lib/eth/client/ipc.rb +1 -1
  20. data/lib/eth/client.rb +118 -16
  21. data/lib/eth/constant.rb +1 -1
  22. data/lib/eth/contract/event.rb +1 -1
  23. data/lib/eth/contract/function.rb +2 -2
  24. data/lib/eth/contract/function_input.rb +7 -2
  25. data/lib/eth/contract/function_output.rb +1 -1
  26. data/lib/eth/contract/initializer.rb +1 -1
  27. data/lib/eth/contract.rb +1 -1
  28. data/lib/eth/eip712.rb +2 -2
  29. data/lib/eth/ens/coin_type.rb +50 -0
  30. data/lib/eth/ens/resolver.rb +68 -24
  31. data/lib/eth/ens.rb +28 -0
  32. data/lib/eth/key/decrypter.rb +1 -1
  33. data/lib/eth/key/encrypter.rb +1 -1
  34. data/lib/eth/key.rb +5 -5
  35. data/lib/eth/rlp/decoder.rb +2 -2
  36. data/lib/eth/rlp/encoder.rb +3 -3
  37. data/lib/eth/rlp/sedes/big_endian_int.rb +1 -1
  38. data/lib/eth/rlp/sedes/binary.rb +2 -2
  39. data/lib/eth/rlp/sedes/list.rb +5 -5
  40. data/lib/eth/rlp/sedes.rb +4 -4
  41. data/lib/eth/rlp.rb +1 -1
  42. data/lib/eth/signature.rb +4 -4
  43. data/lib/eth/solidity.rb +5 -3
  44. data/lib/eth/tx/eip1559.rb +3 -3
  45. data/lib/eth/tx/eip2930.rb +3 -3
  46. data/lib/eth/tx/legacy.rb +3 -3
  47. data/lib/eth/tx.rb +5 -5
  48. data/lib/eth/unit.rb +1 -1
  49. data/lib/eth/util.rb +14 -14
  50. data/lib/eth/version.rb +2 -2
  51. data/lib/eth.rb +2 -2
  52. metadata +9 -3
  53. data/abis/ens.json +0 -422
data/lib/eth/abi/event.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2022 The Ruby-Eth Contributors
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.
data/lib/eth/abi/type.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2022 The Ruby-Eth Contributors
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
- unless ["string", "bytes"].include?(base_type) and sub_type.empty?
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
- else
105
- unless dimensions.last == 0
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 is_dynamic?
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-2022 The Ruby-Eth Contributors
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].is_dynamic?
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.is_dynamic?
85
- raise EncodingError, "Argument must be an Array" unless arg.instance_of? Array
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 Type.size_type, arg.size
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 Type.size_type, offset
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.is_hex? data
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.is_dynamic?
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.is_dynamic?
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.is_dynamic?
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.is_dynamic?
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.is_prefixed? arg or
432
- (arg.size === type.sub_type.to_i * 2 and Util.is_hex? arg)
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-2022 The Ruby-Eth Contributors
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.is_hex? address
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
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2022 The Ruby-Eth Contributors
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.
data/lib/eth/chain.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2022 The Ruby-Eth Contributors
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 mainnet.
41
+ # Chain ID for xDAI mainnet (now Gnosis Chain).
42
42
  XDAI = 100.freeze
43
43
 
44
- # Chain ID for the Polygon Matic mainnet.
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 is_ledger?(v)
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 is_legacy?(v)
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 [0, 1].include? v
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 is_legacy? v
139
+ elsif legacy? v
128
140
 
129
141
  # this is the pre-EIP-155 legacy case
130
142
  return v - 27
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2022 The Ruby-Eth Contributors
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.
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2022 The Ruby-Eth Contributors
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.
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2022 The Ruby-Eth Contributors
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.