使用 web3.js 从交易中获取 USDC(或任何非 ETH 值)

Posted

技术标签:

【中文标题】使用 web3.js 从交易中获取 USDC(或任何非 ETH 值)【英文标题】:Get USDC (or any non-ETH value) from transaction using web3.js 【发布时间】:2022-01-07 15:52:45 【问题描述】:

我正在一个小项目上使用 web3.js 库,该项目订阅智能合约上的事件,以便 NFT 通过 OpenSea 跟踪该项目的所有销售。这在使用 ETH 完成销售时工作正常,但是当使用 OpenSea 提供的另一种支付方式(USDC、DAI、WETH 等)进行销售时,来自 web3.js 的交易价值返回为 0 ,它在 etherscan.io 上也显示 0。以下是代表此问题的示例事务:https://etherscan.io/tx/0x17f050e3fb6d8f0bbb4d9b4e8cd477f8197a87a3a68b360a60a028d7b1037532。无论使用什么类型的货币,关于如何获得正确价值的任何想法?

web3.eth.getTransaction('0x17f050e3fb6d8f0bbb4d9b4e8cd477f8197a87a3a68b360a60a028d7b1037532').then((response) => console.log(response); );

回应


  accessList: [],
  blockHash: '0x6140d3cb5c271fb351e0a6e9e35b32cf0607ad526152f40f2d98107a97b0212b',
  blockNumber: 13545512,
  chainId: '0x1',
  from: '0x3F4D7b0Eba8CB40D94713023d9Dc02FdB0a5169C',
  gas: 391246,
  gasPrice: '157998874325',
  hash: '0x17f050e3fb6d8f0bbb4d9b4e8cd477f8197a87a3a68b360a60a028d7b1037532',
  input: '0xab834bab0000000000000000000000007be8076f4ea4a4ad08075c2508e481d6c946d12b00000000000000000000000074144fb8749f99382091118f7487f4a541be6d7700000000000000000000000000000000000000000000000000000000000000000000000000000000000000005b3256965e7c3cf26e11fcaf296dfc8807c01073000000000000000000000000bd3531da5cf5857e7cfaa92426877b022e612cf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000007be8076f4ea4a4ad08075c2508e481d6c946d12b0000000000000000000000003f4d7b0eba8cb40d94713023d9dc02fdb0a5169c00000000000000000000000074144fb8749f99382091118f7487f4a541be6d770000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd3531da5cf5857e7cfaa92426877b022e612cf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000165a0bc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000618193b7000000000000000000000000000000000000000000000000000000006182e53b690c3f82a9b6570ef2de1af15e15942c931dba8a2bd9d5012b74b213beea4da400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000165a0bc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006182d5b70000000000000000000000000000000000000000000000000000000000000000065ae400a094fafb63173dcf4c7861ca0264920136639dbe27b5956aa6282bb00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000074000000000000000000000000000000000000000000000000000000000000007e0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c08da96edfaed45809c68db44cabb487dba56fd196fe46d02d679f0161dee94293eaedf214e043bc4d2e3dd69cce82e21ead967d7f1cd8fc505c04781e2d144e308da96edfaed45809c68db44cabb487dba56fd196fe46d02d679f0161dee94293eaedf214e043bc4d2e3dd69cce82e21ead967d7f1cd8fc505c04781e2d144e35c5321ae45550685308a405827575e3d6b4a84aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000006423b872dd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000074144fb8749f99382091118f7487f4a541be6d7700000000000000000000000000000000000000000000000000000000000008ff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006423b872dd0000000000000000000000003f4d7b0eba8cb40d94713023d9dc02fdb0a5169c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006400000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
  maxFeePerGas: '201893464202',
  maxPriorityFeePerGas: '1500000000',
  nonce: 19,
  r: '0x4c8e6fbe4a49439d957e0e725f3f7e897329557a972863143ff2a34458ab190',
  s: '0x25afd4caa4cdc1f93923b5f41a89bc191d0e52c27a36e51e3015ed08560fea5d',
  to: '0x7Be8076f4EA4A4AD08075C2508e481d6C946D12b',
  transactionIndex: 328,
  type: 2,
  v: '0x1',
  value: '0'

