0

e.g. These two events:

{
  "anonymous": false,
  "inputs": [
    {
      "indexed": true,
      "internalType": "address",
      "name": "from",
      "type": "address"
    },
    {
      "indexed": true,
      "internalType": "address",
      "name": "to",
      "type": "address"
    },
    {
      "indexed": false,
      "internalType": "uint256",
      "name": "value",
      "type": "uint256"
    }
  ],
  "name": "Transfer",
  "type": "event"
}
{
  "anonymous": false,
  "inputs": [
    {
      "indexed": true,
      "internalType": "address",
      "name": "from",
      "type": "address"
    },
    {
      "indexed": true,
      "internalType": "address",
      "name": "to",
      "type": "address"
    },
    {
      "indexed": true,
      "internalType": "uint256",
      "name": "value",
      "type": "uint256"
    }
  ],
  "name": "Transfer",
  "type": "event"
}

have the same signature: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.

The only difference is that the 3rd input is non-indexed in the first event and indexed in the second event.

This generally wouldn't be a problem, however, we are using getPastLogs to filter events by signature and we need to know the exact contract inputs (including indexed value) to decode them using decodeLog, i.e. This will work with the first event:

const values = web3.eth.abi.decodeLog(
  transferToken.inputs,
  logEvent.data,
  logEvent.topics.slice(1),
);

but it will not work with the second event. will produce an error:

Error: Returned values aren't valid, did it run Out of Gas? You might also see this error if you are not using the correct ABI for the contract you are retrieving data from, requesting data from a block number that does not exist, or querying a node which is not fully synced.

This becomes even greater problem since it seems that there are events with any combination of indexed vs non-indexed inputs.

1 Answer 1

0

While not ideal, and while it does not directly answer the original question, the following approach works to decode all events without knowing whether inputs are indexed or not:

const possibleIndexes = cartesian([
  [true, false],
  [true, false],
  [true, false],
]);

let lastDecodingError;
let values;

for (const indexes of possibleIndexes) {
  try {
    values = web3.eth.abi.decodeLog(
      [
        {
          indexed: indexes[0],
          internalType: 'address',
          name: 'from',
          type: 'address',
        },
        {
          indexed: indexes[1],
          internalType: 'address',
          name: 'to',
          type: 'address',
        },
        {
          indexed: indexes[2],
          internalType: 'uint256',
          name: 'value',
          type: 'uint256',
        },
      ],
      logEvent.data,
      logEvent.topics.slice(1),
    );

    break;
  } catch (error) {
    lastDecodingError = error;
  }
}

if (!values && lastDecodingError) {
  throw lastDecodingError;
}

if (!values) {
  throw new UnexpectedStateError('decodeLog did not produce values or result');
}

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.