def encode_calldata(func_name, arg_types, args): """ :param func_name: :param arg_types: :param args: :return: """ mid = method_id(func_name, arg_types) function_selector = zpad(encode_int(mid), 4) args = encode_abi(arg_types, args) return "0x" + function_selector.hex() + args.hex()
def _get_method_abi(cls, method): m_as = inspect.getargspec(method) arg_names = list(m_as.args)[1:] if 'returns' not in arg_names: # indicates, this is an abi method return None arg_types = list(m_as.defaults) assert len(arg_names) == len(arg_types) == len(set(arg_names)) assert arg_names.pop() == 'returns' # must be last element return_types = arg_types.pop() # can be list or multiple name = method.__func__.func_name m_id = abi.method_id(name, arg_types) return dict(id=m_id, arg_types=arg_types, arg_names=arg_names, return_types=return_types, name=name, method=method)
def test_function_selector(): # https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#function-selector-and-argument-encoding baz_selector = big_endian_to_int(decode_hex('CDCD77C0')) bar_selector = big_endian_to_int(decode_hex('AB55044D')) sam_selector = big_endian_to_int(decode_hex('A5643BF2')) f_selector = big_endian_to_int(decode_hex('8BE65246')) assert big_endian_to_int(sha3('baz(uint32,bool)')[:4]) == baz_selector assert big_endian_to_int(sha3('bar(fixed128x128[2])')[:4]) == bar_selector assert big_endian_to_int( sha3('sam(bytes,bool,uint256[])')[:4]) == sam_selector assert big_endian_to_int( sha3('f(uint256,uint32[],bytes10,bytes)')[:4]) == f_selector assert method_id('baz', ['uint32', 'bool']) == baz_selector assert method_id('bar', ['fixed128x128[2]']) == bar_selector assert method_id('sam', ['bytes', 'bool', 'uint256[]']) == sam_selector assert method_id('f', ['uint256', 'uint32[]', 'bytes10', 'bytes']) == f_selector assert method_id('bar', ['fixed[2]']) == bar_selector assert method_id('sam', ['bytes', 'bool', 'uint[]']) == sam_selector assert method_id('f', ['uint', 'uint32[]', 'bytes10', 'bytes']) == f_selector
def encode_calldata(func_name, arg_types, args): mid = method_id(func_name, arg_types) function_selector = zpad(encode_int(mid), 4) args = encode_abi(arg_types, args) return "0x" + function_selector + args
def method_id(method_name, method_params): return abi.method_id(method_name, method_params)
def __init__(self, contract_interface): if isinstance(contract_interface, str): contract_interface = json.dumps(contract_interface) self.fallback_data = None self.constructor_data = None self.function_data = {} self.event_data = {} for description in contract_interface: entry_type = description.get('type', 'function') encode_types = [] signature = [] # If it's a function/constructor/event if entry_type != 'fallback' and 'inputs' in description: encode_types = [] signature = [] for element in description.get('inputs', []): encode_type = process_abi_type(element) encode_types.append(encode_type) signature.append((encode_type, element['name'])) if entry_type == 'function': normalized_name = normalize_name(description['name']) prefix = method_id(normalized_name, encode_types) decode_types = [] for element in description.get('outputs', []): decode_type = process_abi_type(element) decode_types.append(decode_type) # 1st is 0.6.0 way, 2nd is old is_constant = description.get('stateMutability', '') == 'view' \ or description.get('constant', False) self.function_data[normalized_name] = { 'prefix': prefix, 'encode_types': encode_types, 'decode_types': decode_types, 'is_constant': is_constant, 'signature': signature, 'payable': description.get('payable', False), } elif entry_type == 'event': normalized_name = normalize_name(description['name']) indexed = [ element['indexed'] for element in description['inputs'] ] names = [element['name'] for element in description['inputs']] # event_id == topics[0] self.event_data[event_id(normalized_name, encode_types)] = { 'types': encode_types, 'name': normalized_name, 'names': names, 'indexed': indexed, 'anonymous': description.get('anonymous', False), } elif entry_type == 'constructor': if self.constructor_data is not None: raise ValueError('Only one constructor is supported.') self.constructor_data = { 'encode_types': encode_types, 'signature': signature, } elif entry_type == 'fallback': if self.fallback_data is not None: raise ValueError( 'Only one fallback function is supported.') self.fallback_data = {'payable': description['payable']} else: raise ValueError('Unknown type {}'.format(description['type']))