求助:修复Web3.py中通过ABI解码以太坊交易输入的函数
修复以太坊交易输入解码函数
问题说明
我已确认获取的ABI与Etherscan上的一致,也正确拿到了transaction[input].hex()返回的待解码输入十六进制数据。现在需要修复自己编写的Python函数,实现本地用Web3.py库解码以太坊交易输入的功能,但当前函数匹配不到对应函数签名,无法完成解码。以下是待修复的函数代码、当前输出及ABI,请求帮助完成解码以提取交易数据。
待修复的函数代码
def decode(input_data, abi): print("Decoding input data: ", input_data) print("Using ABI: ", abi) input_bytes = bytes.fromhex(input_data[2:]) # 转换为bytes,跳过'0x'前缀 for item in abi: if item['type'] == 'function': signature = item['name'] + '(' for i in range(len(item['inputs'])): signature += item['inputs'][i]['type'] if i != len(item['inputs']) - 1: signature += ',' signature += ')' signature_hash = Web3.keccak(text=signature).hex() # 移除'0x'前缀后转换为bytes signature_bytes = bytes.fromhex(signature_hash[2:]) # 无法通过以下判断 # print("Signature Bytes: ", signature_bytes) # print("Input Bytes: ", input_bytes) if input_bytes.startswith(signature_bytes): print(f"Function: {item['name']}") print(f"Inputs: {item['inputs']}") print(f"Outputs: {item['outputs']}") print(f"Method ID: {signature_hash[:10]}") print(f"Input Data: {input_data}") break
当前输出
Decoding input data: 0x845d76f7000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020243aff03840e7bf14bd53b7c18015018be4b3c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 Using ABI: [{'inputs': [], 'stateMutability': 'payable', 'type': 'constructor'}, {'anonymous': False, 'inputs': [{'indexed': True, 'internalType': 'address', 'name': 'owner', 'type': 'address'}, {'indexed': True, 'internalType': 'address', 'name': 'spender', 'type': 'address'}, {'indexed': False, 'internalType': 'uint256', 'name': 'value', 'type': 'uint256'}], 'name': 'Approval', 'type': 'event'}, {'anonymous': False, 'inputs': [{'indexed': False, 'internalType': 'uint256', 'name': '_maxTxAmount', 'type': 'uint256'}], 'name': 'MaxTxAmountUpdated', 'type': 'event'}, {'anonymous': False, 'inputs': [{'indexed': True, 'internalType': 'address', 'name': 'previousOwner', 'type': 'address'}, {'indexed': True, 'internalType': 'address', 'name': 'newOwner', 'type': 'address'}], 'name': 'OwnershipTransferred', 'type': 'event'}, {'anonymous': False, 'inputs': [{'indexed': True, 'internalType': 'address', 'name': 'from', 'type': 'address'}, {'indexed': True, 'internalType': 'address', 'name': 'to', 'type': 'address'}, {'indexed': False, 'internalType': 'uint256', 'name': 'value', 'type': 'uint256'}], 'name': 'Transfer', 'type': 'event'}, {'inputs': [], 'name': '_maxTaxSwap', 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [], 'name': '_maxTxAmount', 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [], 'name': '_maxWalletSize', 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [], 'name': '_taxSwapThreshold', 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'internalType': 'address[]', 'name': 'bots_', 'type': 'address[]'}], 'name': 'addBots', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [{'internalType': 'address', 'name': 'owner', 'type': 'address'}, {'internalType': 'address', 'name': 'spender', 'type': 'address'}], 'name': 'allowance', 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'internalType': 'address', 'name': 'spender', 'type': 'address'}, {'internalType': 'uint256', 'name': 'amount', 'type': 'uint256'}], 'name': 'approve', 'outputs': [{'internalType': 'bool', 'name': '', 'type': 'bool'}], 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [{'internalType': 'address', 'name': 'account', 'type': 'address'}], 'name': 'balanceOf', 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [], 'name': 'decimals', 'outputs': [{'internalType': 'uint8', 'name': '', 'type': 'uint8'}], 'stateMutability': 'pure', 'type': 'function'}, {'inputs': [{'internalType': 'address[]', 'name': 'notbot', 'type': 'address[]'}], 'name': 'delBots', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [{'internalType': 'address', 'name': 'a', 'type': 'address'}], 'name': 'isBot', 'outputs': [{'internalType': 'bool', 'name': '', 'type': 'bool'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [], 'name': 'manualSwap', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'name': 'manualsend', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'name': 'name', 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}], 'stateMutability': 'pure', 'type': 'function'}, {'inputs': [], 'name': 'openTrading', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'name': 'owner', 'outputs': [{'internalType': 'address', 'name': '', 'type': 'address'}], 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'internalType': 'uint256', 'name': '_newFee', 'type': 'uint256'}], 'name': 'reduceFee', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'name': 'removeLimits', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'name': 'renounceOwnership', 'outputs': [], 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'name': 'symbol', 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}], 'stateMutability': 'pure', 'type': 'function'}, {'inputs': [], 'name': 'totalSupply', 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}], 'stateMutability': 'pure', 'type': 'function'}, {'inputs': [{'internalType': 'address', 'name': 'recipient', 'type': 'address'}, {'internalType': 'uint256', 'name': 'amount', 'type': 'uint256'}], 'name': 'transfer', 'outputs': [{'internalType': 'bool', 'name': '', 'type': 'bool'}], 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [{'internalType': 'address', 'name': 'sender', 'type': 'address'}, {'internalType': 'address', 'name': 'recipient', 'type': 'address'}, {'internalType': 'uint256', 'name': 'amount', 'type': 'uint256'}], 'name': 'transferFrom', 'outputs': [{'internalType': 'bool', 'name': '', 'type': 'bool'}], 'stateMutability': 'nonpayable', 'type': 'function'}, {'stateMutability': 'payable', 'type': 'receive'}]
修复方案
核心问题定位
你的输入数据方法ID是0x845d76f7,但当前提供的ABI中没有对应签名的函数,这是匹配失败的直接原因。同时原函数仅实现了签名匹配逻辑,未完成参数解码,手动拼接签名也存在出错风险。
方案1:使用Web3.py内置解码函数(推荐)
Web3.py提供了decode_function_input方法,可自动匹配函数签名并解码参数,无需手动实现复杂逻辑:
from web3 import Web3 def decode(input_data, abi): print("Decoding input data: ", input_data) print("Using ABI: ", abi) # 创建合约实例 contract = Web3().eth.contract(abi=abi) try: # 自动匹配函数并解码输入参数 function, decoded_input = contract.decode_function_input(input_data) print(f"函数名称: {function.fn_name}") print(f"解码参数: {decoded_input}") print(f"方法ID: {input_data[:10]}") except ValueError as e: print(f"解码失败: {e}") print("提示:请确认ABI是否包含该交易调用的函数签名")
方案2:修复原函数的签名匹配与参数解码
若坚持手动实现,需确保签名拼接正确,并添加参数解码逻辑,同时需确认ABI包含目标函数:
from web3 import Web3 from eth_abi import decode def decode(input_data, abi): print("Decoding input data: ", input_data) print("Using ABI: ", abi) input_bytes = bytes.fromhex(input_data[2:]) # 提取前4字节作为方法ID method_id = input_bytes[:4] for item in abi: if item['type'] == 'function': # 生成标准函数签名字符串 input_types = [inp['type'] for inp in item['inputs']] signature = f"{item['name']}({','.join(input_types)})" # 计算签名哈希并取前4字节匹配 signature_hash = Web3.keccak(text=signature) if signature_hash[:4] == method_id: print(f"函数名称: {item['name']}") print(f"输入参数定义: {item['inputs']}") print(f"方法ID: {Web3.to_hex(method_id)}") # 解码参数(跳过前4字节的方法ID) param_bytes = input_bytes[4:] try: decoded_params = decode(input_types, param_bytes) # 将参数与名称对应输出 param_dict = {inp['name']: val for inp, val in zip(item['inputs'], decoded_params)} print(f"解码后的参数: {param_dict}") except Exception as e: print(f"参数解码失败: {e}") break else: print("未找到匹配的函数签名,请确认ABI是否完整")
关键提示
你当前的输入数据对应的函数签名不在提供的ABI中,需重新从Etherscan获取完整ABI(可通过方法ID0x845d76f7反向查询,该ID对应的函数大概率是批量转账类函数,比如transferBatch(address[],uint256[]))。
内容的提问来源于stack exchange,提问作者xampL
相关产品推荐
相关产品推荐

