eth 0.5.13 → 0.5.14

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 (52) 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 +1 -3
  5. data/LICENSE.txt +1 -1
  6. data/README.md +1 -3
  7. data/eth.gemspec +3 -0
  8. data/lib/eth/abi/decoder.rb +2 -2
  9. data/lib/eth/abi/encoder.rb +4 -5
  10. data/lib/eth/abi/event.rb +5 -1
  11. data/lib/eth/abi/packed/encoder.rb +196 -0
  12. data/lib/eth/abi/type.rb +12 -12
  13. data/lib/eth/abi.rb +27 -2
  14. data/lib/eth/address.rb +3 -1
  15. data/lib/eth/api.rb +1 -1
  16. data/lib/eth/chain.rb +6 -1
  17. data/lib/eth/client/http.rb +7 -3
  18. data/lib/eth/client/ipc.rb +1 -1
  19. data/lib/eth/client.rb +1 -1
  20. data/lib/eth/constant.rb +1 -1
  21. data/lib/eth/contract/event.rb +69 -16
  22. data/lib/eth/contract/function.rb +1 -1
  23. data/lib/eth/contract/function_input.rb +1 -1
  24. data/lib/eth/contract/function_output.rb +1 -1
  25. data/lib/eth/contract/initializer.rb +1 -1
  26. data/lib/eth/contract.rb +1 -1
  27. data/lib/eth/eip712.rb +3 -2
  28. data/lib/eth/ens/coin_type.rb +1 -1
  29. data/lib/eth/ens/resolver.rb +1 -1
  30. data/lib/eth/ens.rb +1 -1
  31. data/lib/eth/key/decrypter.rb +1 -1
  32. data/lib/eth/key/encrypter.rb +1 -1
  33. data/lib/eth/key.rb +1 -1
  34. data/lib/eth/rlp/decoder.rb +1 -1
  35. data/lib/eth/rlp/encoder.rb +1 -1
  36. data/lib/eth/rlp/sedes/big_endian_int.rb +1 -1
  37. data/lib/eth/rlp/sedes/binary.rb +1 -1
  38. data/lib/eth/rlp/sedes/list.rb +1 -1
  39. data/lib/eth/rlp/sedes.rb +1 -1
  40. data/lib/eth/rlp.rb +1 -1
  41. data/lib/eth/signature.rb +1 -1
  42. data/lib/eth/solidity.rb +1 -1
  43. data/lib/eth/tx/eip1559.rb +1 -1
  44. data/lib/eth/tx/eip2930.rb +1 -1
  45. data/lib/eth/tx/eip7702.rb +495 -0
  46. data/lib/eth/tx/legacy.rb +1 -1
  47. data/lib/eth/tx.rb +50 -1
  48. data/lib/eth/unit.rb +1 -1
  49. data/lib/eth/util.rb +1 -1
  50. data/lib/eth/version.rb +2 -2
  51. data/lib/eth.rb +1 -1
  52. metadata +19 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc5ddb568fad899fb1b19cce7995c8152b799475fbca603932d840d561fa4b4c
4
- data.tar.gz: fc69a4e2c2866a719336cc94a0adb9244383a6c80116ab7da8a1165262743ac9
3
+ metadata.gz: c5f56a3acb3981d3087e8125660e5670b8ba8bf6a5255e2742e439498327cd82
4
+ data.tar.gz: c54057d9b851ad567e846e390949927afe1986387eaba95fc8facb0aa3fef20d
5
5
  SHA512:
6
- metadata.gz: 35062c2f2b04723b2889195a5a16c662e2f2913fed4ecc3d5903a6167ed125d23a3b066125756023b2b71451f5899a58f5a36e61049f0e744b6a24583a6eff9e
7
- data.tar.gz: 51732510c1e64a48d3095fb6a6502038e493ace3390da31cde1006f67f4b7a4e130f78de2ab667ae235ce4285c2bb986a3720be8b6648e91d845de5bdb6f1a8f
6
+ metadata.gz: ee0dacd29dde60d8368c382a8d0fdf444895a66f2795689961112f34e752fced4a350e26b255d5bc4b1872e7c423c5780cc35487bd2b349f984ac0f75facbfd8
7
+ data.tar.gz: ca7fbe6c973aceb5dcc56031dbfa03903392ba9ad2ff0aa90d29c4c6311cc899961954e606c9c400df523305815eb89b26bc1fed2c0d65fcb042b59f0b63064f
@@ -35,7 +35,7 @@ jobs:
35
35
  uses: github/codeql-action/analyze@v3
