eth 0.5.7 → 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codeql.yml +1 -1
  3. data/.github/workflows/docs.yml +2 -2
  4. data/.github/workflows/spec.yml +3 -3
  5. data/CHANGELOG.md +33 -0
  6. data/Gemfile +2 -2
  7. data/LICENSE.txt +1 -1
  8. data/README.md +1 -1
  9. data/abis/ens.json +422 -0
  10. data/eth.gemspec +2 -2
  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 +70 -58
  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/resolver.rb +77 -0
  30. data/lib/eth/key/decrypter.rb +1 -1
  31. data/lib/eth/key/encrypter.rb +1 -1
  32. data/lib/eth/key.rb +5 -5
  33. data/lib/eth/rlp/decoder.rb +2 -2
  34. data/lib/eth/rlp/encoder.rb +3 -3
  35. data/lib/eth/rlp/sedes/big_endian_int.rb +1 -1
  36. data/lib/eth/rlp/sedes/binary.rb +2 -2
  37. data/lib/eth/rlp/sedes/list.rb +5 -5
  38. data/lib/eth/rlp/sedes.rb +4 -4
  39. data/lib/eth/rlp.rb +1 -1
  40. data/lib/eth/signature.rb +4 -4
  41. data/lib/eth/solidity.rb +5 -3
  42. data/lib/eth/tx/eip1559.rb +3 -3
  43. data/lib/eth/tx/eip2930.rb +3 -3
  44. data/lib/eth/tx/legacy.rb +3 -3
  45. data/lib/eth/tx.rb +5 -5
  46. data/lib/eth/unit.rb +1 -1
  47. data/lib/eth/util.rb +14 -14
  48. data/lib/eth/version.rb +2 -2
  49. data/lib/eth.rb +2 -1
  50. metadata +7 -4
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.