44# See License.txt in the project root for license information.
55# --------------------------------------------------------------------
66
7+ import binascii
78import itertools
89import re
910
1011from collections import (
1112 namedtuple ,
1213)
1314
14- from eth_abi import is_encodable
15+ from eth_abi import (
16+ encoding ,
17+ decoding
18+ )
19+
20+ from eth_abi .codec import ABICodec
21+ from eth_abi .registry import (
22+ BaseEquals ,
23+ registry as default_registry ,
24+ )
25+
1526from eth_utils import to_tuple
1627
28+ from trx_utils import (
29+ decode_hex ,
30+ is_bytes ,
31+ is_text ,
32+ to_text
33+ )
34+
1735from tronapi .common .formatters import recursive_map
1836from tronapi .exceptions import FallbackNotFound
1937from tronapi .common .toolz import (
@@ -330,6 +348,72 @@ def filter_by_encodability(args, kwargs, contract_abi):
330348 if check_if_arguments_can_be_encoded (function_abi , args , kwargs )
331349 ]
332350
351+ class AcceptsHexStrMixin :
352+ def validate_value (self , value ):
353+ if is_text (value ):
354+ try :
355+ value = decode_hex (value )
356+ except binascii .Error :
357+ self .invalidate_value (
358+ value ,
359+ msg = 'invalid hex string' ,
360+ )
361+
362+ super ().validate_value (value )
363+
364+
365+ class ByteStringEncoder (AcceptsHexStrMixin , encoding .ByteStringEncoder ):
366+ pass
367+
368+
369+ class BytesEncoder (AcceptsHexStrMixin , encoding .BytesEncoder ):
370+ pass
371+
372+
373+ class TextStringEncoder (encoding .TextStringEncoder ):
374+ @classmethod
375+ def validate_value (cls , value ):
376+ if is_bytes (value ):
377+ try :
378+ value = to_text (value )
379+ except UnicodeDecodeError :
380+ cls .invalidate_value (
381+ value ,
382+ msg = 'not decodable as unicode string' ,
383+ )
384+
385+ super ().validate_value (value )
386+
387+
388+ # We make a copy here just to make sure that eth-abi's default registry is not
389+ # affected by our custom encoder subclasses
390+ registry = default_registry .copy ()
391+
392+ registry .unregister ('address' )
393+ registry .unregister ('bytes<M>' )
394+ registry .unregister ('bytes' )
395+ registry .unregister ('string' )
396+
397+ registry .register (
398+ BaseEquals ('bytes' , with_sub = True ),
399+ BytesEncoder , decoding .BytesDecoder ,
400+ label = 'bytes<M>' ,
401+ )
402+
403+ registry .register (
404+ BaseEquals ('bytes' , with_sub = False ),
405+ ByteStringEncoder , decoding .ByteStringDecoder ,
406+ label = 'bytes' ,
407+ )
408+ registry .register (
409+ BaseEquals ('string' ),
410+ TextStringEncoder , decoding .StringDecoder ,
411+ label = 'string' ,
412+ )
413+
414+ codec = ABICodec (registry )
415+ is_encodable = codec .is_encodable
416+
333417
334418def check_if_arguments_can_be_encoded (function_abi , args , kwargs ):
335419 try :
@@ -483,10 +567,10 @@ def abi_data_tree(types, data):
483567
484568@curry
485569def data_tree_map (func , data_tree ):
486- '''
570+ """
487571 Map func to every ABITypedData element in the tree. func will
488572 receive two args: abi_type, and data
489- '''
573+ """
490574
491575 def map_to_typed_data (elements ):
492576 if isinstance (elements , ABITypedData ) and elements .abi_type is not None :
@@ -498,7 +582,7 @@ def map_to_typed_data(elements):
498582
499583
500584class ABITypedData (namedtuple ('ABITypedData' , 'abi_type, data' )):
501- '''
585+ """
502586 This class marks data as having a certain ABI-type.
503587
504588 >>> a1 = ABITypedData(['address', addr1])
@@ -514,7 +598,7 @@ class ABITypedData(namedtuple('ABITypedData', 'abi_type, data')):
514598 Unlike a typical `namedtuple`, you initialize with a single
515599 positional argument that is iterable, to match the init
516600 interface of all other relevant collections.
517- '''
601+ """
518602
519603 def __new__ (cls , iterable ):
520604 return super ().__new__ (cls , * iterable )
0 commit comments