36
36
  - uses: ruby/setup-ruby@v1
37
37
  with:
38
- ruby-version: '3.3'
38
+ ruby-version: '3.4'
39
39
  bundler-cache: true
40
40
  - name: "Run rufo code formatting checks"
41
41
  run: |
@@ -13,14 +13,14 @@ jobs:
13
13
  - uses: actions/checkout@v4
14
14
  - uses: ruby/setup-ruby@v1
15
15
  with:
16
- ruby-version: '3.3'
16
+ ruby-version: '3.4'
17
17
  bundler-cache: true
18
18
  - name: Run Yard Doc
19
19
  run: |
20
20
  gem install yard
21
21
  yard doc
22
22
  - name: Deploy GH Pages
23
- uses: JamesIves/github-pages-deploy-action@v4.7.1
23
+ uses: JamesIves/github-pages-deploy-action@v4.7.3
24
24
  with:
25
25
  branch: gh-pages
26
26
  folder: doc/
@@ -19,7 +19,7 @@ jobs:
19
19
  fail-fast: false
20
20
  matrix:
21
21
  os: [ubuntu-latest, macos-latest]
22
- ruby: ['3.2', '3.3']
22
+ ruby: ['3.3', '3.4']
23
23
  steps:
24
24
  - uses: actions/checkout@v4
25
25
  - uses: ruby/setup-ruby@v1
@@ -48,8 +48,6 @@ jobs:
48
48
  - name: Run Tests
49
49
  run: |
50
50
  bundle exec rspec
51
- env:
52
- INFURA_TOKEN: ${{ secrets.INFURA_TOKEN }}
53
51
  - name: Upload coverage to Codecov
54
52
  uses: codecov/codecov-action@v5
55
53
  with:
data/LICENSE.txt CHANGED
@@ -187,7 +187,7 @@
187
187
  same "printed page" as the copyright notice for easier
188
188
  identification within third-party archives.
189
189
 
190
- Copyright (c) 2016-2023 The Ruby-Eth Contributors
190
+ Copyright (c) 2016-2025 The Ruby-Eth Contributors
191
191
 
192
192
  Licensed under the Apache License, Version 2.0 (the "License");
193
193
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -80,8 +80,6 @@ The test suite expects working local HTTP and IPC endpoints with a prefunded dev
80
80
  geth --dev --http --ipcpath /tmp/geth.ipc &
81
81
  ```
82
82
 
83
- It also expects an `$INFURA_TOKEN` in environment to test some ENS queries on mainnet.
84
-
85
83
  To run tests, simply use `rspec`. Note, that the Ethereum test fixtures are also required.
86
84
 
87
85
  ```shell
@@ -95,7 +93,7 @@ The goal is to have 100% specification coverage for all code inside this gem.
95
93
  ## Contributing
96
94
  Pull requests are welcome! To contribute, please consider the following:
97
95
  * Code should be fully documented. Run `yard doc` and make sure it does not yield any warnings or undocumented sets.
98
- * Code should be fully covered by tests. Run `rspec` to make sure all tests pass. The CI has an integration that will assis you to identify uncovered lines of code and get coverage up to 100%.
96
+ * Code should be fully covered by tests. Run `rspec` to make sure all tests pass. The CI has an integration that will assist you to identify uncovered lines of code and get coverage up to 100%.
99
97
  * Code should be formatted properly. Try to eliminate the most common issues such as trailing white-spaces or duplicate new-lines. Usage of the `rufo` gem is recommended.
100
98
  * Submit pull requests, questions, or issues to Github: <https://github.com/q9f/eth.rb>
101
99
 
data/eth.gemspec CHANGED
@@ -34,6 +34,9 @@ Gem::Specification.new do |spec|
34
34
  spec.platform = Gem::Platform::RUBY
35
35
  spec.required_ruby_version = ">= 3.0", "< 4.0"
36
36
 
37
+ # bigdecimal for big decimals ;)
38
+ spec.add_dependency "bigdecimal", "~> 3.1"
39
+
37
40
  # forwardable for contracts meta programming
38
41
  spec.add_dependency "forwardable", "~> 1.3"
39
42
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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.
@@ -102,7 +102,7 @@ module Eth
102
102
  when "address"
103
103
 
104
104
  # decoded address with 0x-prefix
