eth 0.5.2 → 0.5.5
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 +4 -4
- data/.github/dependabot.yml +18 -0
- data/.github/workflows/codeql.yml +4 -4
- data/.github/workflows/docs.yml +2 -2
- data/.github/workflows/spec.yml +2 -2
- data/AUTHORS.txt +2 -0
- data/CHANGELOG.md +42 -6
- data/README.md +48 -7
- data/eth.gemspec +1 -1
- data/lib/eth/abi/event.rb +137 -0
- data/lib/eth/abi/type.rb +1 -1
- data/lib/eth/abi.rb +34 -2
- data/lib/eth/chain.rb +7 -1
- data/lib/eth/client.rb +252 -1
- data/lib/eth/contract/event.rb +42 -0
- data/lib/eth/contract/function.rb +57 -0
- data/lib/eth/contract/function_input.rb +37 -0
- data/lib/eth/contract/function_output.rb +37 -0
- data/lib/eth/contract/initializer.rb +47 -0
- data/lib/eth/contract.rb +143 -0
- data/lib/eth/rlp/sedes/binary.rb +2 -2
- data/lib/eth/tx.rb +4 -1
- data/lib/eth/version.rb +1 -1
- data/lib/eth.rb +1 -2
- metadata +18 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 62da01e731dd3a73a356760ac971250f193142090876e62567d73cbb5664213d
|
|
4
|
+
data.tar.gz: 8a951b1b585acd7b58dc327f122dbdd4787145fefbe09d71f1aa4d127787e99e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd1ca2d9f89a545f20cf23a9cff62a83bfe20514b69cb14aac88f08cd101a8bb9e26ba700539259c16d64ee2a3cbae46adf7bedd18b66835785ad701fd515681
|
|
7
|
+
data.tar.gz: a1f51f0dac47d8ce7a4ccd3df0d3decfdb0847df36a4b16587b5dd9ae217aee7375e952207d00611bcb487647ff152d958d4709ebf8b429ec0235220f45d35bd
|
|
@@ -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@
|
|
27
|
+
uses: actions/checkout@v3
|
|
28
28
|
- name: "Initialize CodeQL"
|
|
29
|
-
uses: github/codeql-action/init@
|
|
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@
|
|
33
|
+
uses: github/codeql-action/autobuild@v2
|
|
34
34
|
- name: "Perform CodeQL Analysis"
|
|
35
|
-
uses: github/codeql-action/analyze@
|
|
35
|
+
uses: github/codeql-action/analyze@v2
|
|
36
36
|
- uses: ruby/setup-ruby@v1
|
|
37
37
|
with:
|
|
38
38
|
ruby-version: '2.7'
|
data/.github/workflows/docs.yml
CHANGED
|
@@ -10,7 +10,7 @@ jobs:
|
|
|
10
10
|
docs:
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
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@
|
|
23
|
+
uses: JamesIves/github-pages-deploy-action@v4.3.3
|
|
24
24
|
with:
|
|
25
25
|
branch: gh-pages
|
|
26
26
|
folder: doc/
|
data/.github/workflows/spec.yml
CHANGED
|
@@ -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.
|
|
22
|
+
ruby: ['2.7', '3.1']
|
|
23
23
|
steps:
|
|
24
|
-
- uses: actions/checkout@
|
|
24
|
+
- uses: actions/checkout@v3
|
|
25
25
|
- uses: ruby/setup-ruby@v1
|
|
26
26
|
with:
|
|
27
27
|
ruby-version: ${{ matrix.ruby }}
|
data/AUTHORS.txt
CHANGED
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,7 +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)
|
|
45
|
+
- [2.8. Solidity Compiler Bindings](#28-solidity-compiler-bindings)
|
|
46
|
+
- [2.9. Interact with Smart Contract](#29-interact-with-smart-contract)
|
|
49
47
|
- [3. Documentation](#3-documentation)
|
|
50
48
|
- [4. Testing](#4-testing)
|
|
51
49
|
- [5. Contributing](#5-contributing)
|
|
@@ -231,7 +229,7 @@ cli.get_nonce cli.eth_coinbase["result"]
|
|
|
231
229
|
|
|
232
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.
|
|
233
231
|
|
|
234
|
-
### 2.8 Solidity Compiler Bindings
|
|
232
|
+
### 2.8. Solidity Compiler Bindings
|
|
235
233
|
Link a system-level Solidity compiler (`solc`) to your Ruby library and compile contracts.
|
|
236
234
|
|
|
237
235
|
```ruby
|
|
@@ -253,6 +251,49 @@ contract = solc.compile "spec/fixtures/contracts/greeter.sol"
|
|
|
253
251
|
|
|
254
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.
|
|
255
253
|
|
|
254
|
+
### 2.9. Interact with Smart Contract
|
|
255
|
+
|
|
256
|
+
Create, compile, and deploy smart contracts.
|
|
257
|
+
|
|
258
|
+
```ruby
|
|
259
|
+
contract = Eth::Contract.from_file(file: 'spec/fixtures/contracts/dummy.sol')
|
|
260
|
+
# => #<Eth::Contract::Dummy:0x00007fbeee936598>
|
|
261
|
+
cli = Eth::Client.create "/tmp/geth.ipc"
|
|
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">
|
|
263
|
+
address = cli.deploy_and_wait(contract)
|
|
264
|
+
# => "0x2f2faa160420cee087ded96bad52475147136bd8"
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Transact with or call the deployed contract.
|
|
268
|
+
|
|
269
|
+
```ruby
|
|
270
|
+
cli.transact_and_wait(contract, "set", 1234)
|
|
271
|
+
# => "0x49ca4c0a5729da19a1d2574de9a444a9cd3219bdad81745b54f9cf3bb83b6a06"
|
|
272
|
+
cli.call(contract, "get")
|
|
273
|
+
# => 1234
|
|
274
|
+
```
|
|
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
|
+
|
|
256
297
|
## 3. Documentation
|
|
257
298
|
The documentation can be found at: https://q9f.github.io/eth.rb
|
|
258
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", "
|
|
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"
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
|
16
|
+
|
|
17
|
+
# Provides the {Eth} module.
|
|
18
|
+
module Eth
|
|
19
|
+
|
|
20
|
+
# Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
|
|
21
|
+
module Abi
|
|
22
|
+
|
|
23
|
+
# Provides a module to decode transaction log events.
|
|
24
|
+
module Event
|
|
25
|
+
extend self
|
|
26
|
+
|
|
27
|
+
# Compute topic for ABI event interface.
|
|
28
|
+
#
|
|
29
|
+
# @param interface [Hash] ABI event interface.
|
|
30
|
+
# @return [String] a hex-string topic.
|
|
31
|
+
def compute_topic(interface)
|
|
32
|
+
sig = Abi.signature(interface)
|
|
33
|
+
Util.prefix_hex(Util.bin_to_hex(Util.keccak256(sig)))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# A decoded event log.
|
|
37
|
+
class LogDescription
|
|
38
|
+
# The event ABI interface used to decode the log.
|
|
39
|
+
attr_accessor :event_interface
|
|
40
|
+
|
|
41
|
+
# The the input argument of the event.
|
|
42
|
+
attr_accessor :args
|
|
43
|
+
|
|
44
|
+
# The named input argument of the event.
|
|
45
|
+
attr_accessor :kwargs
|
|
46
|
+
|
|
47
|
+
# The topic hash.
|
|
48
|
+
attr_accessor :topic
|
|
49
|
+
|
|
50
|
+
# Decodes event log argument values.
|
|
51
|
+
#
|
|
52
|
+
# @param event_interface [Hash] event ABI type.
|
|
53
|
+
# @param log [Hash] transaction receipt log
|
|
54
|
+
def initialize(event_interface, log)
|
|
55
|
+
@event_interface = event_interface
|
|
56
|
+
|
|
57
|
+
inputs = event_interface.fetch("inputs")
|
|
58
|
+
data = log.fetch("data")
|
|
59
|
+
topics = log.fetch("topics", [])
|
|
60
|
+
anonymous = event_interface.fetch("anonymous", false)
|
|
61
|
+
|
|
62
|
+
@topic = topics[0] if !anonymous
|
|
63
|
+
@args, @kwargs = Event.decode_log(inputs, data, topics, anonymous)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# The event name. (e.g. Transfer)
|
|
67
|
+
def name
|
|
68
|
+
@name ||= event_interface.fetch("name")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# The event signature. (e.g. Transfer(address,address,uint256))
|
|
72
|
+
def signature
|
|
73
|
+
@signature ||= Abi.signature(event_interface)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Decodes a stream of receipt logs with a set of ABI interfaces.
|
|
78
|
+
#
|
|
79
|
+
# @param interfaces [Array] event ABI types.
|
|
80
|
+
# @param logs [Array] transaction receipt logs
|
|
81
|
+
# @return [Hash] an enumerator of LogDescription objects.
|
|
82
|
+
def decode_logs(interfaces, logs)
|
|
83
|
+
Enumerator.new do |y|
|
|
84
|
+
topic_to_interfaces = Hash[interfaces.map { |i| [compute_topic(i), i] }]
|
|
85
|
+
|
|
86
|
+
logs.each do |log|
|
|
87
|
+
topic = log.fetch("topics", [])[0]
|
|
88
|
+
if topic && interface = topic_to_interfaces[topic]
|
|
89
|
+
y << [log, LogDescription.new(interface, log)]
|
|
90
|
+
else
|
|
91
|
+
y << [log, nil]
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Decodes event log argument values.
|
|
98
|
+
#
|
|
99
|
+
# @param inputs [Array] event ABI types.
|
|
100
|
+
# @param data [String] ABI event data to be decoded.
|
|
101
|
+
# @param topics [Array] ABI event topics to be decoded.
|
|
102
|
+
# @param anonymous [Boolean] If event signature is excluded from topics.
|
|
103
|
+
# @return [[Array, Hash]] decoded positional arguments and decoded keyword arguments.
|
|
104
|
+
# @raise [DecodingError] if decoding fails for type.
|
|
105
|
+
def decode_log(inputs, data, topics, anonymous = false)
|
|
106
|
+
topic_inputs, data_inputs = inputs.partition { |i| i["indexed"] }
|
|
107
|
+
|
|
108
|
+
topic_types = topic_inputs.map { |i| i["type"] }
|
|
109
|
+
data_types = data_inputs.map { |i| i["type"] }
|
|
110
|
+
|
|
111
|
+
# If event is anonymous, all topics are arguments. Otherwise, the first
|
|
112
|
+
# topic will be the event signature.
|
|
113
|
+
if anonymous == false
|
|
114
|
+
topics = topics[1..-1]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
decoded_topics = topics.map.with_index { |t, i| Abi.decode([topic_types[i]], t)[0] }
|
|
118
|
+
decoded_data = Abi.decode(data_types, data)
|
|
119
|
+
|
|
120
|
+
args = []
|
|
121
|
+
kwargs = {}
|
|
122
|
+
|
|
123
|
+
inputs.each_with_index do |input, index|
|
|
124
|
+
if input["indexed"]
|
|
125
|
+
value = decoded_topics[topic_inputs.index(input)]
|
|
126
|
+
else
|
|
127
|
+
value = decoded_data[data_inputs.index(input)]
|
|
128
|
+
end
|
|
129
|
+
args[index] = value
|
|
130
|
+
kwargs[input["name"].to_sym] = value
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
return args, kwargs
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
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
|
|
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
|
@@ -16,12 +16,13 @@
|
|
|
16
16
|
|
|
17
17
|
require "konstructor"
|
|
18
18
|
|
|
19
|
+
require "eth/abi/event"
|
|
19
20
|
require "eth/abi/type"
|
|
20
21
|
|
|
21
22
|
# Provides the {Eth} module.
|
|
22
23
|
module Eth
|
|
23
24
|
|
|
24
|
-
# Provides a Ruby implementation of the Ethereum
|
|
25
|
+
# Provides a Ruby implementation of the Ethereum Application Binary Interface (ABI).
|
|
25
26
|
# ref: https://docs.soliditylang.org/en/develop/abi-spec.html
|
|
26
27
|
module Abi
|
|
27
28
|
extend self
|
|
@@ -43,7 +44,7 @@ module Eth
|
|
|
43
44
|
# @return [String] the encoded ABI data.
|
|
44
45
|
def encode(types, args)
|
|
45
46
|
|
|
46
|
-
#
|
|
47
|
+
# parse all types
|
|
47
48
|
parsed_types = types.map { |t| Type.parse(t) }
|
|
48
49
|
|
|
49
50
|
# prepare the "head"
|
|
@@ -290,6 +291,17 @@ module Eth
|
|
|
290
291
|
end
|
|
291
292
|
end
|
|
292
293
|
|
|
294
|
+
# Build event signature string from ABI interface.
|
|
295
|
+
#
|
|
296
|
+
# @param interface [Hash] ABI event interface.
|
|
297
|
+
# @return [String] interface signature string.
|
|
298
|
+
def signature(interface)
|
|
299
|
+
name = interface.fetch("name")
|
|
300
|
+
inputs = interface.fetch("inputs", [])
|
|
301
|
+
types = inputs.map { |i| i.fetch("type") }
|
|
302
|
+
"#{name}(#{types.join(",")})"
|
|
303
|
+
end
|
|
304
|
+
|
|
293
305
|
private
|
|
294
306
|
|
|
295
307
|
# Properly encodes unsigned integers.
|
|
@@ -334,6 +346,8 @@ module Eth
|
|
|
334
346
|
# Properly encodes byte-strings.
|
|
335
347
|
def encode_bytes(arg, type)
|
|
336
348
|
raise EncodingError, "Expecting String: #{arg}" unless arg.instance_of? String
|
|
349
|
+
arg = handle_hex_string arg, type
|
|
350
|
+
|
|
337
351
|
if type.sub_type.empty?
|
|
338
352
|
size = Util.zpad_int arg.size
|
|
339
353
|
padding = Constant::BYTE_ZERO * (Util.ceil32(arg.size) - arg.size)
|
|
@@ -392,5 +406,23 @@ module Eth
|
|
|
392
406
|
raise EncodingError, "Could not parse address: #{arg}"
|
|
393
407
|
end
|
|
394
408
|
end
|
|
409
|
+
|
|
410
|
+
# The ABI encoder needs to be able to determine between a hex `"123"`
|
|
411
|
+
# and a binary `"123"` string.
|
|
412
|
+
def handle_hex_string(arg, type)
|
|
413
|
+
if Util.is_prefixed? arg or
|
|
414
|
+
(arg.size === type.sub_type.to_i * 2 and Util.is_hex? arg)
|
|
415
|
+
|
|
416
|
+
# There is no way telling whether a string is hex or binary with certainty
|
|
417
|
+
# in Ruby. Therefore, we assume a `0x` prefix to indicate a hex string.
|
|
418
|
+
# Additionally, if the string size is exactly the double of the expected
|
|
419
|
+
# binary size, we can assume a hex value.
|
|
420
|
+
return Util.hex_to_bin arg
|
|
421
|
+
else
|
|
422
|
+
|
|
423
|
+
# Everything else will be assumed binary or raw string.
|
|
424
|
+
return arg.b
|
|
425
|
+
end
|
|
426
|
+
end
|
|
395
427
|
end
|
|
396
428
|
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
|
-
#
|
|
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,6 +149,204 @@ module Eth
|
|
|
149
149
|
end
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
+
# Deploys a contract and waits for it to be mined. Uses
|
|
153
|
+
# `eth_coinbase` or external signer if no sender key is provided.
|
|
154
|
+
#
|
|
155
|
+
# @overload deploy(contract)
|
|
156
|
+
# @param contract [Eth::Contract] contracts to deploy.
|
|
157
|
+
# @overload deploy(contract, *args, **kwargs)
|
|
158
|
+
# @param contract [Eth::Contract] contracts to deploy.
|
|
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
|
+
# @return [String] the contract address.
|
|
163
|
+
def deploy_and_wait(contract, *args, **kwargs)
|
|
164
|
+
hash = wait_for_tx(deploy(contract, *args, **kwargs))
|
|
165
|
+
addr = eth_get_transaction_receipt(hash)["result"]["contractAddress"]
|
|
166
|
+
contract.address = Address.new(addr).to_s
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Deploys a contract. Uses `eth_coinbase` or external signer
|
|
170
|
+
# if no sender key is provided.
|
|
171
|
+
#
|
|
172
|
+
# @overload deploy(contract)
|
|
173
|
+
# @param contract [Eth::Contract] contracts to deploy.
|
|
174
|
+
# @overload deploy(contract, *args, **kwargs)
|
|
175
|
+
# @param contract [Eth::Contract] contracts to deploy.
|
|
176
|
+
# *args Optional variable constructor parameter list
|
|
177
|
+
# **sender_key [Eth::Key] the sender private key.
|
|
178
|
+
# **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
|
179
|
+
# @return [String] the transaction hash.
|
|
180
|
+
# @raise [ArgumentError] in case the contract does not have any source.
|
|
181
|
+
def deploy(contract, *args, **kwargs)
|
|
182
|
+
raise ArgumentError, "Cannot deploy contract without source or binary!" if contract.bin.nil?
|
|
183
|
+
raise ArgumentError, "Missing contract constructor params!" if contract.constructor_inputs.length != args.length
|
|
184
|
+
gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
|
|
185
|
+
data = contract.bin
|
|
186
|
+
unless args.empty?
|
|
187
|
+
data += encode_constructor_params(contract, args)
|
|
188
|
+
end
|
|
189
|
+
params = {
|
|
190
|
+
value: 0,
|
|
191
|
+
gas_limit: gas_limit,
|
|
192
|
+
chain_id: chain_id,
|
|
193
|
+
data: data,
|
|
194
|
+
}
|
|
195
|
+
if kwargs[:legacy]
|
|
196
|
+
params.merge!({
|
|
197
|
+
gas_price: max_fee_per_gas,
|
|
198
|
+
})
|
|
199
|
+
else
|
|
200
|
+
params.merge!({
|
|
201
|
+
priority_fee: max_priority_fee_per_gas,
|
|
202
|
+
max_gas_fee: max_fee_per_gas,
|
|
203
|
+
})
|
|
204
|
+
end
|
|
205
|
+
unless kwargs[:sender_key].nil?
|
|
206
|
+
# Uses the provided key as sender and signer
|
|
207
|
+
params.merge!({
|
|
208
|
+
from: kwargs[:sender_key].address,
|
|
209
|
+
nonce: get_nonce(kwargs[:sender_key].address),
|
|
210
|
+
})
|
|
211
|
+
tx = Eth::Tx.new(params)
|
|
212
|
+
tx.sign kwargs[:sender_key]
|
|
213
|
+
return eth_send_raw_transaction(tx.hex)["result"]
|
|
214
|
+
else
|
|
215
|
+
# Uses the default account as sender and external signer
|
|
216
|
+
params.merge!({
|
|
217
|
+
from: default_account,
|
|
218
|
+
nonce: get_nonce(default_account),
|
|
219
|
+
})
|
|
220
|
+
return eth_send_transaction(params)["result"]
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Calls a contract function without executing it
|
|
225
|
+
# (non-transactional contract read).
|
|
226
|
+
#
|
|
227
|
+
# @overload call(contract, function_name)
|
|
228
|
+
# @param contract [Eth::Contract] subject contract to call.
|
|
229
|
+
# @param function_name [String] method name to be called.
|
|
230
|
+
# @overload call(contract, function_name, value)
|
|
231
|
+
# @param contract [Eth::Contract] subject contract to call.
|
|
232
|
+
# @param function_name [String] method name to be called.
|
|
233
|
+
# @param value [Integer|String] function arguments.
|
|
234
|
+
# @overload call(contract, function_name, value, sender_key, legacy)
|
|
235
|
+
# @param contract [Eth::Contract] subject contract to call.
|
|
236
|
+
# @param function_name [String] method name to be called.
|
|
237
|
+
# @param value [Integer|String] function arguments.
|
|
238
|
+
# @param sender_key [Eth::Key] the sender private key.
|
|
239
|
+
# @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
|
240
|
+
# @return [Object] returns the result of the call.
|
|
241
|
+
def call(contract, function_name, *args, **kwargs)
|
|
242
|
+
func = contract.functions.select { |func| func.name == function_name }[0]
|
|
243
|
+
raise ArgumentError, "function_name does not exist!" if func.nil?
|
|
244
|
+
output = call_raw(contract, func, *args, **kwargs)
|
|
245
|
+
if output&.length == 1
|
|
246
|
+
return output[0]
|
|
247
|
+
else
|
|
248
|
+
return output
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Executes a contract function with a transaction (transactional
|
|
253
|
+
# contract read/write).
|
|
254
|
+
#
|
|
255
|
+
# @overload transact(contract, function_name)
|
|
256
|
+
# @param contract [Eth::Contract] subject contract to call.
|
|
257
|
+
# @param function_name [String] method name to be called.
|
|
258
|
+
# @overload transact(contract, function_name, value)
|
|
259
|
+
# @param contract [Eth::Contract] subject contract to call.
|
|
260
|
+
# @param function_name [String] method name to be called.
|
|
261
|
+
# @param value [Integer|String] function arguments.
|
|
262
|
+
# @overload transact(contract, function_name, value, sender_key, legacy, address)
|
|
263
|
+
# @param contract [Eth::Contract] subject contract to call.
|
|
264
|
+
# @param function_name [String] method name to be called.
|
|
265
|
+
# @param value [Integer|String] function arguments.
|
|
266
|
+
# @param sender_key [Eth::Key] the sender private key.
|
|
267
|
+
# @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
|
268
|
+
# @param address [String] contract address.
|
|
269
|
+
# @return [Object] returns the result of the call.
|
|
270
|
+
def transact(contract, function_name, *args, **kwargs)
|
|
271
|
+
gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
|
|
272
|
+
fun = contract.functions.select { |func| func.name == function_name }[0]
|
|
273
|
+
params = {
|
|
274
|
+
value: 0,
|
|
275
|
+
gas_limit: gas_limit,
|
|
276
|
+
chain_id: chain_id,
|
|
277
|
+
to: kwargs[:address] || contract.address,
|
|
278
|
+
data: call_payload(fun, args),
|
|
279
|
+
}
|
|
280
|
+
if kwargs[:legacy]
|
|
281
|
+
params.merge!({
|
|
282
|
+
gas_price: max_fee_per_gas,
|
|
283
|
+
})
|
|
284
|
+
else
|
|
285
|
+
params.merge!({
|
|
286
|
+
priority_fee: max_priority_fee_per_gas,
|
|
287
|
+
max_gas_fee: max_fee_per_gas,
|
|
288
|
+
})
|
|
289
|
+
end
|
|
290
|
+
unless kwargs[:sender_key].nil?
|
|
291
|
+
# use the provided key as sender and signer
|
|
292
|
+
params.merge!({
|
|
293
|
+
from: kwargs[:sender_key].address,
|
|
294
|
+
nonce: get_nonce(kwargs[:sender_key].address),
|
|
295
|
+
})
|
|
296
|
+
tx = Eth::Tx.new(params)
|
|
297
|
+
tx.sign kwargs[:sender_key]
|
|
298
|
+
return eth_send_raw_transaction(tx.hex)["result"]
|
|
299
|
+
else
|
|
300
|
+
# use the default account as sender and external signer
|
|
301
|
+
params.merge!({
|
|
302
|
+
from: default_account,
|
|
303
|
+
nonce: get_nonce(default_account),
|
|
304
|
+
})
|
|
305
|
+
return eth_send_transaction(params)["result"]
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Executes a contract function with a transaction and waits for it
|
|
310
|
+
# to be mined (transactional contract read/write).
|
|
311
|
+
#
|
|
312
|
+
# @overload transact_and_wait(contract, function_name)
|
|
313
|
+
# @param contract [Eth::Contract] subject contract to call.
|
|
314
|
+
# @param function_name [String] method name to be called.
|
|
315
|
+
# @overload transact_and_wait(contract, function_name, value)
|
|
316
|
+
# @param contract [Eth::Contract] subject contract to call.
|
|
317
|
+
# @param function_name [String] method name to be called.
|
|
318
|
+
# @param value [Integer|String] function arguments.
|
|
319
|
+
# @overload transact_and_wait(contract, function_name, value, sender_key, legacy, address)
|
|
320
|
+
# @param contract [Eth::Contract] subject contract to call.
|
|
321
|
+
# @param function_name [String] method name to be called.
|
|
322
|
+
# @param value [Integer|String] function arguments.
|
|
323
|
+
# @param sender_key [Eth::Key] the sender private key.
|
|
324
|
+
# @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
|
325
|
+
# @param address [String] contract address.
|
|
326
|
+
# @return [Object] returns the result of the call.
|
|
327
|
+
def transact_and_wait(contract, function_name, *args, **kwargs)
|
|
328
|
+
wait_for_tx(transact(contract, function_name, *args, **kwargs))
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# Provides an interface to call `isValidSignature` as per EIP-1271 on a given
|
|
332
|
+
# smart contract to verify the given hash and signature matching the magic
|
|
333
|
+
# value.
|
|
334
|
+
#
|
|
335
|
+
# @param contract [Eth::Contract] a deployed contract implementing EIP-1271.
|
|
336
|
+
# @param hash [String] the message hash to be checked against the signature.
|
|
337
|
+
# @param signature [String] the signature to be recovered by the contract.
|
|
338
|
+
# @param magic [String] the expected magic value (defaults to `1626ba7e`).
|
|
339
|
+
# @return [Boolean] true if magic matches and signature is valid.
|
|
340
|
+
# @raise [ArgumentError] in case the contract cannot be called yet.
|
|
341
|
+
def is_valid_signature(contract, hash, signature, magic = "1626ba7e")
|
|
342
|
+
raise ArgumentError, "Contract not deployed yet." if contract.address.nil?
|
|
343
|
+
hash = Util.hex_to_bin hash if Util.is_hex? hash
|
|
344
|
+
signature = Util.hex_to_bin signature if Util.is_hex? signature
|
|
345
|
+
magic = Util.hex_to_bin magic if Util.is_hex? magic
|
|
346
|
+
result = call(contract, "isValidSignature", hash, signature)
|
|
347
|
+
return result === magic
|
|
348
|
+
end
|
|
349
|
+
|
|
152
350
|
# Gives control over resetting the RPC request ID back to zero.
|
|
153
351
|
# Usually not needed.
|
|
154
352
|
#
|
|
@@ -169,7 +367,7 @@ module Eth
|
|
|
169
367
|
# Waits for an transaction to be mined by the connected chain.
|
|
170
368
|
#
|
|
171
369
|
# @param hash [String] the transaction hash.
|
|
172
|
-
# @return [String] the
|
|
370
|
+
# @return [String] the transaction hash once the transaction is mined.
|
|
173
371
|
# @raise [Timeout::Error] if it's not mined within 5 minutes.
|
|
174
372
|
def wait_for_tx(hash)
|
|
175
373
|
start_time = Time.now
|
|
@@ -193,6 +391,55 @@ module Eth
|
|
|
193
391
|
|
|
194
392
|
private
|
|
195
393
|
|
|
394
|
+
# Non-transactional function call called from call().
|
|
395
|
+
def call_raw(contract, func, *args, **kwargs)
|
|
396
|
+
gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
|
|
397
|
+
params = {
|
|
398
|
+
gas_limit: gas_limit,
|
|
399
|
+
chain_id: chain_id,
|
|
400
|
+
data: call_payload(func, args),
|
|
401
|
+
}
|
|
402
|
+
if kwargs[:address] || contract.address
|
|
403
|
+
params.merge!({ to: kwargs[:address] || contract.address })
|
|
404
|
+
end
|
|
405
|
+
if kwargs[:legacy]
|
|
406
|
+
params.merge!({
|
|
407
|
+
gas_price: max_fee_per_gas,
|
|
408
|
+
})
|
|
409
|
+
else
|
|
410
|
+
params.merge!({
|
|
411
|
+
priority_fee: max_priority_fee_per_gas,
|
|
412
|
+
max_gas_fee: max_fee_per_gas,
|
|
413
|
+
})
|
|
414
|
+
end
|
|
415
|
+
unless kwargs[:sender_key].nil?
|
|
416
|
+
# Uses the provided key as sender and signer
|
|
417
|
+
params.merge!({
|
|
418
|
+
from: kwargs[:sender_key].address,
|
|
419
|
+
nonce: get_nonce(kwargs[:sender_key].address),
|
|
420
|
+
})
|
|
421
|
+
tx = Eth::Tx.new(params)
|
|
422
|
+
tx.sign kwargs[:sender_key]
|
|
423
|
+
end
|
|
424
|
+
raw_result = eth_call(params)["result"]
|
|
425
|
+
types = func.outputs.map { |i| i.type }
|
|
426
|
+
return nil if raw_result == "0x"
|
|
427
|
+
Eth::Abi.decode(types, raw_result)
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# Encodes function call payloads.
|
|
431
|
+
def call_payload(fun, args)
|
|
432
|
+
types = fun.inputs.map { |i| i.type }
|
|
433
|
+
encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
|
|
434
|
+
"0x" + fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
# Encodes constructor params
|
|
438
|
+
def encode_constructor_params(contract, args)
|
|
439
|
+
types = contract.constructor_inputs.map { |input| input.type }
|
|
440
|
+
Util.bin_to_hex(Eth::Abi.encode(types, args))
|
|
441
|
+
end
|
|
442
|
+
|
|
196
443
|
# Prepares parameters and sends the command to the client.
|
|
197
444
|
def send_command(command, args)
|
|
198
445
|
args << "latest" if ["eth_getBalance", "eth_call"].include? command
|
|
@@ -230,3 +477,7 @@ module Eth
|
|
|
230
477
|
end
|
|
231
478
|
end
|
|
232
479
|
end
|
|
480
|
+
|
|
481
|
+
# Load the client/* libraries
|
|
482
|
+
require "eth/client/http"
|
|
483
|
+
require "eth/client/ipc"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
|
16
|
+
|
|
17
|
+
# Provides the {Eth} module.
|
|
18
|
+
module Eth
|
|
19
|
+
|
|
20
|
+
# Provide classes for contract event.
|
|
21
|
+
class Contract::Event
|
|
22
|
+
attr_accessor :name, :signature, :input_types, :inputs, :event_string, :address
|
|
23
|
+
|
|
24
|
+
# Constructor of the {Eth::Contract::Event} class.
|
|
25
|
+
#
|
|
26
|
+
# @param data [Hash] contract event data.
|
|
27
|
+
def initialize(data)
|
|
28
|
+
@name = data["name"]
|
|
29
|
+
@input_types = data["inputs"].collect { |x| x["type"] }
|
|
30
|
+
@inputs = data["inputs"].collect { |x| x["name"] }
|
|
31
|
+
@event_string = "#{@name}(#{@input_types.join(",")})"
|
|
32
|
+
@signature = Digest::Keccak.hexdigest(@event_string, 256)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Set the address of the smart contract
|
|
36
|
+
#
|
|
37
|
+
# @param address [String] contract address.
|
|
38
|
+
def set_address(address)
|
|
39
|
+
@address = address.nil? ? nil : Eth::Address.new(address).address
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
|
16
|
+
|
|
17
|
+
# Provides the {Eth} module.
|
|
18
|
+
module Eth
|
|
19
|
+
|
|
20
|
+
# Provides the methods for smart contract function.
|
|
21
|
+
class Contract::Function
|
|
22
|
+
attr_accessor :name, :inputs, :outputs, :signature, :constant, :function_string
|
|
23
|
+
|
|
24
|
+
# Constructor of the {Eth::Function} class.
|
|
25
|
+
#
|
|
26
|
+
# @param data [Hash] function input and output data.
|
|
27
|
+
def initialize(data)
|
|
28
|
+
@name = data["name"]
|
|
29
|
+
@constant = data["constant"]
|
|
30
|
+
@inputs = data["inputs"].map do |input|
|
|
31
|
+
Eth::Contract::FunctionInput.new(input)
|
|
32
|
+
end
|
|
33
|
+
@outputs = data["outputs"].collect do |output|
|
|
34
|
+
Eth::Contract::FunctionOutput.new(output)
|
|
35
|
+
end
|
|
36
|
+
@function_string = self.class.calc_signature(@name, @inputs)
|
|
37
|
+
@signature = self.class.encoded_function_signature(@function_string)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Creates function strings.
|
|
41
|
+
#
|
|
42
|
+
# @param name [String] function name.
|
|
43
|
+
# @param inputs [Array<Eth::Contract::FunctionInput>] function input class list.
|
|
44
|
+
# @return [String] function string.
|
|
45
|
+
def self.calc_signature(name, inputs)
|
|
46
|
+
"#{name}(#{inputs.collect { |x| x.type }.join(",")})"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Encodes a function signature.
|
|
50
|
+
#
|
|
51
|
+
# @param signature [String] function signature.
|
|
52
|
+
# @return [String] encoded function signature string.
|
|
53
|
+
def self.encoded_function_signature(signature)
|
|
54
|
+
Util.bin_to_hex Util.keccak256(signature)[0..3]
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
|
16
|
+
|
|
17
|
+
# Provides the {Eth} module.
|
|
18
|
+
module Eth
|
|
19
|
+
|
|
20
|
+
# Provide classes for contract function input.
|
|
21
|
+
class Contract::FunctionInput
|
|
22
|
+
attr_accessor :type, :name
|
|
23
|
+
|
|
24
|
+
# Constructor of the {Eth::Contract::FunctionInput} class.
|
|
25
|
+
#
|
|
26
|
+
# @param data [Hash] contract abi data.
|
|
27
|
+
def initialize(data)
|
|
28
|
+
@type = Eth::Abi::Type.parse(data["type"])
|
|
29
|
+
@name = data["name"]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns complete types with subtypes, e.g., `uint256`.
|
|
33
|
+
def type
|
|
34
|
+
@type.base_type + @type.sub_type
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
|
16
|
+
|
|
17
|
+
# Provides the {Eth} module.
|
|
18
|
+
module Eth
|
|
19
|
+
|
|
20
|
+
# Provide classes for contract function output.
|
|
21
|
+
class Contract::FunctionOutput
|
|
22
|
+
attr_accessor :type, :name
|
|
23
|
+
|
|
24
|
+
# Constructor of the {Eth::Contract::FunctionOutput} class.
|
|
25
|
+
#
|
|
26
|
+
# @param data [Hash] contract abi data.
|
|
27
|
+
def initialize(data)
|
|
28
|
+
@type = Eth::Abi::Type.parse(data["type"])
|
|
29
|
+
@name = data["name"]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns complete types with subtypes, e.g., `uint256`.
|
|
33
|
+
def type
|
|
34
|
+
@type.base_type + @type.sub_type
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
|
16
|
+
|
|
17
|
+
# Provides the {Eth} module.
|
|
18
|
+
module Eth
|
|
19
|
+
|
|
20
|
+
# Provide classes for contract initializer.
|
|
21
|
+
class Contract::Initializer
|
|
22
|
+
attr_accessor :contracts, :file
|
|
23
|
+
|
|
24
|
+
# Constructor of the {Eth::Contract::Initializer} class.
|
|
25
|
+
#
|
|
26
|
+
# @param file [String] file path to solidity code.
|
|
27
|
+
def initialize(file)
|
|
28
|
+
sol_output = Eth::Solidity.new.compile(file)
|
|
29
|
+
contracts = sol_output.keys
|
|
30
|
+
|
|
31
|
+
@contracts = []
|
|
32
|
+
contracts.each do |contract|
|
|
33
|
+
abi = sol_output[contract]["abi"]
|
|
34
|
+
name = contract
|
|
35
|
+
code = sol_output[contract]["bin"]
|
|
36
|
+
@contracts << Contract.new(name, code, abi)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Builds and returns all contracts.
|
|
41
|
+
def build_all
|
|
42
|
+
@contracts.each do |contract|
|
|
43
|
+
contract.build
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/eth/contract.rb
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
|
16
|
+
|
|
17
|
+
# Provides the {Eth} module.
|
|
18
|
+
module Eth
|
|
19
|
+
|
|
20
|
+
# Provides classes to access smart contracts
|
|
21
|
+
class Contract
|
|
22
|
+
attr_reader :address
|
|
23
|
+
attr_accessor :key
|
|
24
|
+
attr_accessor :gas_limit, :gas_price, :max_fee_per_gas, :max_priority_fee_per_gas, :nonce
|
|
25
|
+
attr_accessor :bin, :name, :abi, :class_object
|
|
26
|
+
attr_accessor :events, :functions, :constructor_inputs
|
|
27
|
+
|
|
28
|
+
# Constructor of the {Eth::Contract} class.
|
|
29
|
+
#
|
|
30
|
+
# @param name [String] contract name.
|
|
31
|
+
# @param bin [String] contract bin string.
|
|
32
|
+
# @param abi [String] contract abi string.
|
|
33
|
+
def initialize(name, bin, abi)
|
|
34
|
+
@name = name
|
|
35
|
+
@bin = bin
|
|
36
|
+
@abi = abi
|
|
37
|
+
@constructor_inputs, @functions, @events = parse_abi(abi)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Creates a contract wrapper from a Solidity file.
|
|
41
|
+
#
|
|
42
|
+
# @param file [String] solidity file path.
|
|
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
|
+
#
|
|
55
|
+
# @param abi [String] contract abi string.
|
|
56
|
+
# @param address [String] contract address.
|
|
57
|
+
# @param name [String] name of contract.
|
|
58
|
+
# @return [Eth::Contract::Object] Returns the class of the smart contract.
|
|
59
|
+
# @raise [JSON::ParserError] if the json format is wrong.
|
|
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
|
|
66
|
+
contract.address = address
|
|
67
|
+
contract
|
|
68
|
+
end
|
|
69
|
+
|
|
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.
|
|
88
|
+
def address=(addr)
|
|
89
|
+
if addr.is_a? Eth::Address
|
|
90
|
+
@address = addr.to_s
|
|
91
|
+
else
|
|
92
|
+
@address = Eth::Address.new(addr).to_s
|
|
93
|
+
end
|
|
94
|
+
@events.each do |event|
|
|
95
|
+
event.set_address(@address)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Create meta classes for smart contracts.
|
|
100
|
+
def build
|
|
101
|
+
class_name = @name
|
|
102
|
+
parent = self
|
|
103
|
+
class_methods = Class.new do
|
|
104
|
+
extend Forwardable
|
|
105
|
+
def_delegators :parent, :key, :key=
|
|
106
|
+
def_delegators :parent, :name, :abi, :bin
|
|
107
|
+
def_delegators :parent, :gas_limit, :gas_price, :gas_limit=, :gas_price=, :nonce, :nonce=
|
|
108
|
+
def_delegators :parent, :max_fee_per_gas, :max_fee_per_gas=, :max_priority_fee_per_gas, :max_priority_fee_per_gas=
|
|
109
|
+
def_delegators :parent, :events
|
|
110
|
+
def_delegators :parent, :address, :address=
|
|
111
|
+
def_delegator :parent, :functions
|
|
112
|
+
def_delegator :parent, :constructor_inputs
|
|
113
|
+
define_method :parent do
|
|
114
|
+
parent
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
Eth::Contract.send(:remove_const, class_name) if Eth::Contract.const_defined?(class_name, false)
|
|
118
|
+
Eth::Contract.const_set(class_name, class_methods)
|
|
119
|
+
@class_object = class_methods
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
def parse_abi(abi)
|
|
125
|
+
constructor = abi.detect { |x| x["type"] == "constructor" }
|
|
126
|
+
if !constructor.nil?
|
|
127
|
+
constructor_inputs = constructor["inputs"].map { |input| Eth::Contract::FunctionInput.new(input) }
|
|
128
|
+
else
|
|
129
|
+
constructor_inputs = []
|
|
130
|
+
end
|
|
131
|
+
functions = abi.select { |x| x["type"] == "function" }.map { |fun| Eth::Contract::Function.new(fun) }
|
|
132
|
+
events = abi.select { |x| x["type"] == "event" }.map { |evt| Eth::Contract::Event.new(evt) }
|
|
133
|
+
[constructor_inputs, functions, events]
|
|
134
|
+
end
|
|
135
|
+
end
|
|
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"
|
data/lib/eth/rlp/sedes/binary.rb
CHANGED
|
@@ -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
|
|
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
|
|
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/tx.rb
CHANGED
|
@@ -69,13 +69,16 @@ module Eth
|
|
|
69
69
|
# The zero byte is 0x00.
|
|
70
70
|
ZERO_BYTE = "\x00".freeze
|
|
71
71
|
|
|
72
|
+
# Smart contract transaction gas cost
|
|
73
|
+
CREATE_GAS = 32_000.freeze
|
|
74
|
+
|
|
72
75
|
# Creates a new transaction of any type for given parameters and chain ID.
|
|
73
76
|
# Required parameters are (optional in brackets):
|
|
74
77
|
# - EIP-1559: chain_id, nonce, priority_fee, max_gas_fee, gas_limit(, from, to,
|
|
75
78
|
# value, data, access_list)
|
|
76
79
|
# - EIP-2930: chain_id, nonce, gas_price, gas_limit, access_list(, from, to,
|
|
77
80
|
# value, data)
|
|
78
|
-
# - Legacy: nonce, gas_price,
|
|
81
|
+
# - Legacy: nonce, gas_price, gas_limit(, from, to, value, data)
|
|
79
82
|
#
|
|
80
83
|
# @param params [Hash] all necessary transaction fields.
|
|
81
84
|
# @param chain_id [Integer] the EIP-155 Chain ID (legacy transactions only).
|
data/lib/eth/version.rb
CHANGED
data/lib/eth.rb
CHANGED
|
@@ -22,9 +22,8 @@ require "eth/api"
|
|
|
22
22
|
require "eth/address"
|
|
23
23
|
require "eth/chain"
|
|
24
24
|
require "eth/constant"
|
|
25
|
+
require "eth/contract"
|
|
25
26
|
require "eth/client"
|
|
26
|
-
require "eth/client/http"
|
|
27
|
-
require "eth/client/ipc"
|
|
28
27
|
require "eth/eip712"
|
|
29
28
|
require "eth/key"
|
|
30
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.
|
|
4
|
+
version: 0.5.5
|
|
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-
|
|
12
|
+
date: 2022-05-30 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"
|
|
@@ -108,6 +115,7 @@ files:
|
|
|
108
115
|
- eth.gemspec
|
|
109
116
|
- lib/eth.rb
|
|
110
117
|
- lib/eth/abi.rb
|
|
118
|
+
- lib/eth/abi/event.rb
|
|
111
119
|
- lib/eth/abi/type.rb
|
|
112
120
|
- lib/eth/address.rb
|
|
113
121
|
- lib/eth/api.rb
|
|
@@ -116,6 +124,12 @@ files:
|
|
|
116
124
|
- lib/eth/client/http.rb
|
|
117
125
|
- lib/eth/client/ipc.rb
|
|
118
126
|
- lib/eth/constant.rb
|
|
127
|
+
- lib/eth/contract.rb
|
|
128
|
+
- lib/eth/contract/event.rb
|
|
129
|
+
- lib/eth/contract/function.rb
|
|
130
|
+
- lib/eth/contract/function_input.rb
|
|
131
|
+
- lib/eth/contract/function_output.rb
|
|
132
|
+
- lib/eth/contract/initializer.rb
|
|
119
133
|
- lib/eth/eip712.rb
|
|
120
134
|
- lib/eth/key.rb
|
|
121
135
|
- lib/eth/key/decrypter.rb
|