eth 0.5.3 → 0.5.6

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: 0375271f13b257337cbc0ab138c2cdf972de8f8e03cf60bb9b672b2221ac988d
4
- data.tar.gz: 19e85a6be34904b5544d9c6845ae19231616d65f27a8146c747f66068f2c23db
3
+ metadata.gz: aabc7ea4a3cd8e94e91e5e9d3bfb0600960079c72e9f99de61d721cae0a73feb
4
+ data.tar.gz: 04e28c96e36958ca58cd49e1e6182a17bf5bc56cab28bd0052f8881899250294
5
5
  SHA512:
6
- metadata.gz: d5cc31684e8dfbff08b7250436a0bd4a94fa90942fd27b03292806cf2ac190673f1e507d8bcabd80b968a7206401a5210298c75c1ecc7c1d94765a7e94654d0d
7
- data.tar.gz: 11b5a667d5cb333848aee384f4276fb3982a69104ae43c9650aec572ec3d093601c44b1b33167029b3ea37bcba6d8fd46da795ada67f6ad50fc39550fd092434
6
+ metadata.gz: 9e7413915597355913492ea5dc22167507ab4d75b3de8783b8c87fb0849e036316f33264053fd166ada749a08215d599197eb4b94d8c954c898aec80bb91f3d7
7
+ data.tar.gz: c8b0a8c288ffe282edbda04d73dff58baa66e9f50dba1998c2450b775ed27201b988048dcfd3b902ac81d19b6dfe9e73d60d86b0c300df7e0cddc301b14ec13c
@@ -0,0 +1,18 @@
1
+ ---
2
+ updates:
3
+ -
4
+ directory: /
5
+ labels:
6
+ - dependencies
7
+ package-ecosystem: bundler
8
+ schedule:
9
+ interval: weekly
10
+ versioning-strategy: increase
11
+ -
12
+ directory: /
13
+ labels:
14
+ - operations
15
+ package-ecosystem: github-actions
16
+ schedule:
17
+ interval: monthly
18
+ version: 2
@@ -24,15 +24,15 @@ jobs:
24
24
  - ruby
25
25
  steps:
26
26
  - name: "Checkout repository"
27
- uses: actions/checkout@v2
27
+ uses: actions/checkout@v3
28
28
  - name: "Initialize CodeQL"
29
- uses: github/codeql-action/init@v1
29
+ uses: github/codeql-action/init@v2
30
30
  with:
31
31
  languages: "${{ matrix.language }}"
32
32
  - name: Autobuild
33
- uses: github/codeql-action/autobuild@v1
33
+ uses: github/codeql-action/autobuild@v2
34
34
  - name: "Perform CodeQL Analysis"
35
- uses: github/codeql-action/analyze@v1
35
+ uses: github/codeql-action/analyze@v2
36
36
  - uses: ruby/setup-ruby@v1
37
37
  with:
38
38
  ruby-version: '2.7'
@@ -10,7 +10,7 @@ jobs:
10
10
  docs:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
- - uses: actions/checkout@v2
13
+ - uses: actions/checkout@v3
14
14
  - uses: ruby/setup-ruby@v1
15
15
  with:
16
16
  ruby-version: '2.7'
@@ -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@4.1.7
23
+ uses: JamesIves/github-pages-deploy-action@v4.3.3
24
24
  with:
25
25
  branch: gh-pages
26
26
  folder: doc/
@@ -19,9 +19,9 @@ jobs:
19
19
  fail-fast: false
20
20
  matrix:
21
21
  os: [ubuntu-latest, macos-latest]
22
- ruby: ['2.7', '3.0']
22
+ ruby: ['2.7', '3.1']
23
23
  steps:
24
- - uses: actions/checkout@v2
24
+ - uses: actions/checkout@v3
25
25
  - uses: ruby/setup-ruby@v1
26
26
  with:
27
27
  ruby-version: ${{ matrix.ruby }}
