<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Envio</title>
    <description>The latest articles on DEV Community by Envio (@envio).</description>
    <link>https://dev.to/envio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1208820%2F6d83bf5b-2025-4bab-a10e-7b023a7813c2.png</url>
      <title>DEV Community: Envio</title>
      <link>https://dev.to/envio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/envio"/>
    <language>en</language>
    <item>
      <title>Envio Developer Update May 2026</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Fri, 10 Jul 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/envio/envio-developer-update-may-2026-44h6</link>
      <guid>https://dev.to/envio/envio-developer-update-may-2026-44h6</guid>
      <description>&lt;p&gt;The May 2026 update rounds up the latest from Envio — fresh features, performance improvements and ecosystem news across HyperIndex, HyperSync and Envio Cloud. Here's everything that landed this month.&lt;/p&gt;

&lt;p&gt;👉 Read the full update on the Envio blog: &lt;a href="https://docs.envio.dev/blog/envio-developer-update-may-2026" rel="noopener noreferrer"&gt;https://docs.envio.dev/blog/envio-developer-update-may-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Envio is Web3's backend — the fastest, most flexible way to index and query blockchain data. Explore HyperIndex, HyperSync, HyperRPC and Envio Cloud at &lt;a href="https://envio.dev" rel="noopener noreferrer"&gt;https://envio.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>indexing</category>
      <category>news</category>
    </item>
    <item>
      <title>Envio Developer Update April 2026</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Fri, 10 Jul 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/envio/envio-developer-update-april-2026-2emk</link>
      <guid>https://dev.to/envio/envio-developer-update-april-2026-2emk</guid>
      <description>&lt;p&gt;Here's what shipped at Envio in April 2026 — new features, performance gains and ecosystem updates across HyperIndex, HyperSync and Envio Cloud. A quick read to catch up on everything new.&lt;/p&gt;

&lt;p&gt;👉 Read the full update on the Envio blog: &lt;a href="https://docs.envio.dev/blog/envio-developer-update-april-2026" rel="noopener noreferrer"&gt;https://docs.envio.dev/blog/envio-developer-update-april-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Envio is Web3's backend — the fastest, most flexible way to index and query blockchain data. Explore HyperIndex, HyperSync, HyperRPC and Envio Cloud at &lt;a href="https://envio.dev" rel="noopener noreferrer"&gt;https://envio.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>indexing</category>
      <category>news</category>
    </item>
    <item>
      <title>How to Build an Open Source RWA Stablecoin Dashboard</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Fri, 10 Jul 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/envio/how-to-build-an-open-source-rwa-stablecoin-dashboard-4nc9</link>
      <guid>https://dev.to/envio/how-to-build-an-open-source-rwa-stablecoin-dashboard-4nc9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0r1nqkee7zlzuckoii4d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0r1nqkee7zlzuckoii4d.png" alt="How to Build an Open Source RWA Stablecoin Dashboard" width="799" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TL;DR&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The RWA dashboard is open source and backed by an indexer you can run yourself, starting with stablecoins, with the live dashboard at rwaradar.io.&lt;/li&gt;
&lt;li&gt;On the stablecoin side it surfaces total supply, transfer count, transfer amount and volume, mint and burn amounts, and daily snapshots of each.&lt;/li&gt;
&lt;li&gt;Every metric falls out of Transfer events, since mints and burns show up as transfers to and from the zero address.&lt;/li&gt;
&lt;li&gt;USDT is the exception, so the indexer reads its Issue and Redeem events directly for clean mint and burn numbers.&lt;/li&gt;
&lt;li&gt;The transfer and mint/burn logic lives in shared handlers, so every token reuses the same paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real-world assets have gone from a niche thing a few companies were poking at to one of the biggest sectors in crypto over the last few years. This post isn't a market take, though. At Envio, my job is to build technical demos that actually use our products, so I decided to build something real, an open-source RWA dashboard backed by a HyperIndex metrics indexer you can run yourself. If you want to check whether the data lines up, or you want to build something similar, the whole thing is there to fork.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why stablecoins first
&lt;/h2&gt;

&lt;p&gt;RWA is a huge bucket, so I had to pick a starting point. Stablecoins were the obvious one.&lt;/p&gt;

&lt;p&gt;The goal for the stablecoin side of the dashboard is to surface the metrics that actually tell you something. Total supply, transfer count, transfer amount and volume, mint and burn amounts, and daily snapshots of all of it. Nothing exotic, just the numbers you'd want if you were tracking how a stablecoin is actually being used onchain.&lt;/p&gt;

&lt;p&gt;Now that we've covered what the dashboard is supposed to do, let's get into the indexer and the logic behind it. That's the part that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The indexer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Wiring up the handlers
&lt;/h3&gt;

&lt;p&gt;I'm tracking a set of major stablecoins across a dozen chains to start. The full list lives in the &lt;a href="https://github.com/enviodev/rwa/blob/main/indexers/rwa-tokens/config.yaml" rel="noopener noreferrer"&gt;config.yaml&lt;/a&gt; if you want to see exactly which ones.&lt;/p&gt;