105
- "0x#{Util.bin_to_hex data[12..-1]}"
105
+ Address.new(Util.bin_to_hex data[12..-1]).to_s.downcase
106
106
  when "string", "bytes"
107
107
  if type.sub_type.empty?
108
108
  size = Util.deserialize_big_endian_to_int data[0, 32]
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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.
@@ -49,7 +49,6 @@ module Eth
49
49
  head, tail = "", ""
50
50
  head += type(Type.size_type, arg.size)
51
51
  nested_sub = type.nested_sub
52
- nested_sub_size = type.nested_sub.size
53
52
 
54
53
  # calculate offsets
55
54
  if %w(string bytes).include?(type.base_type) && type.sub_type.empty?
@@ -93,15 +92,15 @@ module Eth
93
92
  # @return [String] the encoded primitive type.
94
93
  # @raise [EncodingError] if value does not match type.
95
94
  # @raise [ValueOutOfBounds] if value is out of bounds for type.
96
- # @raise [EncodingError] if encoding fails for type.
95
+ # @raise [ArgumentError] if encoding fails for type.
97
96
  def primitive_type(type, arg)
98
97
  case type.base_type
99
98
  when "uint"
100
99
  uint arg, type
101
- when "bool"
102
- bool arg
103
100
  when "int"
104
101
  int arg, type
102
+ when "bool"
103
+ bool arg
105
104
  when "ureal", "ufixed"
106
105
  ufixed arg, type
107
106
  when "real", "fixed"
data/lib/eth/abi/event.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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.
@@ -44,6 +44,10 @@ module Eth
44
44
  "#{name}(#{types.join(",")})"
45
45
  end
46
46
 
47
+ # Gets the input type for events.
48
+ #
49
+ # @param input [Hash] events input.
50
+ # @return [String] input type.
47
51
  def type(input)
48
52
  if input["type"] == "tuple"
49
53
  "(#{input["components"].map { |c| type(c) }.join(",")})"
