web3.js 智能合约事件

以太坊智能合约能够发出事件,表示在智能合约代码执行中发生的事情。智能合约的前端UI,例如,DApps、web3.js,都可以侦听这些事件。

事件在区块链中的存储

区块链是一个由区块组成的列表,这些块的内容基本上是交易记录。每个交易都有一个附加的交易日志,事件结果存放在交易日志里。合约发出的事件,可以使用合约地址访问。

web3.js中,可以通过智能合约对象中的getPastEvents函数访问事件。

本章示例,我们将实际连接到Ethereum主网来获取OmiseGo ERC-20通证的传输事件。ERC-20标准规定,实现该标准的智能合约必须在传输通证时发出传输事件。

使用web3.js获取OmiseGo智能合约事件的步骤如下:

  1. 创建智能合约对象。
  2. 使用getPastEvents函数获取事件

注意,此次连接到以太坊主网(mainnet)

创建智能合约对象

创建智能合约对象,要设置智能合约的ABI代码及地址,这些信息都可以在etherscan查询到。

const Web3 = require('web3')
const web3 = new Web3('https://mainnet.infura.io/YOUR_INFURA_API_KEY') // 连接到主网

// OMG Token Contract ABI code
const abi = [{"constant":true,"inputs":[],"name":"mintingFinished","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"finishMinting","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_releaseTime","type":"uint256"}],"name":"mintTimelocked","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[],"name":"MintFinished","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","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"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]

// 智能合约地址
const address = '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07'

// 创建智能合约对象
const contract = new web3.eth.Contract(abi, address)

使用getPastEvent`函数获取事件

查看智能合约的事件,可以使用contract对象上的getPastEvents()函数。

contract.getPastEvents(
  'AllEvents', // 过滤事件参数,这里获取全部事件
  {
    fromBlock: 0, // 起始块
    toBlock: 'latest' // 终止块
  },
  (err, events) => { console.log(events) } // 回调函数
)

fromBlock与toBlock指定了查询事件的起始区块与终止区块,如果区块中的事件太多,getPastEvents函数调用会失败。

可以限制一下要查询区块的范围,以免函数执行失败。我们的示例中会查询最新几个区块中的事件,关于最新区块的序号,可以通过etherscan查询。

contract.getPastEvents(
  'AllEvents',
  {
    fromBlock: 8717848,
    toBlock: 'latest'
  },
  (err, events) => { console.log(events) }
)

完整代码如下:app.jsconst Web3 = require('web3')const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_INFURA_ ...