&lt;p&gt;For most of them, tracking &lt;code&gt;Transfer&lt;/code&gt; events is enough. Every metric we care about falls out of transfers, including mints and burns, since those show up as transfers from or to the zero address. USDT is the exception. Its issue and redeem don't emit Transfers, so the indexer tracks its Issue and Redeem events directly. Bridged USDT on other chains does emit zero-address Transfers, so the Transfer handler covers it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;indexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Stablecoins&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Transfer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;handleTransfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;},);&lt;/span&gt;&lt;span class="nx"&gt;indexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USDT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Transfer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;handleTransfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;},);&lt;/span&gt;&lt;span class="nx"&gt;indexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USDT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Issue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;handleSupplyChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;},);&lt;/span&gt;&lt;span class="nx"&gt;indexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USDT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Redeem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;handleSupplyChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;burn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;},);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The point of pulling the logic out into &lt;code&gt;handleTransfer&lt;/code&gt; and &lt;code&gt;handleSupplyChange&lt;/code&gt; is reuse. Every token shares the same transfer logic, and the mint/burn path is shared too. The handlers themselves stay thin and just call into the abstracted functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;handleTransfer&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is the workhorse. It updates everything tied to a transfer.&lt;/p&gt;

&lt;p&gt;First it does the fetching and parsing. It pulls the event params to derive the IDs, and grab the current state of the entities it's about to touch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleTransfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;srcAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EvmOnEventContext&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chainId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;srcAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;midnightTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isMint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;ZERO_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isBurn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;ZERO_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tokenAddress&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dayDataId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentDayId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fromBalanceId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toBalanceId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;activeAddrId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentDayId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;existingToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fromBalance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toBalance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existingActiveAddr&lt;/span&gt;&lt;span class="p"&gt;,]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TokenDayData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dayDataId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isMint&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HolderBalance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fromBalanceId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isBurn&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HolderBalance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toBalanceId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isMint&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DailyActiveAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;activeAddrId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;),]);&lt;/span&gt; &lt;span class="c1"&gt;// continue the snapshot logic}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The snapshot logic is where the only real trick is. Blocks give us a UTC timestamp, so to know whether a transfer belongs to a new day we just check whether its timestamp crossed midnight relative to the last day I recorded. If it's a new day, I start tracking a fresh &lt;code&gt;TokenDayData&lt;/code&gt; entity. Everything else is the same shape as before: if it's a mint, bump supply up; if it's a burn, bump it down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastDayId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;existingToken&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;lastDayId&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isNewDay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;lastDayId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isNewDay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DailyActiveAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getWhere&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;token_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_eq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;stale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DailyActiveAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteUnsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isNewActiveAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isMint&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isNewDay&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;existingActiveAddr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newTotalSupply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;existingToken&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;totalSupply&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isMint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;newTotalSupply&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isBurn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;newTotalSupply&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newTotalSupply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastDayId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt;&lt;span class="p"&gt;,});&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TokenDayData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dayDataId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;token_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;midnightTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dailyTotalSupply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newTotalSupply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dailyMintAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dailyMintAmount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isMint&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;dailyBurnAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dailyBurnAmount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isBurn&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;dailyTransferAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dailyTransferAmount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dailyTransferCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dailyTransferCount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dailyActiveAddresses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dailyActiveAddresses&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isNewActiveAddr&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),});&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isMint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HolderBalance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fromBalanceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;token_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;holder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fromBalance&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;firstTransferTimestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fromBalance&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;firstTransferTimestamp&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;lastTransferTimestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;});}&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isBurn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HolderBalance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;toBalanceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;token_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;holder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toBalance&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;firstTransferTimestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;toBalance&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;firstTransferTimestamp&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;lastTransferTimestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;});}&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isNewActiveAddr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DailyActiveAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;activeAddrId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;token_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;});}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;One thing worth calling out: on a new day I clear out the stale &lt;code&gt;DailyActiveAddress&lt;/code&gt; entries for the token. Active addresses are a per-day count, so they don't carry over. Skipping mint senders from the active-address count is deliberate too, since the zero address isn't a real participant.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;handleSupplyChange&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This one only exists for USDT's &lt;code&gt;Issue&lt;/code&gt; and &lt;code&gt;Redeem&lt;/code&gt;. The logic is mostly a slimmer version of handleTransfer, with one extra input, direction. The events themselves just hand you an amount, so the handler is the thing that decides whether it's a mint or a burn and passes that down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleSupplyChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;srcAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EvmOnEventContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;burn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chainId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;srcAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;midnightTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tokenAddress&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dayDataId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentDayId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;existingToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TokenDayData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dayDataId&lt;/span&gt;&lt;span class="p"&gt;),]);&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastDayId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;existingToken&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;lastDayId&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isNewDay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;lastDayId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isNewDay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DailyActiveAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getWhere&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;token_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_eq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;stale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DailyActiveAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteUnsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newTotalSupply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;existingToken&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;totalSupply&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;newTotalSupply&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nx"&gt;newTotalSupply&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;totalSupply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newTotalSupply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastDayId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentDayId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TokenDayData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dayDataId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;token_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;midnightTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dailyTotalSupply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newTotalSupply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dailyMintAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dailyMintAmount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mint&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;dailyBurnAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dailyBurnAmount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;burn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;dailyTransferAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dailyTransferAmount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dailyTransferCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dailyTransferCount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dailyActiveAddresses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;existingDayData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;dailyActiveAddresses&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;});}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Notice it leaves the transfer fields untouched and only moves supply, mint, and burn. Issue and Redeem aren't transfers, so they shouldn't inflate transfer counts.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;That's the first step of the RWA dashboard, one indexer, with the logic and setup laid out. Tokenised US Treasuries, with NAV and yield tracking, are already in the same indexer, and I'll walk through those next.&lt;/p&gt;