@@ -0,0 +1,196 @@
1
+ # Copyright (c) 2016-2025 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
+
20
+ # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
21
+ module Abi
22
+
23
+ # Encapsulates the module for non-standard packed encoding used in Solidity.
24
+ module Packed
25
+
26
+ # Provides a utility module to assist encoding ABIs.
27
+ module Encoder
28
+ extend self
29
+
30
+ # Encodes a specific value, either static or dynamic in non-standard
31
+ # packed encoding mode.
32
+ #
33
+ # @param type [Eth::Abi::Type] type to be encoded.
34
+ # @param arg [String|Number] value to be encoded.
35
+ # @return [String] the packed encoded type.
36
+ # @raise [EncodingError] if value does not match type.
37
+ # @raise [ArgumentError] if encoding fails for type.
38
+ def type(type, arg)
39
+ case type
40
+ when /^uint(\d+)$/
41
+ uint(arg, $1.to_i / 8)
42
+ when /^int(\d+)$/
43
+ int(arg, $1.to_i / 8)
44
+ when "bool"
45
+ bool(arg)
46
+ when /^ureal(\d+)x(\d+)$/, /^ufixed(\d+)x(\d+)$/
47
+ ufixed(arg, $1.to_i / 8, $2.to_i)
48
+ when /^real(\d+)x(\d+)$/, /^fixed(\d+)x(\d+)$/
49
+ fixed(arg, $1.to_i / 8, $2.to_i)
50
+ when "string"
51
+ string(arg)
52
+ when /^bytes(\d+)$/
53
+ bytes(arg, $1.to_i)
54
+ when "bytes"
55
+ string(arg)
56
+ when /^tuple\((.+)\)$/
57
+ tuple($1.split(","), arg)
58
+ when /^hash(\d+)$/
59
+ hash(arg, $1.to_i / 8)
60
+ when "address"
61
+ address(arg)
62
+ when /^(.+)\[\]$/
63
+ array($1, arg)
64
+ when /^(.+)\[(\d+)\]$/
65
+ fixed_array($1, arg, $2.to_i)
66
+ else
67
+ raise EncodingError, "Unhandled type: #{type}"
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ # Properly encodes signed integers.
74
+ def uint(value, byte_size)
75
+ raise ArgumentError, "Don't know how to handle this input." unless value.is_a? Numeric
76
+ raise ValueOutOfBounds, "Number out of range: #{value}" if value > Constant::UINT_MAX or value < Constant::UINT_MIN
77
+ i = value.to_i
78
+ Util.zpad_int i, byte_size
79
+ end
80
+
81
+ # Properly encodes signed integers.
82
+ def int(value, byte_size)
83
+ raise ArgumentError, "Don't know how to handle this input." unless value.is_a? Numeric
84
+ raise ValueOutOfBounds, "Number out of range: #{value}" if value > Constant::INT_MAX or value < Constant::INT_MIN
85
+ real_size = byte_size * 8
86
+ i = value.to_i % 2 ** real_size
87
+ Util.zpad_int i, byte_size
88
+ end
89
+
90
+ # Properly encodes booleans.
91
+ def bool(value)
92
+ raise EncodingError, "Argument is not bool: #{value}" unless value.instance_of? TrueClass or value.instance_of? FalseClass
93
+ (value ? "\x01" : "\x00").b
94
+ end
95
+
96
+ # Properly encodes unsigned fixed-point numbers.
97
+ def ufixed(value, byte_size, decimals)
98
+ raise ArgumentError, "Don't know how to handle this input." unless value.is_a? Numeric
99
+ raise ValueOutOfBounds, value unless value >= 0 and value < 2 ** decimals
100
+ scaled_value = (value * (10 ** decimals)).to_i
101
+ uint(scaled_value, byte_size)
102
+ end
103
+
104
+ # Properly encodes signed fixed-point numbers.
105
+ def fixed(value, byte_size, decimals)
106
+ raise ArgumentError, "Don't know how to handle this input." unless value.is_a? Numeric
107
+ raise ValueOutOfBounds, value unless value >= -2 ** (decimals - 1) and value < 2 ** (decimals - 1)
108
+ scaled_value = (value * (10 ** decimals)).to_i
109
+ int(scaled_value, byte_size)
110
+ end
111
+
112
+ # Properly encodes byte(-string)s.
113
+ def bytes(value, length)
114
+ raise EncodingError, "Expecting String: #{value}" unless value.instance_of? String
115
+ value = handle_hex_string value, length
116
+ raise ArgumentError, "Value must be a string of length #{length}" unless value.is_a?(String) && value.bytesize == length
117
+ value.b
118
+ end
119
+
120
+ # Properly encodes (byte-)strings.
121
+ def string(value)
122
+ raise ArgumentError, "Value must be a string" unless value.is_a?(String)
123
+ value.b
124
+ end
125
+
126
+ # Properly encodes tuples.
127
+ def tuple(types, values)
128
+ Abi.solidity_packed(types, values)
129
+ end
130
+
131
+ # Properly encodes hash-strings.
132
+ def hash(value, byte_size)
133
+ raise EncodingError, "Argument too long: #{value}" unless byte_size > 0 and byte_size <= 32
134
+ hash_bytes = handle_hex_string value, byte_size
135
+ hash_bytes.b
136
+ end
137
+
138
+ # Properly encodes addresses.
139
+ def address(value)
140
+ if value.is_a? Address
141
+
142
+ # from checksummed address with 0x prefix
143
+ Util.zpad_hex value.to_s[2..-1], 20
144
+ elsif value.is_a? Integer
145
+
146
+ # address from integer
147
+ Util.zpad_int value, 20
148
+ elsif value.size == 20
149
+
150
+ # address from encoded address
151
+ Util.zpad value, 20
152
+ elsif value.size == 40
153
+
154
+ # address from hexadecimal address
155
+ Util.zpad_hex value, 20
156
+ elsif value.size == 42 and value[0, 2] == "0x"
157
+
158
+ # address from hexadecimal address with 0x prefix
159
+ Util.zpad_hex value[2..-1], 20
160
+ else
161
+ raise EncodingError, "Could not parse address: #{value}"
162
+ end
163
+ end
164
+
165
+ # Properly encodes dynamic-sized arrays.
166
+ def array(type, values)
167
+ values.map { |value| type(type, value) }.join.b
168
+ end
169
+
170
+ # Properly encodes fixed-size arrays.
171
+ def fixed_array(type, values, size)
172
+ raise ArgumentError, "Array size does not match" unless values.size == size
173
+ array(type, values)
174
+ end
175
+
176
+ # The ABI encoder needs to be able to determine between a hex `"123"`
177
+ # and a binary `"123"` string.
178
+ def handle_hex_string(val, len)
179
+ if Util.prefixed? val or
180
+ (len === val.size / 2 and Util.hex? val)
181
+
182
+ # There is no way telling whether a string is hex or binary with certainty
183
+ # in Ruby. Therefore, we assume a `0x` prefix to indicate a hex string.
184
+ # Additionally, if the string size is exactly the double of the expected
185
+ # binary size, we can assume a hex value.
186
+ Util.hex_to_bin val
187
+ else
188
+
189
+ # Everything else will be assumed binary or raw string.
190
+ val.b
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
data/lib/eth/abi/type.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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.
@@ -94,7 +94,7 @@ module Eth
94
94
  @base_type = base_type
