2

I am monitoring the events when calling a method from my contract and want to save the output of one of my custom events, to display it.

The call of my method looks like this:

contract.tx
  .method({ storageDepositLimit, gasLimit }, account , 'root', label)
  .signAndSend(alice, ({events = [], status}) => {
    if (status.isInBlock) {
      console.log('in a block')
      events.forEach(({ event, phase }) => {
        if(api.events.contracts.ContractEmitted.is(event)){
          const [account_id, contract_evt] = event.data
          const decoded = new Abi(abi).decodeEvent(contract_evt)
          // This (decoded) is the information I want to save
        }else{
          console.log('\t', phase.toString(), `: ${event.section}.${event.method}`, event.data.toString())
        }
      });
     } else if (status.isFinalized) {
      console.log('finalized')
    }
  })

How can I save 'decoded' outside of the contract call to display the information later?

2 Answers 2

4

All you want to do is have the data available outside the callback. So just set it to some variable -

let decoded = null

function setDecoded (value) {
  decoded = value
}

contract.tx
  .method({ storageDepositLimit, gasLimit }, account , 'root', label)
  .signAndSend(alice, ({events = [], status}) => {
    if (status.isInBlock) {
      console.log('in a block')
      events.forEach(({ event, phase }) => {
        if(api.events.contracts.ContractEmitted.is(event)){
          const [account_id, contract_evt] = event.data

          /* saves the data */
          setDecoded(new Abi(abi).decodeEvent(contract_evt))
        }else{
          console.log('\t', phase.toString(), `: ${event.section}.${event.method}`, event.data.toString())
        }
      });
     } else if (status.isFinalized) {
      console.log('finalized')
    }
  })

Alternatively, you can obviously listen for any events anywhere and still do the same -

let decoded = null

function setDecoded (value) {
  decoded = value
}

api.query.system.events((records) =>
  records.forEach(({ event, phase }) => {
    if(api.events.contracts.ContractEmitted.is(event)){
      const [account_id, contract_evt] = event.data

      /* saves the data if from our contract */
      if (account_id.eq("contract address goes here"))
        setDecoded(new Abi(abi).decodeEvent(contract_evt))
    }
  })
)
3

This is a good question.

From all the examples that I have seen, it looks like you may have to have your program logic inside the signAndSend.

Also, a note that contract.tx.method({ storageDepositLimit, gasLimit }, account , 'root', label).signAndSend(alice) gives you back a tx hash that you can use to query the events later.

If you know which block number this transaction occurred you can take the block hash and query on that block hash like this:

You can use

const apiAt = await api.at(blockHash);
const events = await apiAt.query.system.events();

Looks like you can match the extrinsics with the events:

You can match extrinsic hashes here:

2
  • I tried that before. But the problem is, that it takes some time to fetch the events, and the rest of my program does not wait for the contract call to finish. I would need to wait for the contract.tx to run through...
    – rajohs
    Commented Aug 15, 2022 at 20:30
  • Updated my answer. Maybe @Jaco can shed some light on this.
    – Bruno
    Commented Aug 16, 2022 at 3:54

Your Answer

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

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