&lt;p&gt;If you want to dig into the code, the &lt;a href="https://github.com/enviodev/rwa/tree/main/indexers/rwa-tokens" rel="noopener noreferrer"&gt;stablecoins indexer is here&lt;/a&gt;, and the live dashboard is at &lt;a href="https://rwaradar.io/" rel="noopener noreferrer"&gt;rwaradar.io&lt;/a&gt;. If you're building in the RWA space and want to compare notes, reach out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How does the indexer track stablecoin mints and burns?
&lt;/h3&gt;

&lt;p&gt;For most of the stablecoins, tracking Transfer events is enough. Mints and burns fall out of transfers, since they show up as transfers from or to the zero address, so total supply moves up on a mint and down on a burn without needing dedicated events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is USDT handled differently from the other stablecoins?
&lt;/h3&gt;

&lt;p&gt;USDT is the exception. To get clean mint and burn numbers for it, the indexer tracks its Issue and Redeem events directly through handleSupplyChange, which reads the amount and decides whether it's a mint or a burn. It leaves the transfer fields untouched and only moves supply, mint, and burn, since Issue and Redeem aren't transfers and shouldn't inflate transfer counts.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does the indexer decide when a new day begins for the snapshots?
&lt;/h3&gt;

&lt;p&gt;Blocks give a UTC timestamp, so the handler checks whether a transfer's timestamp crossed midnight relative to the last day it recorded, deriving the current day as Math.floor(timestamp / 86400). When it's a new day, it starts tracking a fresh TokenDayData entity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are mint senders skipped in the daily active address count?
&lt;/h3&gt;

&lt;p&gt;Active addresses are a per-day count, so they don't carry over, and on a new day the stale entries for the token are cleared. Mint senders are skipped deliberately, since a mint comes from the zero address, which isn't a real participant and would otherwise misrepresent daily activity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are handleTransfer and handleSupplyChange pulled into shared functions?
&lt;/h3&gt;

&lt;p&gt;The point is reuse. Every token shares the same transfer logic, and the mint and burn path is shared too, so the event handlers stay thin and just call into the abstracted functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  What metrics does the stablecoin dashboard surface?
&lt;/h3&gt;

&lt;p&gt;It surfaces total supply, transfer count, transfer amount and volume, mint and burn amounts, and daily snapshots of all of it, which are the numbers that show how a stablecoin is actually being used onchain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build With Envio
&lt;/h2&gt;

&lt;p&gt;Envio is a real-time multichain blockchain indexer that turns onchain events into a queryable GraphQL API. Supports any EVM chain, plus Solana and Fuel. Use Envio Cloud or self-host. If you're building onchain, come talk to us about your data needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://envio.beehiiv.com/subscribe?utm_source=envio.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=new-post" rel="noopener noreferrer"&gt;Subscribe to our newsletter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://envio.dev/" rel="noopener noreferrer"&gt;Website&lt;/a&gt; | &lt;a href="https://twitter.com/envio_indexer" rel="noopener noreferrer"&gt;X&lt;/a&gt; | &lt;a href="https://discord.gg/envio" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; | &lt;a href="https://t.me/+5mI61oZibEM5OGQ8" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt; | &lt;a href="https://github.com/enviodev" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://www.youtube.com/channel/UCR7nZ2yzEtc5SZNM0dhrkhA" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt; | &lt;a href="https://www.reddit.com/user/Envio_indexer" rel="noopener noreferrer"&gt;Reddit&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorials</category>
    </item>
    <item>
      <title>Envio vs The Graph</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Fri, 10 Jul 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/envio/envio-vs-the-graph-m0c</link>
      <guid>https://dev.to/envio/envio-vs-the-graph-m0c</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frr5fgdxnn0arv2bbj5vm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frr5fgdxnn0arv2bbj5vm.png" alt="Envio vs The Graph" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Envio HyperIndex and The Graph take different approaches to indexing EVM data. This is a sourced, head-to-head comparison of the two.&lt;/li&gt;
