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.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +18 -0
- data/.github/workflows/codeql.yml +48 -0
- data/.github/workflows/docs.yml +26 -0
- data/.github/workflows/spec.yml +52 -0
- data/.gitignore +43 -0
- data/.gitmodules +3 -0
- data/.rspec +4 -0
- data/.yardopts +1 -0
- data/AUTHORS.txt +29 -0
- data/CHANGELOG.md +218 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +202 -0
- data/README.md +347 -0
- data/Rakefile +6 -0
- data/bin/console +10 -0
- data/bin/setup +9 -0
- data/codecov.yml +6 -0
- data/eth.gemspec +51 -0
- data/lib/eth/abi/event.rb +137 -0
- data/lib/eth/abi/type.rb +178 -0
- data/lib/eth/abi.rb +446 -0
- data/lib/eth/address.rb +106 -0
- data/lib/eth/api.rb +223 -0
- data/lib/eth/chain.rb +157 -0
- data/lib/eth/client/http.rb +63 -0
- data/lib/eth/client/ipc.rb +50 -0
- data/lib/eth/client.rb +499 -0
- data/lib/eth/constant.rb +71 -0
- data/lib/eth/contract/event.rb +42 -0
- data/lib/eth/contract/function.rb +57 -0
- data/lib/eth/contract/function_input.rb +38 -0
- data/lib/eth/contract/function_output.rb +37 -0
- data/lib/eth/contract/initializer.rb +47 -0
- data/lib/eth/contract.rb +143 -0
- data/lib/eth/eip712.rb +184 -0
- data/lib/eth/key/decrypter.rb +146 -0
- data/lib/eth/key/encrypter.rb +207 -0
- data/lib/eth/key.rb +167 -0
- data/lib/eth/rlp/decoder.rb +114 -0
- data/lib/eth/rlp/encoder.rb +78 -0
- data/lib/eth/rlp/sedes/big_endian_int.rb +66 -0
- data/lib/eth/rlp/sedes/binary.rb +97 -0
- data/lib/eth/rlp/sedes/list.rb +84 -0
- data/lib/eth/rlp/sedes.rb +74 -0
- data/lib/eth/rlp.rb +63 -0
- data/lib/eth/signature.rb +163 -0
- data/lib/eth/solidity.rb +75 -0
- data/lib/eth/tx/eip1559.rb +337 -0
- data/lib/eth/tx/eip2930.rb +329 -0
- data/lib/eth/tx/legacy.rb +297 -0
- data/lib/eth/tx.rb +322 -0
- data/lib/eth/unit.rb +49 -0
- data/lib/eth/util.rb +235 -0
- data/lib/eth/version.rb +20 -0
- data/lib/eth.rb +35 -0
- metadata +184 -0
@@ -0,0 +1,137 @@
|
|
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 a Ruby implementation of the Ethereum Application Binary Interface (ABI).
|
21
|
+
module Abi
|
22
|
+
|
23
|
+
# Provides a module to decode transaction log events.
|
24
|
+
module Event
|
25
|
+
extend self
|
26
|
+
|
27
|
+
# Compute topic for ABI event interface.
|
28
|
+
#
|
29
|
+
# @param interface [Hash] ABI event interface.
|
30
|
+
# @return [String] a hex-string topic.
|
31
|
+
def compute_topic(interface)
|
32
|
+
sig = Abi.signature(interface)
|
33
|
+
Util.prefix_hex(Util.bin_to_hex(Util.keccak256(sig)))
|
34
|
+
end
|
35
|
+
|
36
|
+
# A decoded event log.
|
37
|
+
class LogDescription
|
38
|
+
# The event ABI interface used to decode the log.
|
39
|
+
attr_accessor :event_interface
|
40
|
+
|
41
|
+
# The the input argument of the event.
|
42
|
+
attr_accessor :args
|
43
|
+
|
44
|
+
# The named input argument of the event.
|
45
|
+
attr_accessor :kwargs
|
46
|
+
|
47
|
+
# The topic hash.
|
48
|
+
attr_accessor :topic
|
49
|
+
|
50
|
+
# Decodes event log argument values.
|
51
|
+
#
|
52
|
+
# @param event_interface [Hash] event ABI type.
|
53
|
+
# @param log [Hash] transaction receipt log
|
54
|
+
def initialize(event_interface, log)
|
55
|
+
@event_interface = event_interface
|
56
|
+
|
57
|
+
inputs = event_interface.fetch("inputs")
|
58
|
+
data = log.fetch("data")
|
59
|
+
topics = log.fetch("topics", [])
|
60
|
+
anonymous = event_interface.fetch("anonymous", false)
|
61
|
+
|
62
|
+
@topic = topics[0] if !anonymous
|
63
|
+
@args, @kwargs = Event.decode_log(inputs, data, topics, anonymous)
|
64
|
+
end
|
65
|
+
|
66
|
+
# The event name. (e.g. Transfer)
|
67
|
+
def name
|
68
|
+
@name ||= event_interface.fetch("name")
|
69
|
+
end
|
70
|
+
|
71
|
+
# The event signature. (e.g. Transfer(address,address,uint256))
|
72
|
+
def signature
|
73
|
+
@signature ||= Abi.signature(event_interface)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Decodes a stream of receipt logs with a set of ABI interfaces.
|
78
|
+
#
|
79
|
+
# @param interfaces [Array] event ABI types.
|
80
|
+
# @param logs [Array] transaction receipt logs
|
81
|
+
# @return [Hash] an enumerator of LogDescription objects.
|
82
|
+
def decode_logs(interfaces, logs)
|
83
|
+
Enumerator.new do |y|
|
84
|
+
topic_to_interfaces = Hash[interfaces.map { |i| [compute_topic(i), i] }]
|
85
|
+
|
86
|
+
logs.each do |log|
|
87
|
+
topic = log.fetch("topics", [])[0]
|
88
|
+
if topic && interface = topic_to_interfaces[topic]
|
89
|
+
y << [log, LogDescription.new(interface, log)]
|
90
|
+
else
|
91
|
+
y << [log, nil]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Decodes event log argument values.
|
98
|
+
#
|
99
|
+
# @param inputs [Array] event ABI types.
|
100
|
+
# @param data [String] ABI event data to be decoded.
|
101
|
+
# @param topics [Array] ABI event topics to be decoded.
|
102
|
+
# @param anonymous [Boolean] If event signature is excluded from topics.
|
103
|
+
# @return [[Array, Hash]] decoded positional arguments and decoded keyword arguments.
|
104
|
+
# @raise [DecodingError] if decoding fails for type.
|
105
|
+
def decode_log(inputs, data, topics, anonymous = false)
|
106
|
+
topic_inputs, data_inputs = inputs.partition { |i| i["indexed"] }
|
107
|
+
|
108
|
+
topic_types = topic_inputs.map { |i| i["type"] }
|
109
|
+
data_types = data_inputs.map { |i| i["type"] }
|
110
|
+
|
111
|
+
# If event is anonymous, all topics are arguments. Otherwise, the first
|
112
|
+
# topic will be the event signature.
|
113
|
+
if anonymous == false
|
114
|
+
topics = topics[1..-1]
|
115
|
+
end
|
116
|
+
|
117
|
+
decoded_topics = topics.map.with_index { |t, i| Abi.decode([topic_types[i]], t)[0] }
|
118
|
+
decoded_data = Abi.decode(data_types, data)
|
119
|
+
|
120
|
+
args = []
|
121
|
+
kwargs = {}
|
122
|
+
|
123
|
+
inputs.each_with_index do |input, index|
|
124
|
+
if input["indexed"]
|
125
|
+
value = decoded_topics[topic_inputs.index(input)]
|
126
|
+
else
|
127
|
+
value = decoded_data[data_inputs.index(input)]
|
128
|
+
end
|
129
|
+
args[index] = value
|
130
|
+
kwargs[input["name"].to_sym] = value
|
131
|
+
end
|
132
|
+
|
133
|
+
return args, kwargs
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/eth/abi/type.rb
ADDED
@@ -0,0 +1,178 @@
|
|
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 a Ruby implementation of the Ethereum Application Binary Interface (ABI).
|
21
|
+
module Abi
|
22
|
+
|
23
|
+
# Provides a class to handle and parse common ABI types.
|
24
|
+
class Type
|
25
|
+
|
26
|
+
# Provides a specific parser error if type cannot be determined.
|
27
|
+
class ParseError < StandardError; end
|
28
|
+
|
29
|
+
# The base attribute, e.g., `string` or `bytes`.
|
30
|
+
attr :base_type
|
31
|
+
|
32
|
+
# The sub-type attribute, e.g., `256` as size of an uint256.
|
33
|
+
attr :sub_type
|
34
|
+
|
35
|
+
# The dimension attribute, e.g., `[10]` for an array of size 10.
|
36
|
+
attr :dimensions
|
37
|
+
|
38
|
+
# Create a new Type object for base types, sub types, and dimensions.
|
39
|
+
# Should not be used; use {Type.parse} instead.
|
40
|
+
#
|
41
|
+
# @param base_type [String] the base-type attribute.
|
42
|
+
# @param sub_type [String] the sub-type attribute.
|
43
|
+
# @param dimensions [Array] the dimension attribute.
|
44
|
+
# @return [Eth::Abi::Type] an ABI type object.
|
45
|
+
def initialize(base_type, sub_type, dimensions)
|
46
|
+
sub_type = sub_type.to_s
|
47
|
+
@base_type = base_type
|
48
|
+
@sub_type = sub_type
|
49
|
+
@dimensions = dimensions
|
50
|
+
end
|
51
|
+
|
52
|
+
# Converts the self.parse method into a constructor.
|
53
|
+
konstructor :parse
|
54
|
+
|
55
|
+
# Attempts to parse a string containing a common Solidity type.
|
56
|
+
# Creates a new Type upon success (using konstructor).
|
57
|
+
#
|
58
|
+
# @param type [String] a common Solidity type.
|
59
|
+
# @return [Eth::Abi::Type] a parsed Type object.
|
60
|
+
# @raise [ParseError] if it fails to parse the type.
|
61
|
+
def parse(type)
|
62
|
+
_, base_type, sub_type, dimension = /([a-z]*)([0-9]*x?[0-9]*)((\[[0-9]*\])*)/.match(type).to_a
|
63
|
+
|
64
|
+
# type dimension can only be numeric
|
65
|
+
dims = dimension.scan(/\[[0-9]*\]/)
|
66
|
+
raise ParseError, "Unknown characters found in array declaration" if dims.join != dimension
|
67
|
+
|
68
|
+
# enforce base types
|
69
|
+
validate_base_type base_type, sub_type
|
70
|
+
|
71
|
+
# return a new Type (using konstructor)
|
72
|
+
sub_type = sub_type.to_s
|
73
|
+
@base_type = base_type
|
74
|
+
@sub_type = sub_type
|
75
|
+
@dimensions = dims.map { |x| x[1...-1].to_i }
|
76
|
+
end
|
77
|
+
|
78
|
+
# Creates a new uint256 type used for size.
|
79
|
+
#
|
80
|
+
# @return [Eth::Abi::Type] a uint256 size type.
|
81
|
+
def self.size_type
|
82
|
+
@size_type ||= new("uint", 256, [])
|
83
|
+
end
|
84
|
+
|
85
|
+
# Compares two types for their attributes.
|
86
|
+
#
|
87
|
+
# @param another_type [Eth::Abi::Type] another type to be compared.
|
88
|
+
# @return [Boolean] true if all attributes match.
|
89
|
+
def ==(another_type)
|
90
|
+
base_type == another_type.base_type and
|
91
|
+
sub_type == another_type.sub_type and
|
92
|
+
dimensions == another_type.dimensions
|
93
|
+
end
|
94
|
+
|
95
|
+
# Computes the size of a type if possible.
|
96
|
+
#
|
97
|
+
# @return [Integer] the size of the type; or nil if not available.
|
98
|
+
def size
|
99
|
+
s = nil
|
100
|
+
if dimensions.empty?
|
101
|
+
unless ["string", "bytes"].include?(base_type) and sub_type.empty?
|
102
|
+
s = 32
|
103
|
+
end
|
104
|
+
else
|
105
|
+
unless dimensions.last == 0
|
106
|
+
unless nested_sub.is_dynamic?
|
107
|
+
s = dimensions.last * nested_sub.size
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
@size ||= s
|
112
|
+
end
|
113
|
+
|
114
|
+
# Helpes to determine whether array is of dynamic size.
|
115
|
+
#
|
116
|
+
# @return [Boolean] true if array is of dynamic size.
|
117
|
+
def is_dynamic?
|
118
|
+
size.nil?
|
119
|
+
end
|
120
|
+
|
121
|
+
# Types can have nested sub-types in arrays.
|
122
|
+
#
|
123
|
+
# @return [Eth::Abi::Type] nested sub-type.
|
124
|
+
def nested_sub
|
125
|
+
@nested_sub ||= self.class.new(base_type, sub_type, dimensions[0...-1])
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
# Validates all known base types and raises if an issue occurs.
|
131
|
+
def validate_base_type(base_type, sub_type)
|
132
|
+
case base_type
|
133
|
+
when "string"
|
134
|
+
|
135
|
+
# string can not have any suffix
|
136
|
+
raise ParseError, "String type must have no suffix or numerical suffix" unless sub_type.empty?
|
137
|
+
when "bytes"
|
138
|
+
|
139
|
+
# bytes can be no longer than 32 bytes
|
140
|
+
raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub_type.empty? || sub_type.to_i <= 32
|
141
|
+
when "uint", "int"
|
142
|
+
|
143
|
+
# integers must have a numerical suffix
|
144
|
+
raise ParseError, "Integer type must have numerical suffix" unless sub_type =~ /\A[0-9]+\z/
|
145
|
+
|
146
|
+
# integer size must be valid
|
147
|
+
size = sub_type.to_i
|
148
|
+
raise ParseError, "Integer size out of bounds" unless size >= 8 && size <= 256
|
149
|
+
raise ParseError, "Integer size must be multiple of 8" unless size % 8 == 0
|
150
|
+
when "ureal", "real", "fixed", "ufixed"
|
151
|
+
|
152
|
+
# floats must have valid dimensional suffix
|
153
|
+
raise ParseError, "Real type must have suffix of form <high>x<low>, e.g. 128x128" unless sub_type =~ /\A[0-9]+x[0-9]+\z/
|
154
|
+
high, low = sub_type.split("x").map(&:to_i)
|
155
|
+
total = high + low
|
156
|
+
raise ParseError, "Real size out of bounds (max 32 bytes)" unless total >= 8 && total <= 256
|
157
|
+
raise ParseError, "Real high/low sizes must be multiples of 8" unless high % 8 == 0 && low % 8 == 0
|
158
|
+
when "hash"
|
159
|
+
|
160
|
+
# hashs must have numerical suffix
|
161
|
+
raise ParseError, "Hash type must have numerical suffix" unless sub_type =~ /\A[0-9]+\z/
|
162
|
+
when "address"
|
163
|
+
|
164
|
+
# addresses cannot have any suffix
|
165
|
+
raise ParseError, "Address cannot have suffix" unless sub_type.empty?
|
166
|
+
when "bool"
|
167
|
+
|
168
|
+
# booleans cannot have any suffix
|
169
|
+
raise ParseError, "Bool cannot have suffix" unless sub_type.empty?
|
170
|
+
else
|
171
|
+
|
172
|
+
# we cannot parse arbitrary types such as 'decimal' or 'hex'
|
173
|
+
raise ParseError, "Unknown base type"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|