eth 0.5.5 → 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62da01e731dd3a73a356760ac971250f193142090876e62567d73cbb5664213d
4
- data.tar.gz: 8a951b1b585acd7b58dc327f122dbdd4787145fefbe09d71f1aa4d127787e99e
3
+ metadata.gz: 86b3022f82e96aed2d1aad682ad106f3f5efe9488e03ed048e0c5862d30c3284
4
+ data.tar.gz: 40cb5224db9e074360586aca07f6421edc47668fa0f5d81728fa7574f0c2a978
5
5
  SHA512:
6
- metadata.gz: fd1ca2d9f89a545f20cf23a9cff62a83bfe20514b69cb14aac88f08cd101a8bb9e26ba700539259c16d64ee2a3cbae46adf7bedd18b66835785ad701fd515681
7
- data.tar.gz: a1f51f0dac47d8ce7a4ccd3df0d3decfdb0847df36a4b16587b5dd9ae217aee7375e952207d00611bcb487647ff152d958d4709ebf8b429ec0235220f45d35bd
6
+ metadata.gz: cf5872ec79f0c708a5c05060514b9179279db310b1c0c0682679cd90bcd0998f9ef1a7f8787c298380a252462c5ea33fdc3d44c0bdb5e3c57991515514077b85
7
+ data.tar.gz: 4a7adde0050a724270f5779a2fe4fca596202a930ee7e1af1e4493878a21e7102ee75a2d5ce91ac455b016c9c396d6771396e5c890f5dcef7ea220b0eadd2d58
@@ -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@v4.3.3
23
+ uses: JamesIves/github-pages-deploy-action@v4.4.0
24
24
  with:
25
25
  branch: gh-pages
