eth-custom 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
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