Ethers.js: How do I parse event logs?

Created on 10 Apr 2019  路  7Comments  路  Source: ethers-io/ethers.js

I have a smart contract that emits events whenever the following line of code in the contract is called:

emit Transfer(from, to, value);

The script that is used to list these events is shown below:

var ethers = require('ethers');

var provider = new ethers.providers.InfuraProvider('ropsten');
const metacoinArtifacts = require('../build/contracts/MyToken.json');
const address = metacoinArtifacts.networks[3].address;

var filter = {
    address: address,
    fromBlock: 0
};
var callPromise = provider.getLogs(filter);
callPromise.then(function(events) {
    console.log("Printing array of events:");
    console.log(events);
}).catch(function(err){
    console.log(err);
});

The output is the following:

[ { blockNumber: 5196629,
    blockHash: '0x19b083ee0752347f0bba9cd1cf19c827fd108c0f5d4973e33719d97a60cf14ca',
    transactionIndex: 1,
    removed: false,
    address: '0xF92298d72afE68300EA065c0EdaDbb1A29804faa',
    data: '0x00000000000000000000000000000000000000000000021e19e0c9bab2400000',
    topics: 
     [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
       '0x0000000000000000000000000000000000000000000000000000000000000000',
       '0x000000000000000000000000f58e01ac4134468f9ad846034fb9247c6c131d8c' ],
    transactionHash: '0xdad8bc380240548aafecba06bf6cee898513da850bb37859cfea5f93d8dd25da',
    logIndex: 0 },
  { blockNumber: 5301391,
    blockHash: '0x00b7bfeade71c17fd99bcc7c9b684cedad05fede5201e0dbc64614e14b07b07c',
    transactionIndex: 23,
    removed: false,
    address: '0xF92298d72afE68300EA065c0EdaDbb1A29804faa',
    data: '0x00000000000000000000000000000000000000000000000000038d7ea4c68000',
    topics: 
     [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
       '0x000000000000000000000000f58e01ac4134468f9ad846034fb9247c6c131d8c',
       '0x0000000000000000000000002d92bce8a6cf0fd32cffcabed026a6cb34ee0e9b' ],
    transactionHash: '0xf4f973b90fea5b32bf09b55166ee106b81cffd9d1ca8dd4752541d927f12dc18',
    logIndex: 33 },
  { blockNumber: 5301417,
    blockHash: '0x474fd08cad1d1ea870b8ed60d39505afd8b6e6be40f72c61581602056d7c8d1f',
    transactionIndex: 0,
    removed: false,
    address: '0xF92298d72afE68300EA065c0EdaDbb1A29804faa',
    data: '0x00000000000000000000000000000000000000000000000000005af3107a4000',
    topics: 
     [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
       '0x000000000000000000000000f58e01ac4134468f9ad846034fb9247c6c131d8c',
       '0x0000000000000000000000002d92bce8a6cf0fd32cffcabed026a6cb34ee0e9b' ],
    transactionHash: '0x8fa45694dc0c06b8b447f56221551cdec7987414b127d215d27e992f745d30a8',
    logIndex: 0 },
  { blockNumber: 5321681,
    blockHash: '0x600fad7a526ac89210378b63df96c09b45238a526fc10df42bfd34643d6b3cfa',
    transactionIndex: 24,
    removed: false,
    address: '0xF92298d72afE68300EA065c0EdaDbb1A29804faa',
    data: '0x000000000000000000000000000000000000000000000000000000000000000a',
    topics: 
     [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
       '0x000000000000000000000000f58e01ac4134468f9ad846034fb9247c6c131d8c',
       '0x00000000000000000000000015c72944b325a3e1c7a4dbdc6f883bd5948d3d9f' ],
    transactionHash: '0x3518b448d9091b3afa3822c4f7ed2216879bba875078b7cc3499142eb50be828',
    logIndex: 22 },
  { blockNumber: 5326453,
    blockHash: '0x2d709809aa31acc2e047f5d9f2c87aaff958c823725aa3ba7e5cbf5ff5bd7f7a',
    transactionIndex: 33,
    removed: false,
    address: '0xF92298d72afE68300EA065c0EdaDbb1A29804faa',
    data: '0x000000000000000000000000000000000000000000000000000000000000000a',
    topics: 
     [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
       '0x000000000000000000000000f58e01ac4134468f9ad846034fb9247c6c131d8c',
       '0x00000000000000000000000015c72944b325a3e1c7a4dbdc6f883bd5948d3d9f' ],
    transactionHash: '0x0e594a0cfc3bd89df75e9e178f1ef63441e950b621d145fdc063123af595a2f5',
    logIndex: 66 },
  { blockNumber: 5326455,
    blockHash: '0x85d1bb0651b8064e367b3958133712774d205039cfc8d25a9234e875e48c9615',
    transactionIndex: 16,
    removed: false,
    address: '0xF92298d72afE68300EA065c0EdaDbb1A29804faa',
    data: '0x000000000000000000000000000000000000000000000000000000000000000a',
    topics: 
     [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
       '0x000000000000000000000000f58e01ac4134468f9ad846034fb9247c6c131d8c',
       '0x00000000000000000000000015c72944b325a3e1c7a4dbdc6f883bd5948d3d9f' ],
    transactionHash: '0xf8f2affa3ea09c609dba11b2da4ec0946ae72f269887dd239729c5951f661b21',
    logIndex: 38 },
  { blockNumber: 5326525,
    blockHash: '0xa0b85af06cbed82cfdea7658c21983502c01679efa79142d34470eb58c3ba9a2',
    transactionIndex: 43,
    removed: false,
    address: '0xF92298d72afE68300EA065c0EdaDbb1A29804faa',
    data: '0x000000000000000000000000000000000000000000000000000000000000000a',
    topics: 
     [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
       '0x000000000000000000000000f58e01ac4134468f9ad846034fb9247c6c131d8c',
       '0x00000000000000000000000015c72944b325a3e1c7a4dbdc6f883bd5948d3d9f' ],
    transactionHash: '0xc6a8fa37107ed2bd3d9c07be0c86ff8a83002ab590d296cc3af303f09f68b368',
    logIndex: 122 } ]

