6

I am calling a contract function which emits an event in a transaction. This transaction should include the event and is typically visible via:

const receipt = await contractInstance.someFunction()
let logs = receipt.logs

This normally contains a list of the emitted event names in the transaction. However in my call the tests output:

[]
    1) Test someFunction()

    Events emitted during test:
    ---------------------------

    Stored()

    ---------------------------

  1 failing

  1) Contract: Test.js
       Test someFunction():
     AssertionError: Stored event not emitted: expected false to be truthy
      at Context.it (test/test.js:145:12)
      at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)

with testing block that fails:

const receipt = await instance.someFunction();
let event = validationReceipt.logs.some(l => { return l.event == "Stored" });
console.log(validationReceipt.logs);
assert.ok(event, "Stored event not emitted");

First line performs the function call which emits the event Stored. Second line retrieves the instance by event name from the logs. Third line simply logs the contained events. Fourth line asserts that the event exists in the logs.

As shown in the test output, the logs were empty [], but the event was emitted.

Why is the event being shown to have been emitted but also not present in the logs of the transaction that emitted it?

2 Answers 2

12

Turns out transaction receipt logs only include events emitted in the context of the direct contract function being called. If the called function makes another call to a separate external contract that emits an event, those won't be included even if there are emitted.

To make use of those emitted events from other contracts:

const sha3 = require('js-sha3').keccak_256
...

const tx = await instance.someFunction(();
let event = tx.receipt.logs.some(l => { return l.topics[0] == '0x' + sha3("Stored()") });
assert.ok(event, "Stored event not emitted");

where someFunction is a function that calls a function of another contract different to instance.

This grabs the logs from the receipt object. The logs should contain topics, the first of which is a hashed event signature. Thus we can use what we expect our event signature to be, hash it and test for existence in the logs. This works because all events are included in receipt logs but are not returned in the transaction logs provided by truffle/ganache.

This post helped.

On later versions of Truffle (have tested with v5.1.0), the same logs and topics are found under a different transaction receipt property rawLogs:

const tx = await instance.someFunction(();
let event = tx.receipt.rawLogs.some(l => { return l.topics[0] == '0x' + sha3("Stored()") });
assert.ok(event, "Stored event not emitted");
3
  • 1
    Great answer. Just for the record, you don't have to install js-sha3, instead you can use web3.utils.keccak256. Aug 6, 2019 at 16:59
  • 1
    Update: It seems this code doesn't work anymore with truffle ^5.0.30. There are no topics. Aug 6, 2019 at 18:18
  • @PaulRazvanBerg The object has changed slightly but they're still accessible (luckily!). I've update the answer to account for this.
    – Shiri
    Nov 18, 2019 at 13:28
2

You could use web3 and call the Contract method with the truffle instance abi and contract address. Then use the events methods. Don't need to declare web3 as truffle will provide that.

const receipt = await contractInstance.someFunction()

const contract = new web3.eth.Contract(contractInstance.abi, contractInstance.address)

//Now get evens depending on what you need
contract.getPastEvents("allEvents", {fromBlock: 0, toBlock: "latest"})
.then(console.log)  

Follow web3.js documentation for more event methods

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.