[SOLVED] Moralis Streams Error Processing Data

Hey guys,
I am trying to destructure the Moralis stream using the following function:

export function parseEventData(req: any) {
    try {
      const updates: any = {};
      for (const log of req.body.logs) {
        const abi = req.body.abis[log.streamId];
        if (abi) {
          const { filter, update, eventName } = realtimeUpsertParams(abi, log, req.body.confirmed, req.body.block);
          return { data: update, tagName: log.tag, eventName };
        }
      }
    } catch (e: any) {
      console.log(e);
    }
  }

This function gives me the following error:
TypeError: Cannot destructure property 'data' of '(0 , utils_1.parseEventData)(...)' as it is undefined.

I get the error when I use the function over here:

app.post("/webhook", async (req, res) => {
  console.log(req.body) 
  console.log("Handled!")
  res.send('Webhook response')
  res.status(200).end() 
  try {
    verifySignature(req, config.MORALIS_API_KEY);
    const { data, tagName, eventName }: any = parseEventData(req);
    console.log(data);
    await parseUpdate(`SFS_${eventName}`, data);
  } catch (e) {
    console.log(e);
  }
  res.send('ok');
});

It seems like I have left some param undefined, however I’m having a hard time figuring out exactly which one.

EDIT: I found the following function on the Moralis Streams docs:

interface MyEvent {
  from: string;
  to: string;
}

const decodedLogs = Moralis.Streams.parsedLogs<MyEvent>({ webhook, tag });

decodedLogs[0]; // { from: '0x...', to: '0x...' }

Is it possible for me to use this instead of the above 2 functions? If so, is there an example of this function being used?

Thanks!

You can add some logging to se exactly what is the data that you received.

You can also parse the event data with ethers directly if you want.

