eth-custom 0.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.github/dependabot.yml +18 -0
  3. data/.github/workflows/codeql.yml +48 -0
  4. data/.github/workflows/docs.yml +26 -0
  5. data/.github/workflows/spec.yml +52 -0
  6. data/.gitignore +43 -0
  7. data/.gitmodules +3 -0
  8. data/.rspec +4 -0
  9. data/.yardopts +1 -0
  10. data/AUTHORS.txt +29 -0
  11. data/CHANGELOG.md +218 -0
  12. data/Gemfile +17 -0
  13. data/LICENSE.txt +202 -0
  14. data/README.md +347 -0
  15. data/Rakefile +6 -0
  16. data/bin/console +10 -0
  17. data/bin/setup +9 -0
  18. data/codecov.yml +6 -0
  19. data/eth.gemspec +51 -0
  20. data/lib/eth/abi/event.rb +137 -0
  21. data/lib/eth/abi/type.rb +178 -0
  22. data/lib/eth/abi.rb +446 -0
  23. data/lib/eth/address.rb +106 -0
  24. data/lib/eth/api.rb +223 -0
  25. data/lib/eth/chain.rb +157 -0
  26. data/lib/eth/client/http.rb +63 -0
  27. data/lib/eth/client/ipc.rb +50 -0
  28. data/lib/eth/client.rb +499 -0
  29. data/lib/eth/constant.rb +71 -0
  30. data/lib/eth/contract/event.rb +42 -0
  31. data/lib/eth/contract/function.rb +57 -0
  32. data/lib/eth/contract/function_input.rb +38 -0
  33. data/lib/eth/contract/function_output.rb +37 -0
  34. data/lib/eth/contract/initializer.rb +47 -0
  35. data/lib/eth/contract.rb +143 -0
  36. data/lib/eth/eip712.rb +184 -0
  37. data/lib/eth/key/decrypter.rb +146 -0
  38. data/lib/eth/key/encrypter.rb +207 -0
  39. data/lib/eth/key.rb +167 -0
  40. data/lib/eth/rlp/decoder.rb +114 -0
  41. data/lib/eth/rlp/encoder.rb +78 -0
  42. data/lib/eth/rlp/sedes/big_endian_int.rb +66 -0
  43. data/lib/eth/rlp/sedes/binary.rb +97 -0
  44. data/lib/eth/rlp/sedes/list.rb +84 -0
  45. data/lib/eth/rlp/sedes.rb +74 -0
  46. data/lib/eth/rlp.rb +63 -0
  47. data/lib/eth/signature.rb +163 -0
  48. data/lib/eth/solidity.rb +75 -0
  49. data/lib/eth/tx/eip1559.rb +337 -0
  50. data/lib/eth/tx/eip2930.rb +329 -0
  51. data/lib/eth/tx/legacy.rb +297 -0
  52. data/lib/eth/tx.rb +322 -0
  53. data/lib/eth/unit.rb +49 -0
  54. data/lib/eth/util.rb +235 -0
  55. data/lib/eth/version.rb +20 -0
  56. data/lib/eth.rb +35 -0
  57. metadata +184 -0
