【问题标题】:decoding uniswap event data in python with ABI?使用 ABI 在 python 中解码 uniswap 事件数据?
【发布时间】:2022-11-10 06:24:16
【问题描述】:

两天前我开始使用以太坊区块链,所以我的知识仍然有点泛滥。尽管如此,我还是设法连接到一个节点,提取一些通用块数据等等。作为下一个难度级别,我尝试开始构建事件过滤器,以便查看更具体类型的历史数据(明确地说,我不想获取实时数据,我宁愿查询整个链,并获取各种类型数据的历史样本提取)。

请参阅此处我第一次尝试为 USDC Uniswap V2 合约构建事件过滤器,以收集交换事件(现在与速度或效率无关,只是为了使其工作):

w3 = Web3(Web3.HTTPProvider(NODE_ADDRESS))

# uniswap v2 USDC
address = w3.toChecksumAddress('0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc')

# get the ABI for uniswap v2 pair events
resp = requests.get("https://unpkg.com/@uniswap/v2-core@1.0.0/build/IUniswapV2Pair.json")
if resp.status_code==200: 
    abi = json.loads(resp.content)['abi']

# create contract object
contract = w3.eth.contract(address=address, abi=abi)

# get topics by hashing abi event signatures
res = contract.events.Swap.build_filter()

# put this into a filter input dictionary
filter_params = {'fromBlock':int_to_hex(12000000),'toBlock':int_to_hex(12010000),**res.filter_params}
# res.filter_params contains: 'topics' and 'address'

# create a filter id (i.e. a hashed version of the filter data, representing the filter)
method = 'eth_newFilter'
params = [filter_params]
resp = self.block_manager.general_sample_request(method,params)
if 'error' in resp: 
    print(resp)
else: 
    filter_id = resp['result']

# pass on the filter id, in order to query the respective logs
params = [filter_id]
method = 'eth_getFilterLogs'
resp = self.block_manager.general_sample_request(method,params)
# takes about 10-12s for about 12000 events

结果数组包含此结构的事件日志:

resp['result'][0]
>>>
{'address': '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc',
 'topics': ['0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822',
  '0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d',
  '0x0000000000000000000000000ffd670749d4179558b6b367e30e72ce2efea28f'],
 'data': '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
00000000000000000000000000034f0f8a0c7663264000000000000000000000000000000000000000000000\
000000000019002d5b60000000000000000000000000000000000000000000000000000000000000000',
 'blockNumber': '0xb71b01',
 'transactionHash': '0x76403053ee0300411b68fc223b327b51fb4f1a26e1f6cb8667e05ec370e8176e',
 'transactionIndex': '0x22',
 'blockHash': '0x4bd35cb48395e77fd317a0309342c95d6687dbc4fcb85ada2d635fe266d1e769',
 'logIndex': '0x16',
 'removed': False}

据我现在了解,我可以以某种方式应用 ABI 来解码“数据”字段。 我试过这个功能:

contract.decode_function_input(resp['result'][0]['data'])

但它给了我这个错误:

>>> ValueError: Could not find any function with matching selector

似乎解码数据存在一些问题。但是,我现在离获得真实数据如此接近,我不想放弃 xD。任何帮助将不胜感激!

谢谢!

【问题讨论】:

    标签: python events ethereum web3py uniswap


    【解决方案1】:

    我认为问题在于您试图将数据解码为函数输入,但它实际上是一个事件输出。函数输入是调用函数时发送给合约的数据,而事件输出是触发事件时合约发出的数据。它们有不同的格式和选择器,因此您需要使用不同的方法来解码它们。

    要解码事件输出,您可以使用contract.events.Swap().processLog() 方法,该方法将日志字典作为参数并返回一个带有事件名称和解码参数的命名元组。例如:

    # get the first log from the response
    log = resp['result'][0]
    
    # decode the log using the contract event
    decoded = contract.events.Swap().processLog(log)
    
    # print the event name and arguments
    print(decoded.event)
    print(decoded.args)
    

    这应该输出如下内容:

    Swap
    AttributeDict({'sender': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', 'amount0In': 0, 'amount1In': 2200000000000000000, 'amount0Out': 1340087663264, 'amount1Out': 0, 'to': '0x0FfD670749D4179558B6B367E30E72cE2eFEa28F'})
    

    可以看到事件名称为 Swap,参数分别为 sender、amount0In、amount1In、amount0Out、amount1Out 和 to。这些对应于 ABI 中的事件签名:

    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "internalType": "address",
                "name": "sender",
                "type": "address"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount0In",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount1In",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount0Out",
                "type": "uint256"
            },
            {
                "indexed": false,
                "internalType": "uint256",
                "name": "amount1Out",
                "type": "uint256"
            },
            {
                "indexed": true,
                "internalType": "address",
                "name": "to",
                "type": "address"
            }
        ],
        "name": "Swap",
        "type": "event"
    }
    

    您可以使用点表示法访问各个参数,例如:

    # get the sender address
    sender = decoded.args.sender
    
    # get the amount of token0 swapped in
    amount0In = decoded.args.amount0In
    

    【讨论】:

      猜你喜欢
      • 2023-01-05
      • 2020-10-04
      • 2018-09-25
      • 2016-06-24
      • 2011-01-12
      • 2019-06-06
      • 2022-09-28
      • 2014-10-22
      • 1970-01-01
      相关资源
      最近更新 更多