ethlite 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Manifest.txt +10 -0
- data/Rakefile +2 -0
- data/lib/digest/keccak256.rb +111 -0
- data/lib/digest/sha3.rb +108 -0
- data/lib/ethlite/abi/abi_coder.rb +423 -0
- data/lib/ethlite/abi/constant.rb +32 -0
- data/lib/ethlite/abi/exceptions.rb +29 -0
- data/lib/ethlite/abi/type.rb +203 -0
- data/lib/ethlite/abi/utils.rb +227 -0
- data/lib/ethlite/contract.rb +64 -0
- data/lib/ethlite/rpc.rb +48 -0
- data/lib/ethlite/utility.rb +23 -0
- data/lib/ethlite/version.rb +2 -2
- data/lib/ethlite.rb +31 -0
- metadata +25 -1
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
module Ethlite
|
3
|
+
module Abi
|
4
|
+
|
5
|
+
class DeprecatedError < StandardError; end
|
6
|
+
class ChecksumError < StandardError; end
|
7
|
+
class FormatError < StandardError; end
|
8
|
+
class ValidationError < StandardError; end
|
9
|
+
class ValueError < StandardError; end
|
10
|
+
class AssertError < StandardError; end
|
11
|
+
|
12
|
+
class UnknownParentError < StandardError; end
|
13
|
+
class InvalidBlock < ValidationError; end
|
14
|
+
class InvalidUncles < ValidationError; end
|
15
|
+
|
16
|
+
class InvalidTransaction < ValidationError; end
|
17
|
+
class UnsignedTransactionError < InvalidTransaction; end
|
18
|
+
class InvalidNonce < InvalidTransaction; end
|
19
|
+
class InsufficientStartGas < InvalidTransaction; end
|
20
|
+
class InsufficientBalance < InvalidTransaction; end
|
21
|
+
class BlockGasLimitReached < InvalidTransaction; end
|
22
|
+
|
23
|
+
class InvalidSPVProof < ValidationError; end
|
24
|
+
|
25
|
+
class ContractCreationFailed < StandardError; end
|
26
|
+
class TransactionFailed < StandardError; end
|
27
|
+
|
28
|
+
end # module Abi
|
29
|
+
end # module Ethlite
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module Ethlite
|
2
|
+
module Abi
|
3
|
+
class Type
|
4
|
+
|
5
|
+
class ParseError < StandardError;
|
6
|
+
end
|
7
|
+
|
8
|
+
class <<self
|
9
|
+
##
|
10
|
+
# Crazy regexp to seperate out base type component (eg. uint), size (eg.
|
11
|
+
# 256, 128x128, nil), array component (eg. [], [45], nil)
|
12
|
+
#
|
13
|
+
def parse(type)
|
14
|
+
|
15
|
+
return parse('uint256') if type=='trcToken'
|
16
|
+
|
17
|
+
if type =~ /^\((.*)\)((\[[0-9]*\])*)/
|
18
|
+
return Tuple.parse $1, $2.scan(/\[[0-9]*\]/)
|
19
|
+
end
|
20
|
+
|
21
|
+
_, base, sub, dimension = /([a-z]*)([0-9]*x?[0-9]*)((\[[0-9]*\])*)/.match(type).to_a
|
22
|
+
|
23
|
+
dims = dimension.scan(/\[[0-9]*\]/)
|
24
|
+
raise ParseError, "Unknown characters found in array declaration" if dims.join != dimension
|
25
|
+
|
26
|
+
case base
|
27
|
+
when ''
|
28
|
+
return parse 'address'
|
29
|
+
when 'bytes', 'string'
|
30
|
+
raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub.empty? || sub.to_i <= 32
|
31
|
+
when 'uint', 'int'
|
32
|
+
raise ParseError, "Integer type must have numerical suffix" unless sub =~ /\A[0-9]+\z/
|
33
|
+
|
34
|
+
size = sub.to_i
|
35
|
+
raise ParseError, "Integer size out of bounds" unless size >= 8 && size <= 256
|
36
|
+
raise ParseError, "Integer size must be multiple of 8" unless size % 8 == 0
|
37
|
+
when 'fixed', 'ufixed'
|
38
|
+
raise ParseError, "Fixed type must have suffix of form <high>x<low>, e.g. 128x128" unless sub =~ /\A[0-9]+x[0-9]+\z/
|
39
|
+
|
40
|
+
high, low = sub.split('x').map(&:to_i)
|
41
|
+
total = high + low
|
42
|
+
|
43
|
+
raise ParseError, "Fixed size out of bounds (max 32 bytes)" unless total >= 8 && total <= 256
|
44
|
+
raise ParseError, "Fixed high size must be multiple of 8" unless high % 8 == 0
|
45
|
+
raise ParseError, "Low sizes must be 0 to 80" unless low>0 && low<=80
|
46
|
+
when 'hash'
|
47
|
+
raise ParseError, "Hash type must have numerical suffix" unless sub =~ /\A[0-9]+\z/
|
48
|
+
when 'address'
|
49
|
+
raise ParseError, "Address cannot have suffix" unless sub.empty?
|
50
|
+
when 'bool'
|
51
|
+
raise ParseError, "Bool cannot have suffix" unless sub.empty?
|
52
|
+
else
|
53
|
+
raise ParseError, "Unrecognized type base: #{base}"
|
54
|
+
end
|
55
|
+
|
56
|
+
new(base, sub, dims.map {|x| x[1...-1].to_i})
|
57
|
+
end
|
58
|
+
|
59
|
+
def size_type
|
60
|
+
@size_type ||= new('uint', 256, [])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
attr :base, :sub, :dims
|
65
|
+
|
66
|
+
##
|
67
|
+
# @param base [String] base name of type, e.g. uint for uint256[4]
|
68
|
+
# @param sub [String] subscript of type, e.g. 256 for uint256[4]
|
69
|
+
# @param dims [Array[Integer]] dimensions of array type, e.g. [1,2,0]
|
70
|
+
# for uint256[1][2][], [] for non-array type
|
71
|
+
#
|
72
|
+
def initialize(base, sub, dims)
|
73
|
+
@base = base
|
74
|
+
@sub = sub
|
75
|
+
@dims = dims
|
76
|
+
end
|
77
|
+
|
78
|
+
def ==(another_type)
|
79
|
+
base == another_type.base &&
|
80
|
+
sub == another_type.sub &&
|
81
|
+
dims == another_type.dims
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Get the static size of a type, or nil if dynamic.
|
86
|
+
#
|
87
|
+
# @return [Integer, NilClass] size of static type, or nil for dynamic
|
88
|
+
# type
|
89
|
+
#
|
90
|
+
def size
|
91
|
+
@size ||= if dims.empty?
|
92
|
+
if %w(string bytes).include?(base) && sub.empty?
|
93
|
+
nil
|
94
|
+
else
|
95
|
+
32
|
96
|
+
end
|
97
|
+
else
|
98
|
+
if dims.last == 0 # 0 for dynamic array []
|
99
|
+
nil
|
100
|
+
else
|
101
|
+
subtype.dynamic? ? nil : dims.last * subtype.size
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def dynamic?
|
107
|
+
size.nil?
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Type with one dimension lesser.
|
112
|
+
#
|
113
|
+
# @example
|
114
|
+
# Type.parse("uint256[2][]").subtype # => Type.new('uint', 256, [2])
|
115
|
+
#
|
116
|
+
# @return [Ethereum::ABI::Type]
|
117
|
+
#
|
118
|
+
def subtype
|
119
|
+
@subtype ||= self.class.new(base, sub, dims[0...-1])
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
class Tuple < Type
|
125
|
+
|
126
|
+
def self.parse types, dims
|
127
|
+
|
128
|
+
depth = 0
|
129
|
+
collected = []
|
130
|
+
current = ''
|
131
|
+
|
132
|
+
types.split('').each do |c|
|
133
|
+
case c
|
134
|
+
when ',' then
|
135
|
+
if depth==0
|
136
|
+
collected << current
|
137
|
+
current = ''
|
138
|
+
else
|
139
|
+
current += c
|
140
|
+
end
|
141
|
+
when '(' then
|
142
|
+
depth += 1
|
143
|
+
current += c
|
144
|
+
when ')' then
|
145
|
+
depth -= 1
|
146
|
+
current += c
|
147
|
+
else
|
148
|
+
current += c
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
collected << current unless current.empty?
|
153
|
+
|
154
|
+
Tuple.new collected, dims.map {|x| x[1...-1].to_i}
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
attr_reader :types, :parsed_types
|
159
|
+
def initialize types, dims
|
160
|
+
super('tuple', '', dims)
|
161
|
+
@types = types
|
162
|
+
@parsed_types = types.map{|t| Type.parse t}
|
163
|
+
end
|
164
|
+
|
165
|
+
def ==(another_type)
|
166
|
+
another_type.kind_of?(Tuple) &&
|
167
|
+
another_type.types == types &&
|
168
|
+
another_type.dims == dims
|
169
|
+
end
|
170
|
+
|
171
|
+
def size
|
172
|
+
@size ||= calculate_size
|
173
|
+
end
|
174
|
+
|
175
|
+
def calculate_size
|
176
|
+
if dims.empty?
|
177
|
+
s = 0
|
178
|
+
parsed_types.each do |type|
|
179
|
+
ts = type.size
|
180
|
+
return nil if ts.nil?
|
181
|
+
s += ts
|
182
|
+
end
|
183
|
+
s
|
184
|
+
else
|
185
|
+
if dims.last == 0 # 0 for dynamic array []
|
186
|
+
nil
|
187
|
+
else
|
188
|
+
subtype.dynamic? ? nil : dims.last * subtype.size
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
def subtype
|
196
|
+
@subtype ||= Tuple.new(types, dims[0...-1])
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
end # module Abi
|
203
|
+
end # module Ethlite
|
@@ -0,0 +1,227 @@
|
|
1
|
+
module Ethlite
|
2
|
+
module Abi
|
3
|
+
module Utils
|
4
|
+
|
5
|
+
extend self
|
6
|
+
|
7
|
+
include Constant
|
8
|
+
|
9
|
+
##
|
10
|
+
# Not the keccak in sha3, although it's underlying lib named SHA3
|
11
|
+
#
|
12
|
+
def keccak256(x)
|
13
|
+
# Digest::SHA3.new(256).digest(x)
|
14
|
+
## Digest::Keccak.digest(x, 256)
|
15
|
+
Digest::Keccak256.digest( x )
|
16
|
+
end
|
17
|
+
|
18
|
+
=begin
|
19
|
+
## check where required / in use - what for?
|
20
|
+
def keccak512(x)
|
21
|
+
# Digest::SHA3.new(512).digest(x)
|
22
|
+
Digest::Keccak.digest(x, 512)
|
23
|
+
end
|
24
|
+
=end
|
25
|
+
|
26
|
+
def keccak256_rlp(x)
|
27
|
+
keccak256 RLP.encode(x)
|
28
|
+
end
|
29
|
+
|
30
|
+
def sha256(x)
|
31
|
+
Digest::SHA256.digest x
|
32
|
+
end
|
33
|
+
|
34
|
+
def double_sha256(x)
|
35
|
+
sha256 sha256(x)
|
36
|
+
end
|
37
|
+
|
38
|
+
def ripemd160(x)
|
39
|
+
Digest::RMD160.digest x
|
40
|
+
end
|
41
|
+
|
42
|
+
def hash160(x)
|
43
|
+
ripemd160 sha256(x)
|
44
|
+
end
|
45
|
+
|
46
|
+
def hash160_hex(x)
|
47
|
+
encode_hex hash160(x)
|
48
|
+
end
|
49
|
+
|
50
|
+
def mod_exp(x, y, n)
|
51
|
+
x.to_bn.mod_exp(y, n).to_i
|
52
|
+
end
|
53
|
+
|
54
|
+
def mod_mul(x, y, n)
|
55
|
+
x.to_bn.mod_mul(y, n).to_i
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_signed(i)
|
59
|
+
i > Constant::INT_MAX ? (i-Constant::TT256) : i
|
60
|
+
end
|
61
|
+
|
62
|
+
def base58_check_to_bytes(s)
|
63
|
+
leadingzbytes = s.match(/\A1*/)[0]
|
64
|
+
data = Constant::BYTE_ZERO * leadingzbytes.size + BaseConvert.convert(s, 58, 256)
|
65
|
+
|
66
|
+
raise ChecksumError, "double sha256 checksum doesn't match" unless double_sha256(data[0...-4])[0,4] == data[-4..-1]
|
67
|
+
data[1...-4]
|
68
|
+
end
|
69
|
+
|
70
|
+
def bytes_to_base58_check(bytes, magicbyte=0)
|
71
|
+
bs = "#{magicbyte.chr}#{bytes}"
|
72
|
+
leadingzbytes = bs.match(/\A#{Constant::BYTE_ZERO}*/)[0]
|
73
|
+
checksum = double_sha256(bs)[0,4]
|
74
|
+
'1'*leadingzbytes.size + BaseConvert.convert("#{bs}#{checksum}", 256, 58)
|
75
|
+
end
|
76
|
+
|
77
|
+
def ceil32(x)
|
78
|
+
x % 32 == 0 ? x : (x + 32 - x%32)
|
79
|
+
end
|
80
|
+
|
81
|
+
def encode_hex(b)
|
82
|
+
RLP::Utils.encode_hex b
|
83
|
+
end
|
84
|
+
|
85
|
+
def decode_hex(s)
|
86
|
+
RLP::Utils.decode_hex s
|
87
|
+
end
|
88
|
+
|
89
|
+
def big_endian_to_int(s)
|
90
|
+
RLP::Sedes.big_endian_int.deserialize s.sub(/\A(\x00)+/, '')
|
91
|
+
end
|
92
|
+
|
93
|
+
def int_to_big_endian(n)
|
94
|
+
RLP::Sedes.big_endian_int.serialize n
|
95
|
+
end
|
96
|
+
|
97
|
+
def lpad(x, symbol, l)
|
98
|
+
return x if x.size >= l
|
99
|
+
symbol * (l - x.size) + x
|
100
|
+
end
|
101
|
+
|
102
|
+
def rpad(x, symbol, l)
|
103
|
+
return x if x.size >= l
|
104
|
+
x + symbol * (l - x.size)
|
105
|
+
end
|
106
|
+
|
107
|
+
def zpad(x, l)
|
108
|
+
lpad x, BYTE_ZERO, l
|
109
|
+
end
|
110
|
+
|
111
|
+
def zunpad(x)
|
112
|
+
x.sub /\A\x00+/, ''
|
113
|
+
end
|
114
|
+
|
115
|
+
def zpad_int(n, l=32)
|
116
|
+
zpad encode_int(n), l
|
117
|
+
end
|
118
|
+
|
119
|
+
def zpad_hex(s, l=32)
|
120
|
+
zpad decode_hex(s), l
|
121
|
+
end
|
122
|
+
|
123
|
+
def int_to_addr(x)
|
124
|
+
zpad_int x, 20
|
125
|
+
end
|
126
|
+
|
127
|
+
def encode_int(n)
|
128
|
+
raise ArgumentError, "Integer invalid or out of range: #{n}" unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
|
129
|
+
int_to_big_endian n
|
130
|
+
end
|
131
|
+
|
132
|
+
def decode_int(v)
|
133
|
+
raise ArgumentError, "No leading zero bytes allowed for integers" if v.size > 0 && (v[0] == Constant::BYTE_ZERO || v[0] == 0)
|
134
|
+
big_endian_to_int v
|
135
|
+
end
|
136
|
+
|
137
|
+
def bytearray_to_int(arr)
|
138
|
+
o = 0
|
139
|
+
arr.each {|x| o = (o << 8) + x }
|
140
|
+
o
|
141
|
+
end
|
142
|
+
|
143
|
+
def int_array_to_bytes(arr)
|
144
|
+
arr.pack('C*')
|
145
|
+
end
|
146
|
+
|
147
|
+
def bytes_to_int_array(bytes)
|
148
|
+
bytes.unpack('C*')
|
149
|
+
end
|
150
|
+
|
151
|
+
def coerce_to_int(x)
|
152
|
+
if x.is_a?(Numeric)
|
153
|
+
x
|
154
|
+
elsif x.size == 40
|
155
|
+
big_endian_to_int decode_hex(x)
|
156
|
+
else
|
157
|
+
big_endian_to_int x
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def coerce_to_bytes(x)
|
162
|
+
if x.is_a?(Numeric)
|
163
|
+
int_to_big_endian x
|
164
|
+
elsif x.size == 40
|
165
|
+
decode_hex(x)
|
166
|
+
else
|
167
|
+
x
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def coerce_addr_to_hex(x)
|
172
|
+
if x.is_a?(Numeric)
|
173
|
+
encode_hex zpad(int_to_big_endian(x), 20)
|
174
|
+
elsif x.size == 40 || x.size == 0
|
175
|
+
x
|
176
|
+
else
|
177
|
+
encode_hex zpad(x, 20)[-20..-1]
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def normalize_address(x, allow_blank: false)
|
182
|
+
address = Address.new(x)
|
183
|
+
raise ValueError, "address is blank" if !allow_blank && address.blank?
|
184
|
+
address.to_bytes
|
185
|
+
end
|
186
|
+
|
187
|
+
def mk_contract_address(sender, nonce)
|
188
|
+
keccak256_rlp([normalize_address(sender), nonce])[12..-1]
|
189
|
+
end
|
190
|
+
|
191
|
+
def mk_metropolis_contract_address(sender, initcode)
|
192
|
+
keccak256(normalize_address(sender) + initcode)[12..-1]
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
def parse_int_or_hex(s)
|
197
|
+
if s.is_a?(Numeric)
|
198
|
+
s
|
199
|
+
elsif s[0,2] == '0x'
|
200
|
+
big_endian_to_int decode_hex(normalize_hex_without_prefix(s))
|
201
|
+
else
|
202
|
+
s.to_i
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def normalize_hex_without_prefix(s)
|
207
|
+
if s[0,2] == '0x'
|
208
|
+
(s.size % 2 == 1 ? '0' : '') + s[2..-1]
|
209
|
+
else
|
210
|
+
s
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def function_signature method_name, arg_types
|
215
|
+
"#{method_name}(#{arg_types.join(',')})"
|
216
|
+
end
|
217
|
+
|
218
|
+
def signature_hash signature, length=64
|
219
|
+
encode_hex(keccak256(signature))[0...length]
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
end # module Abi
|
226
|
+
end # module Ethlite
|
227
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Ethlite
|
2
|
+
class ContractMethod
|
3
|
+
include Utility
|
4
|
+
|
5
|
+
attr_reader :abi,
|
6
|
+
:signature,
|
7
|
+
:name,
|
8
|
+
:signature_hash,
|
9
|
+
:input_types,
|
10
|
+
:output_types,
|
11
|
+
:constant
|
12
|
+
|
13
|
+
def initialize( abi )
|
14
|
+
## convenience helper - auto-convert to json if string passed in
|
15
|
+
abi = JSON.parse( abi ) if abi.is_a?( String )
|
16
|
+
|
17
|
+
@abi = abi
|
18
|
+
@name = abi['name']
|
19
|
+
@constant = !!abi['constant'] || abi['stateMutability']=='view'
|
20
|
+
@input_types = abi['inputs'] ? abi['inputs'].map{|a| parse_component_type a } : []
|
21
|
+
@output_types = abi['outputs'] ? abi['outputs'].map{|a| parse_component_type a } : nil
|
22
|
+
@signature = Abi::Utils.function_signature( @name, @input_types )
|
23
|
+
@signature_hash = Abi::Utils.signature_hash( @signature, abi['type']=='event' ? 64 : 8)
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse_component_type( argument )
|
27
|
+
if argument['type'] =~ /^tuple((\[[0-9]*\])*)/
|
28
|
+
argument['components'] ? "(#{argument['components'].collect{|c| parse_component_type( c ) }.join(',')})#{$1}"
|
29
|
+
: "()#{$1}"
|
30
|
+
else
|
31
|
+
argument['type']
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def do_call( rpc, contract_address, args )
|
37
|
+
data = '0x' + @signature_hash + Abi::Utils.encode_hex(
|
38
|
+
Abi::AbiCoder.encode_abi(@input_types, args) )
|
39
|
+
|
40
|
+
method = 'eth_call'
|
41
|
+
params = [{ to: contract_address,
|
42
|
+
data: data},
|
43
|
+
'latest']
|
44
|
+
response = rpc.request( method, params )
|
45
|
+
|
46
|
+
|
47
|
+
puts "response:"
|
48
|
+
pp response
|
49
|
+
|
50
|
+
string_data = [remove_0x_head(response)].pack('H*')
|
51
|
+
return nil if string_data.empty?
|
52
|
+
|
53
|
+
result = Abi::AbiCoder.decode_abi( @output_types, string_data )
|
54
|
+
puts
|
55
|
+
puts "result decode_abi:"
|
56
|
+
pp result
|
57
|
+
|
58
|
+
|
59
|
+
result.length==1 ? result.first : result
|
60
|
+
end
|
61
|
+
|
62
|
+
end # class ContractMethod
|
63
|
+
end # module Ethlite
|
64
|
+
|
data/lib/ethlite/rpc.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Ethlite
|
2
|
+
|
3
|
+
class Rpc
|
4
|
+
def initialize( uri )
|
5
|
+
@client_id = Random.rand( 10000000 )
|
6
|
+
|
7
|
+
@uri = URI.parse( uri )
|
8
|
+
end
|
9
|
+
|
10
|
+
def request( method, params=[] )
|
11
|
+
opts = {}
|
12
|
+
if @uri.instance_of?( URI::HTTPS )
|
13
|
+
opts[:use_ssl] = true
|
14
|
+
opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
|
15
|
+
end
|
16
|
+
|
17
|
+
Net::HTTP.start( @uri.host, @uri.port, **opts ) do |http|
|
18
|
+
headers = {"Content-Type" => "application/json"}
|
19
|
+
request = Net::HTTP::Post.new( @uri.request_uri, headers )
|
20
|
+
|
21
|
+
json = { jsonrpc: '2.0',
|
22
|
+
method: method,
|
23
|
+
params: params,
|
24
|
+
id: @client_id }.to_json
|
25
|
+
|
26
|
+
puts "json POST payload:"
|
27
|
+
puts json
|
28
|
+
|
29
|
+
request.body = json
|
30
|
+
response = http.request( request )
|
31
|
+
|
32
|
+
raise "Error code #{response.code} on request #{@uri.to_s} #{request.body}" unless response.kind_of?( Net::HTTPOK )
|
33
|
+
|
34
|
+
body = JSON.parse(response.body, max_nesting: 1500)
|
35
|
+
|
36
|
+
if body['result']
|
37
|
+
body['result']
|
38
|
+
elsif body['error']
|
39
|
+
raise "Error #{@uri.to_s} #{body['error']} on request #{@uri.to_s} #{request.body}"
|
40
|
+
else
|
41
|
+
raise "No response on request #{@uri.to_s} #{request.body}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end # class Rpc
|
46
|
+
|
47
|
+
end # module Ethlite
|
48
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Ethlite
|
2
|
+
|
3
|
+
module Utility
|
4
|
+
|
5
|
+
def hex( num )
|
6
|
+
'0x' + num.to_s(16)
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_hex( h )
|
10
|
+
h.nil? ? 0 : (h.kind_of?(String) ? h.to_i(16) : h)
|
11
|
+
end
|
12
|
+
|
13
|
+
def remove_0x_head( s )
|
14
|
+
return s if !s || s.length<2
|
15
|
+
s[0,2] == '0x' ? s[2..-1] : s
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def wei_to_ether( wei )
|
20
|
+
1.0 * wei / 10**18
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end # module Ethlite
|
data/lib/ethlite/version.rb
CHANGED
data/lib/ethlite.rb
CHANGED
@@ -1,9 +1,40 @@
|
|
1
1
|
require 'cocos'
|
2
2
|
|
3
|
+
require 'uri'
|
4
|
+
require 'net/http'
|
5
|
+
require 'net/https'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
|
9
|
+
require 'openssl'
|
10
|
+
require 'digest'
|
11
|
+
|
12
|
+
## 3rd party gems
|
13
|
+
require 'rlp' ## gem rlp - see https://rubygems.org/gems/rlp
|
14
|
+
|
15
|
+
## bundled require 'digest/keccak' ## gem keccak - see https://rubygems.org/gems/keccak
|
16
|
+
require 'digest/keccak256'
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
3
21
|
## our own code
|
4
22
|
require_relative 'ethlite/version' # note: let version always go first
|
5
23
|
|
6
24
|
|
25
|
+
require_relative 'ethlite/abi/type'
|
26
|
+
require_relative 'ethlite/abi/constant'
|
27
|
+
require_relative 'ethlite/abi/exceptions'
|
28
|
+
require_relative 'ethlite/abi/utils'
|
29
|
+
require_relative 'ethlite/abi/abi_coder'
|
30
|
+
|
31
|
+
|
32
|
+
require_relative 'ethlite/rpc'
|
33
|
+
|
34
|
+
require_relative 'ethlite/utility'
|
35
|
+
require_relative 'ethlite/contract'
|
36
|
+
|
37
|
+
|
7
38
|
|
8
39
|
## add convenience alternate spelling
|
9
40
|
EthLite = Ethlite
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ethlite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rlp
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rdoc
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,7 +86,17 @@ files:
|
|
72
86
|
- Manifest.txt
|
73
87
|
- README.md
|
74
88
|
- Rakefile
|
89
|
+
- lib/digest/keccak256.rb
|
90
|
+
- lib/digest/sha3.rb
|
75
91
|
- lib/ethlite.rb
|
92
|
+
- lib/ethlite/abi/abi_coder.rb
|
93
|
+
- lib/ethlite/abi/constant.rb
|
94
|
+
- lib/ethlite/abi/exceptions.rb
|
95
|
+
- lib/ethlite/abi/type.rb
|
96
|
+
- lib/ethlite/abi/utils.rb
|
97
|
+
- lib/ethlite/contract.rb
|
98
|
+
- lib/ethlite/rpc.rb
|
99
|
+
- lib/ethlite/utility.rb
|
76
100
|
- lib/ethlite/version.rb
|
77
101
|
homepage: https://github.com/pixelartexchange/artbase
|
78
102
|
licenses:
|