What I am wondering is how do I decode the output of this script to get _from_, _to_, _value_ from the event that was originally emitted?

discussion

Most helpful comment

The easiest way to do this, if you are not using the Contract API, is to use the Interface object API:

// You can also pull in your JSON ABI; I'm not sure of the structure inside artifacts
let abi = [ "event Transfer(address indexed from, address indexed to, uint value)" ];
let iface = new ethers.utils.Interface(abi);

var logPromise = provider.getLogs(filter);
logPromise.then(function(logs) {
    console.log("Printing array of events:");
    let events = logs.map((log) => iface.parseLog(log))
    console.log(events);
}).catch(function(err){
    console.log(err);
});

Which will output (given your logs):

[ _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0x0000000000000000000000000000000000000000',
       '1': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '2': [BigNumber],
       from: '0x0000000000000000000000000000000000000000',
       to: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values:
     Result {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x2D92bce8a6cf0FD32CFfCABed026a6cb34ee0e9b',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x2D92bce8a6cf0FD32CFfCABed026a6cb34ee0e9b',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x2D92bce8a6cf0FD32CFfCABed026a6cb34ee0e9b',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x2D92bce8a6cf0FD32CFfCABed026a6cb34ee0e9b',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       value: [BigNumber],
       length: 3 } } ]

Note the values inside each event object are what you would be interested in.

All 7 comments

The easiest way to do this, if you are not using the Contract API, is to use the Interface object API:

// You can also pull in your JSON ABI; I'm not sure of the structure inside artifacts
let abi = [ "event Transfer(address indexed from, address indexed to, uint value)" ];
let iface = new ethers.utils.Interface(abi);

var logPromise = provider.getLogs(filter);
logPromise.then(function(logs) {
    console.log("Printing array of events:");
    let events = logs.map((log) => iface.parseLog(log))
    console.log(events);
}).catch(function(err){
    console.log(err);
});

Which will output (given your logs):

[ _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0x0000000000000000000000000000000000000000',
       '1': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '2': [BigNumber],
       from: '0x0000000000000000000000000000000000000000',
       to: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values:
     Result {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x2D92bce8a6cf0FD32CFfCABed026a6cb34ee0e9b',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x2D92bce8a6cf0FD32CFfCABed026a6cb34ee0e9b',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x2D92bce8a6cf0FD32CFfCABed026a6cb34ee0e9b',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x2D92bce8a6cf0FD32CFfCABed026a6cb34ee0e9b',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       value: [BigNumber],
       length: 3 } },
  _LogDescription {
    decode: [Function],
    name: 'Transfer',
    signature: 'Transfer(address,address,uint256)',
    topic:
     '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    values: {
       '0': '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       '1': '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       '2': [BigNumber],
       from: '0xF58E01Ac4134468F9Ad846034fb9247c6C131d8C',
       to: '0x15c72944b325a3E1c7a4DBdc6F883bD5948d3D9f',
       value: [BigNumber],
       length: 3 } } ]

Note the values inside each event object are what you would be interested in.

I think we are close. I now get the following output:

Printing array of events:
[ undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined ]

Note that this output is produced based on the changes that were made to create the following script:

var ethers = require('ethers');

var provider = new ethers.providers.InfuraProvider('ropsten');
const metacoinArtifacts = require('../build/contracts/MyToken.json');
const address = metacoinArtifacts.networks[3].address;

var abi = [ "event Transfer(address indexed from, address indexed to, uint256 value)" ];
var iface = new ethers.utils.Interface(abi);

var filter = {
    address: address,
    fromBlock: 0
};
var callPromise = provider.getLogs(filter);
callPromise.then(function(events) {
    console.log("Printing array of events:");
    var parsedEvents = events.map(function(log) {iface.parseLog(log)});
    console.log(parsedEvents);
}).catch(function(err){
    console.log(err);
});

What could I be doing wrong here?

You forgot the return in the callback to map. :)

(return iface.parseLog(log))

Is there any good way to convert a Log into an Event?

This is my current attempt to fetch Events from the last n blocks:

const getPastEvents = (eventName, fromBlock, args) => {
  const filter = myContract.filters[eventName](...args)
  filter.fromBlock = fromBlock
  filter.toBlock = "latest"

  const logs = await this.provider.getLogs(filter)

  const events = []
  for (let i in logs) {
    events.push(myAbi.parseLog(logs[i]))
  }

  return events
}

But at the end I'm getting a set of LogDescription which is missing the helpful transaction-accessing methods. Ultimately, the args (aka values) is what I need so not a deal breaker but would be nice to have.

Oh, you'd like the getBlock(), getTransaction() and getTransactionReceipt() operations on the object returned from parseLog? I can add that easy enough.

I may only add it to the v5 branch though, which should be available for public beta later today. :)

These have been added to v5. If you try it out, let me know how they work for you.

Please feel free to re-open or continue discussion (I monitor closed issues) if you have any problems.

Thanks! :)

Oh, that鈥檚 just what console.log does. If you want more context logged, you can use console.dir(result, { depth: null }). :)

Was this page helpful?
0 / 5 - 0 ratings