95
95
  @sub_type = sub_type
96
96
  @dimensions = dims.map { |x| x[1...-1].to_i }
97
- @components = components.map { |component| Abi::Type.parse(component["type"], component.dig("components"), component.dig("name")) } unless components.nil?
97
+ @components = components.map { |component| Abi::Type.parse(component["type"], component.dig("components"), component.dig("name")) } if components&.any?
98
98
  @name = component_name
99
99
  end
100
100
 
@@ -123,10 +123,10 @@ module Eth
123
123
  if dimensions.empty?
124
124
  if !(["string", "bytes", "tuple"].include?(base_type) and sub_type.empty?)
125
125
  s = 32
126
- elsif base_type == "tuple" && components.none?(&:dynamic?)
126
+ elsif base_type == "tuple" and components.none?(&:dynamic?)
127
127
  s = components.sum(&:size)
128
128
  end
129
- elsif dimensions.last != 0 && !nested_sub.dynamic?
129
+ elsif dimensions.last != 0 and !nested_sub.dynamic?
130
130
  s = dimensions.last * nested_sub.size
131
131
  end
132
132
  @size ||= s
@@ -153,7 +153,7 @@ module Eth
153
153
  if base_type == "tuple"
154
154
  "(" + components.map(&:to_s).join(",") + ")" + (dimensions.size > 0 ? dimensions.map { |x| "[#{x == 0 ? "" : x}]" }.join : "")
155
155
  elsif dimensions.empty?
156
- if %w[string bytes].include?(base_type) && sub_type.empty?
156
+ if %w[string bytes].include?(base_type) and sub_type.empty?
157
157
  base_type
158
158
  else
159
159
  "#{base_type}#{sub_type}"
@@ -175,7 +175,7 @@ module Eth
175
175
  when "bytes"
176
176
 
177
177
  # bytes can be no longer than 32 bytes
178
- raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub_type.empty? || sub_type.to_i <= 32
178
+ raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub_type.empty? or (sub_type.to_i <= 32 and sub_type.to_i > 0)
179
179
  when "tuple"
180
180
 
181
181
  # tuples can not have any suffix
@@ -187,16 +187,16 @@ module Eth
187
187
 
188
188
  # integer size must be valid
189
189
  size = sub_type.to_i
190
- raise ParseError, "Integer size out of bounds" unless size >= 8 && size <= 256
190
+ raise ParseError, "Integer size out of bounds" unless size >= 8 and size <= 256
191
191
  raise ParseError, "Integer size must be multiple of 8" unless size % 8 == 0
192
192
  when "ureal", "real", "fixed", "ufixed"
193
193
 
194
194
  # floats must have valid dimensional suffix
195
- raise ParseError, "Real type must have suffix of form <high>x<low>, e.g. 128x128" unless sub_type =~ /\A[0-9]+x[0-9]+\z/
196
- high, low = sub_type.split("x").map(&:to_i)
197
- total = high + low
198
- raise ParseError, "Real size out of bounds (max 32 bytes)" unless total >= 8 && total <= 256
199
- raise ParseError, "Real high/low sizes must be multiples of 8" unless high % 8 == 0 && low % 8 == 0
195
+ raise ParseError, "Real type must have suffix of form <size>x<decimals>, e.g. 128x128" unless sub_type =~ /\A[0-9]+x[0-9]+\z/
196
+ size, decimals = sub_type.split("x").map(&:to_i)
197
+ total = size + decimals
198
+ raise ParseError, "Real size out of bounds (max 32 bytes)" unless total >= 8 and total <= 256
199
+ raise ParseError, "Real size must be multiples of 8" unless size % 8 == 0
200
200
  when "hash"
201
201
 
202
202
  # hashs must have numerical suffix
data/lib/eth/abi.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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,8 +38,12 @@ module Eth
38
38
  #