&lt;li&gt;Sync speed is the clearest gap. In the independent &lt;a href="https://docs.envio.dev/docs/HyperIndex/benchmarks" rel="noopener noreferrer"&gt;Sentio benchmark&lt;/a&gt;, HyperIndex finished the Uniswap V2 Factory workload in 8 seconds against 19 minutes for The Graph, 142x faster.&lt;/li&gt;
&lt;li&gt;HyperIndex handlers are standard TypeScript in Node with any npm package. The Graph uses AssemblyScript compiled to WebAssembly.&lt;/li&gt;
&lt;li&gt;HyperIndex indexes every chain from one &lt;code&gt;config.yaml&lt;/code&gt;. The Graph deploys one subgraph per chain.&lt;/li&gt;
&lt;li&gt;If you do decide to switch, migration is a &lt;a href="https://docs.envio.dev/docs/HyperIndex/migration-guide" rel="noopener noreferrer"&gt;documented flow&lt;/a&gt;, your existing subgraph queries keep working through Envio's query converter, and teams like Katana, Revert Finance, and Sablier have already moved. For the wider field, see &lt;a href="https://docs.envio.dev/blog/best-blockchain-indexers-2026" rel="noopener noreferrer"&gt;Best Blockchain Indexers in 2026&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most teams reach for The Graph first, because subgraphs are the incumbent way to index EVM data, the approach most developers already know. The questions tend to start later, when syncs drag, a schema change means a long backfill, or you need the same data across several chains. That is usually when Envio HyperIndex comes up.&lt;/p&gt;

&lt;p&gt;This is a direct comparison of the two. We put them head to head on what actually separates them, sync speed, the language you write handlers in, multichain support, and reorg handling, then cover what switching involves. For the wider field of indexers, our &lt;a href="https://docs.envio.dev/blog/best-blockchain-indexers-2026" rel="noopener noreferrer"&gt;2026 indexer comparison&lt;/a&gt; ranks Envio, The Graph, Goldsky, SubQuery, Subsquid, Ormi, and Ponder side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sync Speed
&lt;/h2&gt;

&lt;p&gt;Speed is the clearest difference, and it is well documented. HyperIndex pulls data through &lt;a href="https://docs.envio.dev/docs/HyperSync/overview" rel="noopener noreferrer"&gt;HyperSync&lt;/a&gt;, Envio's Rust data engine, which delivers up to 2000x faster data access than standard RPC. HyperIndex can also index over a standard RPC endpoint, either for chains HyperSync does not yet support or if you would rather not use it. The Graph reads through standard RPC only.&lt;/p&gt;

&lt;p&gt;In the independent Sentio Uniswap V2 Factory benchmark, HyperIndex finished in 8 seconds against 19 minutes for The Graph, 142x faster. On the Sentio LBTC workload, it finished in 3 minutes against 3 hours 9 minutes. Full methodology is on the &lt;a href="https://docs.envio.dev/docs/HyperIndex/benchmarks" rel="noopener noreferrer"&gt;benchmarks page&lt;/a&gt;, with the raw runs in the &lt;a href="https://github.com/enviodev/open-indexer-benchmark" rel="noopener noreferrer"&gt;open-indexer-benchmark repo&lt;/a&gt;. Fast sync matters beyond backfills, because a schema change means re-syncing in hours rather than days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handler Language, TypeScript vs AssemblyScript
&lt;/h2&gt;

&lt;p&gt;The Graph's mappings are written in AssemblyScript, a strict subset of TypeScript that compiles to WebAssembly. The syntax looks familiar, but the runtime is not. Standard npm packages do not run, common idioms like optional chaining and class inheritance are restricted, and numbers use AssemblyScript BigInt rather than native JS BigInt.&lt;/p&gt;

&lt;p&gt;HyperIndex handlers are standard TypeScript executed in Node. Any npm package works, generated types come from both your GraphQL schema and your contract ABIs, and there is no WebAssembly step. For teams already writing TypeScript across their stack, this is the difference felt every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multichain Indexing
&lt;/h2&gt;

&lt;p&gt;A subgraph is deployed per chain. Indexing the same protocol on Ethereum and Base means two subgraphs, and cross-chain reads happen in your application layer.&lt;/p&gt;

&lt;p&gt;HyperIndex declares every chain under a single &lt;code&gt;chains&lt;/code&gt; array in one &lt;code&gt;config.yaml&lt;/code&gt;. Adding a chain is one more entry with a chain ID and address, reusing the same contract definition and event signatures, and cross-chain queries run at the database layer behind one GraphQL endpoint. Sablier runs a single indexer across 27 chains this way.&lt;/p&gt;

&lt;p&gt;Read more about &lt;a href="https://docs.envio.dev/docs/HyperIndex/multichain-indexing" rel="noopener noreferrer"&gt;multichain indexing&lt;/a&gt; in our docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reorg Handling
&lt;/h2&gt;

