Back

blockchain - web3 - solidity event log

发布时间: 2022-07-05 23:28:00

refer to: https://ethereum.stackexchange.com/questions/16313/how-can-i-view-event-logs-for-an-ethereum-contract

https://medium.com/mycrypto/understanding-event-logs-on-the-ethereum-blockchain-f4ae7ba50378

EventLog 是EVM的重要部分,可以认为是:

1. 传统的log 用来debug

2. (主动通知作用:)作为solidity 函数的return结果(return是返回值给 其他function, event log则是传到链下)

可以使用 get 或者 watch

1. watch: 监听未来要发生的

2. get: 监听之前所有发生过的event log

3. 在某个tx的response中,就可以看出log.

例子: (truffle 项目)

假设我们有下面的这个contract:

$ cat contracts/TestEvent.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract TestEvent {

  string message;
  uint256 amount;

  event HiEvent(string message, uint256 amount);

  constructor(string memory _message) {
    message = _message;
  }

  function sayHi(uint256 _amount) public {
    amount = _amount;
    emit HiEvent(message, amount);
  }

}

然后,调用方法如下:

$ cat callTestEvent.js
// contract 地址要有
const CONTRACT_ADDRESS = "0x6FCa9C7EDF4898cF8F0D48E60E1CcB51660505e6"
// abi 要有
const contractJson = require('./build/contracts/TestEvent.json')

module.exports = async function (callback) {
  // web3 是Truffle的自动引入的对象
  const contract = new web3.eth.Contract( contractJson.abi, CONTRACT_ADDRESS );

  // 获得 network , 这个是根据参数传入的
  const network = await web3.eth.net.getNetworkType()

  // TODO 这里最最关键。
  // 生成一个tx, 该tx是调用了 mintNFT产生的
  //const tx = contract.methods.mint()
  const tx = contract.methods.sayHi(44)

  // 发送!
  const receipt = await tx
  .send({
    from: (await web3.eth.getAccounts())[0],// 使用了HD wallet中的第一个account
    gas: await tx.estimateGas(),
  })
  .on('transactionHash', (txhash) => {
    console.log(`Mining transaction ... network: ${network}, tx: ${txhash}`)
    // console.log(`https://${network}.etherscan.io/tx/${txhash}`)
  })
  .on('error', function(error){
    console.error(`An error happened: ${error}`)
    callback()
  })
  .then(function(receipt){
    // Success, you've minted the NFT. The transaction is now on chain!
    console.log(
        `Success: The NFT has been minted and mined in block ${receipt.blockNumber}`)
    callback()
  })
}

我是在本地使用了ganache网络, 所以运行命令如下:

$ truffle exec callTestEvent.js  --network=ganache
Using network 'ganache'.

Mining transaction ... network: private, tx: 0x6411ad8e0fc691448861eb446a52fe9a30c784376fc9178451fb842aa0fd9bc6
Success: The NFT has been minted and mined in block 65

点击就可以看到详情了:

看一下如何在 js 中监听这个event :

通过 events.HiEvent.returnValues.message  就可以看到了。
// contract 地址要有
const CONTRACT_ADDRESS = "0x6FCa9C7EDF4898cF8F0D48E60E1CcB51660505e6"
// abi 要有
const contractJson = require('./build/contracts/TestEvent.json')