39
39
  # @param types [Array] types to be ABI-encoded.
40
40
  # @param args [Array] values to be ABI-encoded.
41
+ # @param packed [Bool] set true to return packed encoding (default: `false`).
41
42
  # @return [String] the encoded ABI data.
42
- def encode(types, args)
43
+ def encode(types, args, packed = false)
44
+ return solidity_packed(types, args) if packed
45
+ types = [types] unless types.instance_of? Array
46
+ args = [args] unless args.instance_of? Array
43
47
 
44
48
  # parse all types
45
49
  parsed_types = types.map { |t| Type === t ? t : Type.parse(t) }
@@ -64,6 +68,26 @@ module Eth
64
68
  "#{head}#{tail}"
65
69
  end
66
70
 
71
+ # Encodes Application Binary Interface (ABI) data in non-standard packed mode.
72
+ # It accepts multiple arguments and encodes using the head/tail mechanism.
73
+ #
74
+ # @param types [Array] types to be ABI-encoded.
75
+ # @param args [Array] values to be ABI-encoded.
76
+ # @return [String] the encoded packed ABI data.
77
+ # @raise [ArgumentError] if types and args are of different size.
78
+ def solidity_packed(types, args)
79
+ raise ArgumentError, "Types and values must be the same length" if types.length != args.length
80
+
81
+ # We do not use the type system for packed encoding but want to call the parser once
82
+ # to enforce the type validation.
83
+ _ = types.map { |t| Type === t ? t : Type.parse(t) }
84
+
85
+ packed = types.zip(args).map do |type, arg|
86
+ Abi::Packed::Encoder.type(type, arg)
87
+ end.join
88
+ packed.force_encoding(Encoding::ASCII_8BIT)
89
+ end
90
+
67
91
  # Decodes Application Binary Interface (ABI) data. It accepts multiple
68
92
  # arguments and decodes using the head/tail mechanism.
69
93
  #
@@ -123,6 +147,7 @@ module Eth
123
147
  end
124
148
  end
125
149
 
150
+ require "eth/abi/packed/encoder"
126
151
  require "eth/abi/decoder"
127
152
  require "eth/abi/encoder"
128
153
  require "eth/abi/event"
data/lib/eth/address.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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.
@@ -17,6 +17,8 @@ module Eth
17
17
 
18
18
  # The {Eth::Address} class to handle checksummed Ethereum addresses.
19
19
  class Address
20
+
21
+ # The literal zero address 0x0.
20
22
  ZERO = "0x0000000000000000000000000000000000000000"
21
23
 
22
24
  # Provides a special checksum error if EIP-55 is violated.
data/lib/eth/api.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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,11 +149,16 @@ module Eth
149
149
  # Chain ID for Arbitrum Goerli testnet.
150
150
  GOERLI_ARBITRUM = 421613.freeze
151
151
 
152
+ # Chain ID for Hoodi testnet.
153
+ HOODI = 560048.freeze
154
+
152
155
  # Chain ID for Sepolia testnet.
153
156
  SEPOLIA = 11155111.freeze
154
157
 
155
158
  # Chain ID for Holesovice testnet.
156
159
  HOLESOVICE = 11166111.freeze
160
+
161
+ # Chain ID for Holesovice testnet.
157
162
  HOLESKY = HOLESOVICE
158
163
 
159
164
  # Chain ID for the geth private network preset.
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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.
@@ -49,9 +49,13 @@ module Eth
49
49
  if !(uri.user.nil? && uri.password.nil?)
50
50
  @user = uri.user
51
51
  @password = uri.password
52
- @uri = URI("#{uri.scheme}://#{uri.user}:#{uri.password}@#{@host}:#{@port}#{uri.path}")
52
+ if uri.query
53
+ @uri = URI("#{uri.scheme}://#{uri.user}:#{uri.password}@#{@host}:#{@port}#{uri.path}?#{uri.query}")
54
+ else
55
+ @uri = URI("#{uri.scheme}://#{uri.user}:#{uri.password}@#{@host}:#{@port}#{uri.path}")
56
+ end
53
57
  else
54
- @uri = URI("#{uri.scheme}://#{@host}:#{@port}#{uri.path}")
58
+ @uri = uri
55
59
  end
56
60
  end
57
61
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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/client.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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/constant.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2023 The Ruby-Eth Contributors
1
+ # Copyright (c) 2016-2025 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.