&lt;p&gt;Reorgs are the most common chain-level event a production indexer has to survive. On The Graph, graph-node reverts affected entities automatically when a reorg is detected, bounded by its reorg threshold and prune settings, and because each chain is its own subgraph, multichain coverage means handling that across several deployments.&lt;/p&gt;

&lt;p&gt;HyperIndex tracks per-entity state history for every unfinalised block at the framework level, with rollback on by default. When a reorg happens, the framework rolls each entity back to its pre-reorg state and reprocesses forward against the canonical chain, then prunes history once a block finalises. No handler code is required. The details are in &lt;a href="https://docs.envio.dev/docs/HyperIndex/reorgs-support" rel="noopener noreferrer"&gt;Reorgs Support&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Head-to-Head at a Glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Comparison Point&lt;/th&gt;
&lt;th&gt;Envio HyperIndex&lt;/th&gt;
&lt;th&gt;The Graph&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Handler language&lt;/td&gt;
&lt;td&gt;TypeScript in Node, any npm package&lt;/td&gt;
&lt;td&gt;AssemblyScript compiled to WebAssembly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multichain&lt;/td&gt;
&lt;td&gt;Every chain in one &lt;code&gt;config.yaml&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;One subgraph per chain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data source&lt;/td&gt;
&lt;td&gt;HyperSync, up to 2000x faster than RPC, or standard RPC for chains it does not cover&lt;/td&gt;
&lt;td&gt;Standard RPC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reorg handling&lt;/td&gt;
&lt;td&gt;Framework-level, rollback on by default&lt;/td&gt;
&lt;td&gt;Automatic via graph-node, bounded by prune settings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query language&lt;/td&gt;
&lt;td&gt;Standard GraphQL, plus a converter for subgraph queries&lt;/td&gt;
&lt;td&gt;Custom GraphQL dialect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosted runtime&lt;/td&gt;
&lt;td&gt;Envio Cloud, GitHub-native deploy, or self-host via Docker&lt;/td&gt;
&lt;td&gt;Subgraph Studio and the decentralised network&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Switching From The Graph
&lt;/h2&gt;

&lt;p&gt;If the comparison points you toward Envio, moving is a &lt;a href="https://docs.envio.dev/docs/HyperIndex/migration-guide" rel="noopener noreferrer"&gt;documented flow&lt;/a&gt; rather than a rewrite. It comes down to three steps, convert &lt;code&gt;subgraph.yaml&lt;/code&gt; to &lt;code&gt;config.yaml&lt;/code&gt;, bring your schema across (close to copy and paste, with the &lt;code&gt;@entity&lt;/code&gt; directive removed), and port your handlers from AssemblyScript to TypeScript. Running &lt;code&gt;pnpx envio init&lt;/code&gt; scaffolds the config and schema, your existing subgraph queries keep working through Envio's &lt;a href="https://docs.envio.dev/docs/HyperIndex/query-conversion" rel="noopener noreferrer"&gt;query converter&lt;/a&gt; tool, and the &lt;a href="https://github.com/enviodev/indexer-migration-validator" rel="noopener noreferrer"&gt;Indexer Migration Validator&lt;/a&gt; checks both endpoints field-by-field before you cut over.&lt;/p&gt;

&lt;p&gt;Because AssemblyScript is a subset of TypeScript, most of the handler work is mechanical, which is why many teams now let an AI assistant do the rewrite. Our &lt;a href="https://docs.envio.dev/docs/HyperIndex/migrate-with-ai" rel="noopener noreferrer"&gt;AI migration guide&lt;/a&gt; walks Cursor or Claude Code through the port, and &lt;a href="https://docs.envio.dev/blog/ai-subgraph-migration-hyperindex-claude" rel="noopener noreferrer"&gt;AI-Assisted Subgraph Migration with Claude&lt;/a&gt; shows it end to end.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.envio.dev/blog/case-study-katana-sushiswap" rel="noopener noreferrer"&gt;Katana&lt;/a&gt; moved two production SushiSwap subgraphs off The Graph entity-for-entity. &lt;a href="https://docs.envio.dev/blog/revert-finance-pancakeswap-bnb-hyperindex" rel="noopener noreferrer"&gt;Revert Finance&lt;/a&gt; had a PancakeSwap V3 subgraph stuck at 70 percent sync on BNB Smart Chain for over two years, and HyperIndex synced it to 100 percent in 10 days across 1.7 billion events. The &lt;a href="https://docs.envio.dev/blog/polymarket-hyperindex-case-study" rel="noopener noreferrer"&gt;Polymarket reference indexer&lt;/a&gt; consolidated 8 subgraph domains into one indexer that synced 4 billion Polygon events in 6 days. Envio also offers full white-glove migration help.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;For most EVM teams, HyperIndex is the stronger choice with faster syncs, TypeScript handlers, multichain from a single config, and a documented path off a subgraph. The one case where The Graph still fits is if you need to consume its existing network of public subgraphs, which is its own ecosystem. For building and running your own indexer, Envio is the better tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.envio.dev/docs/HyperIndex/quickstart" rel="noopener noreferrer"&gt;HyperIndex Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.envio.dev/docs/HyperIndex/migration-guide" rel="noopener noreferrer"&gt;Migrate from The Graph&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.envio.dev/docs/HyperIndex/migrate-with-ai" rel="noopener noreferrer"&gt;Migrate using AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.envio.dev/blog/polymarket-hyperindex-case-study" rel="noopener noreferrer"&gt;Polymarket production reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.envio.dev/blog/best-blockchain-indexers-2026" rel="noopener noreferrer"&gt;Best Blockchain Indexers in 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do My Existing Subgraph GraphQL Queries Work After Switching to Envio?
&lt;/h3&gt;

