What is Best Practice for Listening/Subscribing to Class Entries?

My Goal Better Explained:
I want to ‘Watch + Sync’ an address and wish to have a function fired in realtime to send i.e. ‘an email’ when a tx in relation to that address happens.

I can currently achieve this whole aim, but the current method I’m using breaks and appears not best practice (as we’ve discussed).

Current Method:
The address provided by a user is saved into a class called ‘WatchedEthAddress’.
‘Watch + Sync’ cloud function initiates—saving latest txs—that include the address in to ‘EthTransactions’ (query monitors ‘to_address’ in this example).

CloudFile.js:


  Moralis.Cloud.run("watchEthAddress", {
    address,
    sync_historical: false,
  });

  // create query
  const query = new Moralis.Query("EthTransactions");
  query.equalTo("to_address", address);

  // subscribe to query updates ** add this**
  const subscription = await query.subscribe();
  handleNewTransaction(subscription);

  // run query
  const results = await query.find();
  logger.info("user transactions:", results);

  async function handleNewTransaction(subscription) {
    // log each new transaction
    subscription.on("create", function (data) {
      // log alert
      logger.info("ALERT: New Transaction");
      logger.info(data);
      logger.info("---");

      // send alert here: via email i.e. SendGrid

    });
  }
});

Main Question:
How do I ‘listen/subscribe’ to the ‘EthTransactions’ table when it adds a new entry so I can then utilise the new row’s data in an asynchronous alert?

Let me know if this still isn’t explained explicitly what I need. :slight_smile:

1 Like

Hey @ashbeech

You cant subscribe on events this way via cloud functions. Also you shouldn’t run "watchEthAddress" cloud function each time when you start listening to the events. If a wallet already exists in WatchedEthAddress - there is no need to add it again.

Instead of logger.info(data) use logger.info(JSON.strinigify(data)) for be able to see data in the logs.

In your case you need to use aftersave

Moralis.Cloud.afterSave("EthTransactions", async function(request) {
  const address = "0x...1"
  const to_address= request.object.get("to_address");
  if (to_address == address) {
      logger.info("ALERT: New Transaction");
      logger.info("To address" + to_address);
      logger.info(JSON.strinigify(request.object));
      logger.info("---");
  }
});

To clarify, watchEthAddress isn’t getting run each time; a conditional check is run to ensure it doesn’t. Just didn’t include that bit. :slight_smile:

  // find out if address is already watched
  const countQuery = new Moralis.Query("WatchedEthAddress");
  countQuery.equalTo("address", address);
  const watchCount = await countQuery.count();

  if (watchCount > 0) {
    // already watched don't sync again
    return null;
  }
1 Like

You cant subscribe on events this way via cloud functions.

Is the subscription query in CloudFile.js not best practice or do you mean the handling on firing of the event?

// create query
  const query = new Moralis.Query("EthTransactions");
  query.equalTo("to_address", address);

  // subscribe to query updates ** add this**
  const subscription = await query.subscribe();
  handleNewTransaction(subscription);

CloudFile.js is a function in the Cloud code right? If you will call it will work only once. It’s a bad practise to create subscribe() in cloud code. Cloud functions are needed to call them and they return the result. It will retun you info from subscribe only once.

1 Like

In your case you need to use aftersave. I’ve sent you an example above. For example you can create a new table in the database “AddressesToSubscribe”, run for them “watchEthAddress” and then after creating transactions in EthTransactions check if that address is in “AddressesToSubscribe”

Also you need to add check for transaction status:

const confirmed = request.object.get("confirmed");
  if (confirmed) {
   //Alert
  }

Got you. Yes, this is Cloud Function javascript.

So, what is the best practice to listen for transactions on an address and send out alerts asynchronously (user no longer using dapp actively)?

I’m not sure I understood your question :sweat_smile:

1 Like

No worries @Yomoo, I’ve just updated the initial post in the thread; I should have explained more explicitly.

I meant the last question :sweat_smile:.

Where do you want to use “alerts”? For displaying info in the front end or you want just send them somewhere(for example email)?

1 Like

I’m designing with the aim to send push/telegram/twitter/email alerts.

In case if you dont want to process this information for showing it on the frontend in real time the best solution is to use aftersave trigger

So, aftersave is the best solution for your case

Just reading-up on the docs (https://docs.moralis.io/moralis-server/cloud-code/triggers#aftersave) and does appear to be promising solution.

Implementing now.

I will update the thread, but cheers for your help in the meantime.

1 Like

It will be very cool if you will share the solution to your question with the community. :mage:
Feel free to ask me any questions

Happy BUIDLing :man_mechanic:

1 Like

Happily BUIDLing and sharing my solution here, as promised.

1 Like