24

I am currently migrating a truffle project to hardhat. I am facing a problem with listening to events. I have a simple ERC20 token and want to listen to the Transfer event. I am running the contract on a hardhat test network. Here is my test code, which does not catch the Transferevent. Any hits on what I am doing wrong is highly appreciated:

import { ethers } from "hardhat";
import chai from "chai";
import { solidity } from "ethereum-waffle";
import { FlanToken } from "../typechain/MyToken";
import { BigNumber} from "ethers";

chai.use(solidity);
const { assert } = chai;


describe("MyToken", () => {

    let myToken: MyToken;
    let accounts: any;

    beforeEach(async () => {
        accounts = await ethers.getSigners();
        const tokenFactory = await ethers.getContractFactory("MyToken", accounts[0]);
        myToken = (await myToken.deploy()) as MyToken;
        await myToken.deployed();
    });

    describe("token transfer", async () => {

        it("valid transfer", async () => {
            myToken.on("Transfer", (_from,_to,_value) => {
                console.log(_from,_to,_value);
            });

            await myToken.connect(accounts[0]).transfer(accounts[1].address, 1);

            // balance checks
            let balanceSender: BigNumber = await myToken.balanceOf(accounts[0].address);
            let balanceReceiver: BigNumber = await myToken.balanceOf(accounts[1].address);
            assert.equal(balanceSender.toNumber(), 999999, "Unexpected balance of sender afer token transfer.");
            assert.equal(balanceReceiver.toNumber(), 1, "Unexpected balance of receiver afer token transfer.");
        })
    });

});

3 Answers 3

27

While I did not find a solution on why the .on() method is not working, I found a workaround using the transaction's receipt. The following code describes this workaround:

let tx: ContractTransaction = await myToken.connect(accounts[0]).transfer(accounts[1].address, 1);

let receipt: ContractReceipt = await tx.wait();
console.log(receipt.events?.filter((x) => {return x.event == "Transfer"}));
0
14

As far as I can tell it isn't possible to actually use the arguments which are emitted, however you can test for them being emitted using the following chai code example:

await expect(token.transfer(walletTo.address, 7))
  .to.emit(token, 'Transfer')
  .withArgs(wallet.address, walletTo.address, 7);

Here is the reference

Update:

You can also use the emitted arguments, for instance:

Contract:

event Transfer(
        address indexed from, 
        address indexed to, 
        uint256 value
    );

function transfer(address _to, uint256 _value) public {
   emit Transfer(msg.sender, _to, _value);
}

Test:

const transferTx = await token.connect(bob.address).transfer(alice.address, 10);
const result = await transferTx.wait();
expect(result.events[0].args._from).to.equal(bob.address);
expect(result.events[0].args._to).to.equal(alice.address);
expect(result.events[0].args._value).to.equal(10);
2

Check-out this example:

async function main() {
  const EventEmitter = await ethers.getContractFactory("EventEmitter");
  const eventEmitter = await EventEmitter.deploy();
  await eventEmitter.deployed();

  const tx = await eventEmitter.emitBothEvents(42, "foo");

  const receipt = await tx.wait()

  for (const event of receipt.events) {
    console.log(`Event ${event.event} with args ${event.args}`);
  }
}

main()
  .then(() => process.exit(0))
  .catch(error => {
    console.error(error);
    process.exit(1);
  });

from https://github.com/fvictorio/hardhat-examples/blob/master/reading-events/scripts/getEventsFromTx.js.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.