监听Solidity合约事件

Posted sanqima

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了监听Solidity合约事件相关的知识,希望对你有一定的参考价值。

    在ethers.js里,使用contractWithSigner.on()的方式,监听合约的某个事件或者地址上的交易。合约的事件,会通过emit event的方式发出,使用contractWithSigner.on() 注册了该事件,就可以实现监听了。下面以监听EventValue.sol里的ValueChanged事件为例,进行说明。

1、部署合约

    a) 参考这篇文章 [用ethers.js部署合约],来部署EventValue.sol合约,得到合约地址为:0x850A0D21Da477Ea95D44d00f2B534CB0DF8eef92
    //EventValue.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract EventValue {
    event ValueChanged(address indexed author,uint oldValue,uint newValue);
    uint _value;

    constructor(uint value) public {
        uint tmp = _value;
        _value = value;
        emit ValueChanged(msg.sender, tmp, value);
    }
    function getValue() view public returns (uint) {
        return _value;
    }
    function setValue(uint value) public {
        uint tmp = _value;
        _value = value;
        emit ValueChanged(msg.sender, tmp, value);
    }
}

    b) 创建文件夹和文件

mkdir -p test/ethers
cd test/ethers

## 3个脚本
touch 7.er_listenEvent.js
touch 8.any_setValue.js
touch 9.owner_setValue.js

2、编写监听脚本和测试脚本

2.1 监听脚本

    监听合约事件的脚本为7.er_listenEvent.js
    // 7.er_listenEvent.js

const {ethers} = require("ethers")
const fs = require('fs')

let provider = new ethers.providers.JsonRpcProvider('http://localhost:8545')

function getHexString(prikeyPath) {
    const privKeyFile = fs.readFileSync(prikeyPath).toString().trim();
    const privKey = new Buffer.from(privKeyFile, 'hex');    
    return privKey
}

async function listenEvent(){
    var privKey  = getHexString(".secret")
    let wallet = new ethers.Wallet(privKey,provider)
    
    var contractAddr = '0x850A0D21Da477Ea95D44d00f2B534CB0DF8eef92'
    //var contractAddr = '0x305Dd19C5FBAd6b24649A030681C7c494b5481e2'
    var jsonStr = fs.readFileSync('./build/contracts/EventValue.json')
    var jsonInfo = JSON.parse(jsonStr)
    var jsonAbi  = jsonInfo.abi    
    let contract = new ethers.Contract(contractAddr,jsonAbi,provider)
    let contractSign = contract.connect(wallet)

    let curValue = await contractSign.getValue()
    console.log('curValue=',ethers.BigNumber.from(curValue).toNumber())

    let tx = await contractSign.setValue(300)
    console.log('txHash=',tx.hash)
    await tx.wait()

    //1) 监听ValueChanged事件(不区分合约创建者与普通用户)
    contractSign.on("ValueChanged",(author,oldValue,newValue,event) => {
        console.log('---- anyUser ---')
        console.log('user=',author)
        console.log('oldValue=',ethers.BigNumber.from(oldValue).toNumber())
        console.log('newValue=',ethers.BigNumber.from(newValue).toNumber())
        console.log('eventNumber=',event.blockNumber)
    });

    //2) 在这些事件中,找出是合约创建者发起的调用交易
    let filter = contractSign.filters.ValueChanged(wallet.address)
    contractSign.on(filter,(author,oldValue,newValue,event) => {
        console.log('--- the Ower ----')
        console.log('ower=',author)
        console.log('oldValue=',ethers.BigNumber.from(oldValue).toNumber())
        console.log('newValue=',ethers.BigNumber.from(newValue).toNumber())
        console.log('eventNumber=',event.blockNumber)
    })
}

listenEvent()

2.2 普通用户测试脚本

    普通用户的测试脚本为8.any_setValue.js
    // 8.any_setValue.js

const {ethers} = require("ethers")
const fs = require('fs')

let provider = new ethers.providers.JsonRpcProvider('http://localhost:8545')

function getHexString(prikeyPath) {
    const privKeyFile = fs.readFileSync(prikeyPath).toString().trim();
    const privKey = new Buffer.from(privKeyFile, 'hex');    
    return privKey
}