module.exports = async function (callback) {
  // web3 是Truffle的自动引入的对象
  const contract = new web3.eth.Contract( contractJson.abi, CONTRACT_ADDRESS );

  // 获得 network , 这个是根据参数传入的
  const network = await web3.eth.net.getNetworkType()

  // TODO 这里最最关键。
  // 生成一个tx, 该tx是调用了 mintNFT产生的
  //const tx = contract.methods.mint()
  const tx = contract.methods.sayHi(77)

  // 发送!
  const receipt = await tx
  .send({
    from: (await web3.eth.getAccounts())[0],// 使用了HD wallet中的第一个account
    gas: await tx.estimateGas(),
  })
  .on('transactionHash', (txhash) => {
    console.log(`Mining transaction ... network: ${network}, tx: ${txhash}`)
    // console.log(`https://${network}.etherscan.io/tx/${txhash}`)
  })
  .on('error', function(error){
    console.error(`An error happened: ${error}`)
    callback()
  })
  .then(function(receipt){
    console.log('====== total: ')
    console.log(receipt)
    console.log('====== events.HiEvent: ', receipt.events.HiEvent)
    console.log('====== events.HiEvent.returnValues: ', receipt.events.HiEvent.returnValues)
    console.log('====== events.HiEvent.returnValues.message: ', receipt.events.HiEvent.returnValues.message)
    console.log('====== events.HiEvent.returnValues.amount: ', receipt.events.HiEvent.returnValues.amount)
    // Success, you've minted the NFT. The transaction is now on chain!
    console.log(
        `Success: The NFT has been minted and mined in block ${receipt.blockNumber}`)
    callback()
  })

结果为:

====== events.HiEvent:  {
  logIndex: 0,
  transactionIndex: 0,
  transactionHash: '0x17a3f26aa9814465eb8ea5390552ee91e51134217fa4f070d2ff6389e9428918',
  blockHash: '0x5b4d306a6aa256dda472cf2b7e0c17ee24d49b19cae3f82d2405169bb8ba6c6e',
  blockNumber: 69,
  address: '0x6FCa9C7EDF4898cF8F0D48E60E1CcB51660505e6',
  type: 'mined',
  id: 'log_ab8dc71c',
  returnValues: Result {
    '0': 'I am from construction...',
    '1': '99',
    message: 'I am from construction...',
    amount: '99'
  },
  event: 'HiEvent',
  signature: '0xc3a44c66585c11d2584403022700a318b8c006ca535e7f155e74d478032edd28',
  raw: {
    data: '0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006300000000000000000000000000000000000000000000000000000000000000194920616d2066726f6d20636f6e737472756374696f6e2e2e2e00000000000000',
    topics: [
      '0xc3a44c66585c11d2584403022700a318b8c006ca535e7f155e74d478032edd28'
    ]
  }
}
====== events.HiEvent.returnValues:  Result {
  '0': 'I am from construction...',
  '1': '99',
  message: 'I am from construction...',
  amount: '99'
}
====== events.HiEvent.returnValues.message:  I am from construction...
====== events.HiEvent.returnValues.amount:  99

override下的event log:

跟普通方法一样, event log是可以被 override的。 (名称相同,参数不同的函数)

pragma solidity ^0.8.0;

contract TestVariable {

  string message;
  uint256 amount;

  event ShowVar(string name, address value);
  event ShowVar(string name, string value);
  event ShowVar(string name, uint value);

  function setMessage(string memory _message) public {
    message = _message;
  }

  function getMessage() public view returns(string memory){
    return message;
  }

  function setAmount(uint256 _amount) public{
    amount = _amount;
  }

  function getAmount() public view returns(uint256) {
    return amount;
  }

  function printVariables() public{
    emit ShowVar("msg.sender", msg.sender);
    emit ShowVar("amount", amount);
    emit ShowVar("message", message);
  }

}

对于上面的函数,设置好 对应的 amount ,message 之后,就可以直接调用 printVariables() 方法了。如下:

// contract 地址要有
const CONTRACT_ADDRESS = "0x5bEa39E27fD77739C6C8877666942D0aa8230961"
// abi 要有
const contractJson = require('./build/contracts/TestVariable.json')

module.exports = async function (callback) {
  // web3 是Truffle的自动引入的对象
  const contract = new web3.eth.Contract( contractJson.abi, CONTRACT_ADDRESS );

  // 获得 network , 这个是根据参数传入的
  const network = await web3.eth.net.getNetworkType()

  // const tx = contract.methods.setMessage("today is 2022-07-06, hot day!")
  // const tx = contract.methods.setAmount(321)
  const tx = contract.methods.printVariables()

  // 发送!
  const receipt = await tx
  .send({
    from: (await web3.eth.getAccounts())[0],// 使用了HD wallet中的第一个account
    gas: await tx.estimateGas(),
  })
  .on('transactionHash', (txhash) => {
    console.log(`Mining transaction ... network: ${network}, tx: ${txhash}`)
    // console.log(`https://${network}.etherscan.io/tx/${txhash}`)
  })
  .on('error', function(error){
    console.error(`An error happened: ${error}`)
    callback()
  })
  .then(function(receipt){
    console.log('====== total: ')
    console.log(receipt)
    console.log('====== events.ShowVar: ', receipt.events.ShowVar)
    // Success, you've minted the NFT. The transaction is now on chain!
    console.log(
        `Success: The NFT has been minted and mined in block ${receipt.blockNumber}`)
    callback()
  })

}

可以看到,返回的  receipt.events.ShowVar是一个数组(array) , 如下:

Back