&lt;p&gt;You do not have to rewrite them by hand. HyperIndex serves standard GraphQL rather than The Graph's dialect, and Envio provides a &lt;a href="https://docs.envio.dev/docs/HyperIndex/query-conversion" rel="noopener noreferrer"&gt;query converter tool and conversion guide&lt;/a&gt; to translate existing subgraph queries. After switching, the &lt;a href="https://github.com/enviodev/indexer-migration-validator" rel="noopener noreferrer"&gt;Indexer Migration Validator&lt;/a&gt; compares your new endpoint against the original subgraph field-by-field so you can confirm the data matches before cutting over.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I Keep My Subgraph Schema When Moving to HyperIndex?
&lt;/h3&gt;

&lt;p&gt;Largely yes. Schema migration is close to copy and paste. You remove the &lt;code&gt;@entity&lt;/code&gt; directive, and there are small nuances around enums and BigDecimals documented in the &lt;a href="https://docs.envio.dev/docs/HyperIndex/schema" rel="noopener noreferrer"&gt;schema docs&lt;/a&gt;. HyperIndex generates its types from the same GraphQL schema and your contract ABIs, so entity definitions and relationships carry across with minimal rework.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Long Does a The Graph to Envio Migration Take?
&lt;/h3&gt;

&lt;p&gt;It depends on handler complexity, but the shape is fixed at three steps, config, schema, and handlers. Pure handler logic often copies straight across because AssemblyScript is a subset of TypeScript, and &lt;code&gt;pnpx envio init&lt;/code&gt; scaffolds the config and schema for you. Teams also use &lt;a href="https://docs.envio.dev/docs/HyperIndex/migrate-with-ai" rel="noopener noreferrer"&gt;AI-assisted migration&lt;/a&gt; for the rewrite, and Envio offers white-glove help via &lt;a href="https://discord.gg/envio" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can One Envio Indexer Replace Several Per-Chain Subgraphs?
&lt;/h3&gt;

&lt;p&gt;Yes, and it is a common outcome. Because every chain lives in one &lt;code&gt;config.yaml&lt;/code&gt;, teams routinely consolidate multiple subgraph deployments into a single indexer. Sablier replaced 12 deployments with one indexer across 27 chains, and the &lt;a href="https://docs.envio.dev/blog/polymarket-hyperindex-case-study" rel="noopener noreferrer"&gt;Polymarket reference&lt;/a&gt; unified 8 subgraph domains into one indexer syncing 4 billion events in 6 days.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Moving to Envio Mean I Lose Access to The Graph's Public Subgraphs?
&lt;/h3&gt;

&lt;p&gt;Yes, and that is the main reason to stay on The Graph. Its decentralised network hosts the largest set of community-maintained subgraphs for major protocols. Envio indexes your own contracts into your own schema, so if your dependency is on consuming those public subgraphs rather than running your own indexer, The Graph is still the right home for that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is HyperIndex Faster Than The Graph in Independent Benchmarks?
&lt;/h3&gt;

&lt;p&gt;Yes. In the independent Sentio Uniswap V2 Factory benchmark, HyperIndex finished in 8 seconds against 19 minutes for The Graph, 142x faster, and on the Sentio LBTC workload it finished in 3 minutes against 3 hours 9 minutes. The gap comes from HyperSync, Envio's Rust data engine, which delivers up to 2000x faster data access than the standard RPC that The Graph reads through. Full methodology is on the &lt;a href="https://docs.envio.dev/docs/HyperIndex/benchmarks" rel="noopener noreferrer"&gt;benchmarks page&lt;/a&gt; and the raw runs are in the &lt;a href="https://github.com/enviodev/open-indexer-benchmark" rel="noopener noreferrer"&gt;open-indexer-benchmark repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build With Envio
&lt;/h2&gt;

