eth 0.5.3 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
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.