data/CHANGELOG.md CHANGED
@@ -1,20 +1,60 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [0.5.4]
5
+ ### Added
6
+ - Eth/client: method for eip-1271 ([#80](https://github.com/q9f/eth.rb/pull/80))
7
+
8
+ ### Changed
9
+ - Docs: update changelog ([#77](https://github.com/q9f/eth.rb/pull/77))
10
+ - Gem: bump version to 0.5.4 ([#78](https://github.com/q9f/eth.rb/pull/78))
11
+ - Ci: bump ruby version to 3.1 on ci ([#79](https://github.com/q9f/eth.rb/pull/79))
12
+ - Fix typos ([#81](https://github.com/q9f/eth.rb/pull/81))
13
+ - Eth/contract: allow creating from file, abi, bin ([#83](https://github.com/q9f/eth.rb/pull/83))
14
+ - Eth/client: fix account requirement for client.call() ([#85](https://github.com/q9f/eth.rb/pull/85))
15
+ - Add dependency support for openssl 2.2 and greater, including 3.x ([#88](https://github.com/q9f/eth.rb/pull/88))
16
+
17
+ ## [0.5.3]
18
+ ### Added
19
+ - Smart contract support ([#68](https://github.com/q9f/eth.rb/pull/68))
20
+
21
+ ### Changed
22
+ - Eth/abi: decode event log ([#69](https://github.com/q9f/eth.rb/pull/69))
23
+ - Gem: bump version ([#70](https://github.com/q9f/eth.rb/pull/70))
24
+ - Eth/abi/event: batch log decoder ([#71](https://github.com/q9f/eth.rb/pull/71))
25
+
26
+ ## [0.5.2]
27
+ ### Added
28
+ - Eth/solidity: add solidity compiler bindings ([#66](https://github.com/q9f/eth.rb/pull/66))
29
+
30
+ ### Changed
31
+ - Eth: remove duplicated code ([#62](https://github.com/q9f/eth.rb/pull/62))
32
+ - Ci: allow coverage to drop to 99% without failing ([#63](https://github.com/q9f/eth.rb/pull/63))
33
+ - Docs: update readme ([#64](https://github.com/q9f/eth.rb/pull/64))
34
+ - Docs: add wiki to readme ([#65](https://github.com/q9f/eth.rb/pull/65))
35
+
4
36
  ## [0.5.1]
37
+ ### Added
38
+ - Add eth::rlp module ([#52](https://github.com/q9f/eth.rb/pull/52))
39
+ - Eth/client: implement http/ipc ([#37](https://github.com/q9f/eth.rb/pull/37))
40
+
5
41
  ### Changed
6
42
  - Docs: update changelog ([#61](https://github.com/q9f/eth.rb/pull/61))
7
43
  - Eth/chain: add sepolia chain id; docs ([#60](https://github.com/q9f/eth.rb/pull/60))
8
44
  - Eth/rlp: cleanup ([#59](https://github.com/q9f/eth.rb/pull/59))
9
- - Add eth::rlp module ([#52](https://github.com/q9f/eth.rb/pull/52))
10
45
  - Eth/tx: properly serialize signatures ([#58](https://github.com/q9f/eth.rb/pull/58))
11
46
  - Eth/client: fix legacy transfer ([#57](https://github.com/q9f/eth.rb/pull/57))
12
47
  - Gem: relax openssl requirement ([#56](https://github.com/q9f/eth.rb/pull/56))
13
- - Eth/client: implement http/ipc ([#37](https://github.com/q9f/eth.rb/pull/37))
14
48
  - Docs: update changelog ([#53](https://github.com/q9f/eth.rb/pull/53))
15
49
  - Spec: add upstream test fixtures for keystore ([#50](https://github.com/q9f/eth.rb/pull/50))
16
50
 
17
51
  ## [0.5.0]
52
+ ### Added
53
+ - Eth/tx: create legacy, type-1, and type-2 transactions [#33](https://github.com/q9f/eth.rb/pull/33)
54
+ - Signature: implement eip 712 typed structured data signing [#27](https://github.com/q9f/eth.rb/pull/27)
55
+ - Lib: import ABI to eth/abi [#29](https://github.com/q9f/eth.rb/pull/29)
56
+ - Eth/chains: implement eip 155 for replay protection [#20](https://github.com/q9f/eth.rb/pull/20)
57
+
18
58
  ### Changed
19
59
  - Docs: update readme with features [#49](https://github.com/q9f/eth.rb/pull/49)
20
60
  - Eth/tx: add method to estimate intrinsic gas costs [#48](https://github.com/q9f/eth.rb/pull/48)
@@ -26,16 +66,12 @@ All notable changes to this project will be documented in this file.
26
66
  - Lib: improve error handling [#39](https://github.com/q9f/eth.rb/pull/39)
27
67
  - Docs: update readme for tx and keys [#40](https://github.com/q9f/eth.rb/pull/40)
28
68
  - Implement encrypt/decrypt [#22](https://github.com/q9f/eth.rb/pull/22)
29
- - Eth/tx: create legacy, type-1, and type-2 transactions [#33](https://github.com/q9f/eth.rb/pull/33)
30
69
  - Gem: clean up some docs and scripts [#32](https://github.com/q9f/eth.rb/pull/32)
31
- - Signature: implement eip 712 typed structured data signing [#27](https://github.com/q9f/eth.rb/pull/27)
32
- - Lib: import ABI to eth/abi [#29](https://github.com/q9f/eth.rb/pull/29)
33
70
  - Rename util and chain to singular [#26](https://github.com/q9f/eth.rb/pull/26)
34
71
  - Docs: add some examples to readme [#25](https://github.com/q9f/eth.rb/pull/25)
35
72
  - Key/signature: personal sign and verify [#24](https://github.com/q9f/eth.rb/pull/24)
36
73
  - Ci: only run coverage on CI [#23](https://github.com/q9f/eth.rb/pull/23)
37
74
  - Lib/signature: implement personal_recover (eip 191 [#21](https://github.com/q9f/eth.rb/pull/21)
38
- - Eth/chains: implement eip 155 for replay protection [#20](https://github.com/q9f/eth.rb/pull/20)
39
75
  - Eth/util: public_key_to_address should return an eth::address [#19](https://github.com/q9f/eth.rb/pull/19)
40
76
  - Ci: add docs workflow [#18](https://github.com/q9f/eth.rb/pull/18)
41
77
  - Address class implementation and tests [#13](https://github.com/q9f/eth.rb/pull/13)
data/README.md CHANGED
@@ -21,6 +21,7 @@ What you get:
21
21
  - [x] EIP-155 Replay protection with Chain IDs (with presets)
22
22
  - [x] EIP-191 Ethereum Signed Messages (with prefix and type)
23
23
  - [x] EIP-712 Ethereum Signed Type Data
24
+ - [x] EIP-1271 Smart-Contract Authentification
24
25
  - [x] EIP-1559 Ethereum Type-2 Transactions (with priority fee and max gas fee)
25
26
  - [x] EIP-2028 Call-data intrinsic gas cost estimates (plus access lists)
26
27
  - [x] EIP-2718 Ethereum Transaction Envelopes (and types)
@@ -29,11 +30,7 @@ What you get:
29
30
  - [x] RLP-Encoder and Decoder (including sedes)
30
31
  - [x] RPC-Client (IPC/HTTP) for Execution-Layer APIs
31
32
  - [x] Solidity bindings (compile contracts from Ruby)
32
-
33
- Soon (TM):
34
- - [ ] Smart Contract Support
35
- - [ ] EIP-1271 Smart-Contract Authentification
36
- - [ ] HD-Wallets (BIP-32) and Mnemonics (BIP-39)
33
+ - [x] Full smart-contract support (deploy, transact, and call)
37
34
 
38
35
  Contents:
39
36
  - [1. Installation](#1-installation)
@@ -45,8 +42,8 @@ Contents:
45
42
  - [2.5. Ethereum ABI Encoder and Decoder](#25-ethereum-abi-encoder-and-decoder)
46
43
  - [2.6. Ethereum RLP Encoder and Decoder](#26-ethereum-rlp-encoder-and-decoder)
47
44
  - [2.7. Ethereum RPC-Client](#27-ethereum-rpc-client)
48
- - [2.8 Solidity Compiler Bindings](#28-solidity-compiler-bindings)
49
- - [2.9 Interact with Smart Contract](#29-interact-with-smart-contract)
45
+ - [2.8. Solidity Compiler Bindings](#28-solidity-compiler-bindings)
46
+ - [2.9. Interact with Smart Contract](#29-interact-with-smart-contract)
50
47
  - [3. Documentation](#3-documentation)
51
48
  - [4. Testing](#4-testing)
52
49
  - [5. Contributing](#5-contributing)
@@ -232,7 +229,7 @@ cli.get_nonce cli.eth_coinbase["result"]
232
229
 
233
230
  Check out `Eth::Api` for a list of supported RPC-APIs or consult the [Documentation](https://q9f.github.io/eth.rb/) for more details.
234
231
 
235
- ### 2.8 Solidity Compiler Bindings
232
+ ### 2.8. Solidity Compiler Bindings
236
233
  Link a system-level Solidity compiler (`solc`) to your Ruby library and compile contracts.
237
234
 
238
235
  ```ruby
@@ -254,23 +251,49 @@ contract = solc.compile "spec/fixtures/contracts/greeter.sol"
254
251
 
255
252
  The `contract["Greeter"]["bin"]` could be directly used to deploy the contract as `Eth::Tx` payload. Check out the [Documentation](https://q9f.github.io/eth.rb/) for more details.
256
253
 
257
- ### 2.9 Interact with Smart Contract
254
+ ### 2.9. Interact with Smart Contract
258
255
 
259
- Functions to interact with smart contract.
256
+ Create, compile, and deploy smart contracts.
260
257
 
261
258
  ```ruby
262
- contract = Eth::Contract.create(file: 'spec/fixtures/contracts/dummy.sol')
259
+ contract = Eth::Contract.from_file(file: 'spec/fixtures/contracts/dummy.sol')
263
260
  # => #<Eth::Contract::Dummy:0x00007fbeee936598>
264
261
  cli = Eth::Client.create "/tmp/geth.ipc"
265
262
  # => #<Eth::Client::Ipc:0x00007fbeee946128 @gas_limit=21000, @id=0, @max_fee_per_gas=0.2e11, @max_priority_fee_per_gas=0, @path="/tmp/geth.ipc">
266
263
  address = cli.deploy_and_wait(contract)
267
264
  # => "0x2f2faa160420cee087ded96bad52475147136bd8"
265
+ ```
266
+
267
+ Transact with or call the deployed contract.
268
+
269
+ ```ruby
268
270
  cli.transact_and_wait(contract, "set", 1234)
269
271
  # => "0x49ca4c0a5729da19a1d2574de9a444a9cd3219bdad81745b54f9cf3bb83b6a06"
270
272
  cli.call(contract, "get")
271
273
  # => 1234
272
274
  ```
273
275
 
276
+ Or call an existing contract, e.g., the ENS registry:
277
+
278
+ ```ruby
279
+ ens_registry_abi = '[{"inputs":[{"internalType":"contract ENS","name":"_old","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"label","type":"bytes32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"resolver","type":"address"}],"name":"NewResolver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"NewTTL","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"old","outputs":[{"internalType":"contract ENS","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"recordExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setRecord","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"resolver","type":"address"}],"name":"setResolver","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"label","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"}],"name":"setSubnodeOwner","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"label","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setSubnodeRecord","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setTTL","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"ttl","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"}]'
280
+ ens_registry_address = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
281
+ ens_registry_name = "ENSRegistryWithFallback"
282
+ ens_registry = Eth::Contract.from_abi(name: ens_registry_name, address: ens_registry_address, abi: ens_registry_abi)
283
+ # => #<Eth::Contract::ENSRegistryWithFallback:0x000055bece570980>
284
+ ens_registry.address
285
+ # => "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
286
+ cli.call(ens_registry, "old")
287
+ # => "0x112234455c3a32fd11230c42e7bccd4a84e02010"
288
+ ```
289
+
290
+ The gem also comes with an EIP-1271 smart-contract authentification interface.
291
+
292
+ ```ruby
293
+ cli.is_valid_signature contract, hash, signature
294
+ # => true
295
+ ```
296
+
274
297
  ## 3. Documentation
275
298
  The documentation can be found at: https://q9f.github.io/eth.rb
276
299
 
data/eth.gemspec CHANGED
@@ -44,7 +44,7 @@ Gem::Specification.new do |spec|
44
44
  spec.add_dependency "rbsecp256k1", "~> 5.1"
45
45
 
46
46
  # openssl for encrypted key derivation
47
- spec.add_dependency "openssl", "~> 2.2"
47
+ spec.add_dependency "openssl", ">= 2.2", "< 4.0"
48
48
 
49
49
  # scrypt for encrypted key derivation
50
50
  spec.add_dependency "scrypt", "~> 3.0"
data/lib/eth/abi/event.rb CHANGED
@@ -17,7 +17,7 @@
17
17
  # Provides the {Eth} module.
18
18
  module Eth
19
19
 
20
- # Provides a Ruby implementation of the Ethereum Applicatoin Binary Interface (ABI).
20
+ # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
21
21
  module Abi
22
22
 
23
23
  # Provides a module to decode transaction log events.
data/lib/eth/abi/type.rb CHANGED
@@ -17,7 +17,7 @@
17
17
  # Provides the {Eth} module.
18
18
  module Eth
19
19
 
20
- # Provides a Ruby implementation of the Ethereum Applicatoin Binary Interface (ABI).
20
+ # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
21
21
  module Abi
22
22
 
23
23
  # Provides a class to handle and parse common ABI types.
data/lib/eth/abi.rb CHANGED
@@ -22,7 +22,7 @@ require "eth/abi/type"
22
22
  # Provides the {Eth} module.
23
23
  module Eth
24
24
 
25
- # Provides a Ruby implementation of the Ethereum Applicatoin Binary Interface (ABI).
25
+ # Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
26
26
  # ref: https://docs.soliditylang.org/en/develop/abi-spec.html
27
27
  module Abi
28
28
  extend self
@@ -44,7 +44,7 @@ module Eth
44
44
  # @return [String] the encoded ABI data.
45
45
  def encode(types, args)
46
46
 
47
- # prase all types
47
+ # parse all types
48
48
  parsed_types = types.map { |t| Type.parse(t) }
49
49
 
50
50
  # prepare the "head"
@@ -74,7 +74,7 @@ module Eth
74
74
  # @return [String] the encoded type.
75
75
  # @raise [EncodingError] if value does not match type.
76
76
  def encode_type(type, arg)
77
- if %w(string bytes).include? type.base_type and type.sub_type.empty?
77
+ if %w(string bytes).include? type.base_type and type.sub_type.empty? and type.dimensions.empty?
78
78
  raise EncodingError, "Argument must be a String" unless arg.instance_of? String
79
79
 
80
80
  # encodes strings and bytes
@@ -89,10 +89,24 @@ module Eth
89
89
  head += encode_type Type.size_type, arg.size
90
90
  nested_sub = type.nested_sub
91
91
  nested_sub_size = type.nested_sub.size
92
- arg.size.times do |i|
93
92
 
94
- # ref https://github.com/ethereum/tests/issues/691
95
- raise NotImplementedError, "Encoding dynamic arrays with nested dynamic sub-types is not implemented for ABI." if nested_sub.is_dynamic?
93
+ # calculate offsets
94
+ if %w(string bytes).include?(type.base_type) && type.sub_type.empty?
95
+ offset = 0
96
+ arg.size.times do |i|
97
+ if i == 0
98
+ offset = arg.size * 32
99
+ else
100
+ number_of_words = ((arg[i - 1].size + 32 - 1) / 32).floor
101
+ total_bytes_length = number_of_words * 32
102
+ offset += total_bytes_length + 32
103
+ end
104
+
105
+ head += encode_type Type.size_type, offset
106
+ end
107
+ end
108
+
109
+ arg.size.times do |i|
96
110
  head += encode_type nested_sub, arg[i]
97
111
  end
98
112
  return "#{head}#{tail}"
@@ -306,6 +320,7 @@ module Eth
306
320
 
307
321
  # Properly encodes unsigned integers.
308
322
  def encode_uint(arg, type)
323
+ raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
309
324
  raise ValueOutOfBounds, "Number out of range: #{arg}" if arg > Constant::UINT_MAX or arg < Constant::UINT_MIN
310
325
  real_size = type.sub_type.to_i
311
326
  i = arg.to_i
@@ -315,6 +330,7 @@ module Eth
315
330
 
316
331
  # Properly encodes signed integers.
317
332
  def encode_int(arg, type)
333
+ raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
318
334
  raise ValueOutOfBounds, "Number out of range: #{arg}" if arg > Constant::INT_MAX or arg < Constant::INT_MIN
319
335
  real_size = type.sub_type.to_i
320
336
  i = arg.to_i
@@ -330,6 +346,7 @@ module Eth
330
346
 
331
347
  # Properly encodes unsigned fixed-point numbers.
332
348
  def encode_ufixed(arg, type)
349
+ raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
333
350
  high, low = type.sub_type.split("x").map(&:to_i)
334
351
  raise ValueOutOfBounds, arg unless arg >= 0 and arg < 2 ** high
335
352
  return Util.zpad_int((arg * 2 ** low).to_i)
@@ -337,6 +354,7 @@ module Eth
337
354
 
338
355
  # Properly encodes signed fixed-point numbers.
339
356
  def encode_fixed(arg, type)
357
+ raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
340
358
  high, low = type.sub_type.split("x").map(&:to_i)
341
359
  raise ValueOutOfBounds, arg unless arg >= -2 ** (high - 1) and arg < 2 ** (high - 1)
342
360
  i = (arg * 2 ** low).to_i
@@ -346,6 +364,8 @@ module Eth
346
364
  # Properly encodes byte-strings.
347
365
  def encode_bytes(arg, type)
348
366
  raise EncodingError, "Expecting String: #{arg}" unless arg.instance_of? String
367
+ arg = handle_hex_string arg, type
368
+
349
369
  if type.sub_type.empty?
350
370
  size = Util.zpad_int arg.size
351
371
  padding = Constant::BYTE_ZERO * (Util.ceil32(arg.size) - arg.size)
@@ -404,5 +424,23 @@ module Eth
404
424
  raise EncodingError, "Could not parse address: #{arg}"
405
425
  end
406
426
  end
427
+
428
+ # The ABI encoder needs to be able to determine between a hex `"123"`
429
+ # and a binary `"123"` string.
430
+ 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)
433
+
434
+ # There is no way telling whether a string is hex or binary with certainty
435
+ # in Ruby. Therefore, we assume a `0x` prefix to indicate a hex string.
436
+ # Additionally, if the string size is exactly the double of the expected
437
+ # binary size, we can assume a hex value.
438
+ return Util.hex_to_bin arg
439
+ else
440
+
441
+ # Everything else will be assumed binary or raw string.
442
+ return arg.b
443
+ end
444
+ end
407
445
  end
408
446
  end
data/lib/eth/chain.rb CHANGED
@@ -41,6 +41,9 @@ module Eth
41
41
  # Chain ID for Gnosis mainnet.
42
42
  XDAI = 100.freeze
43
43
 
44
+ # Chain ID for the Polygon Matic mainnet.
45
+ MATIC = 137.freeze
46
+
44
47
  # Chain ID for Arbitrum mainnet.
45
48
  ARBITRUM = 42161.freeze
46
49
 
@@ -77,6 +80,9 @@ module Eth
77
80
  # Chain ID for Optimistic Goerli testnet.
78
81
  GOERLI_OPTIMISM = 420.freeze
79
82
 
83
+ # Chain ID for the Polygon Mumbai testnet.
84
+ MUMBAI = 80001.freeze
85
+
80
86
  # Chain ID for Arbitrum Rinkeby testnet.
81
87
  RINKEBY_ARBITRUM = 421611.freeze
82
88
 
@@ -136,7 +142,7 @@ module Eth
136
142
  return v
137
143
  end
138
144
 
139
- # Converst a `v` value into a chain ID. This does not work for legacy signatures
145
+ # Converts a `v` value into a chain ID. This does not work for legacy signatures
140
146
  # with `v < 36` that do not conform with EIP-155.
141
147
  #
142
148
  # @param v [Integer] the signature's `v` value.
data/lib/eth/client.rb CHANGED
@@ -149,108 +149,55 @@ module Eth
149
149
  end
150
150
  end
151
151
 
152
- # Deploy contract and waits for it to be mined.
153
- # Uses `eth_coinbase` or external signer
154
- # if no sender key is provided.
152
+ # Deploys a contract and waits for it to be mined. Uses
153
+ # `eth_coinbase` or external signer if no sender key is provided.
155
154
  #
156
155
  # @overload deploy(contract)
157
156
  # @param contract [Eth::Contract] contracts to deploy.
158
- # @overload deploy(contract, sender_key)
159
- # @param contract [Eth::Contract] contracts to deploy.
160
- # @param sender_key [Eth::Key] the sender private key.
161
- # @overload deploy(contract, sender_key, legacy)
157
+ # @overload deploy(contract, *args, **kwargs)
162
158
  # @param contract [Eth::Contract] contracts to deploy.
163
- # @param sender_key [Eth::Key] the sender private key.
164
- # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
159
+ # *args Optional variable constructor parameter list
160
+ # **sender_key [Eth::Key] the sender private key.
161
+ # **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
162
+ # **gas_limit [Integer] optional gas limit override for deploying the contract.
165
163
  # @return [String] the contract address.
166
- def deploy_and_wait(contract, sender_key: nil, legacy: false)
167
- hash = wait_for_tx(deploy(contract, sender_key: sender_key, legacy: legacy))
168
- contract.address = eth_get_transaction_receipt(hash)["result"]["contractAddress"]
164
+ def deploy_and_wait(contract, *args, **kwargs)
165
+ hash = wait_for_tx(deploy(contract, *args, **kwargs))
166
+ addr = eth_get_transaction_receipt(hash)["result"]["contractAddress"]
167
+ contract.address = Address.new(addr).to_s
169
168
  end
170
169
 
171
- # Deploy contract. Uses `eth_coinbase` or external signer
170
+ # Deploys a contract. Uses `eth_coinbase` or external signer
172
171
  # if no sender key is provided.
173
172
  #
174
173
  # @overload deploy(contract)
175
174
  # @param contract [Eth::Contract] contracts to deploy.
176
- # @overload deploy(contract, sender_key)
177
- # @param contract [Eth::Contract] contracts to deploy.
178
- # @param sender_key [Eth::Key] the sender private key.
179
- # @overload deploy(contract, sender_key, legacy)
175
+ # @overload deploy(contract, *args, **kwargs)
180
176
  # @param contract [Eth::Contract] contracts to deploy.
181
- # @param sender_key [Eth::Key] the sender private key.
182
- # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
177
+ # *args Optional variable constructor parameter list
178
+ # **sender_key [Eth::Key] the sender private key.
179
+ # **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
180
+ # **gas_limit [Integer] optional gas limit override for deploying the contract.
183
181
  # @return [String] the transaction hash.
184
- def deploy(contract, sender_key: nil, legacy: false)
185
- gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
186
- params = {
187
- value: 0,
188
- gas_limit: gas_limit,
189
- chain_id: chain_id,
190
- data: contract.bin,
191
- }
192
- if legacy
193
- params.merge!({
194
- gas_price: max_fee_per_gas,
195
- })
196
- else
197
- params.merge!({
198
- priority_fee: max_priority_fee_per_gas,
199
- max_gas_fee: max_fee_per_gas,
200
- })
201
- end
202
- unless sender_key.nil?
203
- # use the provided key as sender and signer
204
- params.merge!({
205
- from: sender_key.address,
206
- nonce: get_nonce(sender_key.address),
207
- })
208
- tx = Eth::Tx.new(params)
209
- tx.sign sender_key
210
- return eth_send_raw_transaction(tx.hex)["result"]
211
- else
212
- # use the default account as sender and external signer
213
- params.merge!({
214
- from: default_account,
215
- nonce: get_nonce(default_account),
216
- })
217
- return eth_send_transaction(params)["result"]
182
+ # @raise [ArgumentError] in case the contract does not have any source.
183
+ def deploy(contract, *args, **kwargs)
184
+ raise ArgumentError, "Cannot deploy contract without source or binary!" if contract.bin.nil?
185
+ raise ArgumentError, "Missing contract constructor params!" if contract.constructor_inputs.length != args.length
186
+ data = contract.bin
187
+ unless args.empty?
188
+ data += encode_constructor_params(contract, args)
218
189
  end
219
- end
220
-
221
- # Encoding for function calls.
222
- def call_payload(fun, args)
223
- types = fun.inputs.map { |i| i.type }
224
- encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
225
- "0x" + fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str)
226
- end
227
-
228
- # Non-transactional function call called from call().
229
- #
230
- # @overload call_raw(contract, func)
231
- # @param contract [Eth::Contract] subject contract to call.
232
- # @param func [Eth::Contract::Function] method name to be called.
233
- # @overload call_raw(contract, func, value)
234
- # @param contract [Eth::Contract] subject contract to call.
235
- # @param func [Eth::Contract::Function] method name to be called.
236
- # @param value [Integer|String] function arguments.
237
- # @overload call_raw(contract, func, value, sender_key, legacy)
238
- # @param contract [Eth::Contract] subject contract to call.
239
- # @param func [Eth::Contract::Function] method name to be called.
240
- # @param value [Integer|String] function arguments.
241
- # @param sender_key [Eth::Key] the sender private key.
242
- # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
243
- # @return [Object] returns the result of the call.
244
- def call_raw(contract, func, *args, **kwargs)
245
- gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
190
+ gas_limit = if kwargs[:gas_limit]
191
+ kwargs[:gas_limit]
192
+ else
193
+ Tx.estimate_intrinsic_gas(data) + Tx::CREATE_GAS
194
+ end
246
195
  params = {
196
+ value: 0,
247
197
  gas_limit: gas_limit,
248
198
  chain_id: chain_id,
249
- data: call_payload(func, args),
199
+ data: data,
250
200
  }
251
- if kwargs[:address] || contract.address
252
- params.merge!({ to: kwargs[:address] || contract.address })
253
- end
254
201
  if kwargs[:legacy]
255
202
  params.merge!({
256
203
  gas_price: max_fee_per_gas,
@@ -262,26 +209,26 @@ module Eth
262
209
  })
263
210
  end
264
211
  unless kwargs[:sender_key].nil?
265
- # use the provided key as sender and signer
212
+ # Uses the provided key as sender and signer
266
213
  params.merge!({
267
214
  from: kwargs[:sender_key].address,
268
215
  nonce: get_nonce(kwargs[:sender_key].address),
269
216
  })
270
217
  tx = Eth::Tx.new(params)
271
218
  tx.sign kwargs[:sender_key]
219
+ return eth_send_raw_transaction(tx.hex)["result"]
272
220
  else
273
- # use the default account as sender and external signer
221
+ # Uses the default account as sender and external signer
274
222
  params.merge!({
275
223
  from: default_account,
276
224
  nonce: get_nonce(default_account),
277
225
  })
226
+ return eth_send_transaction(params)["result"]
278
227
  end
279
- raw_result = eth_call(params)["result"]
280
- types = func.outputs.map { |i| i.type }
281
- Eth::Abi.decode(types, raw_result)
282
228
  end
283
229
 
284
- # Non-transactional function calls.
230
+ # Calls a contract function without executing it
231
+ # (non-transactional contract read).
285
232
  #
286
233
  # @overload call(contract, function_name)
287
234
  # @param contract [Eth::Contract] subject contract to call.
@@ -290,25 +237,27 @@ module Eth
290
237
  # @param contract [Eth::Contract] subject contract to call.
291
238
  # @param function_name [String] method name to be called.
292
239
  # @param value [Integer|String] function arguments.
293
- # @overload call(contract, function_name, value, sender_key, legacy)
240
+ # @overload call(contract, function_name, value, sender_key, legacy, gas_limit)
294
241
  # @param contract [Eth::Contract] subject contract to call.
295
242
  # @param function_name [String] method name to be called.
296
243
  # @param value [Integer|String] function arguments.
297
244
  # @param sender_key [Eth::Key] the sender private key.
298
245
  # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
246
+ # @param gas_limit [Integer] optional gas limit override for deploying the contract.
299
247
  # @return [Object] returns the result of the call.
300
248
  def call(contract, function_name, *args, **kwargs)
301
249
  func = contract.functions.select { |func| func.name == function_name }[0]
302
250
  raise ArgumentError, "function_name does not exist!" if func.nil?
303
251
  output = call_raw(contract, func, *args, **kwargs)
304
- if output.length == 1
252
+ if output&.length == 1
305
253
  return output[0]
306
254
  else
307
255
  return output
308
256
  end
309
257
  end
310
258
 
311
- # Function call with transaction.
259
+ # Executes a contract function with a transaction (transactional
260
+ # contract read/write).
312
261
  #
313
262
  # @overload transact(contract, function_name)
314
263
  # @param contract [Eth::Contract] subject contract to call.
@@ -317,16 +266,21 @@ module Eth
317
266
  # @param contract [Eth::Contract] subject contract to call.
318
267
  # @param function_name [String] method name to be called.
319
268
  # @param value [Integer|String] function arguments.
320
- # @overload transact(contract, function_name, value, sender_key, legacy, address)
269
+ # @overload transact(contract, function_name, value, sender_key, legacy, address, gas_limit)
321
270
  # @param contract [Eth::Contract] subject contract to call.
322
271
  # @param function_name [String] method name to be called.
323
272
  # @param value [Integer|String] function arguments.
324
273
  # @param sender_key [Eth::Key] the sender private key.
325
274
  # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
326
275
  # @param address [String] contract address.
276
+ # @param gas_limit [Integer] optional gas limit override for deploying the contract.
327
277
  # @return [Object] returns the result of the call.
328
278
  def transact(contract, function_name, *args, **kwargs)
329
- gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
279
+ gas_limit = if kwargs[:gas_limit]
280
+ kwargs[:gas_limit]
281
+ else
282
+ Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
283
+ end
330
284
  fun = contract.functions.select { |func| func.name == function_name }[0]
331
285
  params = {
332
286
  value: 0,
@@ -364,7 +318,8 @@ module Eth
364
318
  end
365
319
  end
366
320
 
367
- # Function call with transaction and waits for it to be mined.
321
+ # Executes a contract function with a transaction and waits for it
322
+ # to be mined (transactional contract read/write).
368
323
  #
369
324
  # @overload transact_and_wait(contract, function_name)
370
325
  # @param contract [Eth::Contract] subject contract to call.
@@ -385,6 +340,25 @@ module Eth
385
340
  wait_for_tx(transact(contract, function_name, *args, **kwargs))
386
341
  end
387
342
 
343
+ # Provides an interface to call `isValidSignature` as per EIP-1271 on a given
344
+ # smart contract to verify the given hash and signature matching the magic
345
+ # value.
346
+ #
347
+ # @param contract [Eth::Contract] a deployed contract implementing EIP-1271.
348
+ # @param hash [String] the message hash to be checked against the signature.
349
+ # @param signature [String] the signature to be recovered by the contract.
350
+ # @param magic [String] the expected magic value (defaults to `1626ba7e`).
351
+ # @return [Boolean] true if magic matches and signature is valid.
352
+ # @raise [ArgumentError] in case the contract cannot be called yet.
353
+ def is_valid_signature(contract, hash, signature, magic = "1626ba7e")
354
+ raise ArgumentError, "Contract not deployed yet." if contract.address.nil?
355
+ hash = Util.hex_to_bin hash if Util.is_hex? hash
356
+ signature = Util.hex_to_bin signature if Util.is_hex? signature
357
+ magic = Util.hex_to_bin magic if Util.is_hex? magic
358
+ result = call(contract, "isValidSignature", hash, signature)
359
+ return result === magic
360
+ end
361
+
388
362
  # Gives control over resetting the RPC request ID back to zero.
389
363
  # Usually not needed.
390
364
  #
@@ -405,7 +379,7 @@ module Eth
405
379
  # Waits for an transaction to be mined by the connected chain.
406
380
  #
407
381
  # @param hash [String] the transaction hash.
408
- # @return [String] the transactin hash once the transaction is mined.
382
+ # @return [String] the transaction hash once the transaction is mined.
409
383
  # @raise [Timeout::Error] if it's not mined within 5 minutes.
410
384
  def wait_for_tx(hash)
411
385
  start_time = Time.now
@@ -429,6 +403,59 @@ module Eth
429
403
 
430
404
  private
431
405
 
406
+ # Non-transactional function call called from call().
407
+ def call_raw(contract, func, *args, **kwargs)
408
+ gas_limit = if kwargs[:gas_limit]
409
+ kwargs[:gas_limit]
410
+ else
411
+ Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
412
+ end
413
+ params = {
414
+ gas_limit: gas_limit,
415
+ chain_id: chain_id,
416
+ data: call_payload(func, args),
417
+ }
418
+ if kwargs[:address] || contract.address
419
+ params.merge!({ to: kwargs[:address] || contract.address })
420
+ end
421
+ if kwargs[:legacy]
422
+ params.merge!({
423
+ gas_price: max_fee_per_gas,
424
+ })
425
+ else
426
+ params.merge!({
427
+ priority_fee: max_priority_fee_per_gas,
428
+ max_gas_fee: max_fee_per_gas,
429
+ })
430
+ end
431
+ unless kwargs[:sender_key].nil?
432
+ # Uses the provided key as sender and signer
433
+ params.merge!({
434
+ from: kwargs[:sender_key].address,
435
+ nonce: get_nonce(kwargs[:sender_key].address),
436
+ })
437
+ tx = Eth::Tx.new(params)
438
+ tx.sign kwargs[:sender_key]
439
+ end
440
+ raw_result = eth_call(params)["result"]
441
+ types = func.outputs.map { |i| i.type }
442
+ return nil if raw_result == "0x"
443
+ Eth::Abi.decode(types, raw_result)
444
+ end
445
+
446
+ # Encodes function call payloads.
447
+ def call_payload(fun, args)
448
+ types = fun.inputs.map { |i| i.type }
449
+ encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
450
+ "0x" + fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str)
451
+ end
452
+
453
+ # Encodes constructor params
454
+ def encode_constructor_params(contract, args)
455
+ types = contract.constructor_inputs.map { |input| input.type }
456
+ Util.bin_to_hex(Eth::Abi.encode(types, args))
457
+ end
458
+
432
459
  # Prepares parameters and sends the command to the client.
433
460
  def send_command(command, args)
434
461
  args << "latest" if ["eth_getBalance", "eth_call"].include? command
@@ -466,3 +493,7 @@ module Eth
466
493
  end
467
494
  end
468
495
  end
496
+
497
+ # Load the client/* libraries
498
+ require "eth/client/http"
499
+ require "eth/client/ipc"
@@ -16,6 +16,7 @@
16
16
 
17
17
  # Provides the {Eth} module.
18
18
  module Eth
19
+
19
20
  # Provide classes for contract event.
20
21
  class Contract::Event
21
22
  attr_accessor :name, :signature, :input_types, :inputs, :event_string, :address
@@ -16,6 +16,7 @@
16
16
 
17
17
  # Provides the {Eth} module.
18
18
  module Eth
19
+
19
20
  # Provides the methods for smart contract function.
20
21
  class Contract::Function
21
22
  attr_accessor :name, :inputs, :outputs, :signature, :constant, :function_string
@@ -36,21 +37,21 @@ module Eth
36
37
  @signature = self.class.encoded_function_signature(@function_string)
37
38
  end
38
39
 
39
- # Create function strings.
40
+ # Creates function strings.
40
41
  #
41
42
  # @param name [String] function name.
42
43
  # @param inputs [Array<Eth::Contract::FunctionInput>] function input class list.
43
44
  # @return [String] function string.
44
45
  def self.calc_signature(name, inputs)
45
- "#{name}(#{inputs.collect { |x| x.type }.join(",")})"
46
+ "#{name}(#{inputs.collect { |x| x.raw_type }.join(",")})"
46
47
  end
47
48
 
48
- # encode function signature.
49
+ # Encodes a function signature.
49
50
  #
50
51
  # @param signature [String] function signature.
51
52
  # @return [String] encoded function signature string.
52
53
  def self.encoded_function_signature(signature)
53
- Digest::Keccak.hexdigest(signature, 256)[0..7]
54
+ Util.bin_to_hex Util.keccak256(signature)[0..3]
54
55
  end
55
56
  end
56
57
  end
@@ -16,19 +16,21 @@
16
16
 
17
17
  # Provides the {Eth} module.
18
18
  module Eth
19
+
19
20
  # Provide classes for contract function input.
20
21
  class Contract::FunctionInput
21
- attr_accessor :type, :name
22
+ attr_accessor :type, :raw_type, :name
22
23
 
23
24
  # Constructor of the {Eth::Contract::FunctionInput} class.
24
25
  #
25
26
  # @param data [Hash] contract abi data.
26
27
  def initialize(data)
28
+ @raw_type = data["type"]
27
29
  @type = Eth::Abi::Type.parse(data["type"])
28
30
  @name = data["name"]
29
31
  end
30
32
 
31
- # Returns types like uint256
33
+ # Returns complete types with subtypes, e.g., `uint256`.
32
34
  def type
33
35
  @type.base_type + @type.sub_type
34
36
  end
@@ -16,15 +16,20 @@
16
16
 
17
17
  # Provides the {Eth} module.
18
18
  module Eth
19
+
19
20
  # Provide classes for contract function output.
20
21
  class Contract::FunctionOutput
21
22
  attr_accessor :type, :name
22
23
 
24
+ # Constructor of the {Eth::Contract::FunctionOutput} class.
25
+ #
26
+ # @param data [Hash] contract abi data.
23
27
  def initialize(data)
24
28
  @type = Eth::Abi::Type.parse(data["type"])
25
29
  @name = data["name"]
26
30
  end
27
31
 
32
+ # Returns complete types with subtypes, e.g., `uint256`.
28
33
  def type
29
34
  @type.base_type + @type.sub_type
30
35
  end
@@ -16,6 +16,7 @@
16
16
 
17
17
  # Provides the {Eth} module.
18
18
  module Eth
19
+
19
20
  # Provide classes for contract initializer.
20
21
  class Contract::Initializer
21
22
  attr_accessor :contracts, :file
@@ -36,7 +37,7 @@ module Eth
36
37
  end
37
38
  end
38
39
 
39
- # Build and return all contracts.
40
+ # Builds and returns all contracts.
40
41
  def build_all
41
42
  @contracts.each do |contract|
42
43
  contract.build
data/lib/eth/contract.rb CHANGED
@@ -37,51 +37,66 @@ module Eth
37
37
  @constructor_inputs, @functions, @events = parse_abi(abi)
38
38
  end
39
39
 
40
- # Creates a contract wrapper.
40
+ # Creates a contract wrapper from a Solidity file.
41
41
  #
42
42
  # @param file [String] solidity file path.
43
- # @param bin [String] contract bin string.
43
+ # @param contract_index [Number] specify contract.
44
+ # @return [Eth::Contract::Object] Returns the class of the smart contract.
45
+ # @raise [ArgumentError] if the file path is empty or no contracts were compiled.
46
+ def self.from_file(file:, contract_index: 0)
47
+ raise ArgumentError, "Cannot find the contract at #{file.to_s}!" if !File.exist?(file.to_s)
48
+ contracts = Eth::Contract::Initializer.new(file).build_all
49
+ raise ArgumentError, "No contracts compiled." if contracts.empty?
50
+ contracts[contract_index].class_object.new
51
+ end
52
+
53
+ # Creates a contract wrapper from ABI and address.
54
+ #
44
55
  # @param abi [String] contract abi string.
45
56
  # @param address [String] contract address.
46
57
  # @param name [String] name of contract.
47
- # @param contract_index [Number] specify contract.
48
58
  # @return [Eth::Contract::Object] Returns the class of the smart contract.
49
59
  # @raise [JSON::ParserError] if the json format is wrong.
50
- # @raise [ArgumentError] if argument is incorrect.
51
- def self.create(file: nil, bin: nil, abi: nil, address: nil, name: nil, contract_index: nil)
52
- if File.exist?(file.to_s)
53
- contracts = Eth::Contract::Initializer.new(file).build_all
54
- raise "No contracts compiled" if contracts.empty?
55
- if contract_index
56
- contract = contracts[contract_index].class_object.new
57
- else
58
- contract = contracts.first.class_object.new
59
- end
60
- elsif ![name, bin, abi].include? nil
61
- begin
62
- abi = abi.is_a?(Array) ? abi : JSON.parse(abi)
63
- rescue JSON::ParserError => e
64
- raise e
65
- end
66
- contract = Eth::Contract.new(name, bin, abi)
67
- contract.build
68
- contract = contract.class_object.new
69
- else
70
- raise ArgumentError, "The argument is incorrect."
71
- end
60
+ # @raise [ArgumentError] if ABI, address, or name is missing.
61
+ def self.from_abi(abi:, address:, name:)
62
+ abi = abi.is_a?(Array) ? abi : JSON.parse(abi)
63
+ contract = Eth::Contract.new(name, nil, abi)
64
+ contract.build
65
+ contract = contract.class_object.new
72
66
  contract.address = address
73
67
  contract
74
68
  end
75
69
 
76
- # Set the address of the smart contract
70
+ # Creates a contract wrapper from binary and ABI.
71
+ #
72
+ # @param bin [String] contract bin string.
73
+ # @param abi [String] contract abi string.
74
+ # @param name [String] name of contract.
75
+ # @return [Eth::Contract::Object] Returns the class of the smart contract.
76
+ # @raise [JSON::ParserError] if the json format is wrong.
77
+ # @raise [ArgumentError] if ABI, binary, or name is missing.
78
+ def self.from_bin(bin:, abi:, name:)
79
+ abi = abi.is_a?(Array) ? abi : JSON.parse(abi)
80
+ contract = Eth::Contract.new(name, bin, abi)
81
+ contract.build
82
+ contract.class_object.new
83
+ end
84
+
85
+ # Sets the address of the smart contract.
86
+ #
87
+ # @param addr [String|Eth::Address] contract address string.
77
88
  def address=(addr)
78
- @address = addr.nil? ? nil : Eth::Address.new(addr).address
89
+ if addr.is_a? Eth::Address
90
+ @address = addr.to_s
91
+ else
92
+ @address = Eth::Address.new(addr).to_s
93
+ end
79
94
  @events.each do |event|
80
95
  event.set_address(@address)
81
96
  end
82
97
  end
83
98
 
84
- # Create classes for smart contracts
99
+ # Create meta classes for smart contracts.
85
100
  def build
86
101
  class_name = @name
87
102
  parent = self
@@ -94,6 +109,7 @@ module Eth
94
109
  def_delegators :parent, :events
95
110
  def_delegators :parent, :address, :address=
96
111
  def_delegator :parent, :functions
112
+ def_delegator :parent, :constructor_inputs
97
113
  define_method :parent do
98
114
  parent
99
115
  end
@@ -118,3 +134,10 @@ module Eth
118
134
  end
119
135
  end
120
136
  end
137
+
138
+ # Load the contract/* libraries
139
+ require "eth/contract/event"
140
+ require "eth/contract/function"
141
+ require "eth/contract/function_input"
142
+ require "eth/contract/function_output"
143
+ require "eth/contract/initializer"
@@ -29,7 +29,7 @@ module Eth
29
29
  # A singleton class for binary values of fixed length.
30
30
  class << self
31
31
 
32
- # Create a serializable bianry of fixed size.
32
+ # Create a serializable binary of fixed size.
33
33
  #
34
34
  # @param l [Integer] the fixed size of the binary.
35
35
  # @param allow_empty [Boolean] indicator wether empty binaries should be allowed.
@@ -47,7 +47,7 @@ module Eth
47
47
  end
48
48
  end
49
49
 
50
- # Create a serializable bianry of variable size.
50
+ # Create a serializable binary of variable size.
51
51
  #
52
52
  # @param min_length [Integer] the minimum size of the binary.
53
53
  # @param max_length [Integer] the maximum size of the binary.
data/lib/eth/signature.rb CHANGED
@@ -38,7 +38,7 @@ module Eth
38
38
  # @param message [String] the message string to be prefixed.
39
39
  # @return [String] an EIP-191 prefixed string.
40
40
  def prefix_message(message)
41
- "#{EIP191_PREFIX_BYTE}Ethereum Signed Message:\n#{message.size}#{message}"
41
+ "#{EIP191_PREFIX_BYTE}Ethereum Signed Message:\n#{message.bytesize}#{message}"
42
42
  end
43
43
 
44
44
  # Dissects a signature blob of 65+ bytes into its `r`, `s`, and `v`
data/lib/eth/tx.rb CHANGED
@@ -78,7 +78,7 @@ module Eth
78
78
  # value, data, access_list)
79
79
  # - EIP-2930: chain_id, nonce, gas_price, gas_limit, access_list(, from, to,
80
80
  # value, data)
81
- # - Legacy: nonce, gas_price, gas_lmit(, from, to, value, data)
81
+ # - Legacy: nonce, gas_price, gas_limit(, from, to, value, data)
82
82
  #
83
83
  # @param params [Hash] all necessary transaction fields.
84
84
  # @param chain_id [Integer] the EIP-155 Chain ID (legacy transactions only).
data/lib/eth/version.rb CHANGED
@@ -16,5 +16,5 @@
16
16
  module Eth
17
17
 
18
18
  # Defines the version of the {Eth} module.
19
- VERSION = "0.5.3".freeze
19
+ VERSION = "0.5.6".freeze
20
20
  end
data/lib/eth.rb CHANGED
@@ -23,14 +23,7 @@ require "eth/address"
23
23
  require "eth/chain"
24
24
  require "eth/constant"
25
25
  require "eth/contract"
26
- require "eth/contract/event"
27
- require "eth/contract/function"
28
- require "eth/contract/function_input"
29
- require "eth/contract/function_output"
30
- require "eth/contract/initializer"
31
26
  require "eth/client"
32
- require "eth/client/http"
33
- require "eth/client/ipc"
34
27
  require "eth/eip712"
35
28
  require "eth/key"
36
29
  require "eth/rlp"
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.3
4
+ version: 0.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Ellis
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-05-06 00:00:00.000000000 Z
12
+ date: 2022-07-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: keccak
@@ -57,16 +57,22 @@ dependencies:
57
57
  name: openssl
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - "~>"
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
62
  version: '2.2'
63
+ - - "<"
64
+ - !ruby/object:Gem::Version
65
+ version: '4.0'
63
66
  type: :runtime
64
67
  prerelease: false
65
68
  version_requirements: !ruby/object:Gem::Requirement
66
69
  requirements:
67
- - - "~>"
70
+ - - ">="
68
71
  - !ruby/object:Gem::Version
69
72
  version: '2.2'
73
+ - - "<"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
70
76
  - !ruby/object:Gem::Dependency
71
77
  name: scrypt
72
78
  requirement: !ruby/object:Gem::Requirement
@@ -89,6 +95,7 @@ executables: []
89
95
  extensions: []
90
96
  extra_rdoc_files: []
91
97
  files:
98
+ - ".github/dependabot.yml"
92
99
  - ".github/workflows/codeql.yml"
93
100
  - ".github/workflows/docs.yml"
94
101
  - ".github/workflows/spec.yml"
@@ -170,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
177
  - !ruby/object:Gem::Version
171
178
  version: '0'
172
179
  requirements: []
173
- rubygems_version: 3.3.8
180
+ rubygems_version: 3.3.15
174
181
  signing_key:
175
182
  specification_version: 4
176
183
  summary: Ruby Ethereum library.