【问题讨论】:

【参考方案1】:

您可以获得包含事件日志的交易收据。在这种情况下,您正在寻找 ERC-20 合约发出的 Transfer 事件,其中 ERC-20 代币发送者与 NFT 接收者相同。

const run = async () => 
    const receipt = await web3.eth.getTransactionReceipt('0x17f050e3fb6d8f0bbb4d9b4e8cd477f8197a87a3a68b360a60a028d7b1037532');
    const nftReceiver = _getNFTReceiver(receipt.logs);

    for (let log of receipt.logs) 
        // keccak256 of "Transfer(address,address,uint256)"
        if (log.topics[0] === '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
            // ERC20 sender (1st param of the Transfer event) is the same as the NFT receiver
            && web3.eth.abi.decodeParameter('address', log.topics[1]).toLowerCase() === nftReceiver.toLowerCase()
            // ERC-20 Transfer returns the value in `data`, while ERC-721 has the same signature but returns empty data
            && log.data !== '0x'
        ) 
            console.log('ERC-20 token contract: ', log.address);
            console.log('ERC-20 token amount (incl. decimals): ', web3.eth.abi.decodeParameter('uint256', log.data));
        
    


const _getNFTReceiver = (logs) => 
    for (let log of logs) 
        // keccak256 of "Transfer(address,address,uint256)"
        if (log.topics[0] === '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
            // ERC-20 Transfer returns the value in `data`, while ERC-721 has the same signature but returns empty data
            && log.data === '0x'
        ) 
            // 2nd parameter of the `Transfer()` event contains the NFT receiver
            return web3.eth.abi.decodeParameter('address', log.topics[2]);
        
    

    return null;


run();

打印:

Token contract:  0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Token amount (incl. decimals):  6000000000

【讨论】:

您是救生员,先生。 _getNFTReceiver () 中的硬编码地址代表什么?所有智能合约的价值都相同吗?非常感谢您的帮助! @TylerPashigian 它是字符串 Transfer(address,address,uint256) 的 keccak-256 哈希值。该字符串表示 ERC-20 和 ERC-721 代币合约在传输代币时都应该发出的事件。对于遵循这些标准的所有代币合约,其价值是相同的。 我明白了,谢谢你的解释!最后一个问题,当将令牌金额转换为正确的十进制值时,您需要获取该令牌的小数位数,我假设如果不向 api(例如 etherscan)发出单独的请求,就无法获取令牌信息获取代币符号、使用价值、小数点等? @TylerPashigian 如果代币合约遵循 ERC20 标准,它还应该实现返回小数位数的decimals() 函数,以及name()symbol() 函数以获得额外的有关令牌的信息。因此,您可以直接调用令牌合约来检索值。另一个有效的解决方案是查询 3rd 方 API(例如 Etherscan),正如您的评论所说,它通常还包括当前市场价格(不是由代币合约单独提供)和其他附加信息。 @TylerPashigian 没有 ABI,这很复杂。如果您假设合约实现了一个标准,您可以使用该标准的通用 ABI(例如 ERC-20;在 Google 上搜索“ERC-20 ABI”)。它无法访问在标准上扩展的特定合约的功能,但至少它是……否则,您可以使用反编译器从(编译的)字节码生成伪代码并从中手动构建 ABI .请参阅 Etherscan/BSCScan 地址详细信息页面上的“反编译”选项...但通常,如果没有 ABI,很难与合约进行通信。

以上是关于使用 web3.js 从交易中获取 USDC(或任何非 ETH 值)的主要内容,如果未能解决你的问题,请参考以下文章

Web3 JS 如何从区块中获取交易

如何使用 web3 js 通过地址获取令牌交易列表

如何获取在与@solana/web3.js 的交易中转移的自定义令牌数量?

以太坊如何使用web3.js或者rpc接口获取交易数据交易时间与确认数?

从 Etherscan Token Tracker 获取代币持有者数量和交易数量

Web3j:获取使用交易哈希传输的交易令牌的价值