eth 0.5.6 → 0.5.8
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/codeql.yml +1 -1
- data/.github/workflows/docs.yml +2 -2
- data/.github/workflows/spec.yml +2 -2
- data/CHANGELOG.md +49 -0
- data/Gemfile +2 -2
- data/README.md +23 -259
- data/abis/ens.json +422 -0
- data/eth.gemspec +2 -2
- data/lib/eth/chain.rb +9 -0
- data/lib/eth/client/http_auth.rb +73 -0
- data/lib/eth/client.rb +114 -128
- data/lib/eth/contract/function_input.rb +1 -1
- data/lib/eth/contract/function_output.rb +1 -1
- data/lib/eth/ens/resolver.rb +77 -0
- 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
- data/lib/eth.rb +1 -0
- metadata +8 -4
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,35 +100,41 @@ 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
|
-
|
100
|
-
|
101
|
-
def transfer_and_wait(destination, amount, sender_key = nil, legacy = false)
|
102
|
-
wait_for_tx(transfer(destination, amount, sender_key, legacy))
|
106
|
+
# See {#transfer} for params and overloads.
|
107
|
+
#
|
108
|
+
# @return [String] the transaction hash once it is mined.
|
109
|
+
def transfer_and_wait(destination, amount, **kwargs)
|
110
|
+
wait_for_tx(transfer(destination, amount, **kwargs))
|
103
111
|
end
|
104
112
|
|
105
113
|
# Simply transfer Ether to an account without any call data or
|
106
114
|
# access lists attached. Uses `eth_coinbase` and external signer
|
107
115
|
# if no sender key is provided.
|
108
116
|
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
# @
|
113
|
-
#
|
114
|
-
|
117
|
+
# **Note**, that many remote providers (e.g., Infura) do not provide
|
118
|
+
# any accounts. Provide a `sender_key` if you experience issues.
|
119
|
+
#
|
120
|
+
# @overload transfer(destination, amount)
|
121
|
+
# @param destination [Eth::Address] the destination address.
|
122
|
+
# @param amount [Integer] the transfer amount in Wei.
|
123
|
+
# @overload transfer(destination, amount, **kwargs)
|
124
|
+
# @param destination [Eth::Address] the destination address.
|
125
|
+
# @param amount [Integer] the transfer amount in Wei.
|
126
|
+
# @param **sender_key [Eth::Key] the sender private key.
|
127
|
+
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
128
|
+
# @param **nonce [Integer] optional specific nonce for transaction.
|
129
|
+
# @return [String] the local transaction hash.
|
130
|
+
def transfer(destination, amount, **kwargs)
|
115
131
|
params = {
|
116
132
|
value: amount,
|
117
133
|
to: destination,
|
118
134
|
gas_limit: gas_limit,
|
119
135
|
chain_id: chain_id,
|
120
136
|
}
|
121
|
-
if legacy
|
137
|
+
if kwargs[:legacy]
|
122
138
|
params.merge!({
|
123
139
|
gas_price: max_fee_per_gas,
|
124
140
|
})
|
@@ -128,22 +144,22 @@ module Eth
|
|
128
144
|
max_gas_fee: max_fee_per_gas,
|
129
145
|
})
|
130
146
|
end
|
131
|
-
unless sender_key.nil?
|
147
|
+
unless kwargs[:sender_key].nil?
|
132
148
|
|
133
149
|
# use the provided key as sender and signer
|
134
150
|
params.merge!({
|
135
|
-
from: sender_key.address,
|
136
|
-
nonce: get_nonce(sender_key.address),
|
151
|
+
from: kwargs[:sender_key].address,
|
152
|
+
nonce: kwargs[:nonce] || get_nonce(kwargs[:sender_key].address),
|
137
153
|
})
|
138
154
|
tx = Eth::Tx.new(params)
|
139
|
-
tx.sign sender_key
|
155
|
+
tx.sign kwargs[:sender_key]
|
140
156
|
return eth_send_raw_transaction(tx.hex)["result"]
|
141
157
|
else
|
142
158
|
|
143
159
|
# use the default account as sender and external signer
|
144
160
|
params.merge!({
|
145
161
|
from: default_account,
|
146
|
-
nonce: get_nonce(default_account),
|
162
|
+
nonce: kwargs[:nonce] || get_nonce(default_account),
|
147
163
|
})
|
148
164
|
return eth_send_transaction(params)["result"]
|
149
165
|
end
|
@@ -152,15 +168,9 @@ module Eth
|
|
152
168
|
# Deploys a contract and waits for it to be mined. Uses
|
153
169
|
# `eth_coinbase` or external signer if no sender key is provided.
|
154
170
|
#
|
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.
|
171
|
+
# See {#deploy} for params and overloads.
|
172
|
+
#
|
173
|
+
# @return [String] the contract address once it's mined.
|
164
174
|
def deploy_and_wait(contract, *args, **kwargs)
|
165
175
|
hash = wait_for_tx(deploy(contract, *args, **kwargs))
|
166
176
|
addr = eth_get_transaction_receipt(hash)["result"]["contractAddress"]
|
@@ -170,14 +180,21 @@ module Eth
|
|
170
180
|
# Deploys a contract. Uses `eth_coinbase` or external signer
|
171
181
|
# if no sender key is provided.
|
172
182
|
#
|
183
|
+
# **Note**, that many remote providers (e.g., Infura) do not provide
|
184
|
+
# any accounts. Provide a `sender_key` if you experience issues.
|
185
|
+
#
|
173
186
|
# @overload deploy(contract)
|
174
187
|
# @param contract [Eth::Contract] contracts to deploy.
|
188
|
+
# @overload deploy(contract, *args)
|
189
|
+
# @param contract [Eth::Contract] the contracts to deploy.
|
190
|
+
# @param *args (optional) variable constructor parameter list.
|
175
191
|
# @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.
|
192
|
+
# @param contract [Eth::Contract] the contracts to deploy.
|
193
|
+
# @param *args (optional) variable constructor parameter list.
|
194
|
+
# @param **sender_key [Eth::Key] the sender private key.
|
195
|
+
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
196
|
+
# @param **gas_limit [Integer] optional gas limit override for deploying the contract.
|
197
|
+
# @param **nonce [Integer] optional specific nonce for transaction.
|
181
198
|
# @return [String] the transaction hash.
|
182
199
|
# @raise [ArgumentError] in case the contract does not have any source.
|
183
200
|
def deploy(contract, *args, **kwargs)
|
@@ -212,7 +229,7 @@ module Eth
|
|
212
229
|
# Uses the provided key as sender and signer
|
213
230
|
params.merge!({
|
214
231
|
from: kwargs[:sender_key].address,
|
215
|
-
nonce: get_nonce(kwargs[:sender_key].address),
|
232
|
+
nonce: kwargs[:nonce] || get_nonce(kwargs[:sender_key].address),
|
216
233
|
})
|
217
234
|
tx = Eth::Tx.new(params)
|
218
235
|
tx.sign kwargs[:sender_key]
|
@@ -221,7 +238,7 @@ module Eth
|
|
221
238
|
# Uses the default account as sender and external signer
|
222
239
|
params.merge!({
|
223
240
|
from: default_account,
|
224
|
-
nonce: get_nonce(default_account),
|
241
|
+
nonce: kwargs[:nonce] || get_nonce(default_account),
|
225
242
|
})
|
226
243
|
return eth_send_transaction(params)["result"]
|
227
244
|
end
|
@@ -230,24 +247,24 @@ module Eth
|
|
230
247
|
# Calls a contract function without executing it
|
231
248
|
# (non-transactional contract read).
|
232
249
|
#
|
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.
|
250
|
+
# @overload call(contract, function)
|
251
|
+
# @param contract [Eth::Contract] the subject contract to call.
|
252
|
+
# @param function [String] method name to be called.
|
253
|
+
# @overload call(contract, function, *args)
|
254
|
+
# @param contract [Eth::Contract] the subject contract to call.
|
255
|
+
# @param function [String] method name to be called.
|
256
|
+
# @param *args optional function arguments.
|
257
|
+
# @overload call(contract, function, *args, **kwargs)
|
258
|
+
# @param contract [Eth::Contract] the subject contract to call.
|
259
|
+
# @param function [String] method name to be called.
|
260
|
+
# @param *args optional function arguments.
|
261
|
+
# @param **sender_key [Eth::Key] the sender private key.
|
262
|
+
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
263
|
+
# @param **gas_limit [Integer] optional gas limit override for deploying the contract.
|
247
264
|
# @return [Object] returns the result of the call.
|
248
|
-
def call(contract,
|
249
|
-
func = contract.functions.select { |func| func.name ==
|
250
|
-
raise ArgumentError, "
|
265
|
+
def call(contract, function, *args, **kwargs)
|
266
|
+
func = contract.functions.select { |func| func.name == function }[0]
|
267
|
+
raise ArgumentError, "this function does not exist!" if func.nil?
|
251
268
|
output = call_raw(contract, func, *args, **kwargs)
|
252
269
|
if output&.length == 1
|
253
270
|
return output[0]
|
@@ -259,31 +276,36 @@ module Eth
|
|
259
276
|
# Executes a contract function with a transaction (transactional
|
260
277
|
# contract read/write).
|
261
278
|
#
|
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
|
-
|
279
|
+
# **Note**, that many remote providers (e.g., Infura) do not provide
|
280
|
+
# any accounts. Provide a `sender_key` if you experience issues.
|
281
|
+
#
|
282
|
+
# @overload transact(contract, function)
|
283
|
+
# @param contract [Eth::Contract] the subject contract to write to.
|
284
|
+
# @param function [String] method name to be executed.
|
285
|
+
# @overload transact(contract, function, *args)
|
286
|
+
# @param contract [Eth::Contract] the subject contract to write to.
|
287
|
+
# @param function [String] method name to be executed.
|
288
|
+
# @param *args optional function arguments.
|
289
|
+
# @overload transact(contract, function, *args, **kwargs)
|
290
|
+
# @param contract [Eth::Contract] the subject contract to write to.
|
291
|
+
# @param function_name [String] method name to be executed.
|
292
|
+
# @param *args optional function arguments.
|
293
|
+
# @param **sender_key [Eth::Key] the sender private key.
|
294
|
+
# @param **legacy [Boolean] enables legacy transactions (pre-EIP-1559).
|
295
|
+
# @param **address [Eth::Address] contract address.
|
296
|
+
# @param **gas_limit [Integer] optional gas limit override for deploying the contract.
|
297
|
+
# @param **nonce [Integer] optional specific nonce for transaction.
|
298
|
+
# @param **tx_value [Integer] optional transaction value field filling.
|
299
|
+
# @return [Object] returns the result of the transaction.
|
300
|
+
def transact(contract, function, *args, **kwargs)
|
279
301
|
gas_limit = if kwargs[:gas_limit]
|
280
302
|
kwargs[:gas_limit]
|
281
303
|
else
|
282
304
|
Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
|
283
305
|
end
|
284
|
-
fun = contract.functions.select { |func| func.name ==
|
306
|
+
fun = contract.functions.select { |func| func.name == function }[0]
|
285
307
|
params = {
|
286
|
-
value: 0,
|
308
|
+
value: kwargs[:tx_value] || 0,
|
287
309
|
gas_limit: gas_limit,
|
288
310
|
chain_id: chain_id,
|
289
311
|
to: kwargs[:address] || contract.address,
|
@@ -303,7 +325,7 @@ module Eth
|
|
303
325
|
# use the provided key as sender and signer
|
304
326
|
params.merge!({
|
305
327
|
from: kwargs[:sender_key].address,
|
306
|
-
nonce: get_nonce(kwargs[:sender_key].address),
|
328
|
+
nonce: kwargs[:nonce] || get_nonce(kwargs[:sender_key].address),
|
307
329
|
})
|
308
330
|
tx = Eth::Tx.new(params)
|
309
331
|
tx.sign kwargs[:sender_key]
|
@@ -312,7 +334,7 @@ module Eth
|
|
312
334
|
# use the default account as sender and external signer
|
313
335
|
params.merge!({
|
314
336
|
from: default_account,
|
315
|
-
nonce: get_nonce(default_account),
|
337
|
+
nonce: kwargs[:nonce] || get_nonce(default_account),
|
316
338
|
})
|
317
339
|
return eth_send_transaction(params)["result"]
|
318
340
|
end
|
@@ -321,23 +343,11 @@ module Eth
|
|
321
343
|
# Executes a contract function with a transaction and waits for it
|
322
344
|
# to be mined (transactional contract read/write).
|
323
345
|
#
|
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))
|
346
|
+
# See {#transact} for params and overloads.
|
347
|
+
#
|
348
|
+
# @return [Object] returns the result of the transaction.
|
349
|
+
def transact_and_wait(contract, function, *args, **kwargs)
|
350
|
+
wait_for_tx(transact(contract, function, *args, **kwargs))
|
341
351
|
end
|
342
352
|
|
343
353
|
# Provides an interface to call `isValidSignature` as per EIP-1271 on a given
|
@@ -393,7 +403,7 @@ module Eth
|
|
393
403
|
end
|
394
404
|
|
395
405
|
# Metafunction to provide all known RPC commands defined in
|
396
|
-
# Eth::Api as snake_case methods to the Eth::Client classes.
|
406
|
+
# {Eth::Api} as snake_case methods to the {Eth::Client} classes.
|
397
407
|
Api::COMMANDS.each do |cmd|
|
398
408
|
method_name = cmd.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
399
409
|
define_method method_name do |*args|
|
@@ -404,39 +414,14 @@ module Eth
|
|
404
414
|
private
|
405
415
|
|
406
416
|
# Non-transactional function call called from call().
|
417
|
+
# @see https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call
|
407
418
|
def call_raw(contract, func, *args, **kwargs)
|
408
|
-
gas_limit = if kwargs[:gas_limit]
|
409
|
-
kwargs[:gas_limit]
|
410
|
-
else
|
411
|
-
Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
|
412
|
-
end
|
413
419
|
params = {
|
414
|
-
gas_limit: gas_limit,
|
415
|
-
chain_id: chain_id,
|
416
420
|
data: call_payload(func, args),
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
if kwargs[:legacy]
|
422
|
-
params.merge!({
|
423
|
-
gas_price: max_fee_per_gas,
|
424
|
-
})
|
425
|
-
else
|
426
|
-
params.merge!({
|
427
|
-
priority_fee: max_priority_fee_per_gas,
|
428
|
-
max_gas_fee: max_fee_per_gas,
|
429
|
-
})
|
430
|
-
end
|
431
|
-
unless kwargs[:sender_key].nil?
|
432
|
-
# Uses the provided key as sender and signer
|
433
|
-
params.merge!({
|
434
|
-
from: kwargs[:sender_key].address,
|
435
|
-
nonce: get_nonce(kwargs[:sender_key].address),
|
436
|
-
})
|
437
|
-
tx = Eth::Tx.new(params)
|
438
|
-
tx.sign kwargs[:sender_key]
|
439
|
-
end
|
421
|
+
to: kwargs[:address] || contract.address,
|
422
|
+
from: kwargs[:from],
|
423
|
+
}.compact
|
424
|
+
|
440
425
|
raw_result = eth_call(params)["result"]
|
441
426
|
types = func.outputs.map { |i| i.type }
|
442
427
|
return nil if raw_result == "0x"
|
@@ -447,7 +432,7 @@ module Eth
|
|
447
432
|
def call_payload(fun, args)
|
448
433
|
types = fun.inputs.map { |i| i.type }
|
449
434
|
encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
|
450
|
-
|
435
|
+
Util.prefix_hex(fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str))
|
451
436
|
end
|
452
437
|
|
453
438
|
# Encodes constructor params
|
@@ -496,4 +481,5 @@ end
|
|
496
481
|
|
497
482
|
# Load the client/* libraries
|
498
483
|
require "eth/client/http"
|
484
|
+
require "eth/client/http_auth"
|
499
485
|
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
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Copyright (c) 2016-2022 The Ruby-Eth Contributors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# -*- encoding : ascii-8bit -*-
|
16
|
+
|
17
|
+
# Provides the {Eth} module.
|
18
|
+
module Eth
|
19
|
+
# Provides ENS specific functionality
|
20
|
+
# ref: https://ens.domains
|
21
|
+
module Ens
|
22
|
+
|
23
|
+
# Utility class for resolving ENS names to Ethereum addresses
|
24
|
+
class Resolver
|
25
|
+
|
26
|
+
# The default address for ENS, which applies to most chains
|
27
|
+
DEFAULT_ADDRESS = "0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e".freeze
|
28
|
+
|
29
|
+
# Create an instance of the ENS Resolver
|
30
|
+
#
|
31
|
+
# @param client [Eth::Client] The client instance
|
32
|
+
# @param address [String] The address of the ENS contract
|
33
|
+
def initialize(client, address = DEFAULT_ADDRESS)
|
34
|
+
@client = client
|
35
|
+
@contract = Eth::Contract.from_abi(
|
36
|
+
name: "ENS",
|
37
|
+
address: address,
|
38
|
+
abi: JSON.parse(File.read(File.join(File.dirname(__FILE__), "../../../abis/ens.json"))),
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Resolve an ENS name to an address
|
43
|
+
#
|
44
|
+
# @param ens_name [String] The ENS name, eg: fancy.eth
|
45
|
+
# @return [String] The owner address of the name, as a hex string
|
46
|
+
def resolve(ens_name)
|
47
|
+
@client.call(@contract, "owner", namehash(ens_name))
|
48
|
+
end
|
49
|
+
|
50
|
+
# Generate node for the given domain name
|
51
|
+
# See: https://docs.ens.domains/contract-api-reference/name-processing
|
52
|
+
#
|
53
|
+
# @param ens_name [String] The ENS name, eg: fancy.eth
|
54
|
+
# @return [String] The node as a hex string
|
55
|
+
def namehash(ens_name)
|
56
|
+
node = ("0" * 64)
|
57
|
+
name = normalize(ens_name)
|
58
|
+
name.split(".").reverse.each do |label|
|
59
|
+
hash = Digest::Keccak.new(256).hexdigest(label)
|
60
|
+
node = Digest::Keccak.new(256).hexdigest([node + hash].pack("H*"))
|
61
|
+
end
|
62
|
+
"0x#{node}"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Normalize a string as specified by http://unicode.org/reports/tr46/
|
66
|
+
#
|
67
|
+
# @param input [String] The input string
|
68
|
+
# @return [String] The normalized output string
|
69
|
+
def normalize(input)
|
70
|
+
# TODO: This is fairly complicated, and there doesn't seem to be a ruby
|
71
|
+
# library which can handle it perfectly.
|
72
|
+
# https://www.unicode.org/reports/tr46/tr46-27.html
|
73
|
+
input.downcase
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
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
data/lib/eth.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.8
|
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-11-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: keccak
|
@@ -109,6 +109,7 @@ files:
|
|
109
109
|
- LICENSE.txt
|
110
110
|
- README.md
|
111
111
|
- Rakefile
|
112
|
+
- abis/ens.json
|
112
113
|
- bin/console
|
113
114
|
- bin/setup
|
114
115
|
- codecov.yml
|
@@ -122,6 +123,7 @@ files:
|
|
122
123
|
- lib/eth/chain.rb
|
123
124
|
- lib/eth/client.rb
|
124
125
|
- lib/eth/client/http.rb
|
126
|
+
- lib/eth/client/http_auth.rb
|
125
127
|
- lib/eth/client/ipc.rb
|
126
128
|
- lib/eth/constant.rb
|
127
129
|
- lib/eth/contract.rb
|
@@ -131,6 +133,7 @@ files:
|
|
131
133
|
- lib/eth/contract/function_output.rb
|
132
134
|
- lib/eth/contract/initializer.rb
|
133
135
|
- lib/eth/eip712.rb
|
136
|
+
- lib/eth/ens/resolver.rb
|
134
137
|
- lib/eth/key.rb
|
135
138
|
- lib/eth/key/decrypter.rb
|
136
139
|
- lib/eth/key/encrypter.rb
|
@@ -163,11 +166,12 @@ post_install_message:
|
|
163
166
|
rdoc_options: []
|
164
167
|
require_paths:
|
165
168
|
- lib
|
169
|
+
- abis
|
166
170
|
required_ruby_version: !ruby/object:Gem::Requirement
|
167
171
|
requirements:
|
168
172
|
- - ">="
|
169
173
|
- !ruby/object:Gem::Version
|
170
|
-
version: '2.
|
174
|
+
version: '2.7'
|
171
175
|
- - "<"
|
172
176
|
- !ruby/object:Gem::Version
|
173
177
|
version: '4.0'
|
@@ -177,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
177
181
|
- !ruby/object:Gem::Version
|
178
182
|
version: '0'
|
179
183
|
requirements: []
|
180
|
-
rubygems_version: 3.3.
|
184
|
+
rubygems_version: 3.3.25
|
181
185
|
signing_key:
|
182
186
|
specification_version: 4
|
183
187
|
summary: Ruby Ethereum library.
|