eth 0.5.17 → 0.5.18

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98f8ce464d7df37a4eba624469d53362687773991ccabf623e9d91d78e450479
4
- data.tar.gz: ce0601d35ca795205565e541c97115f396c5e7553a9aa6a76421167bf6bc4e69
3
+ metadata.gz: 760b6de4102268368fd7ef4f0f4f567192b0ddc52353f67ea6e7d5ca95fcba66
4
+ data.tar.gz: 614de2331a7cd3dfd45d036574a2bebef57d14c6f07070edd11ffc95be381b4d
5
5
  SHA512:
6
- metadata.gz: fb9c363ec65417ce041a3a847f3d573a2128724fabb1b80483453c3097c1f726b123d78fb546b15a691ab83e64e2409ef7ef8d40461348c3948014ad52159991
7
- data.tar.gz: 869b4229c3861eb7be055d0b5559e039269e267ad79203d9f4dd2923d8a08e863af9afce2cb6e973e74130db2fd6a4a04c084a0bc7460b167ab50b3813fa1592
6
+ metadata.gz: b21c15db4d30b89d829bd8025805171d53485d3c98fc0d72bfaf0b5d2f88b758f542658c78191e3b7f80c9c796a16cf3808dd41c6418862baa1c51694b0ee743
7
+ data.tar.gz: 7bedd93e3e673e8c5710ed4ede25428d30ed5c96cdee707f56a7b3462e45b1ed47fa6e06d5f07f0bcb5619e839e385dfa761d66a53975b6e19e2d1321aec67a4
@@ -24,15 +24,15 @@ jobs:
24
24
  - ruby
25
25
  steps:
26
26
  - name: "Checkout repository"
27
- uses: actions/checkout@v6
27
+ uses: actions/checkout@v7
28
28
  - name: "Initialize CodeQL"
29
- uses: github/codeql-action/init@v4
29
+ uses: github/codeql-action/init@v4.38.2
30
30
  with:
31
31
  languages: "${{ matrix.language }}"
32
32
  - name: Autobuild
33
- uses: github/codeql-action/autobuild@v4
33
+ uses: github/codeql-action/autobuild@v4.38.2
34
34
  - name: "Perform CodeQL Analysis"
35
- uses: github/codeql-action/analyze@v4
35
+ uses: github/codeql-action/analyze@v4.38.2
36
36
  - uses: ruby/setup-ruby@v1
37
37
  with:
38
38
  ruby-version: '3.4'
@@ -10,7 +10,7 @@ jobs:
10
10
  docs:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
- - uses: actions/checkout@v6
13
+ - uses: actions/checkout@v7
14
14
  - uses: ruby/setup-ruby@v1
15
15
  with:
16
16
  ruby-version: '3.4'
@@ -20,7 +20,7 @@ jobs:
20
20
  gem install yard
21
21
  yard doc
22
22
  - name: Deploy GH Pages
23
- uses: JamesIves/github-pages-deploy-action@v4.7.6
23
+ uses: JamesIves/github-pages-deploy-action@v4.9.0
24
24
  with:
25
25
  branch: gh-pages
26
26
  folder: doc/
@@ -19,9 +19,14 @@ jobs:
19
19
  fail-fast: false
20
20
  matrix:
21
21
  os: [ubuntu-latest, macos-latest]
22
- ruby: ['3.4', '4.0']
22
+ ruby: [
23
+ { version: "3.4", bigdecimal: "~> 3.0" },
24
+ { version: "4.0", bigdecimal: "~> 4.0" },
25
+ ]
26
+ env:
27
+ BIGDECIMAL_VERSION: ${{ matrix.ruby.bigdecimal }}
23
28
  steps:
24
- - uses: actions/checkout@v6
29
+ - uses: actions/checkout@v7
25
30
  - name: MacOs Dependencies
26
31
  if: matrix.os == 'macos-latest'
27
32
  run: |
@@ -36,7 +41,7 @@ jobs:
36
41
  sudo apt-get install -y autoconf automake libtool pkg-config geth solc
37
42
  - uses: ruby/setup-ruby@v1
38
43
  with:
39
- ruby-version: ${{ matrix.ruby }}
44
+ ruby-version: ${{ matrix.ruby.version }}
40
45
  bundler-cache: true
41
46
  - name: Run Geth
42
47
  run: |
@@ -67,7 +72,7 @@ jobs:
67
72
  tail -n 200 /tmp/geth.log