data/lib/eth/client.rb ADDED
@@ -0,0 +1,499 @@
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
+ # Provides the {Eth} module.
16
+ module Eth
17
+
18
+ # Provides the {Eth::Client} super-class to connect to Ethereum
19
+ # network's RPC-API endpoints (IPC or HTTP).
20
+ class Client
21
+
22
+ # The client's RPC-request ID starting at 0.
23
+ attr_reader :id
24
+
25
+ # The connected network's chain ID.
26
+ attr_reader :chain_id
27
+
28
+ # The connected network's client coinbase.
29
+ attr_accessor :default_account
30
+
31
+ # The default transaction max priority fee per gas in Wei.
32
+ attr_accessor :max_priority_fee_per_gas
33
+
34
+ # The default transaction max fee per gas in Wei.
35
+ attr_accessor :max_fee_per_gas
36
+
37
+ # The default gas limit for the transaction.
38
+ attr_accessor :gas_limit
39
+
40
+ # Creates a new RPC-Client, either by providing an HTTP/S host or
41
+ # an IPC path.
42
+ #
43
+ # @param host [String] either an HTTP/S host or an IPC path.
44
+ # @return [Eth::Client::Ipc] an IPC client.
45
+ # @return [Eth::Client::Http] an HTTP client.
46
+ # @raise [ArgumentError] in case it cannot determine the client type.
47
+ def self.create(host)
48
+ return Client::Ipc.new host if host.end_with? ".ipc"
49
+ return Client::Http.new host if host.start_with? "http"
50
+ raise ArgumentError, "Unable to detect client type!"
51
+ end
52
+
53
+ # Constructor for the {Eth::Client} super-class. Should not be used;
54
+ # use {Client.create} intead.
55
+ def initialize(_)
56
+ @id = 0
57
+ @max_priority_fee_per_gas = 0
58
+ @max_fee_per_gas = Tx::DEFAULT_GAS_PRICE
59
+ @gas_limit = Tx::DEFAULT_GAS_LIMIT
60
+ end
61
+
62
+ # Gets the default account (coinbase) of the connected client.
63
+ #
64
+ # @return [Eth::Address] the coinbase account address.
65
+ def default_account
66
+ @default_account ||= Address.new eth_coinbase["result"]
67
+ end
68
+
69
+ # Gets the chain ID of the connected network.
70
+ #
71
+ # @return [Integer] the chain ID.
72
+ def chain_id
73
+ @chain_id ||= eth_chain_id["result"].to_i 16
74
+ end
75
+
76
+ # Gets the balance for an address.
77
+ #
78
+ # @param address [Eth::Address] the address to get the balance for.
79
+ # @return [Integer] the balance in Wei.
80
+ def get_balance(address)
81
+ eth_get_balance(address)["result"].to_i 16
82
+ end
83
+
84
+ # Gets the next nonce for an address used to draft new transactions.
85
+ #
86
+ # @param address [Eth::Address] the address to get the nonce for.
87
+ # @return [Integer] the next nonce to be used.
88
+ def get_nonce(address)
89
+ eth_get_transaction_count(address, "pending")["result"].to_i 16
90
+ end
91
+
92
+ # 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
94
+ # provided.
95
+ #
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.
101
+ def transfer_and_wait(destination, amount, sender_key = nil, legacy = false)
102
+ wait_for_tx(transfer(destination, amount, sender_key, legacy))
103
+ end
104
+
105
+ # Simply transfer Ether to an account without any call data or
106
+ # access lists attached. Uses `eth_coinbase` and external signer
107
+ # if no sender key is provided.
108
+ #
109
+ # @param destination [Eth::Address] the destination address.
110
+ # @param amount [Integer] the transfer amount in Wei.
111
+ # @param sender_key [Eth::Key] the sender private key.
112
+ # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
113
+ # @return [String] the transaction hash.
114
+ def transfer(destination, amount, sender_key = nil, legacy = false)
115
+ params = {
116
+ value: amount,
117
+ to: destination,
118
+ gas_limit: gas_limit,
119
+ chain_id: chain_id,
120
+ }
121
+ if legacy
122
+ params.merge!({
123
+ gas_price: max_fee_per_gas,
124
+ })
125
+ else
126
+ params.merge!({
127
+ priority_fee: max_priority_fee_per_gas,
128
+ max_gas_fee: max_fee_per_gas,
129
+ })
130
+ end
131
+ unless sender_key.nil?
132
+
133
+ # use the provided key as sender and signer
134
+ params.merge!({
135
+ from: sender_key.address,
136
+ nonce: get_nonce(sender_key.address),
137
+ })
138
+ tx = Eth::Tx.new(params)
139
+ tx.sign sender_key
140
+ return eth_send_raw_transaction(tx.hex)["result"]
141
+ else
142
+
143
+ # use the default account as sender and external signer
144
+ params.merge!({
145
+ from: default_account,
146
+ nonce: get_nonce(default_account),
147
+ })
148
+ return eth_send_transaction(params)["result"]
149
+ end
150
+ end
151
+
152
+ # Deploys a contract and waits for it to be mined. Uses
153
+ # `eth_coinbase` or external signer if no sender key is provided.
154
+ #
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
+ # **gas_limit [Integer] optional gas limit override for deploying the contract.
163
+ # @return [String] the contract address.
164
+ def deploy_and_wait(contract, *args, **kwargs)
165
+ hash = wait_for_tx(deploy(contract, *args, **kwargs))
166
+ addr = eth_get_transaction_receipt(hash)["result"]["contractAddress"]
167
+ contract.address = Address.new(addr).to_s
168
+ end
169
+
170
+ # Deploys a contract. Uses `eth_coinbase` or external signer
171
+ # if no sender key is provided.
172
+ #
173
+ # @overload deploy(contract)
174
+ # @param contract [Eth::Contract] contracts to deploy.
175
+ # @overload deploy(contract, *args, **kwargs)
176
+ # @param contract [Eth::Contract] contracts to deploy.
177
+ # *args Optional variable constructor parameter list
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.
181
+ # @return [String] the transaction hash.
182
+ # @raise [ArgumentError] in case the contract does not have any source.
183
+ def deploy(contract, *args, **kwargs)
184
+ raise ArgumentError, "Cannot deploy contract without source or binary!" if contract.bin.nil?
185
+ raise ArgumentError, "Missing contract constructor params!" if contract.constructor_inputs.length != args.length
186
+ data = contract.bin
187
+ unless args.empty?
188
+ data += encode_constructor_params(contract, args)
189
+ end
190
+ gas_limit = if kwargs[:gas_limit]
191
+ kwargs[:gas_limit]
192
+ else
193
+ Tx.estimate_intrinsic_gas(data) + Tx::CREATE_GAS
194
+ end
195
+ params = {
196
+ value: 0,
197
+ gas_limit: gas_limit,
198
+ chain_id: chain_id,
199
+ data: data,
200
+ }
201
+ if kwargs[:legacy]
202
+ params.merge!({
203
+ gas_price: max_fee_per_gas,
204
+ })
205
+ else
206
+ params.merge!({
207
+ priority_fee: max_priority_fee_per_gas,
208
+ max_gas_fee: max_fee_per_gas,
209
+ })
210
+ end
211
+ unless kwargs[:sender_key].nil?
212
+ # Uses the provided key as sender and signer
213
+ params.merge!({
214
+ from: kwargs[:sender_key].address,
215
+ nonce: get_nonce(kwargs[:sender_key].address),
216
+ })
217
+ tx = Eth::Tx.new(params)
218
+ tx.sign kwargs[:sender_key]
219
+ return eth_send_raw_transaction(tx.hex)["result"]
220
+ else
221
+ # Uses the default account as sender and external signer
222
+ params.merge!({
223
+ from: default_account,
224
+ nonce: get_nonce(default_account),
225
+ })
226
+ return eth_send_transaction(params)["result"]
227
+ end
228
+ end
229
+
230
+ # Calls a contract function without executing it
231
+ # (non-transactional contract read).
232
+ #
233
+ # @overload call(contract, function_name)
234
+ # @param contract [Eth::Contract] subject contract to call.
235
+ # @param function_name [String] method name to be called.
236
+ # @overload call(contract, function_name, value)
237
+ # @param contract [Eth::Contract] subject contract to call.
238
+ # @param function_name [String] method name to be called.
239
+ # @param value [Integer|String] function arguments.
240
+ # @overload call(contract, function_name, value, sender_key, legacy, gas_limit)
241
+ # @param contract [Eth::Contract] subject contract to call.
242
+ # @param function_name [String] method name to be called.
243
+ # @param value [Integer|String] function arguments.
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.
247
+ # @return [Object] returns the result of the call.
248
+ def call(contract, function_name, *args, **kwargs)
249
+ func = contract.functions.select { |func| func.name == function_name }[0]
250
+ raise ArgumentError, "function_name does not exist!" if func.nil?
251
+ output = call_raw(contract, func, *args, **kwargs)
252
+ if output&.length == 1
253
+ return output[0]
254
+ else
255
+ return output
256
+ end
257
+ end
258
+
259
+ # Executes a contract function with a transaction (transactional
260
+ # contract read/write).
261
+ #
262
+ # @overload transact(contract, function_name)
263
+ # @param contract [Eth::Contract] subject contract to call.
264
+ # @param function_name [String] method name to be called.
265
+ # @overload transact(contract, function_name, value)
266
+ # @param contract [Eth::Contract] subject contract to call.
267
+ # @param function_name [String] method name to be called.
268
+ # @param value [Integer|String] function arguments.
269
+ # @overload transact(contract, function_name, value, sender_key, legacy, address, gas_limit)
270
+ # @param contract [Eth::Contract] subject contract to call.
271
+ # @param function_name [String] method name to be called.
272
+ # @param value [Integer|String] function arguments.
273
+ # @param sender_key [Eth::Key] the sender private key.
274
+ # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
275
+ # @param address [String] contract address.
276
+ # @param gas_limit [Integer] optional gas limit override for deploying the contract.
277
+ # @return [Object] returns the result of the call.
278
+ def transact(contract, function_name, *args, **kwargs)
279
+ gas_limit = if kwargs[:gas_limit]
280
+ kwargs[:gas_limit]
281
+ else
282
+ Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
283
+ end
284
+ fun = contract.functions.select { |func| func.name == function_name }[0]
285
+ params = {
286
+ value: 0,
287
+ gas_limit: gas_limit,
288
+ chain_id: chain_id,
289
+ to: kwargs[:address] || contract.address,
290
+ data: call_payload(fun, args),
291
+ }
292
+ if kwargs[:legacy]
293
+ params.merge!({
294
+ gas_price: max_fee_per_gas,
295
+ })
296
+ else
297
+ params.merge!({
298
+ priority_fee: max_priority_fee_per_gas,
299
+ max_gas_fee: max_fee_per_gas,
300
+ })
301
+ end
302
+ unless kwargs[:sender_key].nil?
303
+ # use the provided key as sender and signer
304
+ params.merge!({
305
+ from: kwargs[:sender_key].address,
306
+ nonce: get_nonce(kwargs[:sender_key].address),
307
+ })
308
+ tx = Eth::Tx.new(params)
309
+ tx.sign kwargs[:sender_key]
310
+ return eth_send_raw_transaction(tx.hex)["result"]
311
+ else
312
+ # use the default account as sender and external signer
313
+ params.merge!({
314
+ from: default_account,
315
+ nonce: get_nonce(default_account),
316
+ })
317
+ return eth_send_transaction(params)["result"]
318
+ end
319
+ end
320
+
321
+ # Executes a contract function with a transaction and waits for it
322
+ # to be mined (transactional contract read/write).
323
+ #
324
+ # @overload transact_and_wait(contract, function_name)
325
+ # @param contract [Eth::Contract] subject contract to call.
326
+ # @param function_name [String] method name to be called.
327
+ # @overload transact_and_wait(contract, function_name, value)
328
+ # @param contract [Eth::Contract] subject contract to call.
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))
341
+ end
342
+
343
+ # Provides an interface to call `isValidSignature` as per EIP-1271 on a given
344
+ # smart contract to verify the given hash and signature matching the magic
345
+ # value.
346
+ #
347
+ # @param contract [Eth::Contract] a deployed contract implementing EIP-1271.
348
+ # @param hash [String] the message hash to be checked against the signature.
349
+ # @param signature [String] the signature to be recovered by the contract.
350
+ # @param magic [String] the expected magic value (defaults to `1626ba7e`).
351
+ # @return [Boolean] true if magic matches and signature is valid.
352
+ # @raise [ArgumentError] in case the contract cannot be called yet.
353
+ def is_valid_signature(contract, hash, signature, magic = "1626ba7e")
354
+ raise ArgumentError, "Contract not deployed yet." if contract.address.nil?
355
+ hash = Util.hex_to_bin hash if Util.is_hex? hash
356
+ signature = Util.hex_to_bin signature if Util.is_hex? signature
357
+ magic = Util.hex_to_bin magic if Util.is_hex? magic
358
+ result = call(contract, "isValidSignature", hash, signature)
359
+ return result === magic
360
+ end
361
+
362
+ # Gives control over resetting the RPC request ID back to zero.
363
+ # Usually not needed.
364
+ #
365
+ # @return [Integer] 0
366
+ def reset_id
367
+ @id = 0
368
+ end
369
+
370
+ # Checkes wether a transaction is mined or not.
371
+ #
372
+ # @param hash [String] the transaction hash.
373
+ # @return [Boolean] true if included in a block.
374
+ def is_mined_tx?(hash)
375
+ mined_tx = eth_get_transaction_by_hash hash
376
+ !mined_tx.nil? && !mined_tx["result"].nil? && !mined_tx["result"]["blockNumber"].nil?
377
+ end
378
+
379
+ # Waits for an transaction to be mined by the connected chain.
380
+ #
381
+ # @param hash [String] the transaction hash.
382
+ # @return [String] the transaction hash once the transaction is mined.
383
+ # @raise [Timeout::Error] if it's not mined within 5 minutes.
384
+ def wait_for_tx(hash)
385
+ start_time = Time.now
386
+ timeout = 300
387
+ retry_rate = 0.1
388
+ loop do
389
+ raise Timeout::Error if ((Time.now - start_time) > timeout)
390
+ return hash if is_mined_tx? hash
391
+ sleep retry_rate
392
+ end
393
+ end
394
+
395
+ # Metafunction to provide all known RPC commands defined in
396
+ # Eth::Api as snake_case methods to the Eth::Client classes.
397
+ Api::COMMANDS.each do |cmd|
398
+ method_name = cmd.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
399
+ define_method method_name do |*args|
400
+ send_command cmd, args
401
+ end
402
+ end
403
+
404
+ private
405
+
406
+ # Non-transactional function call called from call().
407
+ 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
+ params = {
414
+ gas_limit: gas_limit,
415
+ chain_id: chain_id,
416
+ data: call_payload(func, args),
417
+ }
418
+ if kwargs[:address] || contract.address
419
+ params.merge!({ to: kwargs[:address] || contract.address })
420
+ end
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
440
+ raw_result = eth_call(params)["result"]
441
+ types = func.outputs.map { |i| i.type }
442
+ return nil if raw_result == "0x"
443
+ Eth::Abi.decode(types, raw_result)
444
+ end
445
+
446
+ # Encodes function call payloads.
447
+ def call_payload(fun, args)
448
+ types = fun.inputs.map { |i| i.type }
449
+ encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
450
+ "0x" + fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str)
451
+ end
452
+
453
+ # Encodes constructor params
454
+ def encode_constructor_params(contract, args)
455
+ types = contract.constructor_inputs.map { |input| input.type }
456
+ Util.bin_to_hex(Eth::Abi.encode(types, args))
457
+ end
458
+
459
+ # Prepares parameters and sends the command to the client.
460
+ def send_command(command, args)
461
+ args << "latest" if ["eth_getBalance", "eth_call"].include? command
462
+ payload = {
463
+ jsonrpc: "2.0",
464
+ method: command,
465
+ params: marshal(args),
466
+ id: next_id,
467
+ }
468
+ output = JSON.parse(send(payload.to_json))
469
+ raise IOError, output["error"]["message"] unless output["error"].nil?
470
+ return output
471
+ end
472
+
473
+ # Increments the request id.
474
+ def next_id
475
+ @id += 1
476
+ end
477
+
478
+ # Recursively marshals all request parameters.
479
+ def marshal(params)
480
+ if params.is_a? Array
481
+ return params.map! { |param| marshal(param) }
482
+ elsif params.is_a? Hash
483
+ return params.transform_values! { |param| marshal(param) }
484
+ elsif params.is_a? Numeric
485
+ return Util.prefix_hex "#{params.to_i.to_s(16)}"
486
+ elsif params.is_a? Address
487
+ return params.to_s
488
+ elsif Util.is_hex? params
489
+ return Util.prefix_hex params
490
+ else
491
+ return params
492
+ end
493
+ end
494
+ end
495
+ end
496
+
497
+ # Load the client/* libraries
498
+ require "eth/client/http"
499
+ require "eth/client/ipc"
@@ -0,0 +1,71 @@
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
+
20
+ # Provides commonly used constants, such as zero bytes or zero keys.
21
+ module Constant
22
+
23
+ # The empty byte is defined as "".
24
+ BYTE_EMPTY = "".freeze
25
+
26
+ # The zero byte is 0x00.
27
+ BYTE_ZERO = "\x00".freeze
28
+
29
+ # The byte one is 0x01.
30
+ BYTE_ONE = "\x01".freeze
31
+
32
+ # The size of a 32-bit number.
33
+ TT32 = (2 ** 32).freeze
34
+
35
+ # The size of a 256-bit number.
36
+ TT256 = (2 ** 256).freeze
37
+
38
+ # The maximum possible value of an UInt256.
39
+ UINT_MAX = (2 ** 256 - 1).freeze
40
+
41
+ # The minimum possible value of an UInt256.
42
+ UINT_MIN = 0.freeze
43
+
44
+ # The maximum possible value of an Int256.
45
+ INT_MAX = (2 ** 255 - 1).freeze
46
+
47
+ # The minimum possible value of an Int256.
48
+ INT_MIN = (-2 ** 255).freeze
49
+
50
+ # A hash containing only zeros.
51
+ HASH_ZERO = ("\x00" * 32).freeze
52
+
53
+ # The RLP short length limit.
54
+ SHORT_LENGTH_LIMIT = 56.freeze
55
+
56
+ # The RLP long length limit.
57
+ LONG_LENGTH_LIMIT = (256 ** 8).freeze
58
+
59
+ # The RLP primitive type offset.
60
+ PRIMITIVE_PREFIX_OFFSET = 0x80.freeze
61
+
62
+ # The RLP array type offset.
63
+ LIST_PREFIX_OFFSET = 0xc0.freeze
64
+
65
+ # The binary encoding is ASCII (8-bit).
66
+ BINARY_ENCODING = "ASCII-8BIT".freeze
67
+
68
+ # Infinity as constant for convenience.
69
+ INFINITY = (1.0 / 0.0).freeze
70
+ end
71
+ end
@@ -0,0 +1,42 @@
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
+
20
+ # Provide classes for contract event.
21
+ class Contract::Event
22
+ attr_accessor :name, :signature, :input_types, :inputs, :event_string, :address
23
+
24
+ # Constructor of the {Eth::Contract::Event} class.
25
+ #
26
+ # @param data [Hash] contract event data.
27
+ def initialize(data)
28
+ @name = data["name"]
29
+ @input_types = data["inputs"].collect { |x| x["type"] }
30
+ @inputs = data["inputs"].collect { |x| x["name"] }
31
+ @event_string = "#{@name}(#{@input_types.join(",")})"
32
+ @signature = Digest::Keccak.hexdigest(@event_string, 256)
33
+ end
34
+
35
+ # Set the address of the smart contract
36
+ #
37
+ # @param address [String] contract address.
38
+ def set_address(address)
39
+ @address = address.nil? ? nil : Eth::Address.new(address).address
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,57 @@
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
+
20
+ # Provides the methods for smart contract function.
21
+ class Contract::Function
22
+ attr_accessor :name, :inputs, :outputs, :signature, :constant, :function_string
23
+
24
+ # Constructor of the {Eth::Function} class.
25
+ #
26
+ # @param data [Hash] function input and output data.
27
+ def initialize(data)
28
+ @name = data["name"]
29
+ @constant = data["constant"]
30
+ @inputs = data["inputs"].map do |input|
31
+ Eth::Contract::FunctionInput.new(input)
32
+ end
33
+ @outputs = data["outputs"].collect do |output|
34
+ Eth::Contract::FunctionOutput.new(output)
35
+ end
36
+ @function_string = self.class.calc_signature(@name, @inputs)
37
+ @signature = self.class.encoded_function_signature(@function_string)
38
+ end
39
+
40
+ # Creates function strings.
41
+ #
42
+ # @param name [String] function name.
43
+ # @param inputs [Array<Eth::Contract::FunctionInput>] function input class list.
44
+ # @return [String] function string.
45
+ def self.calc_signature(name, inputs)
46
+ "#{name}(#{inputs.collect { |x| x.raw_type }.join(",")})"
47
+ end
48
+
49
+ # Encodes a function signature.
50
+ #
51
+ # @param signature [String] function signature.
52
+ # @return [String] encoded function signature string.
53
+ def self.encoded_function_signature(signature)
54
+ Util.bin_to_hex Util.keccak256(signature)[0..3]
55
+ end
56
+ end
57
+ end