<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Boboye's blog]]></title><description><![CDATA[Boboye's blog]]></description><link>https://boboyeak.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 31 Aug 2026 14:53:01 GMT</lastBuildDate><atom:link href="https://boboyeak.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Listen For ERC20 Token Transfers To A Specific Wallet Using Moralis Streams and NodeJS]]></title><description><![CDATA[Introduction
Moralis is an organization whose products have been incredibly helpful to web3 developers and web2 developers who want to work with web3 concepts but one product that has particularly caught my eye is Moralis Streams. It is a tool for li...]]></description><link>https://boboyeak.hashnode.dev/how-to-listen-for-erc20-token-transfers-to-a-specific-wallet-using-moralis-streams-and-nodejs</link><guid isPermaLink="true">https://boboyeak.hashnode.dev/how-to-listen-for-erc20-token-transfers-to-a-specific-wallet-using-moralis-streams-and-nodejs</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[moralis]]></category><category><![CDATA[ERC20]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Web3]]></category><dc:creator><![CDATA[Akinboboye Akinwande]]></dc:creator><pubDate>Thu, 13 Apr 2023 10:12:40 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p><a target="_blank" href="http://moralis.io">Moralis</a> is an organization whose products have been incredibly helpful to web3 developers and web2 developers who want to work with web3 concepts but one product that has particularly caught my eye is Moralis Streams. It is a tool for listening for activity on EVM blockchains and triggering actions off-chain based on those transactions. It can be used in implementing the receiving of payment in tokens for e-commerce websites, setting up email or text message alerts for your wallet etc.</p>
<p>In this article, I will be tutoring you on how to listen for USDT transfers into a particular wallet address on the Ethereum mainnet and how to extract commonly needed data from the request body of the Moralis stream call to your webhook like the value of the transfer, the time it occurred, the chain ID the chain on which the transaction occurred etc.</p>
<h1 id="heading-setting-up-a-moralis-stream">Setting Up a Moralis Stream</h1>
<p>Setting up a stream can be either done programmatically or using the User Interface on the Moralis dashboard. I will be making use of the User Interface in this tutorial. Setting up programmatically is suitable for use when you want to be able to dynamically create and delete streams.</p>
<p>Follow the steps below to setup a Moralis stream</p>
<ol>
<li><p>Go to <a target="_blank" href="http://moralis.io">moralis.io</a> and either login or signup then go to your dashboard.</p>
</li>
<li><p>Click on Web3 APIs and copy your api key. You will be needing this later.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681297352485/7baf9a25-5ae0-43a4-ba0a-c32957445245.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Now go to the Streams section. (This is where it gets fun)</p>
</li>
<li><p>Below is the user interface for managing your Moralis streams. You can choose to create your streams programmatically. Checkout the moralis streams documentation(<a target="_blank" href="https://docs.moralis.io/streams-api/evm">https://docs.moralis.io/streams-api/evm</a>) and Github(<a target="_blank" href="https://github.com/MoralisWeb3/streams-beta">https://github.com/MoralisWeb3/streams-beta</a>).</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681297474072/fa183a55-a083-4481-b035-0b738f0a5d6d.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Click on “create a new stream”</p>
</li>
<li><p>Enter the address of the token contract you want to listen to. For USDT on the ethereum mainnet, it is <em>0xdAC17F958D2ee523a2206206994597C13D831ec7</em></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681297551275/fd47c890-0eb7-4f0f-8a7e-8ccda8ac663d.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Fill in the webhook you want moralis to call when the token is received by the wallet as well as the stream description and  an identifiable tag for the stream. Switch from Demo to Prod. If there is an issue with posting to the webhook url, check the webhook URL text thoroughly. The webhook should return status 200 or else it will not work.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681297834143/8e75c1df-519f-43c8-a997-ae8e8e637857.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Select the network(In this case Ethereum mainnet).</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681297913051/59782fba-7912-4fc7-9308-6efe508d58b4.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Select “contract interactions” under stream options because ERC20 token transfers are token contract interactions.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681297967116/a71cf2d1-8759-445c-abb1-d49db7acc497.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Fill in the abi for ERC20 contract standard. This is publicly available. You can find it here (<a target="_blank" href="https://github.com/Boboye-Ak/project-constants/blob/main/erc20Abi.json">https://github.com/Boboye-Ak/project-constants/blob/main/erc20Abi.json</a>). Copy the entire content of the file and paste it in the field provided.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681298027505/cc55d7d5-0ab8-4362-b485-820984c1d6fd.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Select "Transfer" from among the topics to make sure the stream is only triggered by transfer operations.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681298075539/db5dbd97-366e-463a-97a8-7bd1eb0f7a76.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Under the filter section, select Transfer as topic,  add an “equal” filter, set “to” as the variable and enter the recipient address of the transfer as value then click "update stream".</p>
</li>
</ol>
<p>The stream is now setup to send a post request to your webhook whenever USDT is sent to the wallet in the filter. I will now show you how to setup a middleware to use in NodeJS/Express to extract data from and secure the webhook.</p>
<h1 id="heading-setting-up-middleware-for-securing-and-extracting-data-from-moralis-streams"><strong>Setting Up Middleware For Securing And Extracting Data From Moralis Streams</strong></h1>
<ol>
<li><p>Install moralis SDK in your project with <code>npm install moralis</code> Import into your middleware file and initialize it using the API key you got from your <a target="_blank" href="http://moralis.io">moralis.io</a> dashboard in step 2 of the previous section.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> Moralis = <span class="hljs-built_in">require</span>(<span class="hljs-string">"moralis"</span>).default;
 <span class="hljs-keyword">const</span> MORALIS_API_KEY=process.env.MORALIS_API_KEY

 <span class="hljs-comment">//Initiating Moralis</span>
 Moralis.start({
   <span class="hljs-attr">apiKey</span>:MORALIS_API_KEY ,
 });
</code></pre>
</li>
<li><p>Create a middleware function block named erc20Middleware and follow the next steps inside the code block.</p>
</li>
<li><p>The code block below protects the webhook from intruders that might try to simulate a moralis stream to commit fraud.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> erc20MiddleWare = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
   <span class="hljs-keyword">const</span> { body, headers } = req;
   <span class="hljs-keyword">try</span> {
     <span class="hljs-comment">//Verify Moralis signature</span>
     <span class="hljs-keyword">await</span> Moralis.Streams.verifySignature({
       body,
       <span class="hljs-attr">signature</span>: headers[<span class="hljs-string">"x-signature"</span>],
     });
   } <span class="hljs-keyword">catch</span> (e) {
     <span class="hljs-built_in">console</span>.log(
       <span class="hljs-string">"Not Moralis!... An intruder attempted to send a request to the server"</span>
     );
     <span class="hljs-built_in">console</span>.log(e);
     <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">401</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Not verified as moralis stream"</span> });
   }
 }
