abicoder 0.1.0 → 1.0.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/Manifest.txt +4 -4
- data/README.md +88 -19
- data/Rakefile +1 -1
- data/lib/abicoder/decoder.rb +207 -0
- data/lib/abicoder/encoder.rb +278 -0
- data/lib/abicoder/parser.rb +158 -0
- data/lib/abicoder/types.rb +155 -0
- data/lib/abicoder/version.rb +2 -2
- data/lib/abicoder.rb +37 -15
- metadata +10 -10
- data/lib/abicoder/codec.rb +0 -413
- data/lib/abicoder/type.rb +0 -141
- data/lib/abicoder/type_tuple.rb +0 -106
- data/lib/abicoder/utils.rb +0 -81
data/lib/abicoder/codec.rb
DELETED
@@ -1,413 +0,0 @@
|
|
1
|
-
|
2
|
-
module ABI
|
3
|
-
##
|
4
|
-
# Contract ABI encoding and decoding.
|
5
|
-
#
|
6
|
-
# @see https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
7
|
-
#
|
8
|
-
class Codec
|
9
|
-
class EncodingError < StandardError; end
|
10
|
-
class DecodingError < StandardError; end
|
11
|
-
class ValueError < StandardError; end
|
12
|
-
|
13
|
-
class ValueOutOfBounds < ValueError; end
|
14
|
-
|
15
|
-
##
|
16
|
-
# Encodes multiple arguments using the head/tail mechanism.
|
17
|
-
#
|
18
|
-
def encode_abi(types, args)
|
19
|
-
## for convenience check if types is a String
|
20
|
-
## otherwise assume ABI::Type already
|
21
|
-
types = types.map { |type| type.is_a?( String ) ? Type.parse( type ) : type }
|
22
|
-
|
23
|
-
head_size = (0...args.size)
|
24
|
-
.map {|i| types[i].size || 32 }
|
25
|
-
.reduce(0, &:+)
|
26
|
-
|
27
|
-
head, tail = '', ''
|
28
|
-
args.each_with_index do |arg, i|
|
29
|
-
if types[i].dynamic?
|
30
|
-
head += encode_type(Type.size_type, head_size + tail.size)
|
31
|
-
tail += encode_type(types[i], arg)
|
32
|
-
else
|
33
|
-
head += encode_type(types[i], arg)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
"#{head}#{tail}"
|
38
|
-
end
|
39
|
-
|
40
|
-
##
|
41
|
-
# Encodes a single value (static or dynamic).
|
42
|
-
#
|
43
|
-
# @param type [ABI::Type] value type
|
44
|
-
# @param arg [Object] value
|
45
|
-
#
|
46
|
-
# @return [String] encoded bytes
|
47
|
-
#
|
48
|
-
def encode_type(type, arg)
|
49
|
-
if ['string', 'bytes'].include?(type.base) && type.sub.empty?
|
50
|
-
encode_primitive_type type, arg
|
51
|
-
elsif type.dynamic?
|
52
|
-
raise ArgumentError, "arg must be an array" unless arg.instance_of?(Array)
|
53
|
-
|
54
|
-
head, tail = '', ''
|
55
|
-
if type.dims.last == 0
|
56
|
-
head += encode_type(Type.size_type, arg.size)
|
57
|
-
else
|
58
|
-
raise ArgumentError, "Wrong array size: found #{arg.size}, expecting #{type.dims.last}" unless arg.size == type.dims.last
|
59
|
-
end
|
60
|
-
|
61
|
-
sub_type = type.subtype
|
62
|
-
sub_size = type.subtype.size
|
63
|
-
arg.size.times do |i|
|
64
|
-
if sub_size.nil?
|
65
|
-
head += encode_type(Type.size_type, 32*arg.size + tail.size)
|
66
|
-
tail += encode_type(sub_type, arg[i])
|
67
|
-
else
|
68
|
-
head += encode_type(sub_type, arg[i])
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
"#{head}#{tail}"
|
73
|
-
else # static type
|
74
|
-
if type.dims.empty?
|
75
|
-
encode_primitive_type type, arg
|
76
|
-
else
|
77
|
-
arg.map {|x| encode_type(type.subtype, x) }.join
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def encode_primitive_type(type, arg)
|
83
|
-
case type.base
|
84
|
-
when 'uint'
|
85
|
-
begin
|
86
|
-
real_size = type.sub.to_i
|
87
|
-
i = get_uint arg
|
88
|
-
|
89
|
-
raise ValueOutOfBounds, arg unless i >= 0 && i < 2**real_size
|
90
|
-
Utils.zpad_int i
|
91
|
-
rescue EncodingError
|
92
|
-
raise ValueOutOfBounds, arg
|
93
|
-
end
|
94
|
-
when 'bool'
|
95
|
-
raise ArgumentError, "arg is not bool: #{arg}" unless arg.instance_of?(TrueClass) || arg.instance_of?(FalseClass)
|
96
|
-
Utils.zpad_int(arg ? 1 : 0)
|
97
|
-
when 'int'
|
98
|
-
begin
|
99
|
-
real_size = type.sub.to_i
|
100
|
-
i = get_int arg
|
101
|
-
|
102
|
-
raise ValueOutOfBounds, arg unless i >= -2**(real_size-1) && i < 2**(real_size-1)
|
103
|
-
Utils.zpad_int(i % 2**type.sub.to_i)
|
104
|
-
rescue EncodingError
|
105
|
-
raise ValueOutOfBounds, arg
|
106
|
-
end
|
107
|
-
when 'string'
|
108
|
-
if arg.encoding.name == 'UTF-8'
|
109
|
-
arg = arg.b
|
110
|
-
else
|
111
|
-
begin
|
112
|
-
arg.unpack('U*')
|
113
|
-
rescue ArgumentError
|
114
|
-
raise ValueError, "string must be UTF-8 encoded"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
if type.sub.empty? # variable length type
|
119
|
-
raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size >= TT256
|
120
|
-
size = Utils.zpad_int arg.size
|
121
|
-
value = Utils.rpad arg, BYTE_ZERO, Utils.ceil32(arg.size)
|
122
|
-
"#{size}#{value}"
|
123
|
-
else # fixed length type
|
124
|
-
sub = type.sub.to_i
|
125
|
-
raise ValueOutOfBounds, "invalid string length #{sub}" if arg.size > sub
|
126
|
-
raise ValueOutOfBounds, "invalid string length #{sub}" if sub < 0 || sub > 32
|
127
|
-
Utils.rpad(arg, BYTE_ZERO, 32)
|
128
|
-
end
|
129
|
-
when 'bytes'
|
130
|
-
raise EncodingError, "Expecting string: #{arg}" unless arg.instance_of?(String)
|
131
|
-
arg = arg.b
|
132
|
-
|
133
|
-
if type.sub.empty? # variable length type
|
134
|
-
raise ValueOutOfBounds, "Integer invalid or out of range: #{arg.size}" if arg.size >= TT256
|
135
|
-
size = Utils.zpad_int arg.size
|
136
|
-
value = Utils.rpad arg, BYTE_ZERO, Utils.ceil32(arg.size)
|
137
|
-
"#{size}#{value}"
|
138
|
-
else # fixed length type
|
139
|
-
sub = type.sub.to_i
|
140
|
-
raise ValueOutOfBounds, "invalid bytes length #{sub}" if arg.size > sub
|
141
|
-
raise ValueOutOfBounds, "invalid bytes length #{sub}" if sub < 0 || sub > 32
|
142
|
-
Utils.rpad(arg, BYTE_ZERO, 32)
|
143
|
-
end
|
144
|
-
when 'address'
|
145
|
-
if arg.is_a?(Integer)
|
146
|
-
Utils.zpad_int arg
|
147
|
-
elsif arg.size == 20
|
148
|
-
Utils.zpad arg, 32
|
149
|
-
elsif arg.size == 40
|
150
|
-
Utils.zpad_hex arg
|
151
|
-
elsif arg.size == 42 && arg[0,2] == '0x'
|
152
|
-
Utils.zpad_hex arg[2..-1]
|
153
|
-
else
|
154
|
-
raise EncodingError, "Could not parse address: #{arg}"
|
155
|
-
end
|
156
|
-
else
|
157
|
-
raise EncodingError, "Unhandled type: #{type.base} #{type.sub}"
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
|
162
|
-
def min_data_size( types )
|
163
|
-
types.size*32
|
164
|
-
end
|
165
|
-
|
166
|
-
##
|
167
|
-
# Decodes multiple arguments using the head/tail mechanism.
|
168
|
-
#
|
169
|
-
def decode_abi( types, data, raise_errors = false )
|
170
|
-
## for convenience check if types is a String
|
171
|
-
## otherwise assume ABI::Type already
|
172
|
-
types = types.map { |type| type.is_a?( String ) ? Type.parse( type ) : type }
|
173
|
-
|
174
|
-
outputs = [nil] * types.size
|
175
|
-
start_positions = [nil] * types.size + [data.size]
|
176
|
-
|
177
|
-
# TODO: refactor, a reverse iteration will be better
|
178
|
-
pos = 0
|
179
|
-
types.each_with_index do |t, i|
|
180
|
-
# If a type is static, grab the data directly, otherwise record its
|
181
|
-
# start position
|
182
|
-
if t.dynamic?
|
183
|
-
|
184
|
-
if raise_errors && pos>data.size-1
|
185
|
-
raise DecodingError, "Position out of bounds #{pos}>#{data.size-1}"
|
186
|
-
end
|
187
|
-
|
188
|
-
start_positions[i] = Utils.big_endian_to_int(data[pos, 32])
|
189
|
-
|
190
|
-
if raise_errors && start_positions[i]>data.size-1
|
191
|
-
raise DecodingError, "Start position out of bounds #{start_positions[i]}>#{data.size-1}"
|
192
|
-
end
|
193
|
-
|
194
|
-
j = i - 1
|
195
|
-
while j >= 0 && start_positions[j].nil?
|
196
|
-
start_positions[j] = start_positions[i]
|
197
|
-
j -= 1
|
198
|
-
end
|
199
|
-
|
200
|
-
pos += 32
|
201
|
-
else
|
202
|
-
outputs[i] = zero_padding data, pos, t.size, start_positions
|
203
|
-
pos += t.size
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
# We add a start position equal to the length of the entire data for
|
208
|
-
# convenience.
|
209
|
-
j = types.size - 1
|
210
|
-
while j >= 0 && start_positions[j].nil?
|
211
|
-
start_positions[j] = start_positions[types.size]
|
212
|
-
j -= 1
|
213
|
-
end
|
214
|
-
|
215
|
-
if raise_errors && pos > data.size
|
216
|
-
raise DecodingError, "Not enough data for head"
|
217
|
-
end
|
218
|
-
|
219
|
-
|
220
|
-
types.each_with_index do |t, i|
|
221
|
-
if t.dynamic?
|
222
|
-
offset, next_offset = start_positions[i, 2]
|
223
|
-
if offset<=data.size && next_offset<=data.size
|
224
|
-
outputs[i] = data[offset...next_offset]
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
if raise_errors && outputs.include?(nil)
|
230
|
-
raise DecodingError, "Not all data can be parsed"
|
231
|
-
end
|
232
|
-
|
233
|
-
types.zip(outputs).map {|(type, out)| decode_type(type, out) }
|
234
|
-
end
|
235
|
-
|
236
|
-
|
237
|
-
def zero_padding( data, pos, count, start_positions )
|
238
|
-
if pos >= data.size
|
239
|
-
start_positions[start_positions.size-1] += count
|
240
|
-
"\x00"*count
|
241
|
-
elsif pos + count > data.size
|
242
|
-
start_positions[start_positions.size-1] += ( count - (data.size-pos))
|
243
|
-
data[pos,data.size-pos] + "\x00"*( count - (data.size-pos))
|
244
|
-
else
|
245
|
-
data[pos, count]
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
def decode_typed_data( type_name, data )
|
250
|
-
decode_primitive_type Type.parse(type_name), data
|
251
|
-
end
|
252
|
-
|
253
|
-
def decode_type(type, arg)
|
254
|
-
return nil if arg.nil? || arg.empty?
|
255
|
-
if type.kind_of?( Tuple ) && type.dims.empty?
|
256
|
-
arg ? decode_abi(type.types, arg) : []
|
257
|
-
elsif %w(string bytes).include?(type.base) && type.sub.empty?
|
258
|
-
l = Utils.big_endian_to_int arg[0,32]
|
259
|
-
data = arg[32..-1]
|
260
|
-
data[0, l]
|
261
|
-
elsif !type.dims.empty? && (l = type.dims.last)>0 # static-sized arrays
|
262
|
-
subtype = type.subtype
|
263
|
-
if subtype.dynamic?
|
264
|
-
start_positions = (0...l).map {|i| Utils.big_endian_to_int(arg[32*i, 32]) }
|
265
|
-
start_positions.push arg.size
|
266
|
-
|
267
|
-
outputs = (0...l).map {|i| arg[start_positions[i]...start_positions[i+1]] }
|
268
|
-
|
269
|
-
outputs.map {|out| decode_type(subtype, out) }
|
270
|
-
else
|
271
|
-
(0...l).map {|i| decode_type(subtype, arg[subtype.size*i, subtype.size]) }
|
272
|
-
end
|
273
|
-
|
274
|
-
elsif type.dynamic?
|
275
|
-
l = Utils.big_endian_to_int arg[0,32]
|
276
|
-
raise DecodingError, "Too long length: #{l}" if l>100000
|
277
|
-
subtype = type.subtype
|
278
|
-
|
279
|
-
if subtype.dynamic?
|
280
|
-
raise DecodingError, "Not enough data for head" unless arg.size >= 32 + 32*l
|
281
|
-
|
282
|
-
start_positions = (1..l).map {|i| 32+Utils.big_endian_to_int(arg[32*i, 32]) }
|
283
|
-
start_positions.push arg.size
|
284
|
-
|
285
|
-
outputs = (0...l).map {|i| arg[start_positions[i]...start_positions[i+1]] }
|
286
|
-
|
287
|
-
outputs.map {|out| decode_type(subtype, out) }
|
288
|
-
else
|
289
|
-
(0...l).map {|i| decode_type(subtype, arg[32 + subtype.size*i, subtype.size]) }
|
290
|
-
end
|
291
|
-
|
292
|
-
else
|
293
|
-
decode_primitive_type type, arg
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
def decode_primitive_type(type, data)
|
298
|
-
case type.base
|
299
|
-
when 'address'
|
300
|
-
Utils.encode_hex data[12..-1]
|
301
|
-
when 'string', 'bytes'
|
302
|
-
if type.sub.empty? # dynamic
|
303
|
-
if data.length==32
|
304
|
-
data[0..32]
|
305
|
-
else
|
306
|
-
size = Utils.big_endian_to_int data[0,32]
|
307
|
-
data[32..-1][0,size]
|
308
|
-
end
|
309
|
-
else # fixed
|
310
|
-
data[0, type.sub.to_i]
|
311
|
-
end
|
312
|
-
when 'hash'
|
313
|
-
data[(32 - type.sub.to_i), type.sub.to_i]
|
314
|
-
when 'uint'
|
315
|
-
Utils.big_endian_to_int data
|
316
|
-
when 'int'
|
317
|
-
u = Utils.big_endian_to_int data
|
318
|
-
u >= 2**(type.sub.to_i-1) ? (u - 2**type.sub.to_i) : u
|
319
|
-
when 'ufixed'
|
320
|
-
high, low = type.sub.split('x').map(&:to_i)
|
321
|
-
Utils.big_endian_to_int(data) * 1.0 / 2**low
|
322
|
-
when 'fixed'
|
323
|
-
high, low = type.sub.split('x').map(&:to_i)
|
324
|
-
u = Utils.big_endian_to_int data
|
325
|
-
i = u >= 2**(high+low-1) ? (u - 2**(high+low)) : u
|
326
|
-
i * 1.0 / 2**low
|
327
|
-
when 'bool'
|
328
|
-
data[-1] == BYTE_ONE
|
329
|
-
else
|
330
|
-
raise DecodingError, "Unknown primitive type: #{type.base}"
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
private
|
335
|
-
|
336
|
-
def get_uint(n)
|
337
|
-
case n
|
338
|
-
when Integer
|
339
|
-
raise EncodingError, "Number out of range: #{n}" if n > UINT_MAX || n < UINT_MIN
|
340
|
-
n
|
341
|
-
when String
|
342
|
-
i = if n.size == 40
|
343
|
-
Utils.decode_hex(n)
|
344
|
-
elsif n.size <= 32
|
345
|
-
n
|
346
|
-
else
|
347
|
-
raise EncodingError, "String too long: #{n}"
|
348
|
-
end
|
349
|
-
i = Utils.big_endian_to_int i
|
350
|
-
|
351
|
-
raise EncodingError, "Number out of range: #{i}" if i > UINT_MAX || i < UINT_MIN
|
352
|
-
i
|
353
|
-
when true
|
354
|
-
1
|
355
|
-
when false, nil
|
356
|
-
0
|
357
|
-
else
|
358
|
-
raise EncodingError, "Cannot decode uint: #{n}"
|
359
|
-
end
|
360
|
-
end
|
361
|
-
|
362
|
-
def get_int(n)
|
363
|
-
case n
|
364
|
-
when Integer
|
365
|
-
raise EncodingError, "Number out of range: #{n}" if n > INT_MAX || n < INT_MIN
|
366
|
-
n
|
367
|
-
when String
|
368
|
-
i = if n.size == 40
|
369
|
-
Utils.decode_hex(n)
|
370
|
-
elsif n.size <= 32
|
371
|
-
n
|
372
|
-
else
|
373
|
-
raise EncodingError, "String too long: #{n}"
|
374
|
-
end
|
375
|
-
i = Utils.big_endian_to_int i
|
376
|
-
|
377
|
-
i = i > INT_MAX ? (i-TT256) : i
|
378
|
-
raise EncodingError, "Number out of range: #{i}" if i > INT_MAX || i < INT_MIN
|
379
|
-
i
|
380
|
-
when true
|
381
|
-
1
|
382
|
-
when false, nil
|
383
|
-
0
|
384
|
-
else
|
385
|
-
raise EncodingError, "Cannot decode int: #{n}"
|
386
|
-
end
|
387
|
-
end
|
388
|
-
end # class Codec
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
def self.codec
|
393
|
-
@codec ||= Codec.new
|
394
|
-
end
|
395
|
-
|
396
|
-
def self.encode_abi( types, args )
|
397
|
-
codec.encode_abi( types, args )
|
398
|
-
end
|
399
|
-
|
400
|
-
def self.decode_abi( types, data, raise_errors = false )
|
401
|
-
codec.decode_abi( types, data, raise_errors )
|
402
|
-
end
|
403
|
-
|
404
|
-
## add alternate names
|
405
|
-
## todo/fix: change to encode / decode by default
|
406
|
-
## from encode_abi / decode_abi - why? why not?
|
407
|
-
class << self
|
408
|
-
alias_method :encode, :encode_abi
|
409
|
-
alias_method :decode, :decode_abi
|
410
|
-
end
|
411
|
-
|
412
|
-
end # module ABI
|
413
|
-
|
data/lib/abicoder/type.rb
DELETED
@@ -1,141 +0,0 @@
|
|
1
|
-
module ABI
|
2
|
-
class Type
|
3
|
-
|
4
|
-
class ParseError < StandardError; end
|
5
|
-
|
6
|
-
##
|
7
|
-
# Crazy regexp to seperate out base type component (eg. uint), size (eg.
|
8
|
-
# 256, 128, nil), array component (eg. [], [45], nil)
|
9
|
-
#
|
10
|
-
BASE_TYPE_RX = /([a-z]*)
|
11
|
-
([0-9]*)
|
12
|
-
((\[[0-9]*\])*)
|
13
|
-
/x
|
14
|
-
|
15
|
-
def self._parse_base_type( str )
|
16
|
-
_, base, sub, dimension = BASE_TYPE_RX.match( str ).to_a
|
17
|
-
|
18
|
-
dims = dimension.scan( /\[[0-9]*\]/ )
|
19
|
-
if dims.join != dimension
|
20
|
-
raise ParseError, "Unknown characters found in array declaration"
|
21
|
-
end
|
22
|
-
|
23
|
-
dims = dims.map {|x| x[1...-1].to_i }
|
24
|
-
|
25
|
-
[base, sub, dims]
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
TUPLE_TYPE_RX = /^\((.*)\)
|
31
|
-
((\[[0-9]*\])*)
|
32
|
-
/x
|
33
|
-
|
34
|
-
def self.parse( type )
|
35
|
-
if type =~ TUPLE_TYPE_RX
|
36
|
-
types = $1
|
37
|
-
dims = $2.scan( /\[[0-9]*\]/ )
|
38
|
-
dims = dims.map {|x| x[1...-1].to_i}
|
39
|
-
return Tuple._parse( types, dims )
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
base, sub, dims = _parse_base_type( type )
|
44
|
-
|
45
|
-
case base
|
46
|
-
when 'bytes', 'string'
|
47
|
-
raise ParseError, "Maximum 32 bytes for fixed-length string or bytes" unless sub.empty? || sub.to_i <= 32
|
48
|
-
when 'uint', 'int'
|
49
|
-
raise ParseError, "Integer type must have numerical suffix" unless sub =~ /\A[0-9]+\z/
|
50
|
-
|
51
|
-
size = sub.to_i
|
52
|
-
raise ParseError, "Integer size out of bounds" unless size >= 8 && size <= 256
|
53
|
-
raise ParseError, "Integer size must be multiple of 8" unless size % 8 == 0
|
54
|
-
when 'address'
|
55
|
-
raise ParseError, "Address cannot have suffix" unless sub.empty?
|
56
|
-
when 'bool'
|
57
|
-
raise ParseError, "Bool cannot have suffix" unless sub.empty?
|
58
|
-
else
|
59
|
-
puts " type: >#{type}<"
|
60
|
-
raise ParseError, "Unrecognized type base: #{base}"
|
61
|
-
end
|
62
|
-
|
63
|
-
new( base, sub, dims )
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
def self.size_type
|
68
|
-
@size_type ||= new( 'uint', '256' )
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
attr :base, :sub, :dims
|
73
|
-
|
74
|
-
##
|
75
|
-
# @param base [String] base name of type, e.g. uint for uint256[4]
|
76
|
-
# @param sub [String] subscript of type, e.g. 256 for uint256[4]
|
77
|
-
# @param dims [Array[Integer]] dimensions of array type, e.g. [1,2,0]
|
78
|
-
# for uint256[1][2][], [] for non-array type
|
79
|
-
#
|
80
|
-
def initialize( base, sub, dims=[] )
|
81
|
-
@base = base
|
82
|
-
@sub = sub
|
83
|
-
@dims = dims
|
84
|
-
end
|
85
|
-
|
86
|
-
def ==(another_type)
|
87
|
-
@base == another_type.base &&
|
88
|
-
@sub == another_type.sub &&
|
89
|
-
@dims == another_type.dims
|
90
|
-
end
|
91
|
-
|
92
|
-
##
|
93
|
-
# Get the static size of a type, or nil if dynamic.
|
94
|
-
#
|
95
|
-
# @return [Integer, NilClass] size of static type, or nil for dynamic type
|
96
|
-
#
|
97
|
-
def size
|
98
|
-
@size ||= calculate_size
|
99
|
-
end
|
100
|
-
|
101
|
-
def calculate_size
|
102
|
-
if @dims.empty?
|
103
|
-
if ['string','bytes'].include?( @base ) && @sub.empty?
|
104
|
-
nil
|
105
|
-
else
|
106
|
-
32
|
107
|
-
end
|
108
|
-
else
|
109
|
-
if @dims.last == 0 # note: 0 used for dynamic array []
|
110
|
-
nil
|
111
|
-
else
|
112
|
-
subtype.dynamic? ? nil : @dims.last * subtype.size
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def dynamic?() size.nil?; end
|
118
|
-
|
119
|
-
|
120
|
-
##
|
121
|
-
# Type with one dimension lesser.
|
122
|
-
#
|
123
|
-
# @example
|
124
|
-
# Type.parse("uint256[2][]").subtype # => Type.new('uint', '256', [2])
|
125
|
-
#
|
126
|
-
# @return [ABI::Type]
|
127
|
-
#
|
128
|
-
def subtype
|
129
|
-
@subtype ||= Type.new( @base, @sub, @dims[0...-1] )
|
130
|
-
end
|
131
|
-
|
132
|
-
|
133
|
-
def format
|
134
|
-
## rebuild minimal type string
|
135
|
-
buf = "#{@base}"
|
136
|
-
buf << @sub unless @sub.empty?
|
137
|
-
buf << (@dims.map {|dim| dim==0 ? '[]' : "[#{dim}]"}.join) unless @dims.empty?
|
138
|
-
buf
|
139
|
-
end
|
140
|
-
end # class Type
|
141
|
-
end # module ABI
|
data/lib/abicoder/type_tuple.rb
DELETED
@@ -1,106 +0,0 @@
|
|
1
|
-
module ABI
|
2
|
-
|
3
|
-
|
4
|
-
class Tuple < Type
|
5
|
-
|
6
|
-
def self._parse_tuple_type( str )
|
7
|
-
## note: types assumes string WITHOUT enclosing () e.g.
|
8
|
-
## tuple(string,string,bool) => expected as "string,string,bool"
|
9
|
-
|
10
|
-
depth = 0
|
11
|
-
collected = []
|
12
|
-
current = ''
|
13
|
-
|
14
|
-
### todo/fix: replace with a simple parser!!!
|
15
|
-
## allow () and move verbose tuple() too!!!
|
16
|
-
str.each_char do |c|
|
17
|
-
case c
|
18
|
-
when ',' then
|
19
|
-
if depth == 0
|
20
|
-
collected << current
|
21
|
-
current = ''
|
22
|
-
else
|
23
|
-
current += c
|
24
|
-
end
|
25
|
-
when '(' then
|
26
|
-
depth += 1
|
27
|
-
current += c
|
28
|
-
when ')' then
|
29
|
-
depth -= 1
|
30
|
-
current += c
|
31
|
-
else
|
32
|
-
current += c
|
33
|
-
end
|
34
|
-
end
|
35
|
-
collected << current unless current.empty?
|
36
|
-
|
37
|
-
collected
|
38
|
-
end
|
39
|
-
|
40
|
-
|
41
|
-
## note: use Type.parse NOT Tuple._parse
|
42
|
-
## to parse Tuple!!!
|
43
|
-
def self._parse( tuple, dims=[] )
|
44
|
-
## puts " enter Tuple.parse( types: >#{tuple.inspect}<, dims: >#{dims.inspect}< )"
|
45
|
-
|
46
|
-
# e.g.
|
47
|
-
#=> enter Tuple.parse( types: >"string,string,bool"<, dims: >[]< )
|
48
|
-
types = _parse_tuple_type( tuple )
|
49
|
-
parsed_types = types.map{ |t| Type.parse( t ) }
|
50
|
-
|
51
|
-
Tuple.new( parsed_types, dims )
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
attr_reader :types
|
57
|
-
|
58
|
-
def initialize( types, dims=[] )
|
59
|
-
super( 'tuple', '', dims )
|
60
|
-
@types = types
|
61
|
-
|
62
|
-
## puts "tuple:"
|
63
|
-
## pp self
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
def ==(another_type)
|
68
|
-
another_type.kind_of?(Tuple) &&
|
69
|
-
@types == another_type.types &&
|
70
|
-
@dims == another_type.dims
|
71
|
-
end
|
72
|
-
|
73
|
-
def size
|
74
|
-
@size ||= calculate_size
|
75
|
-
end
|
76
|
-
|
77
|
-
def calculate_size
|
78
|
-
if @dims.empty?
|
79
|
-
s = 0
|
80
|
-
@types.each do |type|
|
81
|
-
ts = type.size
|
82
|
-
return nil if ts.nil?
|
83
|
-
s += ts
|
84
|
-
end
|
85
|
-
s
|
86
|
-
else
|
87
|
-
if @dims.last == 0 # note: 0 used for dynamic array []
|
88
|
-
nil
|
89
|
-
else
|
90
|
-
subtype.dynamic? ? nil : @dims.last * subtype.size
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def subtype
|
96
|
-
@subtype ||= Tuple.new( types, dims[0...-1] )
|
97
|
-
end
|
98
|
-
|
99
|
-
def format
|
100
|
-
## rebuild minimal string
|
101
|
-
buf = "(#{@types.map {|t| t.format }.join(',')})"
|
102
|
-
end
|
103
|
-
|
104
|
-
|
105
|
-
end # class Tuple
|
106
|
-
end ## module ABI
|