eth 0.5.3 → 0.5.4
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/workflows/spec.yml +1 -1
- data/CHANGELOG.md +29 -6
- data/README.md +34 -11
- data/eth.gemspec +1 -1
- data/lib/eth/abi/event.rb +1 -1
- data/lib/eth/abi/type.rb +1 -1
- data/lib/eth/abi.rb +2 -2
- data/lib/eth/chain.rb +1 -1
- data/lib/eth/client.rb +75 -72
- data/lib/eth/contract.rb +43 -28
- data/lib/eth/rlp/sedes/binary.rb +2 -2
- data/lib/eth/tx.rb +1 -1
- data/lib/eth/version.rb +1 -1
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af4a4068c445fcbb0ec94375ffdf650894464bf62d69dd7a14af232452c3af3c
|
4
|
+
data.tar.gz: a962fe008b6ecb75bdc5a70c9363aa31f95d84f82359da53e7195544bbcb9db2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d909d4249f0f7a72cae28c0f4208e1aa8c8ba69779149a20ececf4a53cd6186b43062d7a9aa5921e3c3fee9f3e014df8e6dd01586c0651f714d9bca47a4953da
|
7
|
+
data.tar.gz: ad74d13143142ab3cf71cadfa79cbd1a7a9cf2628c0b5b6e279edd4385b20764b837e14b0f8f7f24d55884893a7b79b4c1323f89aca66adfa40eb6af8bd4db41
|
data/.github/workflows/spec.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,20 +1,47 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [0.5.3]
|
5
|
+
### Added
|
6
|
+
- Smart contract support ([#68](https://github.com/q9f/eth.rb/pull/68))
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
- Eth/abi: decode event log ([#69](https://github.com/q9f/eth.rb/pull/69))
|
10
|
+
- Gem: bump version ([#70](https://github.com/q9f/eth.rb/pull/70))
|
11
|
+
- Eth/abi/event: batch log decoder ([#71](https://github.com/q9f/eth.rb/pull/71))
|
12
|
+
|
13
|
+
## [0.5.2]
|
14
|
+
### Added
|
15
|
+
- Eth/solidity: add solidity compiler bindings ([#66](https://github.com/q9f/eth.rb/pull/66))
|
16
|
+
|
17
|
+
### Changed
|
18
|
+
- Eth: remove duplicated code ([#62](https://github.com/q9f/eth.rb/pull/62))
|
19
|
+
- Ci: allow coverage to drop to 99% without failing ([#63](https://github.com/q9f/eth.rb/pull/63))
|
20
|
+
- Docs: update readme ([#64](https://github.com/q9f/eth.rb/pull/64))
|
21
|
+
- Docs: add wiki to readme ([#65](https://github.com/q9f/eth.rb/pull/65))
|
22
|
+
|
4
23
|
## [0.5.1]
|
24
|
+
### Added
|
25
|
+
- Add eth::rlp module ([#52](https://github.com/q9f/eth.rb/pull/52))
|
26
|
+
- Eth/client: implement http/ipc ([#37](https://github.com/q9f/eth.rb/pull/37))
|
27
|
+
|
5
28
|
### Changed
|
6
29
|
- Docs: update changelog ([#61](https://github.com/q9f/eth.rb/pull/61))
|
7
30
|
- Eth/chain: add sepolia chain id; docs ([#60](https://github.com/q9f/eth.rb/pull/60))
|
8
31
|
- 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
32
|
- Eth/tx: properly serialize signatures ([#58](https://github.com/q9f/eth.rb/pull/58))
|
11
33
|
- Eth/client: fix legacy transfer ([#57](https://github.com/q9f/eth.rb/pull/57))
|
12
34
|
- 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
35
|
- Docs: update changelog ([#53](https://github.com/q9f/eth.rb/pull/53))
|
15
36
|
- Spec: add upstream test fixtures for keystore ([#50](https://github.com/q9f/eth.rb/pull/50))
|
16
37
|
|
17
38
|
## [0.5.0]
|
39
|
+
### Added
|
40
|
+
- Eth/tx: create legacy, type-1, and type-2 transactions [#33](https://github.com/q9f/eth.rb/pull/33)
|
41
|
+
- Signature: implement eip 712 typed structured data signing [#27](https://github.com/q9f/eth.rb/pull/27)
|
42
|
+
- Lib: import ABI to eth/abi [#29](https://github.com/q9f/eth.rb/pull/29)
|
43
|
+
- Eth/chains: implement eip 155 for replay protection [#20](https://github.com/q9f/eth.rb/pull/20)
|
44
|
+
|
18
45
|
### Changed
|
19
46
|
- Docs: update readme with features [#49](https://github.com/q9f/eth.rb/pull/49)
|
20
47
|
- Eth/tx: add method to estimate intrinsic gas costs [#48](https://github.com/q9f/eth.rb/pull/48)
|
@@ -26,16 +53,12 @@ All notable changes to this project will be documented in this file.
|
|
26
53
|
- Lib: improve error handling [#39](https://github.com/q9f/eth.rb/pull/39)
|
27
54
|
- Docs: update readme for tx and keys [#40](https://github.com/q9f/eth.rb/pull/40)
|
28
55
|
- 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
56
|
- 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
57
|
- Rename util and chain to singular [#26](https://github.com/q9f/eth.rb/pull/26)
|
34
58
|
- Docs: add some examples to readme [#25](https://github.com/q9f/eth.rb/pull/25)
|
35
59
|
- Key/signature: personal sign and verify [#24](https://github.com/q9f/eth.rb/pull/24)
|
36
60
|
- Ci: only run coverage on CI [#23](https://github.com/q9f/eth.rb/pull/23)
|
37
61
|
- 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
62
|
- Eth/util: public_key_to_address should return an eth::address [#19](https://github.com/q9f/eth.rb/pull/19)
|
40
63
|
- Ci: add docs workflow [#18](https://github.com/q9f/eth.rb/pull/18)
|
41
64
|
- 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
|
-
|
256
|
+
Create, compile, and deploy smart contracts.
|
260
257
|
|
261
258
|
```ruby
|
262
|
-
contract = Eth::Contract.
|
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", "
|
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
|
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
|
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
|
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
|
-
#
|
47
|
+
# parse all types
|
48
48
|
parsed_types = types.map { |t| Type.parse(t) }
|
49
49
|
|
50
50
|
# prepare the "head"
|
data/lib/eth/chain.rb
CHANGED
@@ -136,7 +136,7 @@ module Eth
|
|
136
136
|
return v
|
137
137
|
end
|
138
138
|
|
139
|
-
#
|
139
|
+
# Converts a `v` value into a chain ID. This does not work for legacy signatures
|
140
140
|
# with `v < 36` that do not conform with EIP-155.
|
141
141
|
#
|
142
142
|
# @param v [Integer] the signature's `v` value.
|
data/lib/eth/client.rb
CHANGED
@@ -149,9 +149,8 @@ module Eth
|
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
152
|
-
#
|
153
|
-
#
|
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.
|
@@ -165,10 +164,11 @@ module Eth
|
|
165
164
|
# @return [String] the contract address.
|
166
165
|
def deploy_and_wait(contract, sender_key: nil, legacy: false)
|
167
166
|
hash = wait_for_tx(deploy(contract, sender_key: sender_key, legacy: legacy))
|
168
|
-
|
167
|
+
addr = eth_get_transaction_receipt(hash)["result"]["contractAddress"]
|
168
|
+
contract.address = Address.new(addr).to_s
|
169
169
|
end
|
170
170
|
|
171
|
-
#
|
171
|
+
# Deploys a contract. Uses `eth_coinbase` or external signer
|
172
172
|
# if no sender key is provided.
|
173
173
|
#
|
174
174
|
# @overload deploy(contract)
|
@@ -181,7 +181,9 @@ module Eth
|
|
181
181
|
# @param sender_key [Eth::Key] the sender private key.
|
182
182
|
# @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
183
183
|
# @return [String] the transaction hash.
|
184
|
+
# @raise [ArgumentError] in case the contract does not have any source.
|
184
185
|
def deploy(contract, sender_key: nil, legacy: false)
|
186
|
+
raise ArgumentError, "Cannot deploy contract without source or binary!" if contract.bin.nil?
|
185
187
|
gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
|
186
188
|
params = {
|
187
189
|
value: 0,
|
@@ -218,70 +220,8 @@ module Eth
|
|
218
220
|
end
|
219
221
|
end
|
220
222
|
|
221
|
-
#
|
222
|
-
|
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
|
246
|
-
params = {
|
247
|
-
gas_limit: gas_limit,
|
248
|
-
chain_id: chain_id,
|
249
|
-
data: call_payload(func, args),
|
250
|
-
}
|
251
|
-
if kwargs[:address] || contract.address
|
252
|
-
params.merge!({ to: kwargs[:address] || contract.address })
|
253
|
-
end
|
254
|
-
if kwargs[:legacy]
|
255
|
-
params.merge!({
|
256
|
-
gas_price: max_fee_per_gas,
|
257
|
-
})
|
258
|
-
else
|
259
|
-
params.merge!({
|
260
|
-
priority_fee: max_priority_fee_per_gas,
|
261
|
-
max_gas_fee: max_fee_per_gas,
|
262
|
-
})
|
263
|
-
end
|
264
|
-
unless kwargs[:sender_key].nil?
|
265
|
-
# use the provided key as sender and signer
|
266
|
-
params.merge!({
|
267
|
-
from: kwargs[:sender_key].address,
|
268
|
-
nonce: get_nonce(kwargs[:sender_key].address),
|
269
|
-
})
|
270
|
-
tx = Eth::Tx.new(params)
|
271
|
-
tx.sign kwargs[:sender_key]
|
272
|
-
else
|
273
|
-
# use the default account as sender and external signer
|
274
|
-
params.merge!({
|
275
|
-
from: default_account,
|
276
|
-
nonce: get_nonce(default_account),
|
277
|
-
})
|
278
|
-
end
|
279
|
-
raw_result = eth_call(params)["result"]
|
280
|
-
types = func.outputs.map { |i| i.type }
|
281
|
-
Eth::Abi.decode(types, raw_result)
|
282
|
-
end
|
283
|
-
|
284
|
-
# Non-transactional function calls.
|
223
|
+
# Calls a contract function without executing it
|
224
|
+
# (non-transactional contract read).
|
285
225
|
#
|
286
226
|
# @overload call(contract, function_name)
|
287
227
|
# @param contract [Eth::Contract] subject contract to call.
|
@@ -308,7 +248,8 @@ module Eth
|
|
308
248
|
end
|
309
249
|
end
|
310
250
|
|
311
|
-
#
|
251
|
+
# Executes a contract function with a transaction (transactional
|
252
|
+
# contract read/write).
|
312
253
|
#
|
313
254
|
# @overload transact(contract, function_name)
|
314
255
|
# @param contract [Eth::Contract] subject contract to call.
|
@@ -364,7 +305,8 @@ module Eth
|
|
364
305
|
end
|
365
306
|
end
|
366
307
|
|
367
|
-
#
|
308
|
+
# Executes a contract function with a transaction and waits for it
|
309
|
+
# to be mined (transactional contract read/write).
|
368
310
|
#
|
369
311
|
# @overload transact_and_wait(contract, function_name)
|
370
312
|
# @param contract [Eth::Contract] subject contract to call.
|
@@ -385,6 +327,25 @@ module Eth
|
|
385
327
|
wait_for_tx(transact(contract, function_name, *args, **kwargs))
|
386
328
|
end
|
387
329
|
|
330
|
+
# Provides an interface to call `isValidSignature` as per EIP-1271 on a given
|
331
|
+
# smart contract to verify the given hash and signature matching the magic
|
332
|
+
# value.
|
333
|
+
#
|
334
|
+
# @param contract [Eth::Contract] a deployed contract implementing EIP-1271.
|
335
|
+
# @param hash [String] the message hash to be checked against the signature.
|
336
|
+
# @param signature [String] the signature to be recovered by the contract.
|
337
|
+
# @param magic [String] the expected magic value (defaults to `1626ba7e`).
|
338
|
+
# @return [Boolean] true if magic matches and signature is valid.
|
339
|
+
# @raise [ArgumentError] in case the contract cannot be called yet.
|
340
|
+
def is_valid_signature(contract, hash, signature, magic = "1626ba7e")
|
341
|
+
raise ArgumentError, "Contract not deployed yet." if contract.address.nil?
|
342
|
+
hash = Util.hex_to_bin hash if Util.is_hex? hash
|
343
|
+
signature = Util.hex_to_bin signature if Util.is_hex? signature
|
344
|
+
magic = Util.hex_to_bin magic if Util.is_hex? magic
|
345
|
+
result = call(contract, "isValidSignature", hash, signature)
|
346
|
+
return result === magic
|
347
|
+
end
|
348
|
+
|
388
349
|
# Gives control over resetting the RPC request ID back to zero.
|
389
350
|
# Usually not needed.
|
390
351
|
#
|
@@ -405,7 +366,7 @@ module Eth
|
|
405
366
|
# Waits for an transaction to be mined by the connected chain.
|
406
367
|
#
|
407
368
|
# @param hash [String] the transaction hash.
|
408
|
-
# @return [String] the
|
369
|
+
# @return [String] the transaction hash once the transaction is mined.
|
409
370
|
# @raise [Timeout::Error] if it's not mined within 5 minutes.
|
410
371
|
def wait_for_tx(hash)
|
411
372
|
start_time = Time.now
|
@@ -429,6 +390,48 @@ module Eth
|
|
429
390
|
|
430
391
|
private
|
431
392
|
|
393
|
+
# Non-transactional function call called from call().
|
394
|
+
def call_raw(contract, func, *args, **kwargs)
|
395
|
+
gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
|
396
|
+
params = {
|
397
|
+
gas_limit: gas_limit,
|
398
|
+
chain_id: chain_id,
|
399
|
+
data: call_payload(func, args),
|
400
|
+
}
|
401
|
+
if kwargs[:address] || contract.address
|
402
|
+
params.merge!({ to: kwargs[:address] || contract.address })
|
403
|
+
end
|
404
|
+
if kwargs[:legacy]
|
405
|
+
params.merge!({
|
406
|
+
gas_price: max_fee_per_gas,
|
407
|
+
})
|
408
|
+
else
|
409
|
+
params.merge!({
|
410
|
+
priority_fee: max_priority_fee_per_gas,
|
411
|
+
max_gas_fee: max_fee_per_gas,
|
412
|
+
})
|
413
|
+
end
|
414
|
+
unless kwargs[:sender_key].nil?
|
415
|
+
# use the provided key as sender and signer
|
416
|
+
params.merge!({
|
417
|
+
from: kwargs[:sender_key].address,
|
418
|
+
nonce: get_nonce(kwargs[:sender_key].address),
|
419
|
+
})
|
420
|
+
tx = Eth::Tx.new(params)
|
421
|
+
tx.sign kwargs[:sender_key]
|
422
|
+
end
|
423
|
+
raw_result = eth_call(params)["result"]
|
424
|
+
types = func.outputs.map { |i| i.type }
|
425
|
+
Eth::Abi.decode(types, raw_result)
|
426
|
+
end
|
427
|
+
|
428
|
+
# Encodes function call payloads.
|
429
|
+
def call_payload(fun, args)
|
430
|
+
types = fun.inputs.map { |i| i.type }
|
431
|
+
encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
|
432
|
+
"0x" + fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str)
|
433
|
+
end
|
434
|
+
|
432
435
|
# Prepares parameters and sends the command to the client.
|
433
436
|
def send_command(command, args)
|
434
437
|
args << "latest" if ["eth_getBalance", "eth_call"].include? command
|
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
|
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
|
51
|
-
def self.
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
#
|
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
|
-
|
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
|
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
@@ -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,
|
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
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.4
|
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-
|
12
|
+
date: 2022-05-16 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
|