&lt;p&gt;Envio is a real-time multichain blockchain indexer that turns onchain events into a queryable GraphQL API. Supports any EVM chain, plus Solana and Fuel. Use Envio Cloud or self-host. If you're building onchain, come talk to us about your data needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://envio.beehiiv.com/subscribe?utm_source=envio.beehiiv.com&amp;amp;utm_medium=newsletter&amp;amp;utm_campaign=new-post" rel="noopener noreferrer"&gt;Subscribe to our newsletter&lt;/a&gt; 💌&lt;/p&gt;

&lt;p&gt;&lt;a href="https://envio.dev/" rel="noopener noreferrer"&gt;Website&lt;/a&gt; | &lt;a href="https://twitter.com/envio_indexer" rel="noopener noreferrer"&gt;X&lt;/a&gt; | &lt;a href="https://discord.gg/envio" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; | &lt;a href="https://t.me/+5mI61oZibEM5OGQ8" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt; | &lt;a href="https://github.com/enviodev" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://www.youtube.com/channel/UCR7nZ2yzEtc5SZNM0dhrkhA" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt; | &lt;a href="https://www.reddit.com/user/Envio_indexer" rel="noopener noreferrer"&gt;Reddit&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Introducing the Envio Docs MCP Server</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Thu, 09 Jul 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/envio/introducing-the-envio-docs-mcp-server-a3h</link>
      <guid>https://dev.to/envio/introducing-the-envio-docs-mcp-server-a3h</guid>
      <description>&lt;p&gt;The Envio Docs MCP Server lets AI assistants like Claude pull straight from our documentation — so you get accurate, up-to-date answers while you build. This post introduces it and how to wire it up.&lt;/p&gt;

&lt;p&gt;👉 Read the full announcement on the Envio blog: &lt;a href="https://docs.envio.dev/blog/envio-docs-mcp-server" rel="noopener noreferrer"&gt;https://docs.envio.dev/blog/envio-docs-mcp-server&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Envio is Web3's backend — the fastest, most flexible way to index and query blockchain data. Explore HyperIndex, HyperSync, HyperRPC and Envio Cloud at &lt;a href="https://envio.dev" rel="noopener noreferrer"&gt;https://envio.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Privacy in Public: A Case Study on Privacy Pools</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Thu, 09 Jul 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/envio/privacy-in-public-a-case-study-on-privacy-pools-49ba</link>
      <guid>https://dev.to/envio/privacy-in-public-a-case-study-on-privacy-pools-49ba</guid>
      <description>&lt;p&gt;Privacy Pools brings privacy to public chains — but indexing that data is its own challenge. This case study looks at how Envio handles it and what onchain privacy means for builders.&lt;/p&gt;

&lt;p&gt;👉 Read the full case study on the Envio blog: &lt;a href="https://docs.envio.dev/blog/privacy-in-public-case-study" rel="noopener noreferrer"&gt;https://docs.envio.dev/blog/privacy-in-public-case-study&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Envio is Web3's backend — the fastest, most flexible way to index and query blockchain data. Explore HyperIndex, HyperSync, HyperRPC and Envio Cloud at &lt;a href="https://envio.dev" rel="noopener noreferrer"&gt;https://envio.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>privacy</category>
      <category>casestudy</category>
    </item>
    <item>
      <title>How Revert Finance Fixed 2 Years of Unsynced PancakeSwap V3 Data with Envio</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Wed, 08 Jul 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/envio/how-revert-finance-fixed-2-years-of-unsynced-pancakeswap-v3-data-with-envio-6a2</link>
      <guid>https://dev.to/envio/how-revert-finance-fixed-2-years-of-unsynced-pancakeswap-v3-data-with-envio-6a2</guid>
      <description>&lt;p&gt;Revert Finance had two years of unsynced PancakeSwap V3 data on BNB Chain. This case study shows how they used Envio's HyperIndex to backfill and stay in sync — and what it meant for their analytics.&lt;/p&gt;

&lt;p&gt;👉 Read the full case study on the Envio blog: &lt;a href="https://docs.envio.dev/blog/revert-finance-pancakeswap-bnb-hyperindex" rel="noopener noreferrer"&gt;https://docs.envio.dev/blog/revert-finance-pancakeswap-bnb-hyperindex&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Envio is Web3's backend — the fastest, most flexible way to index and query blockchain data. Explore HyperIndex, HyperSync, HyperRPC and Envio Cloud at &lt;a href="https://envio.dev" rel="noopener noreferrer"&gt;https://envio.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>indexing</category>
      <category>casestudy</category>
    </item>
    <item>
      <title>How Katana Migrated SushiSwap Data from The Graph to Envio</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Wed, 08 Jul 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/envio/how-katana-migrated-sushiswap-data-from-the-graph-to-envio-4k77</link>
      <guid>https://dev.to/envio/how-katana-migrated-sushiswap-data-from-the-graph-to-envio-4k77</guid>
      <description>&lt;p&gt;When Katana needed reliable SushiSwap data, they moved off The Graph and onto Envio. This case study walks through why they migrated and what changed for their indexing performance and developer experience.&lt;/p&gt;