68
73
  fi
69
74
  - name: Upload coverage to Codecov
70
- uses: codecov/codecov-action@v5
75
+ uses: codecov/codecov-action@v7
71
76
  with:
72
77
  fail_ci_if_error: true
73
78
  token: ${{ secrets.CODECOV_TOKEN }}
data/CHANGELOG.md CHANGED
@@ -1,6 +1,51 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [0.5.18]
5
+ ### Added
6
+ * Add support for BigDecimal 4.x [#402](https://github.com/q9f/eth.rb/pull/402)
7
+
8
+ ### Changed
9
+ * Docs: add SPEC, ACCEPTANCE, and per-domain spec contracts [#405](https://github.com/q9f/eth.rb/pull/405)
10
+ * Build(deps): bump codecov/codecov-action from 6 to 7 [#404](https://github.com/q9f/eth.rb/pull/404)
11
+ * Build(deps): bump actions/checkout from 6 to 7 [#403](https://github.com/q9f/eth.rb/pull/403)
12
+ * Build(deps): bump codecov/codecov-action from 5 to 6 [#400](https://github.com/q9f/eth.rb/pull/400)
13
+ * Build(deps): bump JamesIves/github-pages-deploy-action [#399](https://github.com/q9f/eth.rb/pull/399)
14
+ * Bump version to 0.5.18
15
+
16
+ ## [0.5.17]
17
+ ### Added
18
+ * Add JSONRPC error code to Client::RpcError [#392](https://github.com/q9f/eth.rb/pull/392)
19
+
20
+ ### Changed
21
+ * Update workflow Ruby versions and deploy action [#397](https://github.com/q9f/eth.rb/pull/397)
22
+ * Build(deps): bump JamesIves/github-pages-deploy-action [#395](https://github.com/q9f/eth.rb/pull/395)
23
+ * Build(deps): bump actions/checkout from 5 to 6 [#394](https://github.com/q9f/eth.rb/pull/394)
24
+ * Update README.md [#393](https://github.com/q9f/eth.rb/pull/393)
25
+ * Bump version to 0.5.17 [#398](https://github.com/q9f/eth.rb/pull/398)
26
+
27
+ ## [0.5.16]
28
+ ### Added
29
+ * Add WebSocket transport to client [#388](https://github.com/q9f/eth.rb/pull/388)
30
+ * Support tuple arrays in ABI coder [#387](https://github.com/q9f/eth.rb/pull/387)
31
+ * Add sign and public key helpers for BLS [#366](https://github.com/q9f/eth.rb/pull/366)
32
+ * Add tuple array ABI support [#369](https://github.com/q9f/eth.rb/pull/369)
33
+
34
+ ### Changed
35
+ * Build(deps): bump github/codeql-action from 3 to 4 [#390](https://github.com/q9f/eth.rb/pull/390)
36
+ * Client/ws: fix client origin headers for ws requests [#391](https://github.com/q9f/eth.rb/pull/391)
37
+ * Rename websocket client to Ws and expand websocket tests [#389](https://github.com/q9f/eth.rb/pull/389)
38
+ * Format EIP-4844 transaction constant [#386](https://github.com/q9f/eth.rb/pull/386)
39
+ * Fix ABI tuple handling for ethers test cases [#385](https://github.com/q9f/eth.rb/pull/385)
40
+ * Increase blob throughput limits [#363](https://github.com/q9f/eth.rb/pull/363)
41
+ * Feat: use httpx for http requests [#382](https://github.com/q9f/eth.rb/pull/382)
42
+ * Fix: transform hash keys to strings in encoder for component type compatibility [#378](https://github.com/q9f/eth.rb/pull/378)
43
+ * Fix: improve error handling for missing keys in component encoding [#376](https://github.com/q9f/eth.rb/pull/376)
44
+ * Build(deps): bump actions/checkout from 4 to 5 [#379](https://github.com/q9f/eth.rb/pull/379)
45
+ * Test: add abi decode case for prefixed hex data [#374](https://github.com/q9f/eth.rb/pull/374)
46
+ * Add tests for decoder static arrays and encoder helpers [#373](https://github.com/q9f/eth.rb/pull/373)
47
+ * Chore: bump version to 0.5.16 [#362](https://github.com/q9f/eth.rb/pull/362)
48
+
4
49
  ## [0.5.15]
5
50
  ### Added
6
51
  * Implement EIP712 array encoding [#361](https://github.com/q9f/eth.rb/pull/361)
data/Gemfile CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "bigdecimal", ENV.fetch("BIGDECIMAL_VERSION", "~> 4.0")
6
+
5
7
  group :test, :development do
6
8
  gem "bundler", ">= 2.4"
7
9
  gem "pry", "~> 0.15"
data/eth.gemspec CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
  "changelog_uri" => "https://github.com/q9f/eth.rb/blob/main/CHANGELOG.md",
23
23
  "documentation_uri" => "https://q9f.github.io/eth.rb/",
24
24
  "github_repo" => "https://github.com/q9f/eth.rb",
25
+ "rubygems_mfa_required" => "true",
25
26
  "source_code_uri" => "https://github.com/q9f/eth.rb",
26
27
  }.freeze
27
28
 
@@ -35,7 +36,7 @@ Gem::Specification.new do |spec|
35
36
  spec.required_ruby_version = ">= 3.0", "< 5.0"
36
37
 
37
38
  # bigdecimal for big decimals ;)
38
- spec.add_dependency "bigdecimal", "~> 3.1"
39
+ spec.add_dependency "bigdecimal", ">= 3.1", "< 5.0"
39
40
 
40
41
  # forwardable for contracts meta programming
41
42
  spec.add_dependency "forwardable", "~> 1.3"
@@ -69,6 +69,17 @@ module Eth
69
69
  response = @client.post(@uri, body: payload)
70
70
  response.body.to_s
71
71
  end
72
+
73
+ # Closes the underlying HTTP session and releases all persistent
74
+ # connections held in its pool. Once closed, the client cannot be
75
+ # used anymore; any subsequent request raises an `IOError`. Safe to
76
+ # call multiple times.
77
+ #
78
+ # @return [void]
79
+ def close
80
+ @closed = true
81
+ @client.close
82
+ end
72
83
  end
73
84
 
74
85
  private
@@ -43,8 +43,9 @@ module Eth
43
43
  until read.end_with?("\n")
44
44
  read = read << socket.recvmsg(nil)[0]
45
45
  end
46
- socket.close
47
46
  return read
47
+ ensure
48
+ socket.close unless socket.nil? || socket.closed?
48
49
  end
49
50
  end
50
51
  end
data/lib/eth/client/ws.rb CHANGED
@@ -76,11 +76,16 @@ module Eth
76
76
  end
77
77
  end
78
78
 
79
- # Closes the underlying WebSocket connection.
79
+ # Closes the underlying WebSocket connection. Once closed, the
80
+ # client cannot be used anymore; any subsequent request raises an
81
+ # `IOError`. Safe to call multiple times.
80
82
  #
81
83
  # @return [void]
82
84
  def close
83
- @mutex.synchronize { close_socket }
85
+ @mutex.synchronize do
86
+ @closed = true
87
+ close_socket
88
+ end
84
89
  end
85
90
 
86
91
  private
data/lib/eth/client.rb CHANGED
@@ -81,6 +81,7 @@ module Eth
81
81
  # use {Client.create} intead.
82
82
  def initialize(_)
83
83
  @id = 0
84
+ @closed = false
84
85
  @max_priority_fee_per_gas = Tx::DEFAULT_PRIORITY_FEE
85
86
  @max_fee_per_gas = Tx::DEFAULT_GAS_PRICE
86
87
  end
@@ -378,6 +379,23 @@ module Eth
378
379
  @id = 0
379
380
  end
380
381
 
382
+ # Closes the client and releases any resources held by the underlying
383
+ # connection, such as persistent HTTP connections or an open WebSocket
384
+ # stream. Once closed, the client cannot be used anymore; any
385
+ # subsequent request raises an `IOError`. Safe to call multiple times.
386
+ #
387
+ # @return [void]
388
+ def close
389
+ @closed = true
390
+ end
391
+
392
+ # Checks whether the client has been closed via {#close}.
393
+ #
394
+ # @return [Boolean] true if the client is closed.
395
+ def closed?
396
+ !!@closed
397
+ end
398
+
381
399
  # Checks whether a transaction is mined or not.
382
400
  #
383
401
  # @param hash [String] the transaction hash.
@@ -476,6 +494,7 @@ module Eth
476
494
 
477
495
  # Prepares parameters and sends the command to the client.
478
496
  def send_command(command, args)
497
+ raise IOError, "The client is closed!" if closed?
479
498
  @block_number ||= "latest"
480
499
  args << block_number if ["eth_getBalance", "eth_call"].include? command
481
500
  payload = {
data/lib/eth/contract.rb CHANGED
@@ -45,6 +45,10 @@ module Eth
45
45
  @bin = bin
46
46
  @abi = abi
47
47
  @constructor_inputs, @functions, @events, @errors = parse_abi(abi)
48
+ @sigs2events = {}
49
+ @events.each do |event|
50
+ @sigs2events[event.signature] = event
51
+ end
48
52
  end
49
53
 
50
54
  # Creates a contract wrapper from a Solidity file.
@@ -168,6 +172,7 @@ module Eth
168
172
  def_delegator :parent, :function
169
173
  def_delegator :parent, :error
170
174
  def_delegator :parent, :decode_error
175
+ def_delegator :parent, :decode_log
171
176
  def_delegator :parent, :constructor_inputs
172
177
  define_method :parent do
173
178
  parent
@@ -178,6 +183,21 @@ module Eth
178
183
  @class_object = class_methods
179
184
  end
180
185
 
186
+ # Decodes an event log by looking up the event signature in the
187
+ # contract ABI.
188
+ #
189
+ # @param topics [Array<String>] the list of log topics, including the
190
+ # event selector.
191
+ # @param data [String] the log data containing non-indexed parameters.
192
+ # @return [Hash] a hash of decoded event parameters.
193
+ # @raise [ArgumentError] if the event is not part of the contract ABI.
194
+ def decode_log(topics, data)
195
+ sig = Eth::Util.remove_hex_prefix(topics[0])
196
+ event = @sigs2events[sig]
197
+ raise ArgumentError, "this event does not exist!" if event.nil?
198
+ event.decode_params(topics, data)
199
+ end
200
+
181
201
  private
182
202
 
183
203
  def parse_abi(abi)
@@ -27,14 +27,21 @@ module Eth
27
27
  # code which the signer desires to execute in the context of their EOA.
28
28
  class Authorization
29
29
 
30
+ # The EIP-7702 magic byte, prefixed to the RLP-encoded authorization
31
+ # tuple before hashing so that authorization signatures cannot be
32
+ # replayed as transaction signatures.
33
+ # Ref: https://eips.ethereum.org/EIPS/eip-7702
34
+ MAGIC = 0x05.freeze
35
+
30
36
  # The EIP-155 Chain ID.
31
37
  # Ref: https://eips.ethereum.org/EIPS/eip-155
32
38
  attr_reader :chain_id
33
39
 
34
- # The authority addess.
40
+ # The delegation target: the address whose code the authority's
41
+ # account runs. The authority itself is the signer.
35
42
  attr_reader :address
36
43
 
37
- # The transaction nonce.
44
+ # The authority's account nonce this authorization is valid for.
38
45
  attr_reader :nonce
39
46
 
40
47
  # The signature's y-parity byte (not v).
@@ -52,8 +59,8 @@ module Eth
52
59
  #
53
60
  # @param fields [Hash] all necessary transaction fields.
54
61
  # @option fields [Integer] :chain_id the chain ID.
55
- # @option fields [Eth::Address] :address the authority address.
56
- # @option fields [Integer] :nonce the transaction nonce.
62
+ # @option fields [Eth::Address] :address the delegation target address.
63
+ # @option fields [Integer] :nonce the authority's account nonce.
57
64
  def initialize(fields)
58
65
  @chain_id = fields[:chain_id].to_i
59
66
  @address = fields[:address].to_s
@@ -63,46 +70,63 @@ module Eth
63
70
  @signature_s = fields[:s]
64
71
  end
65
72
 
66
- # Sign the authorization with a given key.
73
+ # Sign the authorization with a given key. The key's account becomes
74
+ # the authority, delegating to the code at {#address}; any key may
75
+ # sign for any delegation target.
76
+ #
77
+ # The signed authorization is valid on chain {#chain_id}, or on any
78
+ # chain if that is 0. Anyone holding it can submit it while the
79
+ # account's nonce equals {#nonce}; on each chain where it is included,
80
+ # the code at {#address} then acts as the account until the account
81
+ # delegates elsewhere. Sign only for code you trust.
67
82
  #
68
83
  # @param key [Eth::Key] the key-pair to use for signing.
69
- # @return [String] a transaction hash.
84
+ # @return [String] the hex-encoded hash that was signed, {#unsigned_hash}.
70
85
  # @raise [Signature::SignatureError] if authorization is already signed.
71
- # @raise [Signature::SignatureError] if sender address does not match signing key.
86
+ # @raise [Address::CheckSumError] if {#address} is not a valid address.
72
87
  def sign(key)
73
88
  if Tx.signed? self
74
89
  raise Signature::SignatureError, "Authorization is already signed!"
75
90
  end
76
91
 
77
- # ensure the sender address matches the given key
78
- unless @address.nil? or @address.empty?
79
- signer_address = Tx.sanitize_address key.address.to_s
80
- from_address = Tx.sanitize_address @address
81
- raise Signature::SignatureError, "Signer does not match sender" unless signer_address == from_address
82
- end
92
+ # reject a delegation target that is not a valid address: malformed
93
+ # input yields a tuple clients reject, and an EIP-55 checksum
94
+ # mismatch most likely means a typo in the target
95
+ Address.new @address
83
96
 
84
- # sign a keccak hash of the unsigned, encoded transaction
85
- signature = key.sign(unsigned_hash, @chain_id)
97
+ # sign a keccak hash of the magic-prefixed, encoded authorization;
98
+ # the chain ID is part of that payload, so the signature carries no
99
+ # EIP-155 v and the y-parity is the raw recovery id
100
+ sign_hash = unsigned_hash
101
+ signature = key.sign(sign_hash)
86
102
  r, s, v = Signature.dissect signature
87
- recovery_id = Chain.to_recovery_id v.to_i(16), @chain_id
103
+ recovery_id = Chain.to_recovery_id v.to_i(16)
88
104
  @signature_y_parity = recovery_id
89
105
  @signature_r = r
90
106
  @signature_s = s
91
- return hash
107
+ return Util.bin_to_hex sign_hash
92
108
  end
93
109
 
94
- # Encodes the unsigned authorization payload required for signing.
110
+ # Encodes the unsigned authorization payload required for signing:
111
+ # the {MAGIC} byte followed by `rlp([chain_id, address, nonce])`.
95
112
  #
96
- # @return [String] an RLP-encoded, unsigned, enveloped EIP-7702 transaction.
113
+ # @return [String] the magic-prefixed, RLP-encoded authorization tuple.
97
114
  def unsigned_encoded
98
115
  authorization_data = []
99
116
  authorization_data.push Util.serialize_int_to_big_endian @chain_id
100
117
  authorization_data.push Util.hex_to_bin @address
101
118
  authorization_data.push Util.serialize_int_to_big_endian @nonce
102
- Rlp.encode authorization_data
119
+ authorization_encoded = Rlp.encode authorization_data
120
+
121
+ # prefix the EIP-7702 magic byte to separate the signing domain
122
+ magic = Util.serialize_int_to_big_endian MAGIC
123
+
124
+ return "#{magic}#{authorization_encoded}"
103
125
  end
104
126
 
105
- # Gets the sign-hash required to sign.
127
+ # Gets the sign-hash required to sign: the Keccak-256 hash of
128
+ # {#unsigned_encoded}, which an EIP-7702 client recovers the
129
+ # authority from.
106
130
  #
107
131
  # @return [String] a Keccak-256 hash.
108
132
  def unsigned_hash
data/lib/eth/version.rb CHANGED
@@ -22,7 +22,7 @@ module Eth
22
22
  MINOR = 5.freeze
23
23
 
24
24
  # Defines the patch version of the {Eth} module.
25
- PATCH = 17.freeze
25
+ PATCH = 18.freeze
26
26
 
27
27
  # Defines the version string of the {Eth} module.
28
28
  VERSION = [MAJOR, MINOR, PATCH].join(".").freeze
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.17
4
+ version: 0.5.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Ellis
@@ -14,16 +14,22 @@ dependencies:
14
14
  name: bigdecimal
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '3.1'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5.0'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: '3.1'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: forwardable
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -238,6 +244,7 @@ metadata:
238
244
  changelog_uri: https://github.com/q9f/eth.rb/blob/main/CHANGELOG.md
239
245
  documentation_uri: https://q9f.github.io/eth.rb/
240
246
  github_repo: https://github.com/q9f/eth.rb
247
+ rubygems_mfa_required: 'true'
241
248
  source_code_uri: https://github.com/q9f/eth.rb
242
249
  rdoc_options: []
243
250
  require_paths: