从前端订阅 Solidity 事件

Subscribing to a Solidity event from frontend

我正在尝试从前端订阅在 Solidty 中定义的 PurchaseMade 事件。我没有得到预期的结果,需要帮助解决我做错的事情。

环境:

初始化合约实例:

export const getContractInstance = () => {
    let web3Provider

    if (typeof window.web3 !== 'undefined') {
        // if metamask is on, web3 is injected...
    web3Provider = web3.currentProvider
    } else {
        // otherwise, use ganache-cli...
    web3Provider = new Web3.providers.HttpProvider('http://localhost:8545')
    }

    web3 = new Web3(web3Provider)

    return new web3.eth.Contract(CryptoKpopAbi, CONTRACT_ADDRESS)
}

正在订阅 PurchaseMade 事件

onBuy = (obj) => {
    web3.eth.subscribe("PurchaseMade", {}, () => {
        debugger
    });

    this.ContractInstance.methods.buy(1).send({
        from: this.state.currentUserAddress,
        gas: GAS_LIMIT,
        value: web3.utils.toWei(price.toString(), "ether"),
    }).then((receipt) => {
        console.log(receipt)
    }).catch((err) => {
        console.log(err.message)
    })
}

我在调用 web3.eth.subscribe 时收到此警告:

Subscription "PurchaseMade" doesn't exist. Subscribing anyway.

我在 tx 收据上收到此错误(在 send()` 成功后

Uncaught TypeError: Cannot read property 'subscriptionName' of undefined

我使用这个官方文档来设置订阅

http://web3js.readthedocs.io/en/1.0/web3-eth-subscribe.html

提前致谢!

更新:

合约中的事件声明

event PurchaseMade(uint objId, uint oldPrice, uint newPrice, string objName, address prevOwner, address newOwner);

合约中的事件调用

function buy(uint _tokenId) payable public {
  address prevOwner = ownerOf(_tokenId);
  uint currentPrice = tokenIdToPrice[_tokenId];

  ...

  PurchaseMade(_tokenId, currentPrice, newPrice,
    tokens[_tokenId].name, prevOwner, msg.sender);
}

您正在尝试订阅活动本身。 API 允许您订阅事件类型并添加过滤器。有效的事件类型是:

  • pendingTransactions:接收发送到区块链的新交易的子集(主要用于想要选择他们处理的交易的矿工)
  • newBlockHeaders:当新区块被添加到区块链时接收通知。
  • syncing:节点同步时收到通知starts/stops
  • logs:接收有关区块链日志更新的通知。这些是您感兴趣的活动。

查看 API documentation 以获取有关如何使用 subscribe("logs") 的示例。

subscribe API 通常用于侦听跨区块链发生的事件。监听特定合约事件的更简单方法是对已部署合约 (documentation) 使用 events。它与上面使用 subscribe 没有太大区别,但它已经具有合约地址和主题过滤器。

this.ContractInstance.events.PurchaseMade({}, (error, data) => {
  if (error)
    console.log("Error: " + error);
  else 
    console.log("Log data: " + data);
});

不过,有一点很重要。使用 web3 1.0,listening to events is not supported using HttpProvider。您必须使用 Websockets 或 IPC。

编辑 - 我忘了说您也可以从交易收据中获取事件:

contractInstance.events.eventName.returnValues;