</code></pre>
</li>
<li><p>Extract the vital data from the request body and store them in an object you add to the request object before passing to the next middleware as shown below. You can now export the middleware.</p>
</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Moralis = <span class="hljs-built_in">require</span>(<span class="hljs-string">"moralis"</span>).default;

<span class="hljs-comment">//Initiating Moralis</span>
Moralis.start({
  <span class="hljs-attr">apiKey</span>: process.env.MORALIS_API_KEY,
});

<span class="hljs-keyword">const</span> erc20MiddleWare = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
  <span class="hljs-keyword">const</span> { body, headers } = req;
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">//Verify Moralis signature</span>
    <span class="hljs-keyword">await</span> Moralis.Streams.verifySignature({
      body,
      <span class="hljs-attr">signature</span>: headers[<span class="hljs-string">"x-signature"</span>],
    });
  } <span class="hljs-keyword">catch</span> (e) {
    <span class="hljs-built_in">console</span>.log(
      <span class="hljs-string">"Not Moralis!... An intruder attempted to send a request to the server"</span>
    );
    <span class="hljs-built_in">console</span>.log(e);
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">401</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Not verified as moralis stream"</span> });
  }
  <span class="hljs-keyword">const</span> streamId = body.streamId;
  <span class="hljs-keyword">const</span> isConfirmed = body.confirmed; <span class="hljs-comment">//For each transaction, the webhook is called twice. Once with the value of confirmed false, then a few minutes later, another with value true(After a few block confirmations.)</span>
  <span class="hljs-keyword">const</span> blockNumber = body.block.number;
  <span class="hljs-keyword">const</span> blockTime = body.block.timestamp;
  <span class="hljs-keyword">let</span> eventTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-built_in">parseInt</span>(blockTime) * <span class="hljs-number">1000</span>).toString();<span class="hljs-comment">//Number of milliseconds since January 1st 1970</span>
  <span class="hljs-keyword">const</span> txHash = body?.logs[<span class="hljs-number">0</span>]?.transactionHash?.toLowerCase();
  <span class="hljs-keyword">const</span> chainId = body.chainId;
  <span class="hljs-keyword">const</span> amountWithDecimals = <span class="hljs-built_in">parseFloat</span>(body.erc20Transfers[<span class="hljs-number">0</span>].valueWithDecimals);
  <span class="hljs-keyword">const</span> amountWithoutDecimals = <span class="hljs-built_in">parseFloat</span>(body.erc20Transfers[<span class="hljs-number">0</span>].value);
  <span class="hljs-keyword">const</span> tokenAddress =
    body.erc20Transfers[<span class="hljs-number">0</span>].contract || body.erc20Transfers[<span class="hljs-number">0</span>].tokenAddress; 
  <span class="hljs-keyword">const</span> tokenDecimals = body.erc20Transfers[<span class="hljs-number">0</span>].tokenDecimals;
  <span class="hljs-keyword">let</span> response;
  <span class="hljs-keyword">try</span> {
    response = <span class="hljs-keyword">await</span> Moralis.EvmApi.transaction.getTransaction({
      <span class="hljs-attr">transactionHash</span>: txHash,
      <span class="hljs-attr">chain</span>: chainId,
    });
  } <span class="hljs-keyword">catch</span> (e) {
    <span class="hljs-built_in">console</span>.log(e);
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"error getting transaction"</span> });
  }
  <span class="hljs-keyword">const</span> senderAddress = response.data.from_address.toLowerCase();
  <span class="hljs-keyword">const</span> data = {
    isConfirmed,
    blockNumber,
    blockTime,
    eventTime,
    txHash,
    chainId,
    amountWithDecimals,
    senderAddress,
    tokenDecimals,
    tokenAddress,
    amountWithoutDecimals,
    streamId,
  };
  req.data = data;
  next();
};

<span class="hljs-built_in">module</span>.exports = { erc20MiddleWare };
</code></pre>
<p>You can console.log the entire request body and rifle through for any data you might find useful. A sample of the request body can be found in the stream settings page of your Moralis dashboard or in the Moralis Streams Github(<a target="_blank" href="https://github.com/MoralisWeb3/streams-beta">https://github.com/MoralisWeb3/streams-beta</a>).</p>
<p>The code above can be found here(<a target="_blank" href="https://github.com/Boboye-Ak/project-constants/blob/main/webhooksMiddleware.js">https://github.com/Boboye-Ak/project-constants/blob/main/webhooksMiddleware.js</a>).</p>
]]></content:encoded></item></channel></rss>