eth 0.5.6 → 0.5.7
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/docs.yml +1 -1
- data/CHANGELOG.md +30 -0
- data/README.md +23 -259
- data/lib/eth/chain.rb +9 -0
- data/lib/eth/client/http_auth.rb +73 -0
- data/lib/eth/client.rb +83 -80
- data/lib/eth/contract/function_input.rb +1 -1
- data/lib/eth/contract/function_output.rb +1 -1
- data/lib/eth/signature.rb +4 -1
- data/lib/eth/tx/eip1559.rb +1 -1
- data/lib/eth/tx/eip2930.rb +1 -1
- data/lib/eth/tx/legacy.rb +1 -1
- data/lib/eth/tx.rb +6 -3
- data/lib/eth/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86b3022f82e96aed2d1aad682ad106f3f5efe9488e03ed048e0c5862d30c3284
|
4
|
+
data.tar.gz: 40cb5224db9e074360586aca07f6421edc47668fa0f5d81728fa7574f0c2a978
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf5872ec79f0c708a5c05060514b9179279db310b1c0c0682679cd90bcd0998f9ef1a7f8787c298380a252462c5ea33fdc3d44c0bdb5e3c57991515514077b85
|
7
|
+
data.tar.gz: 4a7adde0050a724270f5779a2fe4fca596202a930ee7e1af1e4493878a21e7102ee75a2d5ce91ac455b016c9c396d6771396e5c890f5dcef7ea220b0eadd2d58
|
data/.github/workflows/docs.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,36 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [0.5.6]
|
5
|
+
### Added
|
6
|
+
- Eth/client: Add gas limit override option for contract deployments ([#128](https://github.com/q9f/eth.rb/pull/128))
|
7
|
+
- Eth/abi: support dynamic array encoding ([#122](https://github.com/q9f/eth.rb/pull/122))
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- Eth/client: Include contract constructor args when estimating intrinsic gas ([#111](https://github.com/q9f/eth.rb/pull/111))
|
11
|
+
- Eth/abi: allow parsing numerics from string inputs ([#112](https://github.com/q9f/eth.rb/pull/112))
|
12
|
+
- Eth/signature: fix prefix_message for multibyte characters ([#120](https://github.com/q9f/eth.rb/pull/120))
|
13
|
+
- Eth/abi: raise error if numeric comes as string ([#114](https://github.com/q9f/eth.rb/pull/114))
|
14
|
+
- Gem: bump version to 0.5.6 ([#130](https://github.com/q9f/eth.rb/pull/130))
|
15
|
+
|
16
|
+
## [0.5.5]
|
17
|
+
### Added
|
18
|
+
- Eth/contract: Add missing def_delegator for constructor_inputs ([#96](https://github.com/q9f/eth.rb/pull/96))
|
19
|
+
- Eth/client: Enable passing in constructor params to deploy ([#106](https://github.com/q9f/eth.rb/pull/106))
|
20
|
+
- Eth/chain: add matic/mumbai ([#107](https://github.com/q9f/eth.rb/pull/107))
|
21
|
+
|
22
|
+
### Changed
|
23
|
+
- Gem: bump version to 0.5.5 ([#89](https://github.com/q9f/eth.rb/pull/89))
|
24
|
+
- Docs: update changelog for 0.5.4 ([#90](https://github.com/q9f/eth.rb/pull/90))
|
25
|
+
- Ci: add weekly dependency checks ([#91](https://github.com/q9f/eth.rb/pull/91))
|
26
|
+
- Build(deps): bump github/codeql-action from 1 to 2 ([#92](https://github.com/q9f/eth.rb/pull/92))
|
27
|
+
- Build(deps): bump actions/checkout from 2 to 3 ([#93](https://github.com/q9f/eth.rb/pull/93))
|
28
|
+
- Build(deps): bump JamesIves/github-pages-deploy-action from 4.1.7 to 4.3.3 ([#94](https://github.com/q9f/eth.rb/pull/94))
|
29
|
+
- Eth/abi: fix handling of hex values for byte strings ([#100](https://github.com/q9f/eth.rb/pull/100))
|
30
|
+
- Eth/abi: add a testcase for handling hex and bin strings ([#101](https://github.com/q9f/eth.rb/pull/101))
|
31
|
+
- Eth/abi: Fix Eth::Abi::DecodingError in call method ([#105](https://github.com/q9f/eth.rb/pull/105))
|
32
|
+
- Eth: some docs and cleanups ([#108](https://github.com/q9f/eth.rb/pull/108))
|
33
|
+
|
4
34
|
## [0.5.4]
|
5
35
|
### Added
|
6
36
|
- Eth/client: method for eip-1271 ([#80](https://github.com/q9f/eth.rb/pull/80))
|
data/README.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
<!--
|
2
|
+
# @markup markdown
|
3
|
+
# @title Ethereum for Ruby
|
4
|
+
# @author Afri Schoedon
|
5
|
+
-->
|
6
|
+
|
1
7
|
# Ethereum for Ruby
|
2
8
|
|
3
9
|
[](https://github.com/q9f/eth.rb/actions)
|
@@ -30,26 +36,9 @@ What you get:
|
|
30
36
|
- [x] RLP-Encoder and Decoder (including sedes)
|
31
37
|
- [x] RPC-Client (IPC/HTTP) for Execution-Layer APIs
|
32
38
|
- [x] Solidity bindings (compile contracts from Ruby)
|
33
|
-
- [x] Full smart-contract support (deploy, transact, and call)
|
34
|
-
|
35
|
-
Contents:
|
36
|
-
- [1. Installation](#1-installation)
|
37
|
-
- [2. Usage](#2-usage)
|
38
|
-
- [2.1. Ethereum Keys and Addresses (EIP-55)](#21-ethereum-keys-and-addresses-eip-55)
|
39
|
-
- [2.2. Ethereum Signatures (EIP-191, EIP-712)](#22-ethereum-signatures-eip-191-eip-712)
|
40
|
-
- [2.3. Ethereum Chains (EIP-155)](#23-ethereum-chains-eip-155)
|
41
|
-
- [2.4. Ethereum Transactions (EIP-1559, EIP-2718, EIP-2930)](#24-ethereum-transactions-eip-1559-eip-2718-eip-2930)
|
42
|
-
- [2.5. Ethereum ABI Encoder and Decoder](#25-ethereum-abi-encoder-and-decoder)
|
43
|
-
- [2.6. Ethereum RLP Encoder and Decoder](#26-ethereum-rlp-encoder-and-decoder)
|
44
|
-
- [2.7. Ethereum RPC-Client](#27-ethereum-rpc-client)
|
45
|
-
- [2.8. Solidity Compiler Bindings](#28-solidity-compiler-bindings)
|
46
|
-
- [2.9. Interact with Smart Contract](#29-interact-with-smart-contract)
|
47
|
-
- [3. Documentation](#3-documentation)
|
48
|
-
- [4. Testing](#4-testing)
|
49
|
-
- [5. Contributing](#5-contributing)
|
50
|
-
- [6. License and Credits](#6-license-and-credits)
|
39
|
+
- [x] ~~Full~~ Some smart-contract support (deploy, transact, and call)
|
51
40
|
|
52
|
-
##
|
41
|
+
## Installation
|
53
42
|
Add this line to your application's Gemfile:
|
54
43
|
|
55
44
|
```ruby
|
@@ -62,252 +51,27 @@ Or install it yourself as:
|
|
62
51
|
gem install eth
|
63
52
|
```
|
64
53
|
|
65
|
-
##
|
66
|
-
Check out
|
67
|
-
[](https://q9f.github.io/eth.rb)
|
57
|
+
and the
|
69
58
|
[](https://github.com/q9f/eth.rb/wiki)
|
70
|
-
for
|
71
|
-
|
72
|
-
### 2.1. Ethereum Keys and Addresses (EIP-55)
|
73
|
-
Generate a random Secp256k1 key-pair.
|
74
|
-
|
75
|
-
```ruby
|
76
|
-
key = Eth::Key.new
|
77
|
-
# => #<Eth::Key:0x00005574a6ba80b8 @private_key=#<Secp256k1::PrivateKey:0x00005574a6b9a0a8 @data=")&\x86P\xB5\x16\xD9]\xFA;\x1F\xF6\xD9\xCF\xE3Vj/\xE2\x81\xC0\x9D\xE9\x05o!q\x82G\x9A\x10Q">, @public_key=#<Secp256k1::PublicKey:0x00005574a6b9bf98>>
|
78
|
-
```
|
79
|
-
|
80
|
-
Create an password-encrypted Ethereum key-store.
|
81
|
-
|
82
|
-
```ruby
|
83
|
-
my_key = Eth::Key.new priv: "30137644b564785d01420f8043f043d74dcca64008e57c59f8ce713a0005a54b"
|
84
|
-
key_store = Eth::Key::Encrypter.perform my_key, "secret-password-1337"
|
85
|
-
# => "{\"crypto\":{\"cipher\":\"aes-128-ctr\",\"cipherparams\":{\"iv\":\"7e5c0fe1e27f4ea61b0f4427dd63555f\"},\"ciphertext\":\"6353653bba494cdae6bcd510febc980cdc6f7b23cfbdf950d7a909a69625c8fd\",\"kdf\":\"pbkdf2\",\"kdfparams\":{\"c\":262144,\"dklen\":32,\"prf\":\"hmac-sha256\",\"salt\":\"cce96286f3c32267fc91f756365307fe6a4c83b6b2a73c69535f721fa407736c\"},\"mac\":\"3361ffd2b158a1d7bca5a5fd86a251ba3e9d80b602c867a2e0f47023a0e17a57\"},\"id\":\"642ee9fc-72e4-4d0a-902f-247c0b59bfda\",\"version\":3}"
|
86
|
-
restored_key = Eth::Key::Decrypter.perform key_store, "secret-password-1337"
|
87
|
-
# => "30137644b564785d01420f8043f043d74dcca64008e57c59f8ce713a0005a54b"
|
88
|
-
```
|
89
|
-
|
90
|
-
Manage Ethereum address objects adhering to EIP-55 checksum format.
|
91
|
-
|
92
|
-
```ruby
|
93
|
-
address = Eth::Address.new "0xd496b23d61f88a8c7758fca7560dcfac7b3b01f9"
|
94
|
-
# => #<Eth::Address:0x00005574a6bd4fc8 @address="0xd496b23d61f88a8c7758fca7560dcfac7b3b01f9">
|
95
|
-
address.valid?
|
96
|
-
# => true
|
97
|
-
address.checksummed # EIP 55
|
98
|
-
# => "0xD496b23D61F88A8C7758fca7560dCFac7b3b01F9"
|
99
|
-
```
|
100
|
-
|
101
|
-
See `/spec` or [Documentation](https://q9f.github.io/eth.rb/) for more details about key-pairs, encrypting/decrypting key-stores with a secret, and checksummed addresses.
|
102
|
-
|
103
|
-
### 2.2. Ethereum Signatures (EIP-191, EIP-712)
|
104
|
-
Manage keypairs to sign messages in EIP-191 (`personal_sign`) format or typed data in EIP-712 (`sign_typed_data`) format.
|
105
|
-
|
106
|
-
```ruby
|
107
|
-
key = Eth::Key.new priv: "268be6f4a68c40f6862b7ac9aed8f701dc25a95ddb9a44d8b1f520b75f440a9a"
|
108
|
-
# => #<Eth::Key:0x00005574a699adc0 @private_key=#<Secp256k1::PrivateKey:0x00005574a6998200 @data="&\x8B\xE6\xF4\xA6\x8C@\xF6\x86+z\xC9\xAE\xD8\xF7\x01\xDC%\xA9]\xDB\x9AD\xD8\xB1\xF5 \xB7_D\n\x9A">, @public_key=#<Secp256k1::PublicKey:0x00005574a6998160>>
|
109
|
-
key.public_hex
|
110
|
-
# => "04b45200621c013a5fbab999ac33b0c836328a04afa0255ffbe6ea0f6fd97e187b02199886d942a9f50f7e279a2bc74c93b2afcbd7255489939f9b36a5eae5e281"
|
111
|
-
key.address.to_s
|
112
|
-
# => "0xD496b23D61F88A8C7758fca7560dCFac7b3b01F9"
|
113
|
-
key.personal_sign "Hello World!"
|
114
|
-
# => "ac6a59417d8688c8144f01a662384fa691636b48a071d4b7c13902bb87ca472b0bce1d7a758f39a5759ed5e937ce61f50dd1b83158371f8d0faeb9b7d81c194225"
|
115
|
-
```
|
116
|
-
|
117
|
-
Recover and verify personal signatures respecting EIPs 155, 191, and 712.
|
118
|
-
|
119
|
-
```ruby
|
120
|
-
address = Eth::Address.new "0xd496b23d61f88a8c7758fca7560dcfac7b3b01f9"
|
121
|
-
# => #<Eth::Address:0x00005574a6bd4fc8 @address="0xd496b23d61f88a8c7758fca7560dcfac7b3b01f9">
|
122
|
-
signature = "ac6a59417d8688c8144f01a662384fa691636b48a071d4b7c13902bb87ca472b0bce1d7a758f39a5759ed5e937ce61f50dd1b83158371f8d0faeb9b7d81c19422d"
|
123
|
-
# => "ac6a59417d8688c8144f01a662384fa691636b48a071d4b7c13902bb87ca472b0bce1d7a758f39a5759ed5e937ce61f50dd1b83158371f8d0faeb9b7d81c19422d"
|
124
|
-
recovered_key = Eth::Signature.personal_recover "Hello World!", signature, Eth::Chain::GOERLI
|
125
|
-
# => "04b45200621c013a5fbab999ac33b0c836328a04afa0255ffbe6ea0f6fd97e187b02199886d942a9f50f7e279a2bc74c93b2afcbd7255489939f9b36a5eae5e281"
|
126
|
-
Eth::Util.public_key_to_address(recovered_key).to_s
|
127
|
-
# => "0xD496b23D61F88A8C7758fca7560dCFac7b3b01F9"
|
128
|
-
Eth::Signature.verify "Hello World!", signature, address, Eth::Chain::GOERLI
|
129
|
-
# => true
|
130
|
-
```
|
131
|
-
|
132
|
-
See `/spec` or [Documentation](https://q9f.github.io/eth.rb/) for signing typed data as per EIP-712.
|
133
|
-
|
134
|
-
### 2.3. Ethereum Chains (EIP-155)
|
135
|
-
Manage Ethereum chain IDs for EIP-155 replay protection.
|
136
|
-
|
137
|
-
```ruby
|
138
|
-
chain_id = Eth::Chain::OPTIMISM
|
139
|
-
# => 10
|
140
|
-
v = Eth::Chain.to_v 0, Eth::Chain::OPTIMISM
|
141
|
-
# => 55
|
142
|
-
recovery_id = Eth::Chain.to_recovery_id v, Eth::Chain::OPTIMISM
|
143
|
-
# => 0
|
144
|
-
chain_id = Eth::Chain.to_chain_id v
|
145
|
-
# => 10
|
146
|
-
```
|
147
|
-
|
148
|
-
### 2.4. Ethereum Transactions (EIP-1559, EIP-2718, EIP-2930)
|
149
|
-
Create an EIP-1559-conform transaction:
|
150
|
-
|
151
|
-
```ruby
|
152
|
-
payload = {
|
153
|
-
chain_id: Eth::Chain::GOERLI,
|
154
|
-
nonce: 5,
|
155
|
-
priority_fee: 3 * Eth::Unit::GWEI,
|
156
|
-
max_gas_fee: 69 * Eth::Unit::GWEI,
|
157
|
-
gas_limit: 230_420,
|
158
|
-
to: "0xCaA29806044A08E533963b2e573C1230A2cd9a2d",
|
159
|
-
value: 0.069423 * Eth::Unit::ETHER,
|
160
|
-
}
|
161
|
-
# => {:chain_id=>5, :nonce=>5, :priority_fee=>0.3e10, :max_gas_fee=>0.69e11, :gas_limit=>230420, :to=>"0xCaA29806044A08E533963b2e573C1230A2cd9a2d", :value=>0.69423e17}
|
162
|
-
tx = Eth::Tx.new payload
|
163
|
-
# => #<Eth::Tx::Eip1559:0x0000557e35fc5a68 @access_list=[], @amount=69423000000000000, @chain_id=5, @destination="CaA29806044A08E533963b2e573C1230A2cd9a2d", @gas_limit=230420, @max_fee_per_gas=69000000000, @max_priority_fee_per_gas=3000000000, @payload="", @sender="", @signature_r=0, @signature_s=0, @signature_y_parity=nil, @signer_nonce=5, @type=2>
|
164
|
-
my_key = Eth::Key.new priv: "30137644b564785d01420f8043f043d74dcca64008e57c59f8ce713a0005a54b"
|
165
|
-
# => #<Eth::Key:0x0000557e36243178 @private_key=#<Secp256k1::PrivateKey:0x0000557e36242d40 @data="0\x13vD\xB5dx]\x01B\x0F\x80C\xF0C\xD7M\xCC\xA6@\b\xE5|Y\xF8\xCEq:\x00\x05\xA5K">, @public_key=#<Secp256k1::PublicKey:0x0000557e36242cf0>>
|
166
|
-
tx.sign my_key
|
167
|
-
# => "cba302c0ebf8d0205a78ae97f560419b407e32e2426f416abc95a9bfc9dac09c"
|
168
|
-
tx.hex
|
169
|
-
# => "02f873050584b2d05e00851010b872008303841494caa29806044a08e533963b2e573c1230a2cd9a2d87f6a3d9c63df00080c080a03aa187d10b138d3e0155729adb961cd89e10f988ba2d19d6869770b9e5a23d10a04d40864600136ae214916043c7d63b849c98db757e95c86983a036982816e1af"
|
170
|
-
```
|
171
|
-
|
172
|
-
This gem also supports access lists and ABI-encoded data payloads. See `/spec` or [Documentation](https://q9f.github.io/eth.rb/) for more details about the various supported transaction types (legacy, type-1, type-2), payload parameters, and how to estimate intrinsic gas costs.
|
173
|
-
|
174
|
-
### 2.5. Ethereum ABI Encoder and Decoder
|
175
|
-
Encode and decode Ethereum application binary interface data (ABI).
|
176
|
-
|
177
|
-
```ruby
|
178
|
-
Eth::Util.bin_to_hex Eth::Abi.encode(["string", "address"], ["Hello, Bob!", "0xd496b23d61f88a8c7758fca7560dcfac7b3b01f9"])
|
179
|
-
# => "0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000d496b23d61f88a8c7758fca7560dcfac7b3b01f9000000000000000000000000000000000000000000000000000000000000000b48656c6c6f2c20426f6221000000000000000000000000000000000000000000"
|
180
|
-
Eth::Abi.decode(["string", "address"], "0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000d496b23d61f88a8c7758fca7560dcfac7b3b01f9000000000000000000000000000000000000000000000000000000000000000b48656c6c6f2c20426f6221000000000000000000000000000000000000000000")
|
181
|
-
# => ["Hello, Bob!", "0xd496b23d61f88a8c7758fca7560dcfac7b3b01f9"]
|
182
|
-
```
|
183
|
-
|
184
|
-
### 2.6. Ethereum RLP Encoder and Decoder
|
185
|
-
Serialize and deserialize Ethereum recursive-length prefix data (RLP).
|
186
|
-
|
187
|
-
```ruby
|
188
|
-
Eth::Util.bin_to_hex Eth::Rlp.encode ["Hello, Bob!", "0xd496b23d61f88a8c7758fca7560dcfac7b3b01f9"]
|
189
|
-
# => "f78b48656c6c6f2c20426f6221aa307864343936623233643631663838613863373735386663613735363064636661633762336230316639"
|
190
|
-
Eth::Rlp.decode "f78b48656c6c6f2c20426f6221aa307864343936623233643631663838613863373735386663613735363064636661633762336230316639"
|
191
|
-
# => ["Hello, Bob!", "0xd496b23d61f88a8c7758fca7560dcfac7b3b01f9"]
|
192
|
-
```
|
193
|
-
|
194
|
-
Or ;-)
|
195
|
-
|
196
|
-
```ruby
|
197
|
-
Eth::Rlp.decode "c7c0c1c0c3c0c1c0"
|
198
|
-
# => [[], [[]], [[], [[]]]]
|
199
|
-
```
|
200
|
-
|
201
|
-
### 2.7. Ethereum RPC-Client
|
202
|
-
Create an IPC- or HTTP-RPC-API client to seamlessly query the chain state, e.g., Infura over HTTPS with access token:
|
203
|
-
|
204
|
-
```ruby
|
205
|
-
infura = Eth::Client.create "https://mainnet.infura.io/v3/#{access_token}"
|
206
|
-
# => #<Eth::Client::Http:0x000055d43f3ca460 @gas_limit=21000, @host="mainnet.infura.io", @id=0, @max_fee_per_gas=0.2e11, @max_priority_fee_per_gas=0, @port=443, @ssl=true, @uri=#<URI::HTTPS https://mainnet.infura.io/v3/31b...d93>>
|
207
|
-
deposit_contract = Eth::Address.new "0x00000000219ab540356cBB839Cbe05303d7705Fa"
|
208
|
-
# => #<Eth::Address:0x000055d43f381738 @address="0x00000000219ab540356cBB839Cbe05303d7705Fa">
|
209
|
-
infura.get_balance deposit_contract
|
210
|
-
# => 9087314000069000000000069
|
211
|
-
```
|
212
|
-
|
213
|
-
Or set up a local development environment with `geth --dev`:
|
214
|
-
|
215
|
-
```ruby
|
216
|
-
cli = Eth::Client.create "/tmp/geth.ipc"
|
217
|
-
# => #<Eth::Client::Ipc:0x000055d43f51c390 @gas_limit=21000, @id=0, @max_fee_per_gas=0.2e11, @max_priority_fee_per_gas=0, @path="/tmp/geth.ipc">
|
218
|
-
cli.eth_coinbase
|
219
|
-
# => {"jsonrpc"=>"2.0", "id"=>1, "result"=>"0x6868074fb21c48dfad0c448fbabd99383a6598e4"}
|
220
|
-
tx = cli.transfer_and_wait(Eth::Key.new.address, 1337 * Eth::Unit::ETHER)
|
221
|
-
# => "0x141c6dff40df34fe4fce5a65588d2161dab3e0e977fb8049ff7d79bc901034f7"
|
222
|
-
cli.eth_get_transaction_by_hash tx
|
223
|
-
# => {"jsonrpc"=>"2.0", "id"=>8, "result"=> {"blockHash"=>"0x47e742038c75851348dbda87b15fde044d54c442c371f43bea881a44d5589de3", "blockNumber"=>"0x1", "from"=>"0x6868074fb21c48dfad0c448fbabd99383a6598e4", "gas"=>"0x5208", "gasPrice"=>"0x342770c1", "maxFeePerGas"=>"0x77359401", "maxPriorityFeePerGas"=>"0x1", "hash"=>"0x141c6dff40df34fe4fce5a65588d2161dab3e0e977fb8049ff7d79bc901034f7", "input"=>"0x", "nonce"=>"0x0", "to"=>"0x311c61e5dc6123ad016bb7fd687d283c327bcd5f", "transactionIndex"=>"0x0", "value"=>"0x487a9a304539440000", "type"=>"0x2", "accessList"=>[], "chainId"=>"0x539", "v"=>"0x0", "r"=>"0xb42477d69eae65a3a3d91d9cb173e4a45a403fb0a15fa729dbfdc9d13211d7b5", "s"=>"0x4a2f98fc2b61c2d7c907520bc8c6ebe42ea6fe1cb6824f95e4b30e9464395100"}}
|
224
|
-
cli.get_balance "0x311c61e5dc6123ad016bb7fd687d283c327bcd5f"
|
225
|
-
# => 1337000000000000000000
|
226
|
-
cli.get_nonce cli.eth_coinbase["result"]
|
227
|
-
# => 1
|
228
|
-
```
|
229
|
-
|
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.
|
231
|
-
|
232
|
-
### 2.8. Solidity Compiler Bindings
|
233
|
-
Link a system-level Solidity compiler (`solc`) to your Ruby library and compile contracts.
|
234
|
-
|
235
|
-
```ruby
|
236
|
-
solc = Eth::Solidity.new
|
237
|
-
# => #<Eth::Solidity:0x000055f05040c6d0 @compiler="/usr/bin/solc">
|
238
|
-
contract = solc.compile "spec/fixtures/contracts/greeter.sol"
|
239
|
-
# => {"Greeter"=>
|
240
|
-
# {"abi"=>
|
241
|
-
# [{"inputs"=>[{"internalType"=>"string", "name"=>"message", "type"=>"string"}], "stateMutability"=>"nonpayable", "type"=>"constructor"},
|
242
|
-
# {"inputs"=>[], "name"=>"greet", "outputs"=>[{"internalType"=>"string", "name"=>"", "type"=>"string"}], "stateMutability"=>"view", "type"=>"function"},
|
243
|
-
# {"inputs"=>[], "name"=>"kill", "outputs"=>[], "stateMutability"=>"nonpayable", "type"=>"function"}],
|
244
|
-
# "bin"=>
|
245
|
-
# "6080604052348015...6c634300080c0033"},
|
246
|
-
# "Mortal"=>
|
247
|
-
# {"abi"=>[{"inputs"=>[], "stateMutability"=>"nonpayable", "type"=>"constructor"}, {"inputs"=>[], "name"=>"kill", "outputs"=>[], "stateMutability"=>"nonpayable", "type"=>"function"}],
|
248
|
-
# "bin"=>
|
249
|
-
# "6080604052348015...6c634300080c0033"}}
|
250
|
-
```
|
251
|
-
|
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.
|
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
|
-
```
|
59
|
+
for all the details and example snippets.
|
296
60
|
|
297
|
-
##
|
61
|
+
## Documentation
|
298
62
|
The documentation can be found at: https://q9f.github.io/eth.rb
|
299
63
|
|
300
64
|
For any specific version, docs can be generated by `yard`:
|
301
65
|
|
302
66
|
```shell
|
303
67
|
gem install bundler rdoc yard
|
304
|
-
git checkout
|
68
|
+
git checkout $VERSION
|
305
69
|
yard doc
|
306
70
|
```
|
307
71
|
|
308
72
|
The goal is to have 100% API documentation available.
|
309
73
|
|
310
|
-
##
|
74
|
+
## Testing
|
311
75
|
The test suite expects working local HTTP and IPC endpoints with a prefunded developer account, e.g.:
|
312
76
|
|
313
77
|
```shell
|
@@ -324,24 +88,24 @@ rspec
|
|
324
88
|
|
325
89
|
The goal is to have 100% specification coverage for all code inside this gem.
|
326
90
|
|
327
|
-
##
|
91
|
+
## Contributing
|
328
92
|
Pull requests are welcome! To contribute, please consider the following:
|
329
93
|
* Code should be fully documented. Run `yard doc` and make sure it does not yield any warnings or undocumented sets.
|
330
94
|
* Code should be fully covered by tests. Run `rspec` to make sure all tests pass. The CI has an integration that will assis you to identify uncovered lines of code and get coverage up to 100%.
|
331
95
|
* Code should be formatted properly. Try to eliminate the most common issues such as trailing white-spaces or duplicate new-lines. Usage of the `rufo` gem is recommended.
|
332
|
-
* Submit pull requests, questions, or issues to Github: https://github.com/q9f/eth.rb
|
96
|
+
* Submit pull requests, questions, or issues to Github: <https://github.com/q9f/eth.rb>
|
333
97
|
|
334
|
-
##
|
98
|
+
## License and Credits
|
335
99
|
The `eth` gem is licensed under the conditions of [Apache 2.0](./LICENSE.txt). Please see [AUTHORS](./AUTHORS.txt) for contributors and copyright notices.
|
336
100
|
|
337
101
|
This gem is a complete rewrite of the old `eth` gem by Steve Ellis.
|
338
|
-
* https://github.com/se3000/ruby-eth
|
102
|
+
* <https://github.com/se3000/ruby-eth> (MIT)
|
339
103
|
|
340
104
|
It is not only a rewrite of the `eth` gem but also a partial merge of the `ethereum` gem by Marek Kirejczyk and Yuta Kurotaki.
|
341
|
-
* https://github.com/EthWorks/ethereum.rb (MIT)
|
105
|
+
* <https://github.com/EthWorks/ethereum.rb> (MIT)
|
342
106
|
|
343
107
|
This gem also includes a revised version of the ABI gem by Jan Xie and Zhang Yaning.
|
344
|
-
* https://github.com/cryptape/ruby-ethereum-abi (MIT)
|
108
|
+
* <https://github.com/cryptape/ruby-ethereum-abi> (MIT)
|
345
109
|
|
346
110
|
It also contains a condensed version of the RLP gem by Jan Xie and Zhang Yaning.
|
347
|
-
* https://github.com/cryptape/ruby-rlp (MIT)
|
111
|
+
* <https://github.com/cryptape/ruby-rlp> (MIT)
|
data/lib/eth/chain.rb
CHANGED
@@ -92,6 +92,15 @@ module Eth
|
|
92
92
|
# Chain ID for the geth private network preset.
|
93
93
|
PRIVATE_GETH = 1337.freeze
|
94
94
|
|
95
|
+
# Indicates wether the given `v` indicates a legacy chain value
|
96
|
+
# used by ledger wallets without EIP-155 replay protection.
|
97
|
+
#
|
98
|
+
# @param v [Integer] the signature's `v` value.
|
99
|
+
# @return [Boolean] true if ledger's legacy value.
|
100
|
+
def is_ledger?(v)
|
101
|
+
[0, 1].include? v
|
102
|
+
end
|
103
|
+
|
95
104
|
# Indicates wether the given `v` indicates a legacy chain value
|
96
105
|
# without EIP-155 replay protection.
|
97
106
|
#
|
@@ -0,0 +1,73 @@
|
|
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
|
+
require "net/http"
|
16
|
+
|
17
|
+
# Provides the {Eth} module.
|
18
|
+
module Eth
|
19
|
+
|
20
|
+
# Provides an HTTP/S-RPC client with basic authentication.
|
21
|
+
class Client::HttpAuth < Client
|
22
|
+
|
23
|
+
# The host of the HTTP endpoint.
|
24
|
+
attr_reader :host
|
25
|
+
|
26
|
+
# The port of the HTTP endpoint.
|
27
|
+
attr_reader :port
|
28
|
+
|
29
|
+
# The full URI of the HTTP endpoint, including path.
|
30
|
+
attr_reader :uri
|
31
|
+
|
32
|
+
# Attribute indicator for SSL.
|
33
|
+
attr_reader :ssl
|
34
|
+
|
35
|
+
# Attribute for user.
|
36
|
+
attr_reader :user
|
37
|
+
|
38
|
+
# Constructor for the HTTP Client. Should not be used; use
|
39
|
+
# {Client.create} intead.
|
40
|
+
#
|
41
|
+
# @param host [String] an URI pointing to an HTTP RPC-API.
|
42
|
+
def initialize(host)
|
43
|
+
super
|
44
|
+
uri = URI.parse(host)
|
45
|
+
raise ArgumentError, "Unable to parse the HTTP-URI!" unless ["http", "https"].include? uri.scheme
|
46
|
+
@host = uri.host
|
47
|
+
@port = uri.port
|
48
|
+
@ssl = uri.scheme == "https"
|
49
|
+
@user = uri.user
|
50
|
+
@password = uri.password
|
51
|
+
@uri = URI("#{uri.scheme}://#{uri.user}:#{uri.password}@#{@host}:#{@port}#{uri.path}")
|
52
|
+
end
|
53
|
+
|
54
|
+
# Sends an RPC request to the connected HTTP client.
|
55
|
+
#
|
56
|
+
# @param payload [Hash] the RPC request parameters.
|
57
|
+
# @return [String] a JSON-encoded response.
|
58
|
+
def send(payload)
|
59
|
+
http = Net::HTTP.new(@host, @port)
|
60
|
+
http.use_ssl = @ssl
|
61
|
+
header = { "Content-Type" => "application/json" }
|
62
|
+
request = Net::HTTP::Post.new(@uri, header)
|
63
|
+
request.body = payload
|
64
|
+
response = http.request(request)
|
65
|
+
response.body
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# Attribute for password.
|
72
|
+
attr_reader :password
|
73
|
+
end
|
data/lib/eth/client.rb
CHANGED
@@ -28,24 +28,31 @@ module Eth
|
|
28
28
|
# The connected network's client coinbase.
|
29
29
|
attr_accessor :default_account
|
30
30
|
|
31
|
-
# The default transaction max priority fee per gas in Wei.
|
31
|
+
# The default transaction max priority fee per gas in Wei, defaults to {Tx::DEFAULT_PRIORITY_FEE}.
|
32
32
|
attr_accessor :max_priority_fee_per_gas
|
33
33
|
|
34
|
-
# The default transaction max fee per gas in Wei.
|
34
|
+
# The default transaction max fee per gas in Wei, defaults to {Tx::DEFAULT_GAS_PRICE}.
|
35
35
|
attr_accessor :max_fee_per_gas
|
36
36
|
|
37
|
-
# The default gas limit for the transaction.
|
37
|
+
# The default gas limit for the transaction, defaults to {Tx::DEFAULT_GAS_LIMIT}.
|
38
38
|
attr_accessor :gas_limit
|
39
39
|
|
40
40
|
# Creates a new RPC-Client, either by providing an HTTP/S host or
|
41
|
-
# an IPC path.
|
41
|
+
# an IPC path. Supports basic authentication with username and password.
|
42
|
+
#
|
43
|
+
# **Note**, this sets the folling gas defaults: {Tx::DEFAULT_PRIORITY_FEE},
|
44
|
+
# {Tx::DEFAULT_GAS_PRICE}, and {Tx::DEFAULT_GAS_LIMIT}. Use
|
45
|
+
# {#max_priority_fee_per_gas}, {#max_fee_per_gas}, and {#gas_limit} to set
|
46
|
+
# custom values prior to submitting transactions.
|
42
47
|
#
|
43
48
|
# @param host [String] either an HTTP/S host or an IPC path.
|
44
49
|
# @return [Eth::Client::Ipc] an IPC client.
|
50
|
+
# @return [Eth::Client::HttpAuth] an HTTP client with basic authentication.
|
45
51
|
# @return [Eth::Client::Http] an HTTP client.
|
46
52
|
# @raise [ArgumentError] in case it cannot determine the client type.
|
47
53
|
def self.create(host)
|
48
54
|
return Client::Ipc.new host if host.end_with? ".ipc"
|
55
|
+
return Client::HttpAuth.new host if Regexp.new(":.*@.*:", Regexp::IGNORECASE).match host
|
49
56
|
return Client::Http.new host if host.start_with? "http"
|
50
57
|
raise ArgumentError, "Unable to detect client type!"
|
51
58
|
end
|
@@ -54,13 +61,16 @@ module Eth
|
|
54
61
|
# use {Client.create} intead.
|
55
62
|
def initialize(_)
|
56
63
|
@id = 0
|
57
|
-
@max_priority_fee_per_gas =
|
64
|
+
@max_priority_fee_per_gas = Tx::DEFAULT_PRIORITY_FEE
|
58
65
|
@max_fee_per_gas = Tx::DEFAULT_GAS_PRICE
|
59
66
|
@gas_limit = Tx::DEFAULT_GAS_LIMIT
|
60
67
|
end
|
61
68
|
|
62
69
|
# Gets the default account (coinbase) of the connected client.
|
63
70
|
#
|
71
|
+
# **Note**, that many remote providers (e.g., Infura) do not provide
|
72
|
+
# any accounts.
|
73
|
+
#
|
64
74
|
# @return [Eth::Address] the coinbase account address.
|
65
75
|
def default_account
|
66
76
|
@default_account ||= Address.new eth_coinbase["result"]
|
@@ -90,14 +100,12 @@ module Eth
|
|
90
100
|
end
|
91
101
|
|
92
102
|
# Simply transfer Ether to an account and waits for it to be mined.
|
93
|
-
# Uses `eth_coinbase` and external signer if no
|
103
|
+
# Uses `eth_coinbase` and external signer if no sender key is
|
94
104
|
# provided.
|
95
105
|
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
# @
|
99
|
-
# @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
100
|
-
# @return [String] the transaction hash.
|
106
|
+
# See {#transfer} for params and overloads.
|
107
|
+
#
|
108
|
+
# @return [String] the transaction hash once it is mined.
|
101
109
|
def transfer_and_wait(destination, amount, sender_key = nil, legacy = false)
|
102
110
|
wait_for_tx(transfer(destination, amount, sender_key, legacy))
|
103
111
|
end
|
@@ -106,11 +114,14 @@ module Eth
|
|
106
114
|
# access lists attached. Uses `eth_coinbase` and external signer
|
107
115
|
# if no sender key is provided.
|
108
116
|
#
|
117
|
+
# **Note**, that many remote providers (e.g., Infura) do not provide
|
118
|
+
# any accounts. Provide a `sender_key` if you experience issues.
|
119
|
+
#
|
109
120
|
# @param destination [Eth::Address] the destination address.
|
110
121
|
# @param amount [Integer] the transfer amount in Wei.
|
111
122
|
# @param sender_key [Eth::Key] the sender private key.
|
112
123
|
# @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
113
|
-
# @return [String] the transaction hash.
|
124
|
+
# @return [String] the local transaction hash.
|
114
125
|
def transfer(destination, amount, sender_key = nil, legacy = false)
|
115
126
|
params = {
|
116
127
|
value: amount,
|
@@ -152,15 +163,9 @@ module Eth
|
|
152
163
|
# Deploys a contract and waits for it to be mined. Uses
|
153
164
|
# `eth_coinbase` or external signer if no sender key is provided.
|
154
165
|
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
# @
|
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
|
-
# **gas_limit [Integer] optional gas limit override for deploying the contract.
|
163
|
-
# @return [String] the contract address.
|
166
|
+
# See {#deploy} for params and overloads.
|
167
|
+
#
|
168
|
+
# @return [String] the contract address once it's mined.
|
164
169
|
def deploy_and_wait(contract, *args, **kwargs)
|
165
170
|
hash = wait_for_tx(deploy(contract, *args, **kwargs))
|
166
171
|
addr = eth_get_transaction_receipt(hash)["result"]["contractAddress"]
|
@@ -170,14 +175,20 @@ module Eth
|
|
170
175
|
# Deploys a contract. Uses `eth_coinbase` or external signer
|
171
176
|
# if no sender key is provided.
|
172
177
|
#
|
178
|
+
# **Note**, that many remote providers (e.g., Infura) do not provide
|
179
|
+
# any accounts. Provide a `sender_key` if you experience issues.
|
180
|
+
#
|
173
181
|
# @overload deploy(contract)
|
174
182
|
# @param contract [Eth::Contract] contracts to deploy.
|
183
|
+
# @overload deploy(contract, *args)
|
184
|
+
# @param contract [Eth::Contract] the contracts to deploy.
|
185
|
+
# @param *args (optional) variable constructor parameter list.
|
175
186
|
# @overload deploy(contract, *args, **kwargs)
|
176
|
-
# @param contract [Eth::Contract] contracts to deploy.
|
177
|
-
# *args
|
178
|
-
# **sender_key [Eth::Key] the sender private key.
|
179
|
-
# **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
180
|
-
# **gas_limit [Integer] optional gas limit override for deploying the contract.
|
187
|
+
# @param contract [Eth::Contract] the contracts to deploy.
|
188
|
+
# @param *args (optional) variable constructor parameter list.
|
189
|
+
# @param **sender_key [Eth::Key] the sender private key.
|
190
|
+
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
191
|
+
# @param **gas_limit [Integer] optional gas limit override for deploying the contract.
|
181
192
|
# @return [String] the transaction hash.
|
182
193
|
# @raise [ArgumentError] in case the contract does not have any source.
|
183
194
|
def deploy(contract, *args, **kwargs)
|
@@ -230,24 +241,24 @@ module Eth
|
|
230
241
|
# Calls a contract function without executing it
|
231
242
|
# (non-transactional contract read).
|
232
243
|
#
|
233
|
-
# @overload call(contract,
|
234
|
-
# @param contract [Eth::Contract] subject contract to call.
|
235
|
-
# @param
|
236
|
-
# @overload call(contract,
|
237
|
-
# @param contract [Eth::Contract] subject contract to call.
|
238
|
-
# @param
|
239
|
-
# @param
|
240
|
-
# @overload call(contract,
|
241
|
-
# @param contract [Eth::Contract] subject contract to call.
|
242
|
-
# @param
|
243
|
-
# @param
|
244
|
-
# @param sender_key [Eth::Key] the sender private key.
|
245
|
-
# @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
246
|
-
# @param gas_limit [Integer] optional gas limit override for deploying the contract.
|
244
|
+
# @overload call(contract, function)
|
245
|
+
# @param contract [Eth::Contract] the subject contract to call.
|
246
|
+
# @param function [String] method name to be called.
|
247
|
+
# @overload call(contract, function, *args)
|
248
|
+
# @param contract [Eth::Contract] the subject contract to call.
|
249
|
+
# @param function [String] method name to be called.
|
250
|
+
# @param *args optional function arguments.
|
251
|
+
# @overload call(contract, function, *args, **kwargs)
|
252
|
+
# @param contract [Eth::Contract] the subject contract to call.
|
253
|
+
# @param function [String] method name to be called.
|
254
|
+
# @param *args optional function arguments.
|
255
|
+
# @param **sender_key [Eth::Key] the sender private key.
|
256
|
+
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
257
|
+
# @param **gas_limit [Integer] optional gas limit override for deploying the contract.
|
247
258
|
# @return [Object] returns the result of the call.
|
248
|
-
def call(contract,
|
249
|
-
func = contract.functions.select { |func| func.name ==
|
250
|
-
raise ArgumentError, "
|
259
|
+
def call(contract, function, *args, **kwargs)
|
260
|
+
func = contract.functions.select { |func| func.name == function }[0]
|
261
|
+
raise ArgumentError, "this function does not exist!" if func.nil?
|
251
262
|
output = call_raw(contract, func, *args, **kwargs)
|
252
263
|
if output&.length == 1
|
253
264
|
return output[0]
|
@@ -259,29 +270,32 @@ module Eth
|
|
259
270
|
# Executes a contract function with a transaction (transactional
|
260
271
|
# contract read/write).
|
261
272
|
#
|
262
|
-
#
|
263
|
-
#
|
264
|
-
#
|
265
|
-
# @overload transact(contract,
|
266
|
-
# @param contract [Eth::Contract] subject contract to
|
267
|
-
# @param
|
268
|
-
#
|
269
|
-
#
|
270
|
-
# @param
|
271
|
-
# @param
|
272
|
-
#
|
273
|
-
# @param
|
274
|
-
# @param
|
275
|
-
# @param
|
276
|
-
# @param
|
277
|
-
#
|
278
|
-
|
273
|
+
# **Note**, that many remote providers (e.g., Infura) do not provide
|
274
|
+
# any accounts. Provide a `sender_key` if you experience issues.
|
275
|
+
#
|
276
|
+
# @overload transact(contract, function)
|
277
|
+
# @param contract [Eth::Contract] the subject contract to write to.
|
278
|
+
# @param function [String] method name to be executed.
|
279
|
+
# @overload transact(contract, function, *args)
|
280
|
+
# @param contract [Eth::Contract] the subject contract to write to.
|
281
|
+
# @param function [String] method name to be executed.
|
282
|
+
# @param *args optional function arguments.
|
283
|
+
# @overload transact(contract, function, *args, **kwargs)
|
284
|
+
# @param contract [Eth::Contract] the subject contract to write to.
|
285
|
+
# @param function_name [String] method name to be executed.
|
286
|
+
# @param *args optional function arguments.
|
287
|
+
# @param **sender_key [Eth::Key] the sender private key.
|
288
|
+
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
289
|
+
# @param **address [Eth::Address] contract address.
|
290
|
+
# @param **gas_limit [Integer] optional gas limit override for deploying the contract.
|
291
|
+
# @return [Object] returns the result of the transaction.
|
292
|
+
def transact(contract, function, *args, **kwargs)
|
279
293
|
gas_limit = if kwargs[:gas_limit]
|
280
294
|
kwargs[:gas_limit]
|
281
295
|
else
|
282
296
|
Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
|
283
297
|
end
|
284
|
-
fun = contract.functions.select { |func| func.name ==
|
298
|
+
fun = contract.functions.select { |func| func.name == function }[0]
|
285
299
|
params = {
|
286
300
|
value: 0,
|
287
301
|
gas_limit: gas_limit,
|
@@ -321,23 +335,11 @@ module Eth
|
|
321
335
|
# Executes a contract function with a transaction and waits for it
|
322
336
|
# to be mined (transactional contract read/write).
|
323
337
|
#
|
324
|
-
#
|
325
|
-
#
|
326
|
-
#
|
327
|
-
|
328
|
-
|
329
|
-
# @param function_name [String] method name to be called.
|
330
|
-
# @param value [Integer|String] function arguments.
|
331
|
-
# @overload transact_and_wait(contract, function_name, value, sender_key, legacy, address)
|
332
|
-
# @param contract [Eth::Contract] subject contract to call.
|
333
|
-
# @param function_name [String] method name to be called.
|
334
|
-
# @param value [Integer|String] function arguments.
|
335
|
-
# @param sender_key [Eth::Key] the sender private key.
|
336
|
-
# @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
337
|
-
# @param address [String] contract address.
|
338
|
-
# @return [Object] returns the result of the call.
|
339
|
-
def transact_and_wait(contract, function_name, *args, **kwargs)
|
340
|
-
wait_for_tx(transact(contract, function_name, *args, **kwargs))
|
338
|
+
# See {#transact} for params and overloads.
|
339
|
+
#
|
340
|
+
# @return [Object] returns the result of the transaction.
|
341
|
+
def transact_and_wait(contract, function, *args, **kwargs)
|
342
|
+
wait_for_tx(transact(contract, function, *args, **kwargs))
|
341
343
|
end
|
342
344
|
|
343
345
|
# Provides an interface to call `isValidSignature` as per EIP-1271 on a given
|
@@ -393,7 +395,7 @@ module Eth
|
|
393
395
|
end
|
394
396
|
|
395
397
|
# Metafunction to provide all known RPC commands defined in
|
396
|
-
# Eth::Api as snake_case methods to the Eth::Client classes.
|
398
|
+
# {Eth::Api} as snake_case methods to the {Eth::Client} classes.
|
397
399
|
Api::COMMANDS.each do |cmd|
|
398
400
|
method_name = cmd.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
399
401
|
define_method method_name do |*args|
|
@@ -447,7 +449,7 @@ module Eth
|
|
447
449
|
def call_payload(fun, args)
|
448
450
|
types = fun.inputs.map { |i| i.type }
|
449
451
|
encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
|
450
|
-
|
452
|
+
Util.prefix_hex(fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str))
|
451
453
|
end
|
452
454
|
|
453
455
|
# Encodes constructor params
|
@@ -496,4 +498,5 @@ end
|
|
496
498
|
|
497
499
|
# Load the client/* libraries
|
498
500
|
require "eth/client/http"
|
501
|
+
require "eth/client/http_auth"
|
499
502
|
require "eth/client/ipc"
|
@@ -32,7 +32,7 @@ module Eth
|
|
32
32
|
|
33
33
|
# Returns complete types with subtypes, e.g., `uint256`.
|
34
34
|
def type
|
35
|
-
@type.base_type + @type.sub_type
|
35
|
+
@type.base_type + @type.sub_type + @type.dimensions.map { |dimension| "[#{dimension > 0 ? dimension : ""}]" }.join("")
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -31,7 +31,7 @@ module Eth
|
|
31
31
|
|
32
32
|
# Returns complete types with subtypes, e.g., `uint256`.
|
33
33
|
def type
|
34
|
-
@type.base_type + @type.sub_type
|
34
|
+
@type.base_type + @type.sub_type + @type.dimensions.map { |dimension| "[#{dimension > 0 ? dimension : ""}]" }.join("")
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
data/lib/eth/signature.rb
CHANGED
@@ -70,7 +70,10 @@ module Eth
|
|
70
70
|
context = Secp256k1::Context.new
|
71
71
|
r, s, v = dissect signature
|
72
72
|
v = v.to_i(16)
|
73
|
-
|
73
|
+
if !Chain.is_ledger? v and !Chain.is_legacy? v
|
74
|
+
min_v = 2 * chain_id + 35
|
75
|
+
raise SignatureError, "Invalid signature v byte #{v} for chain ID #{chain_id}!" if v < min_v
|
76
|
+
end
|
74
77
|
recovery_id = Chain.to_recovery_id v, chain_id
|
75
78
|
signature_rs = Util.hex_to_bin "#{r}#{s}"
|
76
79
|
recoverable_signature = context.recoverable_signature_from_compact signature_rs, recovery_id
|
data/lib/eth/tx/eip1559.rb
CHANGED
@@ -188,7 +188,7 @@ module Eth
|
|
188
188
|
|
189
189
|
# recover sender address
|
190
190
|
v = Chain.to_v recovery_id, chain_id
|
191
|
-
public_key = Signature.recover(unsigned_hash, "#{r}#{s}#{v.to_s(16)}", chain_id)
|
191
|
+
public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v.to_s(16)}", chain_id)
|
192
192
|
address = Util.public_key_to_address(public_key).to_s
|
193
193
|
@sender = Tx.sanitize_address address
|
194
194
|
end
|
data/lib/eth/tx/eip2930.rb
CHANGED
@@ -183,7 +183,7 @@ module Eth
|
|
183
183
|
|
184
184
|
# recover sender address
|
185
185
|
v = Chain.to_v recovery_id, chain_id
|
186
|
-
public_key = Signature.recover(unsigned_hash, "#{r}#{s}#{v.to_s(16)}", chain_id)
|
186
|
+
public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v.to_s(16)}", chain_id)
|
187
187
|
address = Util.public_key_to_address(public_key).to_s
|
188
188
|
@sender = Tx.sanitize_address address
|
189
189
|
end
|
data/lib/eth/tx/legacy.rb
CHANGED
@@ -156,7 +156,7 @@ module Eth
|
|
156
156
|
unless chain_id.nil?
|
157
157
|
|
158
158
|
# recover sender address
|
159
|
-
public_key = Signature.recover(unsigned_hash, "#{r}#{s}#{v}", chain_id)
|
159
|
+
public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v}", chain_id)
|
160
160
|
address = Util.public_key_to_address(public_key).to_s
|
161
161
|
@sender = Tx.sanitize_address address
|
162
162
|
else
|
data/lib/eth/tx.rb
CHANGED
@@ -39,8 +39,11 @@ module Eth
|
|
39
39
|
# The minimum transaction gas limit required for a value transfer.
|
40
40
|
DEFAULT_GAS_LIMIT = 21_000.freeze
|
41
41
|
|
42
|
-
# The "default" transaction
|
43
|
-
|
42
|
+
# The "default" transaction priority fee of 1.01 GWei. Do not use.
|
43
|
+
DEFAULT_PRIORITY_FEE = (1.01 * Unit::GWEI).freeze
|
44
|
+
|
45
|
+
# The "default" transaction gas price of 42.69 GWei. Do not use.
|
46
|
+
DEFAULT_GAS_PRICE = (42.69 * Unit::GWEI).freeze
|
44
47
|
|
45
48
|
# The calldata gas cost of a non-zero byte as per EIP-2028.
|
46
49
|
COST_NON_ZERO_BYTE = 16.freeze
|
@@ -55,7 +58,7 @@ module Eth
|
|
55
58
|
COST_ADDRESS = 2_400.freeze
|
56
59
|
|
57
60
|
# The maximum transaction gas limit is bound by the block gas limit.
|
58
|
-
BLOCK_GAS_LIMIT =
|
61
|
+
BLOCK_GAS_LIMIT = 30_000_000.freeze
|
59
62
|
|
60
63
|
# The legacy transaction type is 0.
|
61
64
|
TYPE_LEGACY = 0x00.freeze
|
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.7
|
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-10-31 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: keccak
|
@@ -122,6 +122,7 @@ files:
|
|
122
122
|
- lib/eth/chain.rb
|
123
123
|
- lib/eth/client.rb
|
124
124
|
- lib/eth/client/http.rb
|
125
|
+
- lib/eth/client/http_auth.rb
|
125
126
|
- lib/eth/client/ipc.rb
|
126
127
|
- lib/eth/constant.rb
|
127
128
|
- lib/eth/contract.rb
|
@@ -177,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
177
178
|
- !ruby/object:Gem::Version
|
178
179
|
version: '0'
|
179
180
|
requirements: []
|
180
|
-
rubygems_version: 3.3.
|
181
|
+
rubygems_version: 3.3.23
|
181
182
|
signing_key:
|
182
183
|
specification_version: 4
|
183
184
|
summary: Ruby Ethereum library.
|