I’m using the code given by Moralis (https://docs.moralis.io/docs/parse-data) to parse event data:

interface MyEvent {
  from: string;
  to: string;
}

const decodedLogs = Moralis.Streams.parsedLogs<MyEvent>({ webhook, tag });

decodedLogs[0]; // { from: '0x...', to: '0x...' }

How do I pass in the webhook and tag name? Right now, when left unassigned, I’m getting the following error:

Argument of type '{ webhook: any; tag: any; }' is not assignable to parameter of type 'ParseLogOptions'.
  Object literal may only specify known properties, and 'webhook' does not exist in type 'ParseLogOptions'.

I’m putting the code in my webhook processor (assuming this is the right way):

app.post("/webhook", async (req, res) => {
  console.log(req.body) 
  console.log("Handled!")
  res.send('Webhook response')
  res.status(200).end() 
  const decodedLogs = Moralis.Streams.parsedLogs<NewClone>({ webhook, tag });

I tried passing in the webhook and tag directly as strings but that gives an error as well.

Try to do some debugging, to add some logging, to see how the data looks like.

It requires a line with console.log to see how the data looks like.

I’m getting the data using console.log(req.body). This is what it looks like:

{
  confirmed: false,
  chainId: '0x13881',
  abi: [
    {
      anonymous: false,
      inputs: [Array],
      name: 'NewClone',
      type: 'event'
    }
  ],
  streamId: 'b9c0784d-b459-43ba-b510-8a73be21032y',
  tag: 'TEST',
  retries: 0,
  block: {
    number: '28802367',
    hash: '0xd75fe8ed643d531cae6dd4b575983eb8e1769e34a56aa7c03d190db9dc897131',
    timestamp: '1666694855'
  },
  logs: [
    {
      logIndex: '193',
      transactionHash: '0x307c7746df35121d3e4902677bbfe92b9f6a1e53fc2320183c11292d030efe47',
      address: '0xa56f180af0a73d948b6b386616f549279f4d6e4d',
      data: '0x',
      topic0: '0x3bf919a220a0f12ddcaf77fd06ffa4b9c728617774936f0d78b452010319c824',
      topic1: '0x00000000000000000000000051466f61ef8031769b26dfa562bccee00ca31b41',
      topic2: '0x000000000000000000000000dd8c868ee486e2d0778b7c174917a15ce2a4530a',
      topic3: null
    }
  ],
  txs: [],
  txsInternal: [],
  erc20Transfers: [],
  erc20Approvals: [],
  nftApprovals: { ERC1155: [], ERC721: [] },
  nftTransfers: []
}

here is the tag, I’m not sure what should be the webhook, it should contains the events and also the abi

Hey, the following function is not logging anything for some reason. The parseEvent data function is correctly filled in. Any idea why?

app.post("/webhook", async (req, res) => {
  console.log(req.body) 
  console.log("Handled!")
  res.send('Webhook response')
  res.status(200)
  verifySignature(req, config.MORALIS_API_KEY);
  const { data, tagName, eventName }: any = parseEventData(req);
  console.log(data, tagName, eventName, "logged!");
  await parseUpdate(`SFS_${eventName}`, data);
});

Parse event data function:

export function parseEventData(req: any) {

  const json = JSON.parse(req.body)
  try {
    const updates: any = {};
    for (const log of json.logs) {
      const abi = json.abi;
      if (abi) {
        const { update, eventName } = realtimeUpsertParams(abi, log, json.confirmed, json.block);
        return { data: update, tagName: json.tag, eventName }; //json.abi[0].name
      }
    }
  } catch (e: any) {
    console.log(e);
  }
}

realtimeUpsertParams function:

export function realtimeUpsertParams(abi: any, trxData: any, confirmed: any, block: any) {
    const block_number = block.number;
    const address = trxData.address.toLowerCase();
    const transaction_hash = (trxData.transactionHash).toLowerCase();
    const log_index = trxData.logIndex;
    const topics = [trxData.topic0, trxData.topic1, trxData.topic2, trxData.topic3];
    const data = trxData.data;

    const filter = {
        transaction_hash,
        log_index,
    };

    const rest: any = {
        address,
        block_number,
    };

    rest.confirmed = confirmed;

    if (abi) {
        const update = {
            ...filter,
            ...decodeWithEthers(abi, data, topics.filter(t => t !== null)),
            ...rest,
        };
        return { filter, update };
    }

    const update: any = {
        ...filter,
        ...rest,
        data,
        topic0: topics[0],
        topic1: topics[1],
        topic2: topics[2],
        topic3: topics[3],
    };

    return { filter, update };
}

Decode with ethers function:

export function decodeWithEthers(abi: any, data: any, topics: any) {
    try {
        const iface = new ethers.utils.Interface(abi);
        const { args } = iface.parseLog({ data, topics});
        const event = iface.getEvent(topics[0]);
        const decoded: any = {};
        event.inputs.forEach((input: any, index: any) => {
            if (input.type === "uint256") {
            decoded[input.name] = ethers.BigNumber.from(args[index]._hex).toString();
            return;
            }
            decoded[input.name] = args[index];
        });
        return decoded;
    } catch (error) {
        return {};
    }
}

The only thing that successfully logs is console.log(req.body)

you mean that this line doesn’t show?

maybe the latest versions of the files were not loaded?

No, that shows.

This doesn’t show:

An no error nothing to stop that console log?

Nope, no error to stop the console log.

what if you add a try catch before that console.log?

Did that, the issue was I was trying to parse an already parsed object. Fixed it. Now I’m getting the following error:
Error: Cannot use the Master Key, it has not been provided.

How can I use my master key? The error pops up in the parseUpdate function.

I’m using the following syntax which throws errors: {useMasterKey: true})

export async function parseUpdate(tableName: string, object: any) {
  // Check if object exists in db

  const query = new Parse.Query(tableName);
  query.equalTo('transaction_hash', object.transaction_hash);
  const result = await query.first({ useMasterKey: true });
  if (result) {
    // Loop through object's keys
    for (const key in object) {
      result.set(key, object[key]);
    }
    return result?.save(null, { useMasterKey: true });
  } else {
    // Create new object
    const newObject = new Parse.Object(tableName);
    for (const key in object) {
      newObject.set(key, object[key]);
    }
    return newObject.save(null, { useMasterKey: true });
  }
}

When I console.log(data, tagName, eventName), I get eventName undefined.

it looks like somehow the master key should be provided somewhere when parse sdk starts/loads

Do you have your masterKey set in your server’s .env file?

For Moralis.Streams.parsedLogs, it seems to be using property names of webhookData and tag. There is some test data here.

Hey, I managed to get it to work, thanks!

1 Like

Hey Tom I’m struggling with the same thing! Pls can you tell me how you got it to work?