&lt;p&gt;👉 Read the full case study on the Envio blog: &lt;a href="https://docs.envio.dev/blog/case-study-katana-sushiswap" rel="noopener noreferrer"&gt;https://docs.envio.dev/blog/case-study-katana-sushiswap&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Envio is Web3's backend — the fastest, most flexible way to index and query blockchain data. Explore HyperIndex, HyperSync, HyperRPC and Envio Cloud at &lt;a href="https://envio.dev" rel="noopener noreferrer"&gt;https://envio.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>indexing</category>
      <category>casestudy</category>
    </item>
    <item>
      <title>Using ClickHouse Storage in HyperIndex V3</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Tue, 07 Jul 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/envio/using-clickhouse-storage-in-hyperindex-v3-4m26</link>
      <guid>https://dev.to/envio/using-clickhouse-storage-in-hyperindex-v3-4m26</guid>
      <description>&lt;p&gt;HyperIndex V3 adds ClickHouse as a storage backend, unlocking fast analytical queries over your indexed onchain data. This post shows what that means in practice and when to reach for it.&lt;/p&gt;

&lt;p&gt;👉 Read the full article on the Envio blog: &lt;a href="https://docs.envio.dev/blog/clickhouse-storage-hyperindex-v3" rel="noopener noreferrer"&gt;https://docs.envio.dev/blog/clickhouse-storage-hyperindex-v3&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Envio is Web3's backend — the fastest, most flexible way to index and query blockchain data. Explore HyperIndex, HyperSync, HyperRPC and Envio Cloud at &lt;a href="https://envio.dev" rel="noopener noreferrer"&gt;https://envio.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>indexing</category>
      <category>database</category>
    </item>
    <item>
      <title>Production Indexer Reliability with HyperIndex</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Tue, 07 Jul 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/envio/production-indexer-reliability-with-hyperindex-3hdj</link>
      <guid>https://dev.to/envio/production-indexer-reliability-with-hyperindex-3hdj</guid>
      <description>&lt;p&gt;Reliability is what separates a demo from a production indexer. This post covers how HyperIndex keeps your data pipeline resilient — handling reorgs, restarts and failures so your app stays in sync when it matters most.&lt;/p&gt;

&lt;p&gt;👉 Read the full article on the Envio blog: &lt;a href="https://docs.envio.dev/blog/production-indexer-reliability-hyperindex" rel="noopener noreferrer"&gt;https://docs.envio.dev/blog/production-indexer-reliability-hyperindex&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Envio is Web3's backend — the fastest, most flexible way to index and query blockchain data. Explore HyperIndex, HyperSync, HyperRPC and Envio Cloud at &lt;a href="https://envio.dev" rel="noopener noreferrer"&gt;https://envio.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>indexing</category>
      <category>database</category>
    </item>
    <item>
      <title>How to Scale Subgraphs to Millions of Requests</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Mon, 06 Jul 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/envio/how-to-scale-subgraphs-to-millions-of-requests-4c96</link>
      <guid>https://dev.to/envio/how-to-scale-subgraphs-to-millions-of-requests-4c96</guid>
      <description>&lt;p&gt;Subgraphs can buckle when query volume climbs into the millions. This guide walks through the practical steps to scale your indexing setup so it stays fast and reliable under heavy production load.&lt;/p&gt;

&lt;p&gt;👉 Read the full guide on the Envio blog: &lt;a href="https://docs.envio.dev/blog/scale-subgraphs-millions-of-requests" rel="noopener noreferrer"&gt;https://docs.envio.dev/blog/scale-subgraphs-millions-of-requests&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Envio is Web3's backend — the fastest, most flexible way to index and query blockchain data. Explore HyperIndex, HyperSync, HyperRPC and Envio Cloud at &lt;a href="https://envio.dev" rel="noopener noreferrer"&gt;https://envio.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>indexing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Why Blockchain Indexers Hit Rate Limits at Scale</title>
      <dc:creator>Envio</dc:creator>
      <pubDate>Mon, 06 Jul 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/envio/why-blockchain-indexers-hit-rate-limits-at-scale-383k</link>
      <guid>https://dev.to/envio/why-blockchain-indexers-hit-rate-limits-at-scale-383k</guid>
      <description>&lt;p&gt;When your indexer starts throttling under load, raw data access becomes the bottleneck. This post breaks down why rate limits hit at scale and how HyperSync sustains high-throughput onchain data access without choking.&lt;/p&gt;

&lt;p&gt;👉 Read the full article on the Envio blog: &lt;a href="https://docs.envio.dev/blog/hypersync-under-load-no-throttling" rel="noopener noreferrer"&gt;https://docs.envio.dev/blog/hypersync-under-load-no-throttling&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Envio is Web3's backend — the fastest, most flexible way to index and query blockchain data. Explore HyperIndex, HyperSync, HyperRPC and Envio Cloud at &lt;a href="https://envio.dev" rel="noopener noreferrer"&gt;https://envio.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>indexing</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
