abi_coder_rb 0.1.0 → 0.2.0
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/.DS_Store +0 -0
- data/Gemfile.lock +3 -1
- data/README.md +60 -2
- data/flatten.rb +8 -0
- data/flattened_abi_coder.rb +669 -0
- data/lib/.DS_Store +0 -0
- data/lib/abi_coder_rb/decode/decode_array.rb +6 -6
- data/lib/abi_coder_rb/decode/decode_primitive_type.rb +27 -22
- data/lib/abi_coder_rb/decode/decode_tuple.rb +29 -0
- data/lib/abi_coder_rb/decode.rb +3 -33
- data/lib/abi_coder_rb/encode/encode_fixed_array.rb +15 -1
- data/lib/abi_coder_rb/encode/encode_primitive_type.rb +20 -8
- data/lib/abi_coder_rb/encode/encode_tuple.rb +32 -0
- data/lib/abi_coder_rb/encode.rb +13 -43
- data/lib/abi_coder_rb/parser.rb +8 -1
- data/lib/abi_coder_rb/types.rb +10 -3
- data/lib/abi_coder_rb/utils.rb +111 -0
- data/lib/abi_coder_rb/version.rb +1 -1
- data/lib/abi_coder_rb.rb +20 -12
- metadata +20 -3
@@ -0,0 +1,669 @@
|
|
1
|
+
# Generated from https://github.com/wuminzhe/abi_coder_rb
|
2
|
+
module AbiCoderRb
|
3
|
+
def decode_array(type, data)
|
4
|
+
size = decode_uint256(data[0, 32])
|
5
|
+
raise DecodingError, "Too many elements: #{size}" if size > 100_000
|
6
|
+
subtype = type.subtype
|
7
|
+
if subtype.dynamic?
|
8
|
+
raise DecodingError, "Not enough data for head" unless data.size >= 32 + 32 * size
|
9
|
+
start_positions = (1..size).map { |i| 32 + decode_uint256(data[32 * i, 32]) }
|
10
|
+
start_positions.push(data.size)
|
11
|
+
outputs = (0...size).map { |i| data[start_positions[i]...start_positions[i + 1]] }
|
12
|
+
outputs.map { |out| decode_type(subtype, out) }
|
13
|
+
else
|
14
|
+
(0...size).map { |i| decode_type(subtype, data[(32 + subtype.size * i)..]) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
module AbiCoderRb
|
19
|
+
def decode_fixed_array(type, data)
|
20
|
+
l = type.dim
|
21
|
+
subtype = type.subtype
|
22
|
+
if subtype.dynamic?
|
23
|
+
start_positions = (0...l).map { |i| decode_uint256(data[32 * i, 32]) }
|
24
|
+
start_positions.push(data.size)
|
25
|
+
outputs = (0...l).map { |i| data[start_positions[i]...start_positions[i + 1]] }
|
26
|
+
outputs.map { |out| decode_type(subtype, out) }
|
27
|
+
else
|
28
|
+
(0...l).map { |i| decode_type(subtype, data[subtype.size * i, subtype.size]) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
module AbiCoderRb
|
33
|
+
def decode_primitive_type(type, data)
|
34
|
+
result =
|
35
|
+
case type
|
36
|
+
when Uint
|
37
|
+
decode_uint256(data[0, 32])
|
38
|
+
when Int
|
39
|
+
Utils.abi_to_int_signed(bin_to_hex(data[0, 32]), type.bits)
|
40
|
+
when Bool
|
41
|
+
data[31] == BYTE_ONE
|
42
|
+
when String
|
43
|
+
size = decode_uint256(data[0, 32])
|
44
|
+
data[32...(32 + size)].force_encoding("UTF-8")
|
45
|
+
when Bytes
|
46
|
+
size = decode_uint256(data[0, 32])
|
47
|
+
data[32...(32 + size)]
|
48
|
+
when FixedBytes
|
49
|
+
data[0, type.length]
|
50
|
+
when Address
|
51
|
+
bin_to_hex(data[12...32]).force_encoding("UTF-8")
|
52
|
+
else
|
53
|
+
raise DecodingError, "Unknown primitive type: #{type.class.name} #{type.format}"
|
54
|
+
end
|
55
|
+
result = after_decoding_action.call(type.format, result) if after_decoding_action
|
56
|
+
result
|
57
|
+
end
|
58
|
+
private
|
59
|
+
def decode_uint256(bin)
|
60
|
+
bin_to_hex(bin).to_i(16)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
module AbiCoderRb
|
64
|
+
def decode_tuple(type, data)
|
65
|
+
decode_types(type.types, data)
|
66
|
+
end
|
67
|
+
private
|
68
|
+
def decode_types(types, data)
|
69
|
+
start_positions = start_positions(types, data)
|
70
|
+
types.map.with_index do |type, index|
|
71
|
+
start_position = start_positions[index]
|
72
|
+
decode_type(type, data[start_position..])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
def start_positions(types, data)
|
76
|
+
start_positions = ::Array.new(types.size)
|
77
|
+
offset = 0
|
78
|
+
types.each_with_index do |type, index|
|
79
|
+
if type.dynamic?
|
80
|
+
start_positions[index] = decode_uint256(data[offset, 32])
|
81
|
+
offset += 32
|
82
|
+
else
|
83
|
+
start_positions[index] = offset
|
84
|
+
offset += type.size
|
85
|
+
end
|
86
|
+
end
|
87
|
+
start_positions
|
88
|
+
end
|
89
|
+
end
|
90
|
+
module AbiCoderRb
|
91
|
+
def decode(type_str, data)
|
92
|
+
raise DecodingError, "Empty data" if data.nil? || data.empty?
|
93
|
+
decode_type(Type.parse(type_str), data)
|
94
|
+
end
|
95
|
+
private
|
96
|
+
def decode_type(type, data)
|
97
|
+
case type
|
98
|
+
when Tuple ## todo: support empty (unit) tuple - why? why not?
|
99
|
+
decode_tuple(type, data)
|
100
|
+
when FixedArray # static-sized arrays
|
101
|
+
decode_fixed_array(type, data)
|
102
|
+
when Array
|
103
|
+
decode_array(type, data)
|
104
|
+
else
|
105
|
+
decode_primitive_type(type, data)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
module AbiCoderRb
|
110
|
+
def encode_array(type, args)
|
111
|
+
raise ArgumentError, "arg must be an array" unless args.is_a?(::Array)
|
112
|
+
head = "".b
|
113
|
+
tail = "".b # 使用二进制字符串
|
114
|
+
head += encode_uint256(args.size)
|
115
|
+
subtype = type.subtype
|
116
|
+
args.each do |arg|
|
117
|
+
if subtype.dynamic?
|
118
|
+
head += encode_uint256(32 * args.size + tail.size)
|
119
|
+
tail += encode_type(subtype, arg)
|
120
|
+
else
|
121
|
+
head += encode_type(subtype, arg)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
head + tail
|
125
|
+
end
|
126
|
+
end
|
127
|
+
module AbiCoderRb
|
128
|
+
def encode_fixed_array(type, args)
|
129
|
+
raise ArgumentError, "arg must be an array" unless args.is_a?(::Array)
|
130
|
+
raise ArgumentError, "Wrong array size: found #{args.size}, expecting #{type.dim}" unless args.size == type.dim
|
131
|
+
subtype = type.subtype
|
132
|
+
if subtype.dynamic?
|
133
|
+
head = "".b
|
134
|
+
tail = "".b
|
135
|
+
args.each do |arg|
|
136
|
+
head += encode_uint256(32 * args.size + tail.size)
|
137
|
+
tail += encode_type(subtype, arg)
|
138
|
+
end
|
139
|
+
head + tail
|
140
|
+
else
|
141
|
+
args.map { |arg| encode_type(type.subtype, arg) }.join
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
module AbiCoderRb
|
146
|
+
def encode_primitive_type(type, arg)
|
147
|
+
arg = before_encoding_action.call(type.format, arg) if before_encoding_action
|
148
|
+
case type
|
149
|
+
when Uint
|
150
|
+
encode_uint(arg, type.bits)
|
151
|
+
when Int
|
152
|
+
encode_int(arg, type.bits)
|
153
|
+
when Bool
|
154
|
+
encode_bool(arg)
|
155
|
+
when String
|
156
|
+
encode_string(arg)
|
157
|
+
when FixedBytes
|
158
|
+
encode_bytes(arg, type.length)
|
159
|
+
when Bytes
|
160
|
+
encode_bytes(arg)
|
161
|
+
when Address
|
162
|
+
encode_address(arg)
|
163
|
+
else
|
164
|
+
raise EncodingError, "Unknown type: #{type}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
def encode_uint(arg, bits)
|
168
|
+
raise ArgumentError, "arg is not integer: #{arg}" unless arg.is_a?(Integer)
|
169
|
+
raise ValueOutOfBounds, arg unless arg >= 0 && arg < 2**bits
|
170
|
+
lpad_int(arg)
|
171
|
+
end
|
172
|
+
def encode_uint256(arg)
|
173
|
+
encode_uint(arg, 256)
|
174
|
+
end
|
175
|
+
def encode_int(arg, _bits)
|
176
|
+
raise ArgumentError, "arg is not integer: #{arg}" unless arg.is_a?(Integer)
|
177
|
+
hex_to_bin(Utils.int_to_abi_signed_256bit(arg))
|
178
|
+
end
|
179
|
+
def encode_bool(arg)
|
180
|
+
raise ArgumentError, "arg is not bool: #{arg}" unless arg.is_a?(TrueClass) || arg.is_a?(FalseClass)
|
181
|
+
lpad(arg ? BYTE_ONE : BYTE_ZERO) ## was lpad_int( arg ? 1 : 0 )
|
182
|
+
end
|
183
|
+
def encode_string(arg)
|
184
|
+
raise EncodingError, "Expecting string: #{arg}" unless arg.is_a?(::String)
|
185
|
+
arg = arg.b if arg.encoding != "BINARY" ## was: name == 'UTF-8', wasm
|
186
|
+
raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size > UINT_MAX
|
187
|
+
size = lpad_int(arg.size)
|
188
|
+
value = rpad(arg, ceil32(arg.size))
|
189
|
+
size + value
|
190
|
+
end
|
191
|
+
def encode_bytes(arg, length = nil)
|
192
|
+
raise EncodingError, "Expecting string: #{arg}" unless arg.is_a?(::String)
|
193
|
+
arg = arg.b if arg.encoding != Encoding::BINARY
|
194
|
+
if length # fixed length type
|
195
|
+
raise ValueOutOfBounds, "invalid bytes length #{arg.size}, should be #{length}" if arg.size > length
|
196
|
+
raise ValueOutOfBounds, "invalid bytes length #{length}" if length < 0 || length > 32
|
197
|
+
rpad(arg)
|
198
|
+
else # variable length type (if length is nil)
|
199
|
+
raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size > UINT_MAX
|
200
|
+
size = lpad_int(arg.size)
|
201
|
+
value = rpad(arg, ceil32(arg.size))
|
202
|
+
size + value
|
203
|
+
end
|
204
|
+
end
|
205
|
+
def encode_address(arg)
|
206
|
+
if arg.is_a?(Integer)
|
207
|
+
lpad_int(arg)
|
208
|
+
elsif arg.size == 20
|
209
|
+
arg = arg.b if arg.encoding != Encoding::BINARY
|
210
|
+
lpad(arg)
|
211
|
+
elsif arg.size == 40
|
212
|
+
lpad_hex(arg)
|
213
|
+
elsif arg.size == 42 && arg[0, 2] == "0x" ## todo/fix: allow 0X too - why? why not?
|
214
|
+
lpad_hex(arg[2..-1])
|
215
|
+
else
|
216
|
+
raise EncodingError, "Could not parse address: #{arg}"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
private
|
220
|
+
def int_to_eth_abi(value, bits)
|
221
|
+
value = 2**bits + value if value < 0
|
222
|
+
hex = (value % 2**bits).to_s(16)
|
223
|
+
hex = "0#{hex}" if hex.length.odd?
|
224
|
+
hex.rjust(bits / 4, "0")
|
225
|
+
end
|
226
|
+
def rpad(bin, l = 32) ## note: same as builtin String#ljust !!!
|
227
|
+
return bin if bin.size >= l
|
228
|
+
bin + BYTE_ZERO * (l - bin.size)
|
229
|
+
end
|
230
|
+
def lpad(bin) ## note: same as builtin String#rjust !!!
|
231
|
+
l = 32 # NOTE: default l word is 32 bytes
|
232
|
+
return bin if bin.size >= l
|
233
|
+
BYTE_ZERO * (l - bin.size) + bin
|
234
|
+
end
|
235
|
+
def lpad_int(n)
|
236
|
+
raise ArgumentError, "Integer invalid or out of range: #{n}" unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
|
237
|
+
hex = n.to_s(16)
|
238
|
+
hex = "0#{hex}" if hex.length.odd? # wasm, no .odd?
|
239
|
+
bin = hex_to_bin(hex)
|
240
|
+
lpad(bin)
|
241
|
+
end
|
242
|
+
def lpad_hex(hex)
|
243
|
+
raise TypeError, "Value must be a string" unless hex.is_a?(::String)
|
244
|
+
raise TypeError, "Non-hexadecimal digit found" unless hex =~ /\A[0-9a-fA-F]*\z/
|
245
|
+
bin = hex_to_bin(hex)
|
246
|
+
lpad(bin)
|
247
|
+
end
|
248
|
+
def ceil32(x)
|
249
|
+
x % 32 == 0 ? x : (x + 32 - x % 32)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
module AbiCoderRb
|
253
|
+
def encode_tuple(tuple, args)
|
254
|
+
encode_types(tuple.types, args)
|
255
|
+
end
|
256
|
+
private
|
257
|
+
def encode_types(types, args)
|
258
|
+
raise ArgumentError, "args must be an array" unless args.is_a?(::Array)
|
259
|
+
unless args.size == types.size
|
260
|
+
raise ArgumentError,
|
261
|
+
"Wrong number of args: found #{args.size}, expecting #{types.size}"
|
262
|
+
end
|
263
|
+
head_size = types.map { |type| type.size || 32 }.sum
|
264
|
+
head = "".b
|
265
|
+
tail = "".b # 使用二进制字符串
|
266
|
+
types.each_with_index do |type, i|
|
267
|
+
if type.dynamic?
|
268
|
+
head += encode_uint256(head_size + tail.size)
|
269
|
+
tail += encode_type(type, args[i])
|
270
|
+
else
|
271
|
+
head += encode_type(type, args[i])
|
272
|
+
end
|
273
|
+
end
|
274
|
+
head + tail
|
275
|
+
end
|
276
|
+
end
|
277
|
+
module AbiCoderRb
|
278
|
+
def encode(type, value)
|
279
|
+
raise EncodingError, "Value can not be nil" if value.nil?
|
280
|
+
parsed = Type.parse(type)
|
281
|
+
encode_type(parsed, value)
|
282
|
+
end
|
283
|
+
private
|
284
|
+
def encode_type(type, value)
|
285
|
+
if type.is_a?(Tuple)
|
286
|
+
encode_tuple(type, value)
|
287
|
+
elsif type.is_a?(Array)
|
288
|
+
encode_array(type, value)
|
289
|
+
elsif type.is_a?(FixedArray)
|
290
|
+
encode_fixed_array(type, value)
|
291
|
+
else
|
292
|
+
encode_primitive_type(type, value)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
module AbiCoderRb
|
297
|
+
class Type
|
298
|
+
class ParseError < StandardError; end
|
299
|
+
class Parser
|
300
|
+
TUPLE_TYPE_RX = /^\((.*)\)
|
301
|
+
((\[[0-9]*\])*)
|
302
|
+
/x
|
303
|
+
def self.parse(type)
|
304
|
+
type = type.strip
|
305
|
+
if type =~ TUPLE_TYPE_RX
|
306
|
+
types = _parse_tuple_type(::Regexp.last_match(1))
|
307
|
+
dims = _parse_dims(::Regexp.last_match(2))
|
308
|
+
parsed_types = types.map { |t| parse(t) }
|
309
|
+
return _parse_array_type(Tuple.new(parsed_types), dims)
|
310
|
+
end
|
311
|
+
base, sub, dims = _parse_base_type(type)
|
312
|
+
sub ||= 256 if type.start_with?("uint") || type.start_with?("int") # default to 256 if no sub given
|
313
|
+
_validate_base_type(base, sub)
|
314
|
+
subtype = case base
|
315
|
+
when "string" then String.new
|
316
|
+
when "bytes" then sub ? FixedBytes.new(sub) : Bytes.new
|
317
|
+
when "uint" then Uint.new(sub)
|
318
|
+
when "int" then Int.new(sub)
|
319
|
+
when "address" then Address.new
|
320
|
+
when "bool" then Bool.new
|
321
|
+
else
|
322
|
+
raise ParseError, "Unrecognized type base: #{base}"
|
323
|
+
end
|
324
|
+
_parse_array_type(subtype, dims)
|
325
|
+
end
|
326
|
+
BASE_TYPE_RX = /([a-z]*)
|
327
|
+
([0-9]*)
|
328
|
+
((\[[0-9]*\])*)
|
329
|
+
/x
|
330
|
+
def self._parse_base_type(str)
|
331
|
+
_, base, subscript, dimension = BASE_TYPE_RX.match(str).to_a
|
332
|
+
sub = subscript == "" ? nil : subscript.to_i
|
333
|
+
dims = _parse_dims(dimension)
|
334
|
+
[base, sub, dims]
|
335
|
+
end
|
336
|
+
def self._parse_dims(str)
|
337
|
+
dims = str.scan(/\[[0-9]*\]/)
|
338
|
+
dims.map do |dim|
|
339
|
+
size = dim[1...-1]
|
340
|
+
size == "" ? -1 : size.to_i
|
341
|
+
end
|
342
|
+
end
|
343
|
+
def self._parse_array_type(subtype, dims)
|
344
|
+
dims.each do |dim|
|
345
|
+
subtype = if dim == -1
|
346
|
+
Array.new(subtype)
|
347
|
+
else
|
348
|
+
FixedArray.new(subtype, dim)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
subtype
|
352
|
+
end
|
353
|
+
def self._validate_base_type(base, sub)
|
354
|
+
case base
|
355
|
+
when "string"
|
356
|
+
raise ParseError, "String cannot have suffix" if sub
|
357
|
+
when "bytes"
|
358
|
+
raise ParseError, "Maximum 32 bytes for fixed-length bytes" if sub && sub > 32
|
359
|
+
when "uint", "int"
|
360
|
+
raise ParseError, "Integer type must have numerical suffix" unless sub
|
361
|
+
raise ParseError, "Integer size out of bounds" unless sub >= 8 && sub <= 256
|
362
|
+
raise ParseError, "Integer size must be multiple of 8" unless sub % 8 == 0
|
363
|
+
when "address"
|
364
|
+
raise ParseError, "Address cannot have suffix" if sub
|
365
|
+
when "bool"
|
366
|
+
raise ParseError, "Bool cannot have suffix" if sub
|
367
|
+
else
|
368
|
+
raise ParseError, "Unrecognized type base: #{base}"
|
369
|
+
end
|
370
|
+
end
|
371
|
+
def self._parse_tuple_type(str)
|
372
|
+
depth = 0
|
373
|
+
collected = []
|
374
|
+
current = ""
|
375
|
+
str.each_char do |c|
|
376
|
+
case c
|
377
|
+
when ","
|
378
|
+
if depth == 0
|
379
|
+
collected << current
|
380
|
+
current = ""
|
381
|
+
else
|
382
|
+
current += c
|
383
|
+
end
|
384
|
+
when "("
|
385
|
+
depth += 1
|
386
|
+
current += c
|
387
|
+
when ")"
|
388
|
+
depth -= 1
|
389
|
+
current += c
|
390
|
+
else
|
391
|
+
current += c
|
392
|
+
end
|
393
|
+
end
|
394
|
+
collected << current unless current.empty?
|
395
|
+
collected
|
396
|
+
end
|
397
|
+
end # class Parser
|
398
|
+
end # class Type
|
399
|
+
end # module ABI
|
400
|
+
module AbiCoderRb
|
401
|
+
class Type
|
402
|
+
def self.parse(type) ## convenience helper
|
403
|
+
Parser.parse(type)
|
404
|
+
end
|
405
|
+
def size
|
406
|
+
end
|
407
|
+
def dynamic?
|
408
|
+
size.nil?
|
409
|
+
end
|
410
|
+
def format
|
411
|
+
end
|
412
|
+
end
|
413
|
+
class Address < Type
|
414
|
+
def size
|
415
|
+
32
|
416
|
+
end
|
417
|
+
def format
|
418
|
+
"address"
|
419
|
+
end
|
420
|
+
def ==(other)
|
421
|
+
other.is_a?(Address)
|
422
|
+
end
|
423
|
+
end # class Address
|
424
|
+
class Bytes < Type
|
425
|
+
def size
|
426
|
+
nil
|
427
|
+
end
|
428
|
+
def format
|
429
|
+
"bytes"
|
430
|
+
end
|
431
|
+
def ==(other)
|
432
|
+
other.is_a?(Bytes)
|
433
|
+
end
|
434
|
+
end # class Bytes
|
435
|
+
class FixedBytes < Type
|
436
|
+
attr_reader :length
|
437
|
+
def initialize(length)
|
438
|
+
@length = length # in bytes (1,2,...32)
|
439
|
+
end
|
440
|
+
def size
|
441
|
+
32
|
442
|
+
end
|
443
|
+
def format
|
444
|
+
"bytes#{@length}"
|
445
|
+
end
|
446
|
+
def ==(other)
|
447
|
+
other.is_a?(FixedBytes) && @length == other.length
|
448
|
+
end
|
449
|
+
end # class FixedBytes
|
450
|
+
class Int < Type
|
451
|
+
attr_reader :bits
|
452
|
+
def initialize(bits = 256)
|
453
|
+
@bits = bits # in bits (8,16,...256)
|
454
|
+
end
|
455
|
+
def size
|
456
|
+
32
|
457
|
+
end
|
458
|
+
def format
|
459
|
+
"int#{@bits}"
|
460
|
+
end
|
461
|
+
def ==(other)
|
462
|
+
other.is_a?(Int) && @bits == other.bits
|
463
|
+
end
|
464
|
+
end # class Int
|
465
|
+
class Uint < Type
|
466
|
+
attr_reader :bits
|
467
|
+
def initialize(bits = 256)
|
468
|
+
@bits = bits # in bits (8,16,...256)
|
469
|
+
end
|
470
|
+
def size
|
471
|
+
32
|
472
|
+
end
|
473
|
+
def format
|
474
|
+
"uint#{@bits}"
|
475
|
+
end
|
476
|
+
def ==(other)
|
477
|
+
other.is_a?(Uint) && @bits == other.bits
|
478
|
+
end
|
479
|
+
end # class Uint
|
480
|
+
class Bool < Type
|
481
|
+
def size
|
482
|
+
32
|
483
|
+
end
|
484
|
+
def format
|
485
|
+
"bool"
|
486
|
+
end
|
487
|
+
def ==(other)
|
488
|
+
other.is_a?(Bool)
|
489
|
+
end
|
490
|
+
end # class Bool
|
491
|
+
class String < Type
|
492
|
+
def size
|
493
|
+
nil
|
494
|
+
end
|
495
|
+
def format
|
496
|
+
"string"
|
497
|
+
end
|
498
|
+
def ==(other)
|
499
|
+
other.is_a?(String)
|
500
|
+
end
|
501
|
+
end # class String
|
502
|
+
class Array < Type
|
503
|
+
attr_reader :subtype
|
504
|
+
def initialize(subtype)
|
505
|
+
@subtype = subtype
|
506
|
+
end
|
507
|
+
def size
|
508
|
+
nil
|
509
|
+
end
|
510
|
+
def format
|
511
|
+
"#{@subtype.format}[]"
|
512
|
+
end
|
513
|
+
def ==(other)
|
514
|
+
other.is_a?(Array) && @subtype == other.subtype
|
515
|
+
end
|
516
|
+
end # class Array
|
517
|
+
class FixedArray < Type
|
518
|
+
attr_reader :subtype, :dim
|
519
|
+
def initialize(subtype, dim)
|
520
|
+
@subtype = subtype
|
521
|
+
@dim = dim
|
522
|
+
end
|
523
|
+
def size
|
524
|
+
@subtype.dynamic? ? nil : @dim * subtype.size
|
525
|
+
end
|
526
|
+
def format
|
527
|
+
"#{@subtype.format}[#{@dim}]"
|
528
|
+
end
|
529
|
+
def ==(other)
|
530
|
+
other.is_a?(FixedArray) &&
|
531
|
+
@dim == other.dim &&
|
532
|
+
@subtype == other.subtype
|
533
|
+
end
|
534
|
+
end # class FixedArray
|
535
|
+
class Tuple < Type
|
536
|
+
attr_reader :types
|
537
|
+
def initialize(types)
|
538
|
+
@types = types
|
539
|
+
end
|
540
|
+
def size
|
541
|
+
s = 0
|
542
|
+
has_dynamic = false
|
543
|
+
@types.each do |type|
|
544
|
+
ts = type.size
|
545
|
+
if ts.nil?
|
546
|
+
has_dynamic = true
|
547
|
+
else
|
548
|
+
s += ts
|
549
|
+
end
|
550
|
+
end
|
551
|
+
return if has_dynamic
|
552
|
+
s
|
553
|
+
end
|
554
|
+
def format
|
555
|
+
"(#{@types.map { |t| t.format }.join(",")})" ## rebuild minimal string
|
556
|
+
end
|
557
|
+
def ==(other)
|
558
|
+
other.is_a?(Tuple) && @types == other.types
|
559
|
+
end
|
560
|
+
end # class Tuple
|
561
|
+
end # module ABI
|
562
|
+
module AbiCoderRb
|
563
|
+
module Utils
|
564
|
+
class << self
|
565
|
+
def hex_to_bin(hex)
|
566
|
+
hex = hex[2..] if %w[0x 0X].include?(hex[0, 2]) ## cut-of leading 0x or 0X if present
|
567
|
+
hex.scan(/../).map { |x| x.hex.chr }.join
|
568
|
+
end
|
569
|
+
def bin_to_hex(bin)
|
570
|
+
bin.each_byte.map { |byte| "%02x" % byte }.join
|
571
|
+
end
|
572
|
+
def hex?(str)
|
573
|
+
str.start_with?("0x") && str.length.even? && str[2..].match?(/\A\b[0-9a-fA-F]+\b\z/)
|
574
|
+
end
|
575
|
+
def lpad(str, sym, len)
|
576
|
+
return str if str.size >= len
|
577
|
+
sym * (len - str.size) + str
|
578
|
+
end
|
579
|
+
def zpad(str, len)
|
580
|
+
lpad str, BYTE_ZERO, len
|
581
|
+
end
|
582
|
+
def ffpad(str, len)
|
583
|
+
lpad str, BYTE_FF, len
|
584
|
+
end
|
585
|
+
def uint_to_big_endian(num, size)
|
586
|
+
raise "Can only serialize integers" unless num.is_a?(Integer)
|
587
|
+
raise "Cannot serialize negative integers" if num.negative?
|
588
|
+
raise "Integer too large (does not fit in #{size} bytes)" if size && num >= 256**size
|
589
|
+
s = if num.zero?
|
590
|
+
BYTE_EMPTY
|
591
|
+
else
|
592
|
+
hex = num.to_s(16)
|
593
|
+
hex = "0#{hex}" if hex.size.odd?
|
594
|
+
hex_to_bin hex
|
595
|
+
end
|
596
|
+
s = size ? "#{BYTE_ZERO * [0, size - s.size].max}#{s}" : s
|
597
|
+
zpad s, size
|
598
|
+
end
|
599
|
+
def int_to_abi_signed_256bit(value)
|
600
|
+
min = -2**255
|
601
|
+
max = 2**255 - 1
|
602
|
+
raise "Value out of range" if value < min || value > max
|
603
|
+
value = (1 << 256) + value if value < 0
|
604
|
+
hex_str = value.to_s(16)
|
605
|
+
hex_str.rjust(64, "0")
|
606
|
+
end
|
607
|
+
def int_to_abi_signed(value)
|
608
|
+
raise "Value out of range" if value < -2**31 || value > 2**31 - 1
|
609
|
+
hex_str = [value].pack("l>").unpack1("H*")
|
610
|
+
if value >= 0
|
611
|
+
hex_str.rjust(64, "0")
|
612
|
+
else
|
613
|
+
hex_str.rjust(64, "f")
|
614
|
+
end
|
615
|
+
end
|
616
|
+
def abi_to_int_signed(hex_str, bits)
|
617
|
+
hex_str = "0x#{hex_str}" if hex_str[0, 2] != "0x" || hex_str[0, 2] != "0X"
|
618
|
+
expected_length = bits / 4
|
619
|
+
extended_hex_str = if hex_str.length < expected_length
|
620
|
+
extend_char = hex_str[0] == "f" ? "f" : "0"
|
621
|
+
extend_char * (expected_length - hex_str.length) + hex_str
|
622
|
+
else
|
623
|
+
hex_str
|
624
|
+
end
|
625
|
+
binary_str = extended_hex_str.to_i(16).to_s(2).rjust(bits, extended_hex_str[0])
|
626
|
+
if binary_str[0] == "1" # 负数
|
627
|
+
-((binary_str.tr("01", "10").to_i(2) + 1) & ((1 << bits) - 1))
|
628
|
+
else # 正数
|
629
|
+
binary_str.to_i(2)
|
630
|
+
end
|
631
|
+
end
|
632
|
+
end
|
633
|
+
end
|
634
|
+
end
|
635
|
+
module AbiCoderRb
|
636
|
+
VERSION = "0.1.0"
|
637
|
+
end
|
638
|
+
module AbiCoderRb
|
639
|
+
class DecodingError < StandardError; end
|
640
|
+
class EncodingError < StandardError; end
|
641
|
+
class ValueError < StandardError; end
|
642
|
+
class ValueOutOfBounds < ValueError; end
|
643
|
+
BYTE_EMPTY = "".b.freeze
|
644
|
+
BYTE_ZERO = "\x00".b.freeze
|
645
|
+
BYTE_ONE = "\x01".b.freeze ## note: used for encoding bool for now
|
646
|
+
BYTE_FF = "\xff".b.freeze
|
647
|
+
UINT_MAX = 2**256 - 1 ## same as 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
648
|
+
UINT_MIN = 0
|
649
|
+
INT_MAX = 2**255 - 1 ## same as 57896044618658097711785492504343953926634992332820282019728792003956564819967
|
650
|
+
INT_MIN = -2**255 ## same as -57896044618658097711785492504343953926634992332820282019728792003956564819968
|
651
|
+
def hex_to_bin(hex) # convert hex(adecimal) string to binary string
|
652
|
+
hex = hex[2..] if %w[0x 0X].include?(hex[0, 2]) ## cut-of leading 0x or 0X if present
|
653
|
+
hex.scan(/../).map { |x| x.hex.chr }.join
|
654
|
+
end
|
655
|
+
alias hex hex_to_bin
|
656
|
+
def bin_to_hex(bin) # convert binary string to hex string
|
657
|
+
bin.each_byte.map { |byte| "%02x" % byte }.join
|
658
|
+
end
|
659
|
+
def hex?(str)
|
660
|
+
str.start_with?("0x") && str.length.even? && str[2..].match?(/\A\b[0-9a-fA-F]+\b\z/)
|
661
|
+
end
|
662
|
+
attr_accessor :before_encoding_action, :after_decoding_action
|
663
|
+
def before_encoding(action)
|
664
|
+
self.before_encoding_action = action
|
665
|
+
end
|
666
|
+
def after_decoding(action)
|
667
|
+
self.after_decoding_action = action
|
668
|
+
end
|
669
|
+
end
|
data/lib/.DS_Store
CHANGED
Binary file
|
@@ -1,21 +1,21 @@
|
|
1
1
|
module AbiCoderRb
|
2
2
|
def decode_array(type, data)
|
3
|
-
|
4
|
-
raise DecodingError, "Too
|
3
|
+
size = decode_uint256(data[0, 32])
|
4
|
+
raise DecodingError, "Too many elements: #{size}" if size > 100_000
|
5
5
|
|
6
6
|
subtype = type.subtype
|
7
7
|
|
8
8
|
if subtype.dynamic?
|
9
|
-
raise DecodingError, "Not enough data for head" unless data.size >= 32 + 32 *
|
9
|
+
raise DecodingError, "Not enough data for head" unless data.size >= 32 + 32 * size
|
10
10
|
|
11
|
-
start_positions = (1..
|
11
|
+
start_positions = (1..size).map { |i| 32 + decode_uint256(data[32 * i, 32]) }
|
12
12
|
start_positions.push(data.size)
|
13
13
|
|
14
|
-
outputs = (0...
|
14
|
+
outputs = (0...size).map { |i| data[start_positions[i]...start_positions[i + 1]] }
|
15
15
|
|
16
16
|
outputs.map { |out| decode_type(subtype, out) }
|
17
17
|
else
|
18
|
-
(0...
|
18
|
+
(0...size).map { |i| decode_type(subtype, data[(32 + subtype.size * i)..]) }
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|