eth 0.5.10 → 0.5.11
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/.github/workflows/spec.yml +8 -3
- data/CHANGELOG.md +16 -0
- data/eth.gemspec +4 -1
- data/lib/eth/abi/decoder.rb +135 -0
- data/lib/eth/abi/encoder.rb +304 -0
- data/lib/eth/abi/event.rb +13 -2
- data/lib/eth/abi/type.rb +1 -1
- data/lib/eth/abi.rb +10 -385
- data/lib/eth/api.rb +45 -51
- data/lib/eth/chain.rb +9 -0
- data/lib/eth/client/http.rb +18 -4
- data/lib/eth/client/ipc.rb +2 -2
- data/lib/eth/client.rb +59 -125
- data/lib/eth/contract.rb +11 -1
- data/lib/eth/solidity.rb +7 -4
- data/lib/eth/tx/eip1559.rb +10 -5
- data/lib/eth/tx/eip2930.rb +10 -5
- data/lib/eth/tx/legacy.rb +0 -2
- data/lib/eth/tx.rb +9 -2
- data/lib/eth/util.rb +1 -0
- data/lib/eth/version.rb +11 -2
- metadata +20 -5
- data/lib/eth/client/http_auth.rb +0 -73
data/lib/eth/client/ipc.rb
CHANGED
@@ -24,7 +24,7 @@ module Eth
|
|
24
24
|
attr_accessor :path
|
25
25
|
|
26
26
|
# Constructor for the IPC Client. Should not be used; use
|
27
|
-
# {Client.create}
|
27
|
+
# {Client.create} instead.
|
28
28
|
#
|
29
29
|
# @param path [String] an URI pointing to an IPC RPC-API.
|
30
30
|
def initialize(path)
|
@@ -36,7 +36,7 @@ module Eth
|
|
36
36
|
#
|
37
37
|
# @param payload [Hash] the RPC request parameters.
|
38
38
|
# @return [String] a JSON-encoded response.
|
39
|
-
def
|
39
|
+
def send_request(payload)
|
40
40
|
socket = UNIXSocket.new(@path)
|
41
41
|
socket.puts(payload)
|
42
42
|
read = socket.recvmsg(nil)[0]
|
data/lib/eth/client.rb
CHANGED
@@ -34,28 +34,22 @@ module Eth
|
|
34
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, defaults to {Tx::DEFAULT_GAS_LIMIT}.
|
38
|
-
attr_accessor :gas_limit
|
39
|
-
|
40
37
|
# A custom error type if a contract interaction fails.
|
41
38
|
class ContractExecutionError < StandardError; end
|
42
39
|
|
43
40
|
# Creates a new RPC-Client, either by providing an HTTP/S host or
|
44
41
|
# an IPC path. Supports basic authentication with username and password.
|
45
42
|
#
|
46
|
-
# **Note**, this sets the folling gas defaults: {Tx::DEFAULT_PRIORITY_FEE}
|
47
|
-
# {Tx::DEFAULT_GAS_PRICE
|
48
|
-
# {#
|
49
|
-
# custom values prior to submitting transactions.
|
43
|
+
# **Note**, this sets the folling gas defaults: {Tx::DEFAULT_PRIORITY_FEE}
|
44
|
+
# and {Tx::DEFAULT_GAS_PRICE. Use {#max_priority_fee_per_gas} and
|
45
|
+
# {#max_fee_per_gas} to set custom values prior to submitting transactions.
|
50
46
|
#
|
51
47
|
# @param host [String] either an HTTP/S host or an IPC path.
|
52
48
|
# @return [Eth::Client::Ipc] an IPC client.
|
53
|
-
# @return [Eth::Client::HttpAuth] an HTTP client with basic authentication.
|
54
49
|
# @return [Eth::Client::Http] an HTTP client.
|
55
50
|
# @raise [ArgumentError] in case it cannot determine the client type.
|
56
51
|
def self.create(host)
|
57
52
|
return Client::Ipc.new host if host.end_with? ".ipc"
|
58
|
-
return Client::HttpAuth.new host if Regexp.new(":.*@.*:", Regexp::IGNORECASE).match host
|
59
53
|
return Client::Http.new host if host.start_with? "http"
|
60
54
|
raise ArgumentError, "Unable to detect client type!"
|
61
55
|
end
|
@@ -66,7 +60,6 @@ module Eth
|
|
66
60
|
@id = 0
|
67
61
|
@max_priority_fee_per_gas = Tx::DEFAULT_PRIORITY_FEE
|
68
62
|
@max_fee_per_gas = Tx::DEFAULT_GAS_PRICE
|
69
|
-
@gas_limit = Tx::DEFAULT_GAS_LIMIT
|
70
63
|
end
|
71
64
|
|
72
65
|
# Gets the default account (coinbase) of the connected client.
|
@@ -76,7 +69,7 @@ module Eth
|
|
76
69
|
#
|
77
70
|
# @return [Eth::Address] the coinbase account address.
|
78
71
|
def default_account
|
79
|
-
raise ArgumentError, "The default account is not available on remote connections!" unless local?
|
72
|
+
raise ArgumentError, "The default account is not available on remote connections!" unless local? || @default_account
|
80
73
|
@default_account ||= Address.new eth_coinbase["result"]
|
81
74
|
end
|
82
75
|
|
@@ -146,41 +139,10 @@ module Eth
|
|
146
139
|
params = {
|
147
140
|
value: amount,
|
148
141
|
to: destination,
|
149
|
-
gas_limit:
|
142
|
+
gas_limit: Tx::DEFAULT_GAS_LIMIT,
|
150
143
|
chain_id: chain_id,
|
151
144
|
}
|
152
|
-
|
153
|
-
params.merge!({
|
154
|
-
gas_price: max_fee_per_gas,
|
155
|
-
})
|
156
|
-
else
|
157
|
-
params.merge!({
|
158
|
-
priority_fee: max_priority_fee_per_gas,
|
159
|
-
max_gas_fee: max_fee_per_gas,
|
160
|
-
})
|
161
|
-
end
|
162
|
-
unless kwargs[:sender_key].nil?
|
163
|
-
|
164
|
-
# use the provided key as sender and signer
|
165
|
-
params.merge!({
|
166
|
-
from: kwargs[:sender_key].address,
|
167
|
-
nonce: kwargs[:nonce] || get_nonce(kwargs[:sender_key].address),
|
168
|
-
})
|
169
|
-
tx = Eth::Tx.new(params)
|
170
|
-
tx.sign kwargs[:sender_key]
|
171
|
-
return eth_send_raw_transaction(tx.hex)["result"]
|
172
|
-
else
|
173
|
-
|
174
|
-
# we do not allow accessing accounts on remote connections
|
175
|
-
raise ArgumentError, "The default account is not available on remote connections, please provide a :sender_key!" unless local?
|
176
|
-
|
177
|
-
# use the default account as sender and external signer
|
178
|
-
params.merge!({
|
179
|
-
from: default_account,
|
180
|
-
nonce: kwargs[:nonce] || get_nonce(default_account),
|
181
|
-
})
|
182
|
-
return eth_send_transaction(params)["result"]
|
183
|
-
end
|
145
|
+
send_transaction(params, kwargs[:legacy], kwargs[:sender_key], kwargs[:nonce])
|
184
146
|
end
|
185
147
|
|
186
148
|
# Transfers a token that implements the ERC20 `transfer()` interface.
|
@@ -207,7 +169,7 @@ module Eth
|
|
207
169
|
# @param amount [Integer] the transfer amount (mind the `decimals()`).
|
208
170
|
# @param **sender_key [Eth::Key] the sender private key.
|
209
171
|
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
210
|
-
# @param **gas_limit [Integer] optional gas limit override for
|
172
|
+
# @param **gas_limit [Integer] optional gas limit override for the transfer.
|
211
173
|
# @param **nonce [Integer] optional specific nonce for transaction.
|
212
174
|
# @param **tx_value [Integer] optional transaction value field filling.
|
213
175
|
# @return [Object] returns the result of the transaction.
|
@@ -266,37 +228,7 @@ module Eth
|
|
266
228
|
chain_id: chain_id,
|
267
229
|
data: data,
|
268
230
|
}
|
269
|
-
|
270
|
-
params.merge!({
|
271
|
-
gas_price: max_fee_per_gas,
|
272
|
-
})
|
273
|
-
else
|
274
|
-
params.merge!({
|
275
|
-
priority_fee: max_priority_fee_per_gas,
|
276
|
-
max_gas_fee: max_fee_per_gas,
|
277
|
-
})
|
278
|
-
end
|
279
|
-
unless kwargs[:sender_key].nil?
|
280
|
-
# Uses the provided key as sender and signer
|
281
|
-
params.merge!({
|
282
|
-
from: kwargs[:sender_key].address,
|
283
|
-
nonce: kwargs[:nonce] || get_nonce(kwargs[:sender_key].address),
|
284
|
-
})
|
285
|
-
tx = Eth::Tx.new(params)
|
286
|
-
tx.sign kwargs[:sender_key]
|
287
|
-
return eth_send_raw_transaction(tx.hex)["result"]
|
288
|
-
else
|
289
|
-
|
290
|
-
# Does not allow accessing accounts on remote connections
|
291
|
-
raise ArgumentError, "The default account is not available on remote connections, please provide a :sender_key!" unless local?
|
292
|
-
|
293
|
-
# Uses the default account as sender and external signer
|
294
|
-
params.merge!({
|
295
|
-
from: default_account,
|
296
|
-
nonce: kwargs[:nonce] || get_nonce(default_account),
|
297
|
-
})
|
298
|
-
return eth_send_transaction(params)["result"]
|
299
|
-
end
|
231
|
+
send_transaction(params, kwargs[:legacy], kwargs[:sender_key], kwargs[:nonce])
|
300
232
|
end
|
301
233
|
|
302
234
|
# Calls a contract function without executing it
|
@@ -315,7 +247,6 @@ module Eth
|
|
315
247
|
# @param *args optional function arguments.
|
316
248
|
# @param **sender_key [Eth::Key] the sender private key.
|
317
249
|
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
318
|
-
# @param **gas_limit [Integer] optional gas limit override for deploying the contract.
|
319
250
|
# @return [Object] returns the result of the call.
|
320
251
|
def call(contract, function, *args, **kwargs)
|
321
252
|
func = contract.functions.select { |func| func.name == function }
|
@@ -328,9 +259,9 @@ module Eth
|
|
328
259
|
end
|
329
260
|
output = call_raw(contract, selected_func, *args, **kwargs)
|
330
261
|
if output&.length == 1
|
331
|
-
|
262
|
+
output[0]
|
332
263
|
else
|
333
|
-
|
264
|
+
output
|
334
265
|
end
|
335
266
|
end
|
336
267
|
|
@@ -354,7 +285,7 @@ module Eth
|
|
354
285
|
# @param **sender_key [Eth::Key] the sender private key.
|
355
286
|
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
356
287
|
# @param **address [Eth::Address] contract address.
|
357
|
-
# @param **gas_limit [Integer] optional gas limit override for
|
288
|
+
# @param **gas_limit [Integer] optional gas limit override for transacting with the contract.
|
358
289
|
# @param **nonce [Integer] optional specific nonce for transaction.
|
359
290
|
# @param **tx_value [Integer] optional transaction value field filling.
|
360
291
|
# @return [Object] returns the result of the transaction.
|
@@ -362,7 +293,7 @@ module Eth
|
|
362
293
|
gas_limit = if kwargs[:gas_limit]
|
363
294
|
kwargs[:gas_limit]
|
364
295
|
else
|
365
|
-
Tx.estimate_intrinsic_gas(contract.bin)
|
296
|
+
Tx.estimate_intrinsic_gas(contract.bin)
|
366
297
|
end
|
367
298
|
fun = contract.functions.select { |func| func.name == function }[0]
|
368
299
|
params = {
|
@@ -372,37 +303,7 @@ module Eth
|
|
372
303
|
to: kwargs[:address] || contract.address,
|
373
304
|
data: call_payload(fun, args),
|
374
305
|
}
|
375
|
-
|
376
|
-
params.merge!({
|
377
|
-
gas_price: max_fee_per_gas,
|
378
|
-
})
|
379
|
-
else
|
380
|
-
params.merge!({
|
381
|
-
priority_fee: max_priority_fee_per_gas,
|
382
|
-
max_gas_fee: max_fee_per_gas,
|
383
|
-
})
|
384
|
-
end
|
385
|
-
unless kwargs[:sender_key].nil?
|
386
|
-
# use the provided key as sender and signer
|
387
|
-
params.merge!({
|
388
|
-
from: kwargs[:sender_key].address,
|
389
|
-
nonce: kwargs[:nonce] || get_nonce(kwargs[:sender_key].address),
|
390
|
-
})
|
391
|
-
tx = Eth::Tx.new(params)
|
392
|
-
tx.sign kwargs[:sender_key]
|
393
|
-
return eth_send_raw_transaction(tx.hex)["result"]
|
394
|
-
else
|
395
|
-
|
396
|
-
# do not allow accessing accounts on remote connections
|
397
|
-
raise ArgumentError, "The default account is not available on remote connections, please provide a :sender_key!" unless local?
|
398
|
-
|
399
|
-
# use the default account as sender and external signer
|
400
|
-
params.merge!({
|
401
|
-
from: default_account,
|
402
|
-
nonce: kwargs[:nonce] || get_nonce(default_account),
|
403
|
-
})
|
404
|
-
return eth_send_transaction(params)["result"]
|
405
|
-
end
|
306
|
+
send_transaction(params, kwargs[:legacy], kwargs[:sender_key], kwargs[:nonce])
|
406
307
|
end
|
407
308
|
|
408
309
|
# Executes a contract function with a transaction and waits for it
|
@@ -437,7 +338,7 @@ module Eth
|
|
437
338
|
signature = Util.hex_to_bin signature if Util.hex? signature
|
438
339
|
magic = Util.hex_to_bin magic if Util.hex? magic
|
439
340
|
result = call(contract, "isValidSignature", hash, signature)
|
440
|
-
|
341
|
+
result === magic
|
441
342
|
end
|
442
343
|
|
443
344
|
# Gives control over resetting the RPC request ID back to zero.
|
@@ -496,11 +397,45 @@ module Eth
|
|
496
397
|
# Allows to determine if we work with a local connectoin
|
497
398
|
def local?
|
498
399
|
if self.instance_of? Eth::Client::Ipc
|
499
|
-
|
400
|
+
true
|
500
401
|
elsif self.host === "127.0.0.1" || self.host === "localhost"
|
501
|
-
|
402
|
+
true
|
502
403
|
else
|
503
|
-
|
404
|
+
false
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
# Prepares a transaction to be send for the given params.
|
409
|
+
def send_transaction(params, legacy, key, nonce)
|
410
|
+
if legacy
|
411
|
+
params.merge!({ gas_price: max_fee_per_gas })
|
412
|
+
else
|
413
|
+
params.merge!({
|
414
|
+
priority_fee: max_priority_fee_per_gas,
|
415
|
+
max_gas_fee: max_fee_per_gas,
|
416
|
+
})
|
417
|
+
end
|
418
|
+
unless key.nil?
|
419
|
+
|
420
|
+
# use the provided key as sender and signer
|
421
|
+
params.merge!({
|
422
|
+
from: key.address,
|
423
|
+
nonce: nonce || get_nonce(key.address),
|
424
|
+
})
|
425
|
+
tx = Eth::Tx.new(params)
|
426
|
+
tx.sign key
|
427
|
+
eth_send_raw_transaction(tx.hex)["result"]
|
428
|
+
else
|
429
|
+
|
430
|
+
# do not allow accessing accounts on remote connections
|
431
|
+
raise ArgumentError, "The default account is not available on remote connections, please provide a :sender_key!" unless local?
|
432
|
+
|
433
|
+
# use the default account as sender and external signer
|
434
|
+
params.merge!({
|
435
|
+
from: default_account,
|
436
|
+
nonce: nonce || get_nonce(default_account),
|
437
|
+
})
|
438
|
+
eth_send_transaction(params)["result"]
|
504
439
|
end
|
505
440
|
end
|
506
441
|
|
@@ -541,9 +476,9 @@ module Eth
|
|
541
476
|
params: marshal(args),
|
542
477
|
id: next_id,
|
543
478
|
}
|
544
|
-
output = JSON.parse(
|
479
|
+
output = JSON.parse(send_request(payload.to_json))
|
545
480
|
raise IOError, output["error"]["message"] unless output["error"].nil?
|
546
|
-
|
481
|
+
output
|
547
482
|
end
|
548
483
|
|
549
484
|
# Increments the request id.
|
@@ -564,18 +499,18 @@ module Eth
|
|
564
499
|
def marshal(params)
|
565
500
|
params = params.dup
|
566
501
|
if params.is_a? Array
|
567
|
-
|
502
|
+
params.map! { |param| marshal(param) }
|
568
503
|
elsif params.is_a? Hash
|
569
504
|
params = camelize!(params)
|
570
|
-
|
505
|
+
params.transform_values! { |param| marshal(param) }
|
571
506
|
elsif params.is_a? Numeric
|
572
|
-
|
507
|
+
Util.prefix_hex "#{params.to_i.to_s(16)}"
|
573
508
|
elsif params.is_a? Address
|
574
|
-
|
509
|
+
params.to_s
|
575
510
|
elsif Util.hex? params
|
576
|
-
|
511
|
+
Util.prefix_hex params
|
577
512
|
else
|
578
|
-
|
513
|
+
params
|
579
514
|
end
|
580
515
|
end
|
581
516
|
end
|
@@ -583,5 +518,4 @@ end
|
|
583
518
|
|
584
519
|
# Load the client/* libraries
|
585
520
|
require "eth/client/http"
|
586
|
-
require "eth/client/http_auth"
|
587
521
|
require "eth/client/ipc"
|
data/lib/eth/contract.rb
CHANGED
@@ -14,6 +14,8 @@
|
|
14
14
|
|
15
15
|
# -*- encoding : ascii-8bit -*-
|
16
16
|
|
17
|
+
require "forwardable"
|
18
|
+
|
17
19
|
# Provides the {Eth} module.
|
18
20
|
module Eth
|
19
21
|
|
@@ -27,11 +29,19 @@ module Eth
|
|
27
29
|
|
28
30
|
# Constructor of the {Eth::Contract} class.
|
29
31
|
#
|
32
|
+
# **Note**, do not use this directly. Use
|
33
|
+
# {from_abi}, {from_bin}, or {from_file}!
|
34
|
+
#
|
30
35
|
# @param name [String] contract name.
|
31
36
|
# @param bin [String] contract bin string.
|
32
37
|
# @param abi [String] contract abi string.
|
33
38
|
def initialize(name, bin, abi)
|
34
|
-
|
39
|
+
|
40
|
+
# The contract name will be the class name and needs title casing.
|
41
|
+
_name = name.dup
|
42
|
+
_name[0] = name[0].upcase
|
43
|
+
|
44
|
+
@name = _name
|
35
45
|
@bin = bin
|
36
46
|
@abi = abi
|
37
47
|
@constructor_inputs, @functions, @events = parse_abi(abi)
|
data/lib/eth/solidity.rb
CHANGED
@@ -28,10 +28,12 @@ module Eth
|
|
28
28
|
|
29
29
|
# Instantiates a Solidity `solc` system compiler binding that can be
|
30
30
|
# used to compile Solidity contracts.
|
31
|
-
|
31
|
+
#
|
32
|
+
# @param path [String] optional override of the solidity compiler path.
|
33
|
+
def initialize(path = nil)
|
32
34
|
|
33
|
-
# Currently only supports `solc`.
|
34
|
-
solc = get_compiler_path
|
35
|
+
# Currently only supports `solc`. Try to override with `path`.
|
36
|
+
solc = path || get_compiler_path
|
35
37
|
raise SystemCallError, "Unable to find the solc compiler path!" if solc.nil?
|
36
38
|
@compiler = solc
|
37
39
|
end
|
@@ -43,9 +45,10 @@ module Eth
|
|
43
45
|
def compile(contract)
|
44
46
|
raise Errno::ENOENT, "Contract file not found: #{contract}" unless File.exist? contract
|
45
47
|
flag_opt = "--optimize"
|
48
|
+
flag_ir = "--via-ir"
|
46
49
|
flag_json = "--combined-json=bin,abi"
|
47
50
|
path = File.realpath contract
|
48
|
-
output, error, status = Open3.capture3 @compiler, flag_opt, flag_json, path
|
51
|
+
output, error, status = Open3.capture3 @compiler, flag_opt, flag_ir, flag_json, path
|
49
52
|
raise SystemCallError, "Unable to run solc compiler!" if status.exitstatus === 127
|
50
53
|
raise CompilerError, error unless status.success?
|
51
54
|
json = JSON.parse output
|
data/lib/eth/tx/eip1559.rb
CHANGED
@@ -186,11 +186,16 @@ module Eth
|
|
186
186
|
# last but not least, set the type.
|
187
187
|
@type = TYPE_1559
|
188
188
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
189
|
+
unless recovery_id.nil?
|
190
|
+
# recover sender address
|
191
|
+
v = Chain.to_v recovery_id, chain_id
|
192
|
+
public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v.to_s(16)}", chain_id)
|
193
|
+
address = Util.public_key_to_address(public_key).to_s
|
194
|
+
@sender = Tx.sanitize_address address
|
195
|
+
else
|
196
|
+
# keep the 'from' field blank
|
197
|
+
@sender = Tx.sanitize_address nil
|
198
|
+
end
|
194
199
|
end
|
195
200
|
|
196
201
|
# Creates an unsigned copy of a transaction payload.
|
data/lib/eth/tx/eip2930.rb
CHANGED
@@ -181,11 +181,16 @@ module Eth
|
|
181
181
|
# last but not least, set the type.
|
182
182
|
@type = TYPE_2930
|
183
183
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
184
|
+
unless recovery_id.nil?
|
185
|
+
# recover sender address
|
186
|
+
v = Chain.to_v recovery_id, chain_id
|
187
|
+
public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v.to_s(16)}", chain_id)
|
188
|
+
address = Util.public_key_to_address(public_key).to_s
|
189
|
+
@sender = Tx.sanitize_address address
|
190
|
+
else
|
191
|
+
# keep the 'from' field blank
|
192
|
+
@sender = Tx.sanitize_address nil
|
193
|
+
end
|
189
194
|
end
|
190
195
|
|
191
196
|
# Creates an unsigned copy of a transaction payload.
|
data/lib/eth/tx/legacy.rb
CHANGED
@@ -154,13 +154,11 @@ module Eth
|
|
154
154
|
_set_signature(v, r, s)
|
155
155
|
|
156
156
|
unless chain_id.nil?
|
157
|
-
|
158
157
|
# recover sender address
|
159
158
|
public_key = Signature.recover(unsigned_hash, "#{r.rjust(64, "0")}#{s.rjust(64, "0")}#{v}", chain_id)
|
160
159
|
address = Util.public_key_to_address(public_key).to_s
|
161
160
|
@sender = Tx.sanitize_address address
|
162
161
|
else
|
163
|
-
|
164
162
|
# keep the 'from' field blank
|
165
163
|
@sender = Tx.sanitize_address nil
|
166
164
|
end
|
data/lib/eth/tx.rb
CHANGED
@@ -51,6 +51,9 @@ module Eth
|
|
51
51
|
# The calldata gas cost of a zero byte.
|
52
52
|
COST_ZERO_BYTE = 4.freeze
|
53
53
|
|
54
|
+
# The initcode gas cost for each word (32 bytes).
|
55
|
+
COST_INITCODE_WORD = 2.freeze
|
56
|
+
|
54
57
|
# The access list gas cost of a storage key as per EIP-2930.
|
55
58
|
COST_STORAGE_KEY = 1_900.freeze
|
56
59
|
|
@@ -156,7 +159,7 @@ module Eth
|
|
156
159
|
end
|
157
160
|
|
158
161
|
# Estimates intrinsic gas for provided call data (EIP-2028) and
|
159
|
-
# access lists (EIP-2930).
|
162
|
+
# access lists (EIP-2930). Respects initcode word cost (EIP-3860).
|
160
163
|
#
|
161
164
|
# @param data [String] the call data.
|
162
165
|
# @param list [Array] the access list.
|
@@ -173,6 +176,10 @@ module Eth
|
|
173
176
|
# count non-zero bytes
|
174
177
|
none = data.size - zero
|
175
178
|
gas += none * COST_NON_ZERO_BYTE
|
179
|
+
|
180
|
+
# count "words" as per EIP-3860
|
181
|
+
word_count = (data.length.to_f / 32.0).ceil
|
182
|
+
gas += word_count * COST_INITCODE_WORD
|
176
183
|
end
|
177
184
|
unless list.nil? or list.empty?
|
178
185
|
list.each do |entry|
|
@@ -187,7 +194,7 @@ module Eth
|
|
187
194
|
end
|
188
195
|
end
|
189
196
|
end
|
190
|
-
return gas
|
197
|
+
return gas.to_i
|
191
198
|
end
|
192
199
|
|
193
200
|
# Validates the common transaction fields such as nonce, gas limit,
|
data/lib/eth/util.rb
CHANGED
@@ -28,6 +28,7 @@ module Eth
|
|
28
28
|
# @return [Eth::Address] an Ethereum address.
|
29
29
|
def public_key_to_address(str)
|
30
30
|
str = hex_to_bin str if hex? str
|
31
|
+
str = Secp256k1::PublicKey.from_data(str).uncompressed
|
31
32
|
bytes = keccak256(str[1..-1])[-20..-1]
|
32
33
|
Address.new bin_to_prefixed_hex bytes
|
33
34
|
end
|
data/lib/eth/version.rb
CHANGED
@@ -15,6 +15,15 @@
|
|
15
15
|
# Provides the {Eth} module.
|
16
16
|
module Eth
|
17
17
|
|
18
|
-
# Defines the version of the {Eth} module.
|
19
|
-
|
18
|
+
# Defines the major version of the {Eth} module.
|
19
|
+
MAJOR = 0.freeze
|
20
|
+
|
21
|
+
# Defines the minor version of the {Eth} module.
|
22
|
+
MINOR = 5.freeze
|
23
|
+
|
24
|
+
# Defines the patch version of the {Eth} module.
|
25
|
+
PATCH = 11.freeze
|
26
|
+
|
27
|
+
# Defines the version string of the {Eth} module.
|
28
|
+
VERSION = [MAJOR, MINOR, PATCH].join(".").freeze
|
20
29
|
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.
|
4
|
+
version: 0.5.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Ellis
|
@@ -9,8 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-08-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: forwardable
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.3'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.3'
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: keccak
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,14 +59,14 @@ dependencies:
|
|
45
59
|
requirements:
|
46
60
|
- - "~>"
|
47
61
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
62
|
+
version: '6.0'
|
49
63
|
type: :runtime
|
50
64
|
prerelease: false
|
51
65
|
version_requirements: !ruby/object:Gem::Requirement
|
52
66
|
requirements:
|
53
67
|
- - "~>"
|
54
68
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
69
|
+
version: '6.0'
|
56
70
|
- !ruby/object:Gem::Dependency
|
57
71
|
name: openssl
|
58
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,6 +134,8 @@ files:
|
|
120
134
|
- eth.gemspec
|
121
135
|
- lib/eth.rb
|
122
136
|
- lib/eth/abi.rb
|
137
|
+
- lib/eth/abi/decoder.rb
|
138
|
+
- lib/eth/abi/encoder.rb
|
123
139
|
- lib/eth/abi/event.rb
|
124
140
|
- lib/eth/abi/type.rb
|
125
141
|
- lib/eth/address.rb
|
@@ -127,7 +143,6 @@ files:
|
|
127
143
|
- lib/eth/chain.rb
|
128
144
|
- lib/eth/client.rb
|
129
145
|
- lib/eth/client/http.rb
|
130
|
-
- lib/eth/client/http_auth.rb
|
131
146
|
- lib/eth/client/ipc.rb
|
132
147
|
- lib/eth/constant.rb
|
133
148
|
- lib/eth/contract.rb
|
data/lib/eth/client/http_auth.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
# Copyright (c) 2016-2023 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
|