Duplicate events being triggered

We are using moralis stream to listen to events in order for our backend to call certain methods. For some reason we are seeing transactions duplicate. In the following code, “buySocialImpact” should only be called once, yet we can see muttiple buys occuring.

app.post('/stream', async (req, res) => {
  try {
    const { confirmed, erc20Transfers } = req.body;

    if (confirmed) {
      return res.status(200).json({ message: 'We just need unconfirmed transaction.' });
    }

    // Process alt token impact
    for (let i = 0; i < erc20Transfers.length; i++) {
      const item = erc20Transfers[i];

      // Return if transaction hash is undefined
      if (!item.transactionHash) {
        return;
      }

      // Return if self call
      if (SELF_AVAILABLE_CONTRACTS.includes(item.from.toLowerCase())) {
        return;
      }

      // Return if not whitelisted token
      if (!TOKEN_WHITELIST.includes(item.tokenSymbol)) {
        return;
      }

      // Return if 0 value sent or if receiver is not SIP contract
      if (item.value == 0 || item.to.toLowerCase() != sipContract.address.toLowerCase()) {
        return;
      }

      const { from, value, contract: token, tokenName, tokenSymbol, tokenDecimals, transactionHash } = item;

      // Check if the funds correctly received
      const sendTx = await provider.getTransaction(transactionHash);
      const sendReceipt = await sendTx.wait();
      if (sendReceipt.status == 0) {
        return;
      }
      console.log(erc20Transfers.length, erc20Transfers);
      console.log(`Registering a new impact...`);

      const gasPrice = await provider.getGasPrice();
      const buyTx = await sipContract.connect(operator).buySocialImpact(from, token, value, { gasPrice })
      const buyReceipt = await buyTx.wait();

      const { impactId, customer } = buyReceipt.events[0].args;

      // Send a receipt email to customer
      try {
        const email = await getEmailByWalletAddress(db, 'donors', from);
        await sendEmail(email, `You just bought an social impact ${formatUnits(value, tokenDecimals)} ${tokenSymbol}(${tokenName}) successfully!`);
      } catch (err) {
        console.log(err);
      }

      todayDonations.push({ ...buyReceipt.events[0].args, tokenDecimals, tokenSymbol });

      // for test currently
      console.log('Sending impacts list to charity partners.');
      const [peopleFeedMessage, treesPlantMessage, animalsFeedMessage] = getCharityMessages(todayDonations);
      const notificationText = '\n\nPlease accept the each donations above with the impactId on charity dashboard.';
      sendEmail(process.env.PEOPLE_FEED_PARTNER_EMAIL, peopleFeedMessage + notificationText);
      sendEmail(process.env.TREES_PLANT_PARTNER_EMAIL, treesPlantMessage + notificationText);
      sendEmail(process.env.ANIMALS_FEED_PARTNER_EMAIL, animalsFeedMessage + notificationText);

      // run a full test process
      const isAllAccepted = await accept(impactId);
      // if (isAllAccepted) {
      //   const isAllProceed = await processImpact([impactId]);
      //   if (!isAllProceed) {
      //     await admit(impactId);
      //   }
      // }

      console.log(' >> ', impactId.toString(), customer, formatUnits(value, tokenDecimals), tokenSymbol);
    }

    res.send('Proceed successfully.');
  } catch (err) {
    console.error('Error:', err.message);
    res.status(405).json({ message: err.message });
  }
});

Result

ubuntu@ip-172-31-68-96:~/sip/SIP-backend$ yarn start
yarn run v1.22.19
$ node ./src/index.js
Running on port 3000
1 [
  {
    transactionHash: '0xde5dd76294ea20fcec8d18dbc5d5ccf49efd73c3a06d3bc387baa0fc3363869c',
    logIndex: '234',
    contract: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174',
    from: '0xea904dddefda764893d2d4fa1e9040f3c4741cad',
    to: '0x050de9ccaa981dbfb629caece5627c8ac27a4e09',
    value: '1000000',
    tokenName: 'USD Coin (PoS)',
    tokenSymbol: 'USDC',
    tokenDecimals: '6',
    valueWithDecimals: '1'
  }
]
confirmed: false
Registering a new impact...
Email not found.
Sending impacts list to charity partners.
Accepting an impact 52
 >> All charities accepted an impact 52 successfully!
 >>  52 0xeA904DdDEfdA764893d2D4fa1E9040f3c4741CaD 1.0 USDC
1 [
  {
    transactionHash: '0xde5dd76294ea20fcec8d18dbc5d5ccf49efd73c3a06d3bc387baa0fc3363869c',
    logIndex: '234',
    contract: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174',
    from: '0xea904dddefda764893d2d4fa1e9040f3c4741cad',
    to: '0x050de9ccaa981dbfb629caece5627c8ac27a4e09',
    value: '1000000',
    tokenName: 'USD Coin (PoS)',
    tokenSymbol: 'USDC',
    tokenDecimals: '6',
    valueWithDecimals: '1'
  }
]
confirmed: false
Registering a new impact...
Email not found.
Sending impacts list to charity partners.
Accepting an impact 53
 >> All charities accepted an impact 53 successfully!
 >>  53 0xeA904DdDEfdA764893d2D4fa1E9040f3c4741CaD 1.0 USDC

Contract address found here: https://polygonscan.com/address/0x050De9CCaa981DbfB629CAeCE5627c8ac27A4e09

Any idea why or what could be triggering this event to fire more than once?

I’m thinking that for unconfirmed transactions that it could happen to send the request twice if there is a reorg. Maybe you can try to check if you already received that event before and ignore it if it is a duplicate (you still have to return status code 200 because if you don’t return status code 200 then you will receive the same request again as a retry)

What is the delay in seconds between those 2 requests? How often it happens?

There are a few seconds between buy methods being called, can you review the code above where 200 response is returned if confirmed?

I don’t know what is to review here

We are already checking here

I don’t know on what you are referring.
I wanted to say to check if there is a duplicate so that it doesn’t affect your code logic further if it happens to be a duplicate

Im referring to checking duplicate

You are already checking if there are duplicates?