eth 0.5.0 → 0.5.3

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codeql.yml +4 -0
  3. data/.github/workflows/spec.yml +14 -3
  4. data/.yardopts +1 -0
  5. data/AUTHORS.txt +14 -1
  6. data/CHANGELOG.md +63 -13
  7. data/README.md +121 -18
  8. data/bin/console +2 -1
  9. data/bin/setup +3 -4
  10. data/codecov.yml +6 -0
  11. data/eth.gemspec +5 -7
  12. data/lib/eth/abi/event.rb +137 -0
  13. data/lib/eth/abi/type.rb +8 -7
  14. data/lib/eth/abi.rb +29 -11
  15. data/lib/eth/address.rb +12 -5
  16. data/lib/eth/api.rb +223 -0
  17. data/lib/eth/chain.rb +31 -28
  18. data/lib/eth/client/http.rb +63 -0
  19. data/lib/eth/client/ipc.rb +50 -0
  20. data/lib/eth/client.rb +468 -0
  21. data/lib/eth/constant.rb +71 -0
  22. data/lib/eth/contract/event.rb +41 -0
  23. data/lib/eth/contract/function.rb +56 -0
  24. data/lib/eth/contract/function_input.rb +36 -0
  25. data/lib/eth/contract/function_output.rb +32 -0
  26. data/lib/eth/contract/initializer.rb +46 -0
  27. data/lib/eth/contract.rb +120 -0
  28. data/lib/eth/eip712.rb +2 -2
  29. data/lib/eth/key/decrypter.rb +16 -13
  30. data/lib/eth/key/encrypter.rb +27 -25
  31. data/lib/eth/key.rb +21 -16
  32. data/lib/eth/rlp/decoder.rb +114 -0
  33. data/lib/eth/rlp/encoder.rb +78 -0
  34. data/lib/eth/rlp/sedes/big_endian_int.rb +66 -0
  35. data/lib/eth/rlp/sedes/binary.rb +97 -0
  36. data/lib/eth/rlp/sedes/list.rb +84 -0
  37. data/lib/eth/rlp/sedes.rb +74 -0
  38. data/lib/eth/rlp.rb +63 -0
  39. data/lib/eth/signature.rb +11 -8
  40. data/lib/eth/solidity.rb +75 -0
  41. data/lib/eth/tx/eip1559.rb +22 -14
  42. data/lib/eth/tx/eip2930.rb +23 -15
  43. data/lib/eth/tx/legacy.rb +14 -10
  44. data/lib/eth/tx.rb +28 -34
  45. data/lib/eth/unit.rb +1 -1
  46. data/lib/eth/util.rb +68 -11
  47. data/lib/eth/version.rb +3 -3
  48. data/lib/eth.rb +15 -2
  49. metadata +31 -23
  50. data/lib/eth/abi/constant.rb +0 -63
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2016-2022 The Ruby-Eth Contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "socket"
16
+
17
+ # Provides the {Eth} module.
18
+ module Eth
19
+
20
+ # Provides an IPC-RPC client.
21
+ class Client::Ipc < Client
22
+
23
+ # The path of the IPC socket.
24
+ attr_accessor :path
25
+
26
+ # Constructor for the IPC Client. Should not be used; use
27
+ # {Client.create} intead.
28
+ #
29
+ # @param path [String] an URI pointing to an IPC RPC-API.
30
+ def initialize(path)
31
+ super
32
+ @path = path
33
+ end
34
+
35
+ # Sends an RPC request to the connected IPC socket.
36
+ #
37
+ # @param payload [Hash] the RPC request parameters.
38
+ # @return [String] a JSON-encoded response.
39
+ def send(payload)
40
+ socket = UNIXSocket.new(@path)
41
+ socket.puts(payload)
42
+ read = socket.recvmsg(nil)[0]
43
+ until read.end_with?("\n")
44
+ read = read << socket.recvmsg(nil)[0]
45
+ end
46
+ socket.close
47
+ return read
48
+ end
49
+ end
50
+ end
data/lib/eth/client.rb ADDED
@@ -0,0 +1,468 @@
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
+ # Deploy contract and waits for it to be mined.
153
+ # Uses `eth_coinbase` or external signer
154
+ # if no sender key is provided.
155
+ #
156
+ # @overload deploy(contract)
157
+ # @param contract [Eth::Contract] contracts to deploy.
158
+ # @overload deploy(contract, sender_key)
159
+ # @param contract [Eth::Contract] contracts to deploy.
160
+ # @param sender_key [Eth::Key] the sender private key.
161
+ # @overload deploy(contract, sender_key, legacy)
162
+ # @param contract [Eth::Contract] contracts to deploy.
163
+ # @param sender_key [Eth::Key] the sender private key.
164
+ # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
165
+ # @return [String] the contract address.
166
+ def deploy_and_wait(contract, sender_key: nil, legacy: false)
167
+ hash = wait_for_tx(deploy(contract, sender_key: sender_key, legacy: legacy))
168
+ contract.address = eth_get_transaction_receipt(hash)["result"]["contractAddress"]
169
+ end
170
+
171
+ # Deploy contract. Uses `eth_coinbase` or external signer
172
+ # if no sender key is provided.
173
+ #
174
+ # @overload deploy(contract)
175
+ # @param contract [Eth::Contract] contracts to deploy.
176
+ # @overload deploy(contract, sender_key)
177
+ # @param contract [Eth::Contract] contracts to deploy.
178
+ # @param sender_key [Eth::Key] the sender private key.
179
+ # @overload deploy(contract, sender_key, legacy)
180
+ # @param contract [Eth::Contract] contracts to deploy.
181
+ # @param sender_key [Eth::Key] the sender private key.
182
+ # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
183
+ # @return [String] the transaction hash.
184
+ def deploy(contract, sender_key: nil, legacy: false)
185
+ gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
186
+ params = {
187
+ value: 0,
188
+ gas_limit: gas_limit,
189
+ chain_id: chain_id,
190
+ data: contract.bin,
191
+ }
192
+ if legacy
193
+ params.merge!({
194
+ gas_price: max_fee_per_gas,
195
+ })
196
+ else
197
+ params.merge!({
198
+ priority_fee: max_priority_fee_per_gas,
199
+ max_gas_fee: max_fee_per_gas,
200
+ })
201
+ end
202
+ unless sender_key.nil?
203
+ # use the provided key as sender and signer
204
+ params.merge!({
205
+ from: sender_key.address,
206
+ nonce: get_nonce(sender_key.address),
207
+ })
208
+ tx = Eth::Tx.new(params)
209
+ tx.sign sender_key
210
+ return eth_send_raw_transaction(tx.hex)["result"]
211
+ else
212
+ # use the default account as sender and external signer
213
+ params.merge!({
214
+ from: default_account,
215
+ nonce: get_nonce(default_account),
216
+ })
217
+ return eth_send_transaction(params)["result"]
218
+ end
219
+ end
220
+
221
+ # Encoding for function calls.
222
+ def call_payload(fun, args)
223
+ types = fun.inputs.map { |i| i.type }
224
+ encoded_str = Util.bin_to_hex(Eth::Abi.encode(types, args))
225
+ "0x" + fun.signature + (encoded_str.empty? ? "0" * 64 : encoded_str)
226
+ end
227
+
228
+ # Non-transactional function call called from call().
229
+ #
230
+ # @overload call_raw(contract, func)
231
+ # @param contract [Eth::Contract] subject contract to call.
232
+ # @param func [Eth::Contract::Function] method name to be called.
233
+ # @overload call_raw(contract, func, value)
234
+ # @param contract [Eth::Contract] subject contract to call.
235
+ # @param func [Eth::Contract::Function] method name to be called.
236
+ # @param value [Integer|String] function arguments.
237
+ # @overload call_raw(contract, func, value, sender_key, legacy)
238
+ # @param contract [Eth::Contract] subject contract to call.
239
+ # @param func [Eth::Contract::Function] method name to be called.
240
+ # @param value [Integer|String] function arguments.
241
+ # @param sender_key [Eth::Key] the sender private key.
242
+ # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
243
+ # @return [Object] returns the result of the call.
244
+ def call_raw(contract, func, *args, **kwargs)
245
+ gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
246
+ params = {
247
+ gas_limit: gas_limit,
248
+ chain_id: chain_id,
249
+ data: call_payload(func, args),
250
+ }
251
+ if kwargs[:address] || contract.address
252
+ params.merge!({ to: kwargs[:address] || contract.address })
253
+ end
254
+ if kwargs[:legacy]
255
+ params.merge!({
256
+ gas_price: max_fee_per_gas,
257
+ })
258
+ else
259
+ params.merge!({
260
+ priority_fee: max_priority_fee_per_gas,
261
+ max_gas_fee: max_fee_per_gas,
262
+ })
263
+ end
264
+ unless kwargs[:sender_key].nil?
265
+ # use the provided key as sender and signer
266
+ params.merge!({
267
+ from: kwargs[:sender_key].address,
268
+ nonce: get_nonce(kwargs[:sender_key].address),
269
+ })
270
+ tx = Eth::Tx.new(params)
271
+ tx.sign kwargs[:sender_key]
272
+ else
273
+ # use the default account as sender and external signer
274
+ params.merge!({
275
+ from: default_account,
276
+ nonce: get_nonce(default_account),
277
+ })
278
+ end
279
+ raw_result = eth_call(params)["result"]
280
+ types = func.outputs.map { |i| i.type }
281
+ Eth::Abi.decode(types, raw_result)
282
+ end
283
+
284
+ # Non-transactional function calls.
285
+ #
286
+ # @overload call(contract, function_name)
287
+ # @param contract [Eth::Contract] subject contract to call.
288
+ # @param function_name [String] method name to be called.
289
+ # @overload call(contract, function_name, value)
290
+ # @param contract [Eth::Contract] subject contract to call.
291
+ # @param function_name [String] method name to be called.
292
+ # @param value [Integer|String] function arguments.
293
+ # @overload call(contract, function_name, value, sender_key, legacy)
294
+ # @param contract [Eth::Contract] subject contract to call.
295
+ # @param function_name [String] method name to be called.
296
+ # @param value [Integer|String] function arguments.
297
+ # @param sender_key [Eth::Key] the sender private key.
298
+ # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
299
+ # @return [Object] returns the result of the call.
300
+ def call(contract, function_name, *args, **kwargs)
301
+ func = contract.functions.select { |func| func.name == function_name }[0]
302
+ raise ArgumentError, "function_name does not exist!" if func.nil?
303
+ output = call_raw(contract, func, *args, **kwargs)
304
+ if output.length == 1
305
+ return output[0]
306
+ else
307
+ return output
308
+ end
309
+ end
310
+
311
+ # Function call with transaction.
312
+ #
313
+ # @overload transact(contract, function_name)
314
+ # @param contract [Eth::Contract] subject contract to call.
315
+ # @param function_name [String] method name to be called.
316
+ # @overload transact(contract, function_name, value)
317
+ # @param contract [Eth::Contract] subject contract to call.
318
+ # @param function_name [String] method name to be called.
319
+ # @param value [Integer|String] function arguments.
320
+ # @overload transact(contract, function_name, value, sender_key, legacy, address)
321
+ # @param contract [Eth::Contract] subject contract to call.
322
+ # @param function_name [String] method name to be called.
323
+ # @param value [Integer|String] function arguments.
324
+ # @param sender_key [Eth::Key] the sender private key.
325
+ # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
326
+ # @param address [String] contract address.
327
+ # @return [Object] returns the result of the call.
328
+ def transact(contract, function_name, *args, **kwargs)
329
+ gas_limit = Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
330
+ fun = contract.functions.select { |func| func.name == function_name }[0]
331
+ params = {
332
+ value: 0,
333
+ gas_limit: gas_limit,
334
+ chain_id: chain_id,
335
+ to: kwargs[:address] || contract.address,
336
+ data: call_payload(fun, args),
337
+ }
338
+ if kwargs[:legacy]
339
+ params.merge!({
340
+ gas_price: max_fee_per_gas,
341
+ })
342
+ else
343
+ params.merge!({
344
+ priority_fee: max_priority_fee_per_gas,
345
+ max_gas_fee: max_fee_per_gas,
346
+ })
347
+ end
348
+ unless kwargs[:sender_key].nil?
349
+ # use the provided key as sender and signer
350
+ params.merge!({
351
+ from: kwargs[:sender_key].address,
352
+ nonce: get_nonce(kwargs[:sender_key].address),
353
+ })
354
+ tx = Eth::Tx.new(params)
355
+ tx.sign kwargs[:sender_key]
356
+ return eth_send_raw_transaction(tx.hex)["result"]
357
+ else
358
+ # use the default account as sender and external signer
359
+ params.merge!({
360
+ from: default_account,
361
+ nonce: get_nonce(default_account),
362
+ })
363
+ return eth_send_transaction(params)["result"]
364
+ end
365
+ end
366
+
367
+ # Function call with transaction and waits for it to be mined.
368
+ #
369
+ # @overload transact_and_wait(contract, function_name)
370
+ # @param contract [Eth::Contract] subject contract to call.
371
+ # @param function_name [String] method name to be called.
372
+ # @overload transact_and_wait(contract, function_name, value)
373
+ # @param contract [Eth::Contract] subject contract to call.
374
+ # @param function_name [String] method name to be called.
375
+ # @param value [Integer|String] function arguments.
376
+ # @overload transact_and_wait(contract, function_name, value, sender_key, legacy, address)
377
+ # @param contract [Eth::Contract] subject contract to call.
378
+ # @param function_name [String] method name to be called.
379
+ # @param value [Integer|String] function arguments.
380
+ # @param sender_key [Eth::Key] the sender private key.
381
+ # @param legacy [Boolean] enables legacy transactions (pre-EIP-1559).
382
+ # @param address [String] contract address.
383
+ # @return [Object] returns the result of the call.
384
+ def transact_and_wait(contract, function_name, *args, **kwargs)
385
+ wait_for_tx(transact(contract, function_name, *args, **kwargs))
386
+ end
387
+
388
+ # Gives control over resetting the RPC request ID back to zero.
389
+ # Usually not needed.
390
+ #
391
+ # @return [Integer] 0
392
+ def reset_id
393
+ @id = 0
394
+ end
395
+
396
+ # Checkes wether a transaction is mined or not.
397
+ #
398
+ # @param hash [String] the transaction hash.
399
+ # @return [Boolean] true if included in a block.
400
+ def is_mined_tx?(hash)
401
+ mined_tx = eth_get_transaction_by_hash hash
402
+ !mined_tx.nil? && !mined_tx["result"].nil? && !mined_tx["result"]["blockNumber"].nil?
403
+ end
404
+
405
+ # Waits for an transaction to be mined by the connected chain.
406
+ #
407
+ # @param hash [String] the transaction hash.
408
+ # @return [String] the transactin hash once the transaction is mined.
409
+ # @raise [Timeout::Error] if it's not mined within 5 minutes.
410
+ def wait_for_tx(hash)
411
+ start_time = Time.now
412
+ timeout = 300
413
+ retry_rate = 0.1
414
+ loop do
415
+ raise Timeout::Error if ((Time.now - start_time) > timeout)
416
+ return hash if is_mined_tx? hash
417
+ sleep retry_rate
418
+ end
419
+ end
420
+
421
+ # Metafunction to provide all known RPC commands defined in
422
+ # Eth::Api as snake_case methods to the Eth::Client classes.
423
+ Api::COMMANDS.each do |cmd|
424
+ method_name = cmd.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
425
+ define_method method_name do |*args|
426
+ send_command cmd, args
427
+ end
428
+ end
429
+
430
+ private
431
+
432
+ # Prepares parameters and sends the command to the client.
433
+ def send_command(command, args)
434
+ args << "latest" if ["eth_getBalance", "eth_call"].include? command
435
+ payload = {
436
+ jsonrpc: "2.0",
437
+ method: command,
438
+ params: marshal(args),
439
+ id: next_id,
440
+ }
441
+ output = JSON.parse(send(payload.to_json))
442
+ raise IOError, output["error"]["message"] unless output["error"].nil?
443
+ return output
444
+ end
445
+
446
+ # Increments the request id.
447
+ def next_id
448
+ @id += 1
449
+ end
450
+
451
+ # Recursively marshals all request parameters.
452
+ def marshal(params)
453
+ if params.is_a? Array
454
+ return params.map! { |param| marshal(param) }
455
+ elsif params.is_a? Hash
456
+ return params.transform_values! { |param| marshal(param) }
457
+ elsif params.is_a? Numeric
458
+ return Util.prefix_hex "#{params.to_i.to_s(16)}"
459
+ elsif params.is_a? Address
460
+ return params.to_s
461
+ elsif Util.is_hex? params
462
+ return Util.prefix_hex params
463
+ else
464
+ return params
465
+ end
466
+ end
467
+ end
468
+ end
@@ -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,41 @@
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
+ # Provide classes for contract event.
20
+ class Contract::Event
21
+ attr_accessor :name, :signature, :input_types, :inputs, :event_string, :address
22
+
23
+ # Constructor of the {Eth::Contract::Event} class.
24
+ #
25
+ # @param data [Hash] contract event data.
26
+ def initialize(data)
27
+ @name = data["name"]
28
+ @input_types = data["inputs"].collect { |x| x["type"] }
29
+ @inputs = data["inputs"].collect { |x| x["name"] }
30
+ @event_string = "#{@name}(#{@input_types.join(",")})"
31
+ @signature = Digest::Keccak.hexdigest(@event_string, 256)
32
+ end
33
+
34
+ # Set the address of the smart contract
35
+ #
36
+ # @param address [String] contract address.
37
+ def set_address(address)
38
+ @address = address.nil? ? nil : Eth::Address.new(address).address
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,56 @@
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 the methods for smart contract function.
20
+ class Contract::Function
21
+ attr_accessor :name, :inputs, :outputs, :signature, :constant, :function_string
22
+
23
+ # Constructor of the {Eth::Function} class.
24
+ #
25
+ # @param data [Hash] function input and output data.
26
+ def initialize(data)
27
+ @name = data["name"]
28
+ @constant = data["constant"]
29
+ @inputs = data["inputs"].map do |input|
30
+ Eth::Contract::FunctionInput.new(input)
31
+ end
32
+ @outputs = data["outputs"].collect do |output|
33
+ Eth::Contract::FunctionOutput.new(output)
34
+ end
35
+ @function_string = self.class.calc_signature(@name, @inputs)
36
+ @signature = self.class.encoded_function_signature(@function_string)
37
+ end
38
+
39
+ # Create function strings.
40
+ #
41
+ # @param name [String] function name.
42
+ # @param inputs [Array<Eth::Contract::FunctionInput>] function input class list.
43
+ # @return [String] function string.
44
+ def self.calc_signature(name, inputs)
45
+ "#{name}(#{inputs.collect { |x| x.type }.join(",")})"
46
+ end
47
+
48
+ # encode function signature.
49
+ #
50
+ # @param signature [String] function signature.
51
+ # @return [String] encoded function signature string.
52
+ def self.encoded_function_signature(signature)
53
+ Digest::Keccak.hexdigest(signature, 256)[0..7]
54
+ end
55
+ end
56
+ end