Web3py:解码后找不到ABI函数

问题描述 投票:0回答:1

这是交易https://etherscan.io/tx/0x6465187a7bb43a6db42ee63e5f5cc30fb094393957a7f1ce6c08b5afddf3e0bc

我不知道为什么我的脚本在

Chainlink: LINK Token
地址上解码后找不到 ABI Transfer() 函数。主要问题是脚本工作正常,我测试了许多交易并附加了其中的 2 个交易。

也许问题出在解码后的 Transfer() 输入参数中?但如何解决呢?

import requests
import json
from web3 import Web3
from web3._utils.events import get_event_data
from eth_utils import event_abi_to_log_topic
from hexbytes import HexBytes


API_ETHERSCAN = "" # etherscan works without API, you can remove it from url, but make some seconds delay between requests

transactions = [
    '0xff8db775b90935b1ade58182054c0be04f613ea23f9e1df73a6114a726e76237', # Transfer +95352033474036727055914 RIO
    '0x7bdfe6c2a9309773ddeafddc2624edc2b38f13ec257182576d95d8b5f5ea2cd1', # Transfer +29000000000000000000 INJ
    '0x6465187a7bb43a6db42ee63e5f5cc30fb094393957a7f1ce6c08b5afddf3e0bc', # ABI not found. But must be +7,601.747 LINK
]

testnet = 'https://eth.rpc.blxrbdn.com'
#testnet = 'https://eth.merkle.io'

w3 = Web3(Web3.HTTPProvider(testnet))
for t_hash in transactions:

    print(f"tx_hash={t_hash}")
    tx_receipt = w3.eth.get_transaction_receipt(t_hash)

    for i, log in enumerate(tx_receipt['logs']):
        print(f" {i+1}) log['address']={log['address']}")
        abi = json.loads(json.loads(requests.get(f"https://api.etherscan.io/api?module=contract&action=getabi&address={log['address']}&apikey={API_ETHERSCAN}").text)['result'])
        contract = w3.eth.contract(log["address"], abi=abi)

        event_abi = [a for a in contract.abi if a["type"] == "event"]
        topic2abi = {event_abi_to_log_topic(_): _ for _ in event_abi}
        log_ = {
            'address': None, #Web3.toChecksumAddress(address),
            'blockHash': None, #HexBytes(blockHash),
            'blockNumber': None,
            'data': log['data'], 
            'logIndex': None,
            'topics': [HexBytes(_) for _ in log["topics"]],
            'transactionHash': None, #HexBytes(transactionHash),
            'transactionIndex': None
        }
        try:
            event_abi = topic2abi[log['topics'][0]]
        except KeyError as e:
            exit('ABI event not found!')
        data = get_event_data(w3.codec, event_abi, log_)['args']
        print(f"     {event_abi['name']} {data['value'] if 'value' in data else ''}")

输出:

tx_hash=0xff8db775b90935b1ade58182054c0be04f613ea23f9e1df73a6114a726e76237
 1) log['address']=0xf21661D0D1d76d3ECb8e1B9F1c923DBfffAe4097
     Transfer 95352033474036727055914
tx_hash=0x7bdfe6c2a9309773ddeafddc2624edc2b38f13ec257182576d95d8b5f5ea2cd1
 1) log['address']=0xe28b3B32B6c345A34Ff64674606124Dd5Aceca30
     Transfer 29000000000000000000
tx_hash=0x6465187a7bb43a6db42ee63e5f5cc30fb094393957a7f1ce6c08b5afddf3e0bc
 1) log['address']=0x514910771AF9Ca656af840dff83E8264EcF986CA
ABI event not found!
python ethereum solidity smartcontracts web3py
1个回答
0
投票

我添加这一行是为了检查

event_abi

的结构
print("event_abi['name']",event_abi)

我得到了这些结果:

 {'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'}

 {'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'}


 [{'anonymous': False, 'inputs': [{'indexed': True, 'name': 'from', 'type': 'address'}, {'indexed': True, 'name': 'to', 'type': 'address'}, {'indexed': False, 'name': 'value', 'type': 'uint256'}, {'indexed': False, 'name': 'data', 'type': 'bytes'}], 'name': 'Transfer', 'type': 'event'}, {'anonymous': False, 'inputs': [{'indexed': True, 'name': 'owner', 'type': 'address'}, {'indexed': True, 'name': 'spender', 'type': 'address'}, {'indexed': False, 'name': 'value', 'type': 'uint256'}], 'name': 'Approval', 'type': 'event'}]

前 2 个结果是

dict
,但第三个结果是
list
。我第一次收到这个错误:

---> 69 print(f"     {event_abi['name']} {data['value'] if 'value' in data else ''}")

TypeError: list indices must be integers or slices, not str

因为

event_abi
可以是字典,也可以是字典列表。为了处理这种变化,我必须根据 event_abi 的类型调整访问“name”键的方式。所以我添加了这个

try:
    event_abi_entry = topic2abi[log['topics'][0]]
    if isinstance(event_abi_entry, dict):
        event_name = event_abi_entry.get('name', 'DefaultNmae')
        data = get_event_data(w3.codec, event_abi_entry, log_)['args']
        print(f"     {event_name} {data.get('value', '')}")
    elif isinstance(event_abi_entry, list):
        for abi_entry in event_abi_entry:
            event_name = abi_entry.get('name', 'DefaultName')
            data = get_event_data(w3.codec, abi_entry, log_)['args']
            print(f"     {event_name} {data.get('value', '')}")
    else:
        print("Event ABI entry is not in the expected format.")
except KeyError as e:
    exit('ABI event not found!')

并且它不会抛出 KeyError。工作证明:

© www.soinside.com 2019 - 2024. All rights reserved.