【问题标题】:Filter web3.eth.getTransactionCount() based on transaction type根据交易类型过滤 web3.eth.getTransactionCount()
【发布时间】:2022-01-14 14:56:44
【问题描述】:

我正在使用这行代码来获取特定合约下的所有交易计数。

web3.eth.getTransactionCount("//contract address").then(console.log);

但我只想计算完成 NFT 铸造的交易。

因此,正如您在屏幕截图中看到的那样,有六个事务,getTransactionCount() 将返回六个。但我只想计算那些具有“Mint NFT”方法的交易。那么,有没有办法做到这一点?

【问题讨论】:

    标签: javascript blockchain web3 web3js


    【解决方案1】:

    web3 getTransactionCount() 函数 (docs) 是 eth_getTransactionCount JSON-RPC 方法 (docs) 的包装器,返回 指定地址发送的已挖掘交易数量。

    由于您的代码指定了“合约地址”,我假设您希望返回对合约地址执行指定操作的交易量 - 由任何调用者。

    请注意,截图中“方法”列中的“Mint NFT”仅代表执行的函数名称。这并不意味着实际上已经开采了 NFT。所以理论上你可以有一个名为mintNFT()的函数来执行一个完全不同的动作:

    function mintNFT() external {
        // does not mint any NFT
        counter++;
    }
    

    另外——这对于下一段很重要——一个合约可以包含多个同名的函数,这些函数会导致不同的函数选择器,因为它们具有不同的参数数据类型。

    // all of these can be in the same contract
    mintNFT(address to) // selector `0x54ba0f27`
    mintNFT(address to, uint256 ID) // selector `0x3c168eab`
    mintNFT(uint256 ID) // selector `0x92642744`
    

    因此,如果您想通过调用的函数进行过滤,您需要知道(或计算)其特定的选择器 - 而不仅仅是函数名称。它是函数名称的 keccak-256 散列的前 4 个字节(8 个十六进制字符),后面是用逗号分隔的参数数据类型,用括号括起来。示例:

    // keccak-256 hash of this string, first 4 bytes
    // and you get the `0x3c168eab` selector mentioned earlier
    mintNFT(address,uint256)
    

    最后,没有本地方式(在以太坊 JSON-RPC API 中,一些其他区块链,如 Polygon 或 BSC 也实现)来获取地址发送或接收的交易列表。由于 web3 是 JSON-RPC API 的包装库(另外它包含一些相关的帮助程序和实用函数),因此无法使用 web3 来实现此结果。

    因此,您需要将所有现有交易(至少在您感兴趣的区块范围内)收集到可搜索的数据库中。或者 - 使用已经存在的可搜索集合。

    出于此答案的目的,我将使用PolygonScan API,它可以免费用于有限使用,因为您的问题表明目标合同在 Polygon 上。而this contract 实现了两个具有相同名称(mint())但函数选择器不同的函数。让我们使用 2003 行中定义的后一个函数:

    function mint(
        address to,
        uint32 batch,
        uint32 sequence,
        uint32 limit,
        string memory name,
        string memory page,
        string memory description,
        string memory link,
        string memory content,
        string memory created
    )
    

    选择器是根据下面的字符串计算出来的

    mint(address,uint32,uint32,uint32,string,string,string,string,string,string)
    

    其值为0xab2a6d77

    那么这个过程就很简单了。一旦获得合约地址的所有交易列表,您只需通过选择的函数选择器过滤它们,该选择器始终是原始交易的data 字段的前 4 个字节(命名为input 在 API 中)。

    请注意,可以向data 字段(通常为 0)中少于 4 个字节的合约发送交易,因此您的代码也应考虑到这一点。

    const axios = require("axios");
    
    const API_KEY = "YourApiKeyToken";
    
    const CONTRACT_ADDRESS = "0x90410A6bc2285dF5A726b0b89D8bE60C9B6fA26E";
    const SELECTOR = "0xab2a6d77";
    
    const run = async () => {
        const allTransactions = await _getAllTransactionsTo(CONTRACT_ADDRESS);
        const filteredTransactions = _filterTransactionsBySelector(allTransactions, SELECTOR);
        const txHashes = _getTransactionHashes(filteredTransactions);
        console.log(txHashes);
    }
    
    const _getAllTransactionsTo = async (address) => {
        const response = await axios(
            "https://api.polygonscan.com/api"
            + "?module=account"
            + "&action=txlist"
            + "&address=" + address
            + "&startblock=0"
            + "&endblock=99999999"
            + "&page=1"
            + "&offset=10"
            + "&sort=asc"
            + "&apikey=" + API_KEY
        );
    
        // the API returns transaction both `from` and `to` the address
        // this filter is unnecessary for contract addresses (as there are no transactions `from` a contract)
        return response.data.result.filter((item) => {
            // mind that the API might return the params in lowercase, while your input address might be checksum
            return item.to.toLowerCase() === address.toLowerCase();
        });
    }
    
    const _filterTransactionsBySelector = (allTransactions, selector) => {
        return allTransactions.filter((item) => {
            return item?.input.startsWith(selector);
        });
    }
    
    const _getTransactionHashes = (transactions) => {
        return transactions.map((item) => {
            return item.hash;
        });
    }
    
    run();
    

    它打印调用指定mint() 函数的事务的哈希值(只是选择器指定的这个 - 而不是另一个)。

    [
      '0xd6a141780585e0833382cfa5940db4bd1b2acde8108c949421242077d6a5d16d',
      '0x63bfaae7afbd50f1ee052182aeee7147ba256c6285bc2783f8607a881dbf135f',
      '0x57cd8c74c13aded28841f14a79b1901a5e12a87aae38ea4f8af19a7ef976e281',
      '0x8dbbb9f7fa11ec0c025d1cec2ac75862a89dc10fe69d4599f2401db2a089c0c9',
      '0x34fa6285fbf63313127422be8b84214906642a2399b971e863b0b7950bd57ca4',
      '0x4fcab773f03ed5f12b85c2329e14226b5afb4120e9227e8da423bd7d88fb06ed',
      '0x67d540059dcf9d6c6a63e03f8882fe1522897d09c03f9185c540c807cf1972b8'
    ]
    

    【讨论】:

    • 有没有办法直接得到总数?因为此 API 的总交易数限制为 10000。
    • @Kundan 如答案中所述,无法直接获取此事务计数-这就是我们在脚本中进行此计算的原因。如果您需要更大的范围,您可以找到另一个允许请求更大范围的第三方数据提供者,或者您可以运行自己的 Polygon 节点,将 RPC-API 发布到您的应用程序,没有任何限制。
    猜你喜欢
    • 2022-01-04
    • 2020-11-19
    • 2021-05-29
    • 2021-10-22
    • 2019-12-05
    • 2021-10-07
    • 2023-01-19
    • 2021-10-02
    • 2018-07-22
    相关资源
    最近更新 更多