26
26
  folder: doc/
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
  [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/q9f/eth.rb/Spec)](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
- ## 1. Installation
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
- ## 2. Usage
66
- Check out
67
- [![Yard Doc API](https://img.shields.io/badge/documentation-API-blue)](https://q9f.github.io/eth.rb)
68
- and
54
+ ## Usage
55
+ Check out the
56
+ [![Yard API Docs](https://img.shields.io/badge/documentation-API-blue)](https://q9f.github.io/eth.rb)
57
+ and the
69
58
  [![Usage Wiki](https://img.shields.io/badge/usage-WIKI-blue)](https://github.com/q9f/eth.rb/wiki)
70
- for full details.
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
- ## 3. Documentation
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 v0.5.0
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
- ## 4. Testing
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
- ## 5. Contributing
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
- ## 6. License and Credits
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/ (MIT)
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/abi.rb CHANGED
@@ -74,7 +74,7 @@ module Eth
74
74
  # @return [String] the encoded type.
75
75
  # @raise [EncodingError] if value does not match type.
76
76
  def encode_type(type, arg)
77
- if %w(string bytes).include? type.base_type and type.sub_type.empty?
77
+ if %w(string bytes).include? type.base_type and type.sub_type.empty? and type.dimensions.empty?
78
78
  raise EncodingError, "Argument must be a String" unless arg.instance_of? String
79
79
 
80
80
  # encodes strings and bytes
@@ -89,10 +89,24 @@ module Eth
89
89
  head += encode_type Type.size_type, arg.size
90
90
  nested_sub = type.nested_sub
91
91
  nested_sub_size = type.nested_sub.size
92
- arg.size.times do |i|
93
92
 
94
- # ref https://github.com/ethereum/tests/issues/691
95
- raise NotImplementedError, "Encoding dynamic arrays with nested dynamic sub-types is not implemented for ABI." if nested_sub.is_dynamic?
93
+ # calculate offsets
94
+ if %w(string bytes).include?(type.base_type) && type.sub_type.empty?
95
+ offset = 0
96
+ arg.size.times do |i|
97
+ if i == 0
98
+ offset = arg.size * 32
99
+ else
100
+ number_of_words = ((arg[i - 1].size + 32 - 1) / 32).floor
101
+ total_bytes_length = number_of_words * 32
102
+ offset += total_bytes_length + 32
103
+ end
104
+
105
+ head += encode_type Type.size_type, offset
106
+ end
107
+ end
108
+
109
+ arg.size.times do |i|
96
110
  head += encode_type nested_sub, arg[i]
97
111
  end
98
112
  return "#{head}#{tail}"
@@ -306,6 +320,7 @@ module Eth
306
320
 
307
321
  # Properly encodes unsigned integers.
308
322
  def encode_uint(arg, type)
323
+ raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
309
324
  raise ValueOutOfBounds, "Number out of range: #{arg}" if arg > Constant::UINT_MAX or arg < Constant::UINT_MIN
310
325
  real_size = type.sub_type.to_i
311
326
  i = arg.to_i
@@ -315,6 +330,7 @@ module Eth
315
330
 
316
331
  # Properly encodes signed integers.
317
332
  def encode_int(arg, type)
333
+ raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
318
334
  raise ValueOutOfBounds, "Number out of range: #{arg}" if arg > Constant::INT_MAX or arg < Constant::INT_MIN
319
335
  real_size = type.sub_type.to_i
320
336
  i = arg.to_i
@@ -330,6 +346,7 @@ module Eth
330
346
 
331
347
  # Properly encodes unsigned fixed-point numbers.
332
348
  def encode_ufixed(arg, type)
349
+ raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
333
350
  high, low = type.sub_type.split("x").map(&:to_i)
334
351
  raise ValueOutOfBounds, arg unless arg >= 0 and arg < 2 ** high
335
352
  return Util.zpad_int((arg * 2 ** low).to_i)
@@ -337,6 +354,7 @@ module Eth
337
354
 
338
355
  # Properly encodes signed fixed-point numbers.
339
356
  def encode_fixed(arg, type)
357
+ raise ArgumentError, "Don't know how to handle this input." unless arg.is_a? Numeric
340
358
  high, low = type.sub_type.split("x").map(&:to_i)
341
359
  raise ValueOutOfBounds, arg unless arg >= -2 ** (high - 1) and arg < 2 ** (high - 1)
342
360
  i = (arg * 2 ** low).to_i
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 = 0
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 sender key is
103
+ # Uses `eth_coinbase` and external signer if no sender key is
94
104
  # provided.
95
105
  #
96
- # @param destination [Eth::Address] the destination address.
97
- # @param amount [Integer] the transfer amount in Wei.
98
- # @param sender_key [Eth::Key] the sender private key.
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,14 +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
- # @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.
166
+ # See {#deploy} for params and overloads.
167
+ #
168
+ # @return [String] the contract address once it's mined.
163
169
  def deploy_and_wait(contract, *args, **kwargs)
164
170
  hash = wait_for_tx(deploy(contract, *args, **kwargs))
165
171
  addr = eth_get_transaction_receipt(hash)["result"]["contractAddress"]
@@ -169,23 +175,34 @@ module Eth
169
175
  # Deploys a contract. Uses `eth_coinbase` or external signer
170
176
  # if no sender key is provided.
171
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
+ #
172
181
  # @overload deploy(contract)
173
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.
174
186
  # @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).
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.
179
192
  # @return [String] the transaction hash.
180
193
  # @raise [ArgumentError] in case the contract does not have any source.
181
194
  def deploy(contract, *args, **kwargs)
182
195
  raise ArgumentError, "Cannot deploy contract without source or binary!" if contract.bin.nil?
183
196
  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
197
  data = contract.bin
186
198
  unless args.empty?
187
199
  data += encode_constructor_params(contract, args)
188
200
  end
201
+ gas_limit = if kwargs[:gas_limit]
202
+ kwargs[:gas_limit]
203
+ else
204
+ Tx.estimate_intrinsic_gas(data) + Tx::CREATE_GAS
205
+ end
189
206
  params = {
190
207
  value: 0,
191
208
  gas_limit: gas_limit,
@@ -224,23 +241,24 @@ module Eth
224
241
  # Calls a contract function without executing it
225
242
  # (non-transactional contract read).
226
243
  #
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).
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.
240
258
  # @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?
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?
244
262
  output = call_raw(contract, func, *args, **kwargs)
245
263
  if output&.length == 1
246
264
  return output[0]
@@ -252,24 +270,32 @@ module Eth
252
270
  # Executes a contract function with a transaction (transactional
253
271
  # contract read/write).
254
272
  #
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
+ # **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)
293
+ gas_limit = if kwargs[:gas_limit]
294
+ kwargs[:gas_limit]
295
+ else
296
+ Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
297
+ end
298
+ fun = contract.functions.select { |func| func.name == function }[0]
273
299
  params = {
274
300
  value: 0,
275
301
  gas_limit: gas_limit,
@@ -309,23 +335,11 @@ module Eth
309
335
  # Executes a contract function with a transaction and waits for it
310
336
  # to be mined (transactional contract read/write).
311
337
  #
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))
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))
329
343
  end
330
344
 
331
345
  # Provides an interface to call `isValidSignature` as per EIP-1271 on a given
@@ -381,7 +395,7 @@ module Eth
381
395
  end
382
396
 
383
397
  # Metafunction to provide all known RPC commands defined in
384
- # Eth::Api as snake_case methods to the Eth::Client classes.
398
+ # {Eth::Api} as snake_case methods to the {Eth::Client} classes.
385
399
  Api::COMMANDS.each do |cmd|
386
400
  method_name = cmd.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
387
401
  define_method method_name do |*args|
@@ -393,7 +407,11 @@ module Eth
393
407
 
394
408
  # Non-transactional function call called from call().
395
409
  def call_raw(contract, func, *args, **kwargs)
396
- gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
410
+ gas_limit = if kwargs[:gas_limit]
411
+ kwargs[:gas_limit]
412
+ else
413
+ Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
414
+ end
397
415
  params = {
398
416
  gas_limit: gas_limit,
399
417
  chain_id: chain_id,
@@ -431,7 +449,7 @@ module Eth
431
449
  def call_payload(fun, args)
432
450
  types = fun.inputs.map { |i| i.type }
433
451
  encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
434
- "0x" + fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str)
452
+ Util.prefix_hex(fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str))
435
453
  end
436
454
 
437
455
  # Encodes constructor params
@@ -480,4 +498,5 @@ end
480
498
 
481
499
  # Load the client/* libraries
482
500
  require "eth/client/http"
501
+ require "eth/client/http_auth"
483
502
  require "eth/client/ipc"
@@ -43,7 +43,7 @@ module Eth
43
43
  # @param inputs [Array<Eth::Contract::FunctionInput>] function input class list.
44
44
  # @return [String] function string.
45
45
  def self.calc_signature(name, inputs)
46
- "#{name}(#{inputs.collect { |x| x.type }.join(",")})"
46
+ "#{name}(#{inputs.collect { |x| x.raw_type }.join(",")})"
47
47
  end
48
48
 
49
49
  # Encodes a function signature.
@@ -19,19 +19,20 @@ module Eth
19
19
 
20
20
  # Provide classes for contract function input.
21
21
  class Contract::FunctionInput
22
- attr_accessor :type, :name
22
+ attr_accessor :type, :raw_type, :name
23
23
 
24
24
  # Constructor of the {Eth::Contract::FunctionInput} class.
25
25
  #
26
26
  # @param data [Hash] contract abi data.
27
27
  def initialize(data)
28
+ @raw_type = data["type"]
28
29
  @type = Eth::Abi::Type.parse(data["type"])
29
30
  @name = data["name"]
30
31
  end
31
32
 
32
33
  # Returns complete types with subtypes, e.g., `uint256`.
33
34
  def type
34
- @type.base_type + @type.sub_type
35
+ @type.base_type + @type.sub_type + @type.dimensions.map { |dimension| "[#{dimension > 0 ? dimension : ""}]" }.join("")
35
36
  end
36
37
  end
37
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
@@ -38,7 +38,7 @@ module Eth
38
38
  # @param message [String] the message string to be prefixed.
39
39
  # @return [String] an EIP-191 prefixed string.
40
40
  def prefix_message(message)
41
- "#{EIP191_PREFIX_BYTE}Ethereum Signed Message:\n#{message.size}#{message}"
41
+ "#{EIP191_PREFIX_BYTE}Ethereum Signed Message:\n#{message.bytesize}#{message}"
42
42
  end
43
43
 
44
44
  # Dissects a signature blob of 65+ bytes into its `r`, `s`, and `v`
@@ -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
- raise SignatureError, "Invalid signature v byte #{v} for chain ID #{chain_id}!" if v < chain_id
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
@@ -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
@@ -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 gas price of 20 GWei. Do not use.
43
- DEFAULT_GAS_PRICE = (20 * Unit::GWEI).freeze
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 = 25_000_000.freeze
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
@@ -16,5 +16,5 @@
16
16
  module Eth
17
17
 
18
18
  # Defines the version of the {Eth} module.
19
- VERSION = "0.5.5".freeze
19
+ VERSION = "0.5.7".freeze
20
20
  end
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.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-05-30 00:00:00.000000000 Z
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.8
181
+ rubygems_version: 3.3.23
181
182
  signing_key:
182
183
  specification_version: 4
183
184
  summary: Ruby Ethereum library.