function isNumber(val) {
    return !isNaN(val);
}

async function preGetValue(contract) {
    let value = await contract.getValue()
    let valone = ethers.BigNumber.from(value).toNumber()
    console.log("curValue=",valone)
}

async function preSetValue(contract,num) {
    let tx = await contract.setValue(num)
    console.log('tx=',tx.hash)
    await tx.wait()
}

async function doValue(num){
    // var privKey  = getHexString(".secret")
    // other user
    let privKey = '0x0272...d322'
    let wallet = new ethers.Wallet(privKey,provider)
    
    var contractAddr = '0x850A0D21Da477Ea95D44d00f2B534CB0DF8eef92'
    var jsonStr = fs.readFileSync('./build/contracts/EventValue.json')
    var jsonInfo = JSON.parse(jsonStr)
    var jsonAbi  = jsonInfo.abi    
    let contract = new ethers.Contract(contractAddr,jsonAbi,wallet)
    
    await preSetValue(contract,num)
    await preGetValue(contract)
}

var count = process.argv[2]
if (isNumber(count)) {
    doValue(count)
} else {
    console.log('please input a number')
}

2.3 owner用户测试脚本

    合约的部署者,也叫owner用户,其测试脚本如下
    // 9.ower_setValue.js

const {ethers} = require("ethers")
const fs = require('fs')

let provider = new ethers.providers.JsonRpcProvider('http://localhost:8545')

function getHexString(prikeyPath) {
    const privKeyFile = fs.readFileSync(prikeyPath).toString().trim();
    const privKey = new Buffer.from(privKeyFile, 'hex');    
    return privKey
}

function isNumber(val) {
    return !isNaN(val);
}

async function preGetValue(contract) {
    let value = await contract.getValue()
    let valone = ethers.BigNumber.from(value).toNumber()
    console.log("curValue=",valone)
}

async function preSetValue(contract,num) {
    let tx = await contract.setValue(num)
    console.log('tx=',tx.hash)
    await tx.wait()
}

async function doValue(num){
    var privKey  = getHexString(".secret")
    let wallet = new ethers.Wallet(privKey,provider)
    
    var contractAddr = '0x850A0D21Da477Ea95D44d00f2B534CB0DF8eef92'
    var jsonStr = fs.readFileSync('./build/contracts/EventValue.json')
    var jsonInfo = JSON.parse(jsonStr)
    var jsonAbi  = jsonInfo.abi    
    let contract = new ethers.Contract(contractAddr,jsonAbi,wallet)

    await preSetValue(contract,num)
    await preGetValue(contract)
}

var count = process.argv[2]
if (isNumber(count)) {
    doValue(count)
} else {
    console.log('please input a number')
}

3、进行测试

3.1 开启事件监听

node test\\ethers\\7.er_listenEvent.js

3.2 普通用户测试

node test\\ethers\\8.any_setValue.js 700

    如图(2) 所示:

图(2) 普通用户,设置value

3.3 owner用户测试

node test\\ethers\\9.owner_setValue.js 702

    如图(3) 所示:

图(3) owner用户,设置value

    由图(2)、图(3)可知普通用户和owner用户,都可以修改value的值,并且7.er_listenEvent.js脚本监听到了这个value值的修改。

参考文献

    [1] ethers.js V5 事件监听
    [2] ethers.js Provider使用
    [3] ethers.js合约详解
    [4] hardhat里的合约监听

以上是关于监听Solidity合约事件的主要内容,如果未能解决你的问题,请参考以下文章

区块链开发之Solidity编程基础合约事件

详解 Solidity 事件Event - 完全搞懂事件的使用

完全搞懂事件

智能合约实战 solidity 语法学习 13 [ 事件event emit日志logs 异常throw revertrequireassert] 附代码

智能合约实战 solidity 语法学习 13 [ 事件event emit日志logs 异常throw revertrequireassert] 附代码

智能合约实战 solidity 语法学习 13 [ 事件event emit日志logs 异常throw revertrequireassert] 附代码