12
12
from ethereum import utils
13
13
from ethereum .utils import (
14
14
big_endian_to_int , ceil32 , int_to_big_endian , encode_int , is_numeric , is_string ,
15
- rzpad , TT255 , TT256 , zpad ,
15
+ rzpad , zpad , str_to_bytes
16
16
)
17
+ from ethereum .utils import TT256 , TT255
17
18
18
19
# The number of bytes is encoded as a uint256
19
20
# Type used to encode a string/bytes length
@@ -259,7 +260,7 @@ def encode_single(typ, arg): # pylint: disable=too-many-return-statements,too-m
259
260
if not - 2 ** bits <= i < 2 ** bits :
260
261
raise ValueOutOfBounds (repr (arg ))
261
262
262
- value = i % 2 ** sub # convert negative to "equivalent" positive
263
+ value = i % 2 ** 256 # convert negative to "equivalent" positive
263
264
value_encoded = int_to_big_endian (value )
264
265
return zpad (value_encoded , 32 )
265
266
@@ -309,6 +310,11 @@ def encode_single(typ, arg): # pylint: disable=too-many-return-statements,too-m
309
310
value = fixed_point % 2 ** 256
310
311
return zpad (int_to_big_endian (value ), 32 )
311
312
313
+ # Decimals
314
+ if base == 'decimal' :
315
+ val_to_encode = int (arg * 10 ** int (sub ))
316
+ return zpad (encode_int (val_to_encode % 2 ** 256 ), 32 )
317
+
312
318
if base == 'string' :
313
319
if isinstance (arg , utils .unicode ):
314
320
arg = arg .encode ('utf8' )
@@ -412,24 +418,25 @@ def __init__(self, contract_interface):
412
418
if entry_type != 'fallback' and 'inputs' in description :
413
419
encode_types = [
414
420
element ['type' ]
415
- for element in description .get ('inputs' )
421
+ for element in description .get ('inputs' , [] )
416
422
]
417
423
418
424
signature = [
419
425
(element ['type' ], element ['name' ])
420
- for element in description .get ('inputs' )
426
+ for element in description .get ('inputs' , [] )
421
427
]
422
428
423
429
if entry_type == 'function' :
424
430
normalized_name = normalize_name (description ['name' ])
431
+ prefix = method_id (normalized_name , encode_types )
425
432
426
433
decode_types = [
427
434
element ['type' ]
428
- for element in description [ 'outputs' ]
435
+ for element in description . get ( 'outputs' , [])
429
436
]
430
437
431
438
self .function_data [normalized_name ] = {
432
- 'prefix' : method_id ( normalized_name , encode_types ) ,
439
+ 'prefix' : prefix ,
433
440
'encode_types' : encode_types ,
434
441
'decode_types' : decode_types ,
435
442
'is_constant' : description .get ('constant' , False ),
@@ -724,7 +731,7 @@ def encode_abi(types, args):
724
731
def decode_single (typ , data ):
725
732
base , sub , _ = typ
726
733
if base == 'address' :
727
- return encode_hex (data [12 :])
734
+ return '0x' + encode_hex (data [12 :])
728
735
elif base == 'hash' :
729
736
return data [32 - int (sub ):]
730
737
elif base == 'string' or base == 'bytes' :
@@ -746,8 +753,14 @@ def decode_single(typ, data):
746
753
o = big_endian_to_int (data )
747
754
i = (o - 2 ** (high + low )) if o >= 2 ** (high + low - 1 ) else o
748
755
return (i * 1.0 // 2 ** low )
756
+ elif base == 'decimal' :
757
+ o = big_endian_to_int (data )
758
+ i = (o - 2 ** 256 if o > 2 ** 255 else o )
759
+ return i / 10 ** int (sub )
749
760
elif base == 'bool' :
750
761
return bool (int (encode_hex (data ), 16 ))
762
+ else :
763
+ raise EncodingError ("Unhandled type: %r %r" % (base , sub ))
751
764
752
765
753
766
# Decodes multiple arguments using the head/tail mechanism
@@ -799,7 +812,7 @@ def dec(typ, arg):
799
812
# Dynamic-sized strings are encoded as <len(str)> + <str>
800
813
if base in ('string' , 'bytes' ) and not sub :
801
814
L = big_endian_to_int (arg [:32 ])
802
- assert len (arg [32 :]) == ceil32 (L ), "Wrong data size for string/bytes object"
815
+ assert len (arg [32 :]) == ceil32 (L ), "Wrong data size for string/bytes object: expected %d actual %d" % ( ceil32 ( L ), len ( arg [ 32 :]))
803
816
return arg [32 :][:L ]
804
817
# Dynamic-sized arrays
805
818
elif sz is None :
0 commit comments