<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>madavre.eth</title>
        <link>https://paragraph.com/@madavre</link>
        <description>undefined</description>
        <lastBuildDate>Wed, 08 Apr 2026 13:51:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Unleashing the Power of Messari Standardized Subgraphs: Querying Multiple DeFi Exchanges Simultaneously]]></title>
            <link>https://paragraph.com/@madavre/unleashing-the-power-of-messari-standardized-subgraphs-querying-multiple-defi-exchanges-simultaneously</link>
            <guid>iLTAwykBxNIyiXfXWBMC</guid>
            <pubDate>Wed, 15 May 2024 16:39:36 GMT</pubDate>
            <description><![CDATA[Final repo of this blog.If you’re diving into the world of decentralized finance (DeFi), you know how important it is to get accurate and comprehensive data. But what if we could get this data not just from one DeFi protocol, but from dozens all at once? That’s where Messari’s standardized subgraphs come in. These standardized subgraphs let us query multiple exchanges with a single query, essentially asking the same question of many different DeFi communities all at the same time! Imagine bei...]]></description>
            <content:encoded><![CDATA[<p><em>Final </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/marcusrein/messari-queries"><em>repo</em></a><em> of this blog.</em></p><hr><p>If you’re diving into the world of decentralized finance (DeFi), you know how important it is to get accurate and comprehensive data. But what if we could get this data not just from one DeFi protocol, but from dozens all at once?</p><p><strong>That’s where </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://subgraphs.messari.io/"><strong>Messari’s standardized subgraphs</strong></a><strong> come in.</strong></p><p>These standardized subgraphs let us query multiple exchanges with a single query, essentially asking the same question of many different DeFi communities all at the same time! Imagine being able to track the Total Value Locked (TVL) across dozens of different protocols or analyzing trade volumes and user metrics - all with a single query!</p><p>In this post, we’ll walk you through the advantages of using Messari standardized subgraphs, show you how to query multiple exchanges, and even give you some creative queries to try out. Let’s get started!</p><h3 id="h-why-messari-standardized-subgraphs-are-awesome" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>Why Messari Standardized Subgraphs Are Awesome</strong></h3><ol><li><p><strong>Consistent Data Structure</strong>: Messari&apos;s subgraphs stick to a consistent schema, making it super easy to write queries that work across different exchanges. No more tweaking queries for each platform!</p></li><li><p><strong>Comprehensive Insights</strong>: By querying multiple exchanges at once, you can get a complete view of the DeFi landscape. This is perfect for comparing TVL, spotting market trends, and finding new opportunities.</p></li><li><p><strong>Efficient and Fast</strong>: Standardized subgraphs let you fetch data from various sources in one go. This saves time and cuts down on the hassle of handling multiple data sources.</p></li></ol><h3 id="h-how-to-query-multiple-exchanges-a-step-by-step-guide" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>How to Query Multiple Exchanges: A Step-by-Step Guide</strong></h3><h4 id="h-step-1-find-messari-subgraphs-that-index-exchanges" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><strong>Step 1: Find Messari Subgraphs that Index Exchanges</strong></h4><p>Go to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://subgraphs.messari.io/">subgraphs.messari.io</a> and find the Exchanges category. All subgraphs under each category have the same standardized schema for us to query (Exchanges, erc721, Governance, etc).</p><p>We will query Messari’s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/explorer/subgraphs/GAGwGKc4ArNKKq9eFTcwgd1UGymvqhTier9Npqo1YvZB?view=Overview&amp;chain=mainnet">Curve Finance subgraph</a> and their <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/explorer/subgraphs/7h1x51fyT5KigAhXd8sdE3kzzxQDJxxz1y66LTFiC3mS?view=Overview&amp;chain=mainnet">SushiSwap subgraph</a>, however if we wanted to we could send this query to nearly 40(!) Messari-standard Exchange subgraphs. Every Messari Exchange subgraph uses this <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/messari/subgraphs/blob/master/schema-dex-amm.graphql">schema</a>, which will make designing queries simple!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/060e37ff37095424e0a37466bbc23b29158b9eed2b998100efe79fa206dfde6e.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><strong>Step 2: Design a Query and Test in the Subgraph’s Playground</strong></p><p>Let’s find the TVL of both Curve Finance and SushiSwap on August 20th, 2023.</p><p>After analyzing the subgraph’s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/messari/subgraphs/blob/master/schema-dex-amm.graphql">schema</a>, as well as finding the UNIX timestamp for that specific date, here is our GraphQL query:</p><pre data-type="codeBlock" text="{
  dailySnapshot8_20_23: financialsDailySnapshots(
    where: {timestamp_gte: 1629417600, timestamp_lt: 1629504000},
  ) {
    totalValueLockedUSD
  }
}
"><code>{
  <span class="hljs-attr">dailySnapshot8_20_23:</span> <span class="hljs-string">financialsDailySnapshots(</span>
    <span class="hljs-attr">where:</span> {<span class="hljs-attr">timestamp_gte:</span> <span class="hljs-number">1629417600</span>, <span class="hljs-attr">timestamp_lt:</span> <span class="hljs-number">1629504000</span>},
  <span class="hljs-string">)</span> {
    <span class="hljs-string">totalValueLockedUSD</span>
  }
}
</code></pre><p>We can run this query in each subgraph’s playground and see both are returning data:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/93ec8dcc6a135a871665af61f0c19d4f3062d96a27eccc3f4a81970b8d563e92.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/475c3f7d704b12d2d4795b05c2e4d285b5133b5d3387e83a36ef195cf2f8c68b.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>But now, how do we build this in programmatically into our dapp?</p><h4 id="h-step-3-set-up-our-project" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><strong>Step 3: Set Up Our Project</strong></h4><p>First things first, make sure you have <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nodejs.org/en">Node.js</a> installed. Then, set up a new project:</p><pre data-type="codeBlock" text="mkdir messari-subgraphs
cd messari-subgraphs
npm init -y
"><code>mkdir messari<span class="hljs-operator">-</span>subgraphs
cd messari<span class="hljs-operator">-</span>subgraphs
npm init <span class="hljs-operator">-</span>y
</code></pre><h4 id="h-step-4-gather-subgraph-endpoints" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><strong>Step 4: Gather Subgraph Endpoints</strong></h4><p>Create a file named <code>app.js</code> and gather both subgraph’s endpoints by pressing the <strong>Query</strong> button on each of their dashboards.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a782c9942282c4172d21a186d8a5330bfe03d1098c8a7bb976d72d99d7dc80af.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Save the endpoints as an array inside of a <code>getTVLs()</code> function:</p><pre data-type="codeBlock" text="//app.js	

async function getTVLs() {
        const urls = [
        {
            url: &quot;https://gateway.thegraph.com/api/&lt;API_KEY&gt;/subgraphs/id/GAGwGKc4ArNKKq9eFTcwgd1UGymvqhTier9Npqo1YvZB&quot;,
            name: &quot;Curve Finance&quot;,
        },
        {
            url: &quot;https://gateway.thegraph.com/api/&lt;API_KEY&gt;/subgraphs/id/7h1x51fyT5KigAhXd8sdE3kzzxQDJxxz1y66LTFiC3mS&quot;,
            name: &quot;SushiSwap&quot;,
        },
    ];
};
"><code>/<span class="hljs-regexp">/app.js	

async function getTVLs() {
        const urls = [
        {
            url: "https:/</span><span class="hljs-regexp">/gateway.thegraph.com/api</span><span class="hljs-regexp">/&#x3C;API_KEY>/subgraphs</span><span class="hljs-regexp">/id/</span><span class="hljs-title class_">GAGwGKc4ArNKKq9eFTcwgd1UGymvqhTier9Npqo1Yv</span>ZB<span class="hljs-string">",
            name: "</span><span class="hljs-title class_">Curve</span> <span class="hljs-title class_">Finance</span><span class="hljs-string">",
        },
        {
            url: "</span><span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/gateway.thegraph.com/api</span><span class="hljs-regexp">/&#x3C;API_KEY>/subgraphs</span><span class="hljs-regexp">/id/</span>7h1x51fyT5KigAhXd8sdE3kzzxQDJxxz1y66LTFiC3mS<span class="hljs-string">",
            name: "</span><span class="hljs-title class_">SushiSwap</span><span class="hljs-string">",
        },
    ];
};
</span></code></pre><p><strong>Step 5: Gather API Key</strong></p><p>Go to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.thegraph.com/studio">Subgraph Studio</a> and set up an API Key, then drop the API key into the endpoints:</p><pre data-type="codeBlock" text="//app.js

async function getTVLs() {
  const urls = [
      	{
            url:     &quot;https://gateway.thegraph.com/api/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs/id/GAGwGKc4ArNKKq9eFTcwgd1UGymvqhTier9Npqo1YvZB&quot;,
            name: &quot;Curve Finance&quot;,
        },
        {
            url: &quot;https://gateway.thegraph.com/api/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs/id/7h1x51fyT5KigAhXd8sdE3kzzxQDJxxz1y66LTFiC3mS&quot;,
            name: &quot;SushiSwap&quot;,
        },
    ];
};
"><code>/<span class="hljs-regexp">/app.js

async function getTVLs() {
  const urls = [
      	{
            url:     "https:/</span><span class="hljs-regexp">/gateway.thegraph.com/api</span><span class="hljs-regexp">/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs</span><span class="hljs-regexp">/id/</span><span class="hljs-title class_">GAGwGKc4ArNKKq9eFTcwgd1UGymvqhTier9Npqo1Yv</span>ZB<span class="hljs-string">",
            name: "</span><span class="hljs-title class_">Curve</span> <span class="hljs-title class_">Finance</span><span class="hljs-string">",
        },
        {
            url: "</span><span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/gateway.thegraph.com/api</span><span class="hljs-regexp">/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs</span><span class="hljs-regexp">/id/</span>7h1x51fyT5KigAhXd8sdE3kzzxQDJxxz1y66LTFiC3mS<span class="hljs-string">",
            name: "</span><span class="hljs-title class_">SushiSwap</span><span class="hljs-string">",
        },
    ];
};
</span></code></pre><p><strong>Step 6: Programmatically Send Query to Endpoints</strong></p><p>Next, we will create an array of POST requests to fetch the Total Value Locked (TVL) data for August 20th, 2023, from multiple subgraphs:</p><pre data-type="codeBlock" text="//app.js

const requests = urls.map((entry) =&gt;
        fetch(entry.url, {
            method: &quot;POST&quot;,
            headers: {
                &quot;Content-Type&quot;: &quot;application/json&quot;,
            },
            body: JSON.stringify({
                query: `
                    {
                        dailySnapshot8_20_23: financialsDailySnapshots(
                            where: { timestamp_gte: 1629417600, timestamp_lt: 1629504000 }
                        ) {
                            totalValueLockedUSD
                        }
                    }
                `,
            }),
        })
    );

    const results = await Promise.all(requests);
    const tvls = await Promise.all(results.map((result) =&gt; result.json()));
"><code><span class="hljs-comment">//app.js</span>

const requests <span class="hljs-operator">=</span> urls.map((entry) <span class="hljs-operator">=</span><span class="hljs-operator">></span>
        fetch(entry.url, {
            method: <span class="hljs-string">"POST"</span>,
            headers: {
                <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
            },
            body: JSON.stringify({
                query: `
                    {
                        dailySnapshot8_20_23: financialsDailySnapshots(
                            where: { timestamp_gte: <span class="hljs-number">1629417600</span>, timestamp_lt: <span class="hljs-number">1629504000</span> }
                        ) {
                            totalValueLockedUSD
                        }
                    }
                `,
            }),
        })
    );

    const results <span class="hljs-operator">=</span> await Promise.all(requests);
    const tvls <span class="hljs-operator">=</span> await Promise.all(results.map((result) <span class="hljs-operator">=</span><span class="hljs-operator">></span> result.json()));
</code></pre><p>By using the <code>map</code> function on the <code>urls</code> array, we ensure that each subgraph endpoint is queried with the same GraphQL query.</p><p><strong>Step 7: Display The Returned Data</strong></p><p>Now that we&apos;ve fetched the data from multiple subgraphs, the next step is to display it on our webpage. We will take the data returned from the subgraphs and dynamically create HTML elements to show this information.</p><ol><li><p><strong>Get the Data Container</strong>:</p><ul><li><p>First, we need to select the HTML element where we will display our data. This element should have the ID <code>data-container</code>.</p></li></ul></li><li><p><strong>Iterate Over the Results</strong>:</p><ul><li><p>We loop through the array of TVL results, and for each result, we create a new HTML <code>div</code> element to display the data.</p></li></ul></li><li><p><strong>Create HTML Elements</strong>:</p><ul><li><p>Inside this loop, we create elements for the exchange name and the TVL, and then append these elements to the <code>data-container</code>.</p></li></ul></li></ol><p>Here is the final <code>app.js</code> file:</p><pre data-type="codeBlock" text="async function getTVLs() {
    const urls = [
        {
            url: &quot;https://gateway.thegraph.com/api/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs/id/GAGwGKc4ArNKKq9eFTcwgd1UGymvqhTier9Npqo1YvZB&quot;,
            name: &quot;Curve Finance&quot;,
        },
        {
            url: &quot;https://gateway.thegraph.com/api/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs/id/7h1x51fyT5KigAhXd8sdE3kzzxQDJxxz1y66LTFiC3mS&quot;,
            name: &quot;SushiSwap&quot;,
        },
    ];

    const requests = urls.map((entry) =&gt;
        fetch(entry.url, {
            method: &quot;POST&quot;,
            headers: {
                &quot;Content-Type&quot;: &quot;application/json&quot;,
            },
            body: JSON.stringify({
                query: `
                    {
                        dailySnapshot8_20_23: financialsDailySnapshots(
                            where: { timestamp_gte: 1629417600, timestamp_lt: 1629504000 }
                        ) {
                            totalValueLockedUSD
                        }
                    }
                `,
            }),
        })
    );

    const results = await Promise.all(requests);
    const tvls = await Promise.all(results.map((result) =&gt; result.json()));

    const dataContainer = document.getElementById(&quot;data-container&quot;);
    tvls.forEach((feed, index) =&gt; {
        const platformName = urls[index].name;
        const feedData = feed.data.dailySnapshot8_20_23;
        feedData.forEach((snapshot) =&gt; {
            const snapshotElement = document.createElement(&quot;div&quot;);
            snapshotElement.innerHTML = `
                &lt;h3&gt;${platformName}&lt;/h3&gt;
                &lt;p&gt;Total Value Locked USD: ${snapshot.totalValueLockedUSD}&lt;/p&gt;
                &lt;hr&gt;
            `;
            dataContainer.appendChild(snapshotElement);
        });
    });
}

getTVLs();
"><code>async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTVLs</span>(<span class="hljs-params"></span>) </span>{
    const urls <span class="hljs-operator">=</span> [
        {
            url: <span class="hljs-string">"https://gateway.thegraph.com/api/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs/id/GAGwGKc4ArNKKq9eFTcwgd1UGymvqhTier9Npqo1YvZB"</span>,
            name: <span class="hljs-string">"Curve Finance"</span>,
        },
        {
            url: <span class="hljs-string">"https://gateway.thegraph.com/api/0ab7a83b03a36ac8a536cd8fa19a8ad4/subgraphs/id/7h1x51fyT5KigAhXd8sdE3kzzxQDJxxz1y66LTFiC3mS"</span>,
            name: <span class="hljs-string">"SushiSwap"</span>,
        },
    ];

    const requests <span class="hljs-operator">=</span> urls.map((entry) <span class="hljs-operator">=</span><span class="hljs-operator">></span>
        fetch(entry.url, {
            method: <span class="hljs-string">"POST"</span>,
            headers: {
                <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
            },
            body: JSON.stringify({
                query: `
                    {
                        dailySnapshot8_20_23: financialsDailySnapshots(
                            where: { timestamp_gte: <span class="hljs-number">1629417600</span>, timestamp_lt: <span class="hljs-number">1629504000</span> }
                        ) {
                            totalValueLockedUSD
                        }
                    }
                `,
            }),
        })
    );

    const results <span class="hljs-operator">=</span> await Promise.all(requests);
    const tvls <span class="hljs-operator">=</span> await Promise.all(results.map((result) <span class="hljs-operator">=</span><span class="hljs-operator">></span> result.json()));

    const dataContainer <span class="hljs-operator">=</span> document.getElementById(<span class="hljs-string">"data-container"</span>);
    tvls.forEach((feed, index) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
        const platformName <span class="hljs-operator">=</span> urls[index].<span class="hljs-built_in">name</span>;
        const feedData <span class="hljs-operator">=</span> feed.data.dailySnapshot8_20_23;
        feedData.forEach((snapshot) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
            const snapshotElement <span class="hljs-operator">=</span> document.createElement(<span class="hljs-string">"div"</span>);
            snapshotElement.innerHTML <span class="hljs-operator">=</span> `
                <span class="hljs-operator">&#x3C;</span>h3<span class="hljs-operator">></span>${platformName}<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>h3<span class="hljs-operator">></span>
                <span class="hljs-operator">&#x3C;</span>p<span class="hljs-operator">></span>Total Value Locked USD: ${snapshot.totalValueLockedUSD}<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>p<span class="hljs-operator">></span>
                <span class="hljs-operator">&#x3C;</span>hr<span class="hljs-operator">></span>
            `;
            dataContainer.appendChild(snapshotElement);
        });
    });
}

getTVLs();
</code></pre><h4 id="h-step-8-create-the-html-file" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><strong>Step 8: Create the HTML File</strong></h4><p>Create an HTML file to display the results:</p><pre data-type="codeBlock" text="// index.html

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
    &lt;head&gt;
        &lt;meta charset=&quot;UTF-8&quot; /&gt;
        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
        &lt;title&gt;TVL on Aug 20th, 2023&lt;/title&gt;
        &lt;link rel=&quot;stylesheet&quot; href=&quot;styles.css&quot; /&gt;
        &lt;link
            href=&quot;https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,300;1,300&amp;display=swap&quot;
            rel=&quot;stylesheet&quot;
        /&gt;
    &lt;/head&gt;
    &lt;body class=&quot;container&quot;&gt;
        &lt;h1&gt;TVL on Aug 20th, 2023&lt;/h1&gt;
        &lt;div id=&quot;data-container&quot;&gt;&lt;/div&gt;
        &lt;script type=&quot;text/javascript&quot; src=&quot;app.js&quot;&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;
"><code><span class="hljs-comment">// index.html</span>

<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">!</span>DOCTYPE html<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span>html lang<span class="hljs-operator">=</span><span class="hljs-string">"en"</span><span class="hljs-operator">></span>
    <span class="hljs-operator">&#x3C;</span>head<span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>meta charset<span class="hljs-operator">=</span><span class="hljs-string">"UTF-8"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>meta name<span class="hljs-operator">=</span><span class="hljs-string">"viewport"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"width=device-width, initial-scale=1.0"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>title<span class="hljs-operator">></span>TVL on Aug 20th, <span class="hljs-number">2023</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>title<span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>link rel<span class="hljs-operator">=</span><span class="hljs-string">"stylesheet"</span> href<span class="hljs-operator">=</span><span class="hljs-string">"styles.css"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>link
            href<span class="hljs-operator">=</span><span class="hljs-string">"https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,300;1,300&#x26;display=swap"</span>
            rel<span class="hljs-operator">=</span><span class="hljs-string">"stylesheet"</span>
        <span class="hljs-operator">/</span><span class="hljs-operator">></span>
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>head<span class="hljs-operator">></span>
    <span class="hljs-operator">&#x3C;</span>body class<span class="hljs-operator">=</span><span class="hljs-string">"container"</span><span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>h1<span class="hljs-operator">></span>TVL on Aug 20th, <span class="hljs-number">2023</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>div id<span class="hljs-operator">=</span><span class="hljs-string">"data-container"</span><span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
        <span class="hljs-operator">&#x3C;</span>script <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"text/javascript"</span> src<span class="hljs-operator">=</span><span class="hljs-string">"app.js"</span><span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>script<span class="hljs-operator">></span>
    <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>body<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>html<span class="hljs-operator">></span>
</code></pre><h4 id="h-step-9-add-some-style" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0"><strong>Step 9: Add Some Style</strong></h4><p>Create a CSS file (<code>styles.css</code>) to make everything look nice:</p><pre data-type="codeBlock" text="// styles.css

body {
    font-family: &quot;Raleway&quot;, sans-serif;
    background-color: #f4f4f9;
    color: #333;
    margin: 0;
    padding: 20px;
}

.container {
    max-width: 800px;
    margin: auto;
    padding: 20px;
    background-color: #ffffff;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

h1 {
    color: #0a4870;
    text-align: center;
}

div#data-container {
    margin-top: 20px;
}

div#data-container &gt; div {
    padding: 10px;
    border-bottom: 1px solid #eee;
}

h3 {
    color: #0a4870;
    margin: 0 0 5px 0;
}

p {
    margin: 5px 0;
}

hr {
    margin-top: 10px;
    border: none;
    height: 1px;
    background-color: #eee;
}
"><code>// styles<span class="hljs-selector-class">.css</span>

<span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Raleway"</span>, sans-serif;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f4f4f9</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">800px</span>;
    <span class="hljs-attribute">margin</span>: auto;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ffffff</span>;
    <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">10px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
}

<span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#0a4870</span>;
    <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-tag">div</span><span class="hljs-selector-id">#data-container</span> {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-tag">div</span><span class="hljs-selector-id">#data-container</span> > <span class="hljs-selector-tag">div</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">border-bottom</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#eee</span>;
}

<span class="hljs-selector-tag">h3</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#0a4870</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">5px</span> <span class="hljs-number">0</span>;
}

<span class="hljs-selector-tag">p</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">5px</span> <span class="hljs-number">0</span>;
}

hr {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">border</span>: none;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">1px</span>;
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#eee</span>;
}
</code></pre><h3 id="h-more-creative-queries-for-exchange-subgraphs" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>More Creative Queries for Exchange Subgraphs</strong></h3><p>Once you’ve got the basic setup down, you can start writing more interesting queries to get even more insights about many DeFi protocols. Here are a few ideas:</p><p><strong>Number of Daily Active Users Between Jan 1st, 2021 and Feb 1st, 2021</strong></p><pre data-type="codeBlock" text="query DailyActiveUsers {
  usageMetricsDailySnapshots(
    where: {timestamp_gt: &quot;1609480861&quot;, timestamp_lt: &quot;1612159261&quot;}
  ) {
    dailyActiveUsers
    timestamp
  }
}
"><code>query <span class="hljs-title class_">DailyActiveUsers</span> {
  <span class="hljs-title function_">usageMetricsDailySnapshots</span>(<span class="hljs-params">
    where: {timestamp_gt: <span class="hljs-string">"1609480861"</span>, timestamp_lt: <span class="hljs-string">"1612159261"</span>}
  </span>) {
    dailyActiveUsers
    timestamp
  }
}
</code></pre><p><strong>Daily Trading Volume, Daily Revenue, and TVL Over the Past 10 Days</strong></p><pre data-type="codeBlock" text="{
  financialsDailySnapshots(
    first: 10
    orderBy: timestamp
    orderDirection: desc
  ) {
    timestamp
    dailyVolumeUSD
    dailyTotalRevenueUSD
    totalValueLockedUSD
  }
}
"><code>{
  financialsDailySnapshots(
    <span class="hljs-keyword">first</span>: <span class="hljs-number">10</span>
    orderBy: <span class="hljs-type">timestamp</span>
    orderDirection: <span class="hljs-keyword">desc</span>
  ) {
    <span class="hljs-type">timestamp</span>
    dailyVolumeUSD
    dailyTotalRevenueUSD
    totalValueLockedUSD
  }
}
</code></pre><p>By querying these standardized subgraphs, you can gather valuable insights across multiple exchanges efficiently, helping you stay ahead in the fast-paced DeFi landscape. Happy querying!</p><p>Marcus Rein</p><p>Developer Relations and Success</p><p>Edge &amp; Node - Working on The Graph</p>]]></content:encoded>
            <author>madavre@newsletter.paragraph.com (madavre.eth)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9489707494f1853cf7539790ab60b1a921ab86a801ef51320102c8b7573fe6da.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[How to Deploy and Index Factory Pattern Smart Contracts Using Remix IDE and The Graph's Subgraphs]]></title>
            <link>https://paragraph.com/@madavre/how-to-deploy-and-index-factory-pattern-smart-contracts-using-remix-ide-and-the-graph-s-subgraphs</link>
            <guid>g842nL0gXWbjursIiN3B</guid>
            <pubDate>Thu, 07 Dec 2023 13:46:31 GMT</pubDate>
            <description><![CDATA[TLDR? Watch the video of this tutorial! Final repo of this tutorial: https://github.com/marcusrein/TutorialSubgraphTemplate Documentation on Data Source Templating with Subgraphs: https://thegraph.com/docs/en/developing/creating-a-subgraph/#data-source-templatesIntroDo you have a child? Imagine having ten more. Then fifty more after that. Then imagine you have ten thousand. Whelp, in this shoehorned metaphor, it turns out that YOU are responsible for the information, safety, and whereabouts o...]]></description>
            <content:encoded><![CDATA[<p><strong>TLDR? Watch the video of this tutorial!</strong></p><div data-type="youtube" videoId="VzBCoXTEqeY">
      <div class="youtube-player" data-id="VzBCoXTEqeY" style="background-image: url('https://i.ytimg.com/vi/VzBCoXTEqeY/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=VzBCoXTEqeY">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><p>Final repo of this tutorial:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/marcusrein/TutorialSubgraphTemplate">https://github.com/marcusrein/TutorialSubgraphTemplate</a></p><p>Documentation on Data Source Templating with Subgraphs:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/en/developing/creating-a-subgraph/#data-source-templates">https://thegraph.com/docs/en/developing/creating-a-subgraph/#data-source-templates</a></p><h1 id="h-intro" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Intro</h1><p>Do you have a child?</p><p>Imagine having ten more. Then fifty more after that. Then imagine you have ten thousand.</p><p>Whelp, in this shoehorned metaphor, it turns out that YOU are responsible for the information, safety, and whereabouts of each and every single child!</p><p>Good luck!</p><p>So what does this have to do with decentralized data you might ask?</p><p>It all comes down to smart contracts.</p><p>Smart contracts aren’t just incredibly powerful executable warrior-files securely deployed to countless nodes throughout earth, hell-bent on disrupting the entrenched extractive ethos of web2…</p><p>Smart contracts, when lovingly set up and are in the mood, <em>can also have children</em>.</p><p>Lots and lots and LOTS of children. Infinite children!</p><p>Wouldn’t it be nice to be able to keep track of your children, no matter how infinite they may be?</p><p>I think so!</p><h2 id="h-welcome-to-a-walkthrough-tutorial-on-how-to-deploy-and-index-factory-pattern-contracts-using-remix-ide-and-the-graphs-subgraphs" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Welcome to a walkthrough tutorial on how to deploy and index factory pattern contracts using Remix IDE and The Graph’s subgraphs</h2><h1 id="h-who-this-tutorial-is-for" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Who This Tutorial Is For</h1><ul><li><p>Web2 devs curious about getting started in web3</p></li><li><p>Web3 devs looking to take their dapp to the next level by allowing their smart contracts to replicate and keep track of those replications’ actions.</p></li></ul><h1 id="h-requirements" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Requirements</h1><ul><li><p>A low to moderate level of understanding of Solidity, Typescript, and APIs</p><ul><li><p>Here are a few of my favorite resources:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.cryptozombies.io">Solidity quickstart</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.freecodecamp.org/news/learn-typescript-beginners-guide/">Typescript quickstart</a></p></li></ul></li></ul></li><li><p>A low to moderate level of understanding of how blockchain functions</p></li><li><p>A decentralized wallet like Metamask</p></li></ul><h1 id="h-objectives" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Objectives</h1><ul><li><p>Deploy a gas-efficient Factory Pattern using clones</p></li><li><p>Deploy a subgraph that features templating to index and search the contract and any children it produces</p></li></ul><h1 id="h-what-we-are-building" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What We are Building:</h1><p>We are going to be building a gas-efficient Factory Pattern smart contract and deploy it on the Goerli testnet. We will first build it locally before deploying on-chain.</p><p>We’ll then index and query the parent and any child created from the parent efficiently with a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.graphprotocol.com">Graph Protocol</a> Subgraph Template.</p><p>This is an high-level preview of what we will be building. <strong>Keep this diagram handy ! If you ever feel lost, refer to this!</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a885005ed371c10ca2219cf4421a3371f118ccc2ddca93a55ee18426cd6d418b.png" alt="Indexing a Factory Pattern Smart Contract with a Subgraph" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Indexing a Factory Pattern Smart Contract with a Subgraph</figcaption></figure><h1 id="h-section-1-building-a-factory-pattern-efficiently" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Section 1: Building a Factory Pattern Efficiently</h1><p>A Factory Pattern in solidity is ideally going to be a different pattern than a traditional Factory Pattern in other programming languages due to gas.</p><p>The typical Factory Pattern involves cloning the logic every time a cloned smart contract is made, which adds more data to every transaction, which wastes gas.</p><p>But no worries, there is a solution!</p><p>The EIP-1167 specification allows us to create a <strong>cloned</strong> <strong>proxy</strong> (aka ‘child’. The technical term is proxy, but ‘child’ is going to be used in this tutorial for the sake of shoehorning the metaphor) to forward all of the logic to an initial “implementation contract” through delegateCall, and then any calls other child smart contracts make will communicate with this implementation contract, call the function there, then relay the return value back to the caller!</p><p>I personally learned a TON about this pattern with these two resources:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://betterprogramming.pub/learn-solidity-the-factory-pattern-75d11c3e7d29">https://betterprogramming.pub/learn-solidity-the-factory-pattern-75d11c3e7d29</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=7H7GVI1gsTc">https://www.youtube.com/watch?v=7H7GVI1gsTc</a> (The beginning 5min of this is amazing and critical for you to understand!)</p><p><strong>Please read the article and watch the video if you are unsure about these concepts.</strong></p><h2 id="h-building-an-implementation-contract-for-your-factory-to-clone" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Building an <strong>Implementation Contract</strong> for your Factory to Clone</h2><p>In this tutorial, I’m going to be using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://remix.ethereum.org/">Remix IDE</a> which was specifically designed for interacting with Solidity and the blockchain.</p><p>Create a new file in Remix named Factory.sol</p><p>Let’s first write out a very basic contract of what we will want to create as our very first implementation contract that future child contracts will be based off of.</p><p><code>Factory.sol</code></p><pre data-type="codeBlock" text="//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import &quot;@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol&quot;;

contract Child {
   string public message = &apos;Default message&apos;;
   function initialize(string memory _message) public initializer {
       message = _message;
   }
}
"><code><span class="hljs-comment">//SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Child</span> </span>{
   <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> message <span class="hljs-operator">=</span> <span class="hljs-string">'Default message'</span>;
   <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initialize</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _message</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">initializer</span> </span>{
       message <span class="hljs-operator">=</span> _message;
   }
}
</code></pre><p>You may be wondering why we are using <code>initialize</code> instead of a <code>constructor</code> .</p><p><code>initialize</code> is used instead of <code>constructor</code> because this contract will be an implementation contract and should only be run once on this implementation contract.</p><p>The import <code>Initializable</code> has some great helper code that only allows initialize to run once on the implementation contract, then never again on the children.</p><p>To read more about <code>initialize</code>, check out the official OpenZeppelin documentation on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies#the-constructor-caveat">“The Constructor Caveat.”</a></p><p>Now that this contract can be created, let&apos;s give it a basic set of functionality.</p><p><code>Factory.sol</code></p><pre data-type="codeBlock" text="//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import &quot;@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol&quot;;

contract Child is Initializable {
   string public message = &apos;Default message&apos;;
   uint256 updatedMessageTally = 0;

   event MessageUpdated(string message, uint256 
updatedMessageTally);

   function initialize(string memory _message) public initializer {
       message = _message;
   }
   function updateMessage(string memory _message) public {
       message = _message;
       updatedMessageTally++;
       emit MessageUpdated(_message, updatedMessageTally);
   }
 }
"><code><span class="hljs-comment">//SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Child</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Initializable</span> </span>{
   <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> message <span class="hljs-operator">=</span> <span class="hljs-string">'Default message'</span>;
   <span class="hljs-keyword">uint256</span> updatedMessageTally <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;

   <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">MessageUpdated</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message, <span class="hljs-keyword">uint256</span> 
updatedMessageTally</span>)</span>;

   <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initialize</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _message</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">initializer</span> </span>{
       message <span class="hljs-operator">=</span> _message;
   }
   <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateMessage</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _message</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
       message <span class="hljs-operator">=</span> _message;
       updatedMessageTally<span class="hljs-operator">+</span><span class="hljs-operator">+</span>;
       <span class="hljs-keyword">emit</span> MessageUpdated(_message, updatedMessageTally);
   }
 }
</code></pre><p>First, each child will have a tally of how many times the message has been updated.</p><p>Second, we define the <code>MessageUpdated</code> event that will eventually be emitted when the message is updated.</p><p>Next, the function <code>updateMessage</code> updates this message stored on the child, triggers an increase in the child’s tally, as well as emits a <code>MessageUpdated</code> event to be indexed by our (not yet written) subgraph that we will work on in Section 4.</p><p>Amazing! You’ve created a simple smart contract that can only be initialized once and is ready to be copied into infinite ‘child’ or proxy contracts by way of a Factory.</p><h2 id="h-building-the-factory" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Building the Factory!</h2><p>Create a new file named “CloneFactory.sol”.</p><p>Read up on the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/taipei-ethereum-meetup/reason-why-you-should-use-eip1167-proxy-contract-with-tutorial-cbb776d98e53">EIP-1167 standard</a>, copy the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol">standard</a> into your <code>CloneFactory.sol</code> file, then import it into your main <code>Factory.sol</code> file.</p><p><code>CloneFactory.sol</code></p><pre data-type="codeBlock" text="//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import &apos;./CloneFactory.sol&apos;;
import &quot;@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol&quot;;

contract Factory is CloneFactory {
    Child[] public children;

    address implementation;

   constructor(address _implementation) {
       implementation = _implementation;
    }

    event ChildCreated(uint date, string message, address childAddress);

    function createChild(string memory message) public {
       Child child = Child(createClone(parent));
       child.initialize(message);
       children.push(child);
       emit ChildCreated(block.timestamp, message, address(child));
    }

    function getChildren() external view returns(Child[] memory){
        return children;
    }
}

contract Child is Initializable {
   string public message = &apos;Default message&apos;;
   uint256 updatedMessageTally = 0;

   event MessageUpdated(string message, uint256 updatedMessageTally);

   function initialize(string memory _message) public initializer {
       message = _message;
   }

   function updateMessage(string memory _message) public {
       message = _message;
       updatedMessageTally++;
       emit MessageUpdated(_message, updatedMessageTally);
   }
 }
"><code><span class="hljs-comment">//SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.0;</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">'./CloneFactory.sol'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Factory</span> <span class="hljs-keyword">is</span> <span class="hljs-title">CloneFactory</span> </span>{
    Child[] <span class="hljs-keyword">public</span> children;

    <span class="hljs-keyword">address</span> implementation;

   <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _implementation</span>) </span>{
       implementation <span class="hljs-operator">=</span> _implementation;
    }

    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">ChildCreated</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> date, <span class="hljs-keyword">string</span> message, <span class="hljs-keyword">address</span> childAddress</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createChild</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> message</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
       Child child <span class="hljs-operator">=</span> Child(createClone(parent));
       child.initialize(message);
       children.<span class="hljs-built_in">push</span>(child);
       <span class="hljs-keyword">emit</span> ChildCreated(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>, message, <span class="hljs-keyword">address</span>(child));
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getChildren</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span>(<span class="hljs-params">Child[] <span class="hljs-keyword">memory</span></span>)</span>{
        <span class="hljs-keyword">return</span> children;
    }
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Child</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Initializable</span> </span>{
   <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> message <span class="hljs-operator">=</span> <span class="hljs-string">'Default message'</span>;
   <span class="hljs-keyword">uint256</span> updatedMessageTally <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;

   <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">MessageUpdated</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message, <span class="hljs-keyword">uint256</span> updatedMessageTally</span>)</span>;

   <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initialize</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _message</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">initializer</span> </span>{
       message <span class="hljs-operator">=</span> _message;
   }

   <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateMessage</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span> _message</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
       message <span class="hljs-operator">=</span> _message;
       updatedMessageTally<span class="hljs-operator">+</span><span class="hljs-operator">+</span>;
       <span class="hljs-keyword">emit</span> MessageUpdated(_message, updatedMessageTally);
   }
 }
</code></pre><p>Our factory is ready to start making proxies!</p><p>Let’s highlight a few key things to go over here for your understanding:</p><ol><li><p>The <code>constructor</code> is being used as opposed to <code>initialize</code> as this will not be an implementation contract when deployed. This is the Factory contract that will not carry any data, just logic for the implementation to reference upon its deployment.</p></li><li><p>An event <code>ChildCreated</code> is made and is emitted in the function call <code>createChild</code>. This will be very helpful when we are trying to index these events with our subgraph in the next section!</p></li><li><p><code>createClone(parent)</code> is called as its clones the parent address of the implementation contract that&apos;s imported upon its creation. This is an important part of the EIP-1167 standard as we are not creating a new child, but a CLONED child.</p></li></ol><p>Now that we have our two smart contracts (Factory and Child) ready, lets deploy!</p><h1 id="h-section-2-deploying-our-two-smart-contracts-in-the-correct-order" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Section 2. Deploying Our Two Smart Contracts In the Correct Order</h1><p>First thing’s first, go back to your Remix IDE and choose your virtual environment to test out your code.</p><p>Make sure your environment is set to Remix VM to keep the deployment local before we go deploy on Goerli.</p><p>Deploy your contracts and perform the following steps in this order:</p><ol><li><p><code>Child</code> is your Implementation Contract as its the first one! Every Child after that will not be the implementation as its not the first!</p><p>You’ll need to initialize it with whatever word or phrase you&apos;d prefer. I’ll put in “Blockchain!”. Remember, this can only be done once on the implementation contract. Feel free to try it on any future Child contracts (you won&apos;t be able to!).</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9db23c21ebeae1e7e722e0068e091ffc03fccca687d8c9adabdeb15de0e59b0a.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Now that the implementation is active, you’re ready to create your Factory based on the address of this implementation!</p><p>2. Copy the address of the deployed Implementation contract and put it into the <code>address_parent</code> input field of <code>Factory - contracts/Factory.sol</code>, then click Deploy.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4c27eed4d588038e935371afab4ef41c58f56acc2d48be55b790a5e2a86a1ab5.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Your Factory is now deployed its first Child based off the initial Child Implementation contract!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e8766742fa6866ebc1572a5078dc745f314208b425a93503c8b21dcc74f628bc.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Now let&apos;s make another child!</p><p>3. At your deployed Factory, create a child by inputting a string into <code>createChild</code>, then press the button! Perform this as many times as you’d like. Feel free to give them names or many words to identify each differently!</p><p>After you’ve created your children, go ahead and click “getChildren.”</p><p>Every time you create a child with your factory, a new address will pop up here! See how the addresses grow every time I add a new Child.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e739c526adbd23ce5a5b5e2fb1271edbed616bc32fe68f4ce8d0aa4203019ccf.png" alt="First Child" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">First Child</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3487b337c38caa0463c3f38fa890bc4b0c1261fd7f3c1bc4e52f7e6ad9892c1a.png" alt="Second Child" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Second Child</figcaption></figure><p>If you ever want to see how your children are doing and interact with their contracts directly as opposed to just listing them out, take the address and input it into the Deploy “At Address” field and <strong>make sure the contract you’ll be deploying is a Child.</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/228ce3e061307a85d2cbee1c04fec7d3a2bff448392657289eaddf661200564c.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Click “AtAddress” and boom! You can start interacting with your child!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9412d4a05dad7e7bd0e9a706b83223658cd7de5d39bfbbbc1c4591664a94f7ef.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>If you try to Initialize your Child, you should see an error message as it has already initialized with the message you fed into it, and initialize can only be run once!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b6caff9a01ecdab2a7487c74647e2c43740e48c1e4d23b5f36052db4268f5df5.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>However, you CAN update the message of the contract using “updateMessage”, then check on the message using “message”.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ad280009c4f6227ab182900c6a675e635fab4729a8645aeb54acac91db09a778.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-congratulations" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Congratulations!</h3><h3 id="h-now-that-youve-been-able-to-deploy-your-factory-pattern-onto-your-test-environment-go-ahead-and-change-your-environments-from-remix-vm-to-injected-provider-then-deploy-it-again-on-the-test-network-goerli" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Now that you’ve been able to deploy your Factory Pattern onto your test environment, go ahead and change your environments from Remix VM to “Injected Provider”, then deploy it again on the test network Goerli!</h3><p>Let&apos;s take a moment to appreciate how amazing this journey has been so far. you have created two smart contracts, you have understood and built an interesting little piece of software architecture, and have now deployed your smart contracts on the blockchain!</p><p>Now that your smart contract children are on the blockchain, let&apos;s create a dynamic subgraph that can index your Children, no matter how many of them are created from the factory!</p><p>To do this your subgraph will need to have templating enabled. Let’s go do that right now.</p><h1 id="h-section-3-indexing-our-infinite-children-with-subgraph-templating" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Section 3: Indexing Our Infinite Children With Subgraph Templating</h1><p>Web2 has Google to index and search web2.</p><p>Web3 has The Graph to index and search the blockchain.</p><p>The Graph (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.thegraph.com">www.thegraph.com</a>) has done the hard work of creating a self-sustaining ecosystem that allows developers easy and affordable access to this data.</p><p>You access this blockchain data through an API they developed called a <strong>Subgraph</strong>.</p><p>Subgraphs can access different parts of the Ethereum blockchain depending on how the Subgraph is designed.</p><p>Read more about The Graph, Subgraphs, and more at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/en/">https://thegraph.com/docs/en/</a></p><h3 id="h-lets-create-a-subgraph-to-index-our-factory-and-dynamically-created-children" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Let’s create a subgraph to index our Factory and dynamically created Children!</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c2c1353a59a3137a48aa5af570b016f8726b00558cbea7fbd175ce806cd4fcf3.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Go to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.thegraph.com">www.thegraph.com</a> and click on Subgraph Studio.</p><p>Click on Create a Subgraph, give it a title, and ensure you are on the Goerli Network.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b49b8be005e1e0283e7d674eaec5279b174538b4064fa9a31d374f29bee51eb9.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>You’ll see a list of instructions on the right of the screen.</p><p>If you haven’t installed graph-cli, do so in your terminal, then run graph init by copy/pasting the code and then follow these instructions:</p><p>1. Choose the ethereum network</p><p>2. Confirm the prenamed subgraph slug as well as the prenamed directory</p><p>3. Choose Goerli network, then init your subgraph with the code in the website by copy/pasting it into your terminal.</p><p>4. When it asks for your contract’s address, go back to remix and choose the contract address of your Factory from the Remix IDE</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c56c8384bd3da3f859784056ef8406bca6cf48d53438a7052efc254388fce679.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>5. Get the ABI of your Factory from the Remix IDE as well, and save it as a json file anywhere on your computer (I saved mine in the working folder itself). Write the path into this portion of the CLI when it asks for it.</p><p>6. Also get the ABI for your Child contract and save it as well. You’ll need this later!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/52e3591b071d6529e9d5265cd8598bcb11d4faaf7461a5adec77c0e93d416c43.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>7. Name the contract “Factory”</p><p>8. Say Yes to indexing the contract events, after which it will install all dependencies.</p><p>9. When it asks you if you want to add another contract, add your Child contract address you previously deployed!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c56c8384bd3da3f859784056ef8406bca6cf48d53438a7052efc254388fce679.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>10. Remember saving the ABI for the child contract? Link that path now.</p><p>11. Name the second contract “Child”</p><p>12. Do not add any more contracts</p><p>13. After the installation, go back to your subgraph’s page at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.thegraph.com">www.thegraph.com</a> and copy/paste the “authenticate in CLI” code into your terminal.</p><p>14. cd into your folder as instructed.</p><p>15. Do NOT continue with graph codegen &amp;&amp; graph build commands. We’ll do those in Section 4.</p><h3 id="h-another-congratulations-you-have-set-up-90percent-of-a-subgraph-to-be-ready-to-index-your-smart-contracts-that-are-active-on-the-blockchain-now-we-need-to-implement-subgraph-templates-by-altering-a-little-bit-of-code-prior-to-deploying" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Another congratulations! You have set up 90% of a subgraph to be ready to index your smart contracts that are active on the blockchain! Now we need to implement subgraph templates by altering a little bit of code prior to deploying.</h3><h1 id="h-section-4-subgraph-templating" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Section 4: Subgraph Templating</h1><p>Read the official documentation on subgraph templating <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/en/developing/creating-a-subgraph/#data-source-templates">here.</a></p><p>By default, a subgraph indexes a single hard-coded smart contract’s events. It is also able to index many hard-coded smart contracts.</p><p>But what happens when a smart contract can dynamically create many smart contracts and hard-coding is impossible as each child has a new address?</p><h3 id="h-enter-subgraph-templating" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Enter subgraph templating!</h3><p>Subgraph templating allows for any dynamic creation of new smart contracts to be indexed automatically by the subgraph without changing any code!</p><p>And lucky for us, implementing a subgraph template is super easy.</p><p>First, lets open up subgraph.yaml that was generated from your amazing use of the CLI.</p><p>This file gives us a high-level perspective of what our subgraph is going to be indexing.</p><p><code>subgraph.yaml</code></p><pre data-type="codeBlock" text="specVersion: 0.0.5
schema:
   file: ./schema.graphql
dataSources:
   - kind: ethereum
     name: Factory
     network: goerli
     source:
         address: &quot;0xCd5282c80fC3829db19743628D02d0e4281D74A4&quot;
         abi: Factory
     mapping:
         kind: ethereum/events
         apiVersion: 0.0.7
         language: wasm/assemblyscript
         entities:
             - ChildCreated
         abis:
             - name: Factory
               file: ./abis/Factory.json
         eventHandlers:
             - event: ChildCreated(uint256,string,address)
               handler: handleChildCreated
         file: ./src/factory.ts
"><code>specVersion: <span class="hljs-number">0</span><span class="hljs-number">.0</span><span class="hljs-number">.5</span>
schema:
   file: ./schema.graphql
dataSources:
   <span class="hljs-operator">-</span> kind: ethereum
     name: Factory
     network: goerli
     source:
         <span class="hljs-keyword">address</span>: <span class="hljs-string">"0xCd5282c80fC3829db19743628D02d0e4281D74A4"</span>
         <span class="hljs-built_in">abi</span>: Factory
     <span class="hljs-keyword">mapping</span>:
         kind: ethereum<span class="hljs-operator">/</span>events
         apiVersion: <span class="hljs-number">0</span><span class="hljs-number">.0</span><span class="hljs-number">.7</span>
         language: wasm<span class="hljs-operator">/</span>assemblyscript
         entities:
             <span class="hljs-operator">-</span> ChildCreated
         abis:
             <span class="hljs-operator">-</span> name: Factory
               file: ./abis<span class="hljs-operator">/</span>Factory.json
         eventHandlers:
             <span class="hljs-operator">-</span> <span class="hljs-function"><span class="hljs-keyword">event</span>: <span class="hljs-title">ChildCreated</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span>,<span class="hljs-keyword">string</span>,<span class="hljs-keyword">address</span></span>)
               <span class="hljs-title">handler</span>: <span class="hljs-title">handleChildCreated</span>
         <span class="hljs-title">file</span>: ./<span class="hljs-title">src</span>/<span class="hljs-title">factory</span>.<span class="hljs-title">ts</span>
</span></code></pre><p>The two edits we need to do are as such:</p><ol><li><p>Edit the startblock</p></li><li><p>Implement templating</p></li></ol><h3 id="h-editing-the-startblock" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Editing the Startblock</h3><p>Editing the start block will significantly accelerate the performance of your subgraph, as your subgraph will not have to search very old blocks, only the recent relevant blocks where your smart contracts have since been deployed!</p><p>Go to your Remix IDE and copy the Factory’s address:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/27bb49bb9e64b64ff67b37ff5d7ecb5504cd7c98fe065cecc1ed3bf7c4435310.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Go to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.etherscan.io">www.etherscan.io</a> and enter that address in the search bar.</p><p>After entering the address, click on the “B” to find your smart contract on Goerli.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8112b52ee650d9a5ef4c8a5cc8565cbbfce4967837c2e0bda728a73ab12f6a09.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>See how the initial startblock was “8328718”?</p><p>That is when we should start indexing our subgraph!</p><p>Copy/paste that number as such into subgraph.yaml:</p><p><code>subgraph.yaml</code></p><pre data-type="codeBlock" text="{...^ Previous Code ^ ...}
- kind: ethereum
   name: Factory
   network: goerli
   source:
     address: &quot;0xCd5282c80fC3829db19743628D02d0e4281D74A4&quot;
     abi: Factory
     startBlock: 8328718
"><code>{...^ Previous Code <span class="hljs-operator">^</span> ...}
<span class="hljs-operator">-</span> kind: ethereum
   name: Factory
   network: goerli
   source:
     <span class="hljs-keyword">address</span>: <span class="hljs-string">"0xCd5282c80fC3829db19743628D02d0e4281D74A4"</span>
     <span class="hljs-built_in">abi</span>: Factory
     startBlock: <span class="hljs-number">8328718</span>
</code></pre><h3 id="h-implementing-subgraph-templating" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Implementing Subgraph Templating</h3><p>We are ready to index and query our Factory smart contract, but what about the <strong>children</strong>!?</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4067922b796ef6584c7f0e727d16f80ac1309d608d825aeb4c11928b031fcbf0.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Don’t fear! Let’s give the subgraph.yaml a “template” portion so any children that are created will dynamically be indexed!</p><p>Templating is simple.</p><ol><li><p>Add ‘templates’ to your Child portion of your subgraph.yaml file</p></li><li><p>Remove the “address” from the Child portion (see the “source” of the Child and compare that source to the one above. The child has their source address removed).</p></li></ol><p><code>subgraph.yaml</code></p><pre data-type="codeBlock" text="specVersion: 0.0.5
schema:
   file: ./schema.graphql
dataSources:
   - kind: ethereum
     name: Factory
     network: goerli
     source:
         address: &quot;0xCd5282c80fC3829db19743628D02d0e4281D74A4&quot;
         abi: Factory
         startBlock: 8328718
     mapping:
         kind: ethereum/events
         apiVersion: 0.0.7
         language: wasm/assemblyscript
         entities:
             - ChildCreated
         abis:
             - name: Factory
               file: ./abis/Factory.json
         eventHandlers:
             - event: ChildCreated(uint256,string,address)
               handler: handleChildCreated
         file: ./src/factory.ts
templates:
   - kind: ethereum
     name: Child
     network: goerli
     source:
         abi: Child
     mapping:
         kind: ethereum/events
         apiVersion: 0.0.7
         language: wasm/assemblyscript
         entities:
             - Initialized
             - MessageUpdated
         abis:
             - name: Child
               file: ./abis/Child.json
         eventHandlers:
             - event: Initialized(uint8)
               handler: handleInitialized
             - event: MessageUpdated(string,uint256)
               handler: handleMessageUpdated
         file: ./src/child.ts
"><code><span class="hljs-attr">specVersion:</span> <span class="hljs-number">0.0</span><span class="hljs-number">.5</span>
<span class="hljs-attr">schema:</span>
   <span class="hljs-attr">file:</span> <span class="hljs-string">./schema.graphql</span>
<span class="hljs-attr">dataSources:</span>
   <span class="hljs-bullet">-</span> <span class="hljs-attr">kind:</span> <span class="hljs-string">ethereum</span>
     <span class="hljs-attr">name:</span> <span class="hljs-string">Factory</span>
     <span class="hljs-attr">network:</span> <span class="hljs-string">goerli</span>
     <span class="hljs-attr">source:</span>
         <span class="hljs-attr">address:</span> <span class="hljs-string">"0xCd5282c80fC3829db19743628D02d0e4281D74A4"</span>
         <span class="hljs-attr">abi:</span> <span class="hljs-string">Factory</span>
         <span class="hljs-attr">startBlock:</span> <span class="hljs-number">8328718</span>
     <span class="hljs-attr">mapping:</span>
         <span class="hljs-attr">kind:</span> <span class="hljs-string">ethereum/events</span>
         <span class="hljs-attr">apiVersion:</span> <span class="hljs-number">0.0</span><span class="hljs-number">.7</span>
         <span class="hljs-attr">language:</span> <span class="hljs-string">wasm/assemblyscript</span>
         <span class="hljs-attr">entities:</span>
             <span class="hljs-bullet">-</span> <span class="hljs-string">ChildCreated</span>
         <span class="hljs-attr">abis:</span>
             <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Factory</span>
               <span class="hljs-attr">file:</span> <span class="hljs-string">./abis/Factory.json</span>
         <span class="hljs-attr">eventHandlers:</span>
             <span class="hljs-bullet">-</span> <span class="hljs-attr">event:</span> <span class="hljs-string">ChildCreated(uint256,string,address)</span>
               <span class="hljs-attr">handler:</span> <span class="hljs-string">handleChildCreated</span>
         <span class="hljs-attr">file:</span> <span class="hljs-string">./src/factory.ts</span>
<span class="hljs-attr">templates:</span>
   <span class="hljs-bullet">-</span> <span class="hljs-attr">kind:</span> <span class="hljs-string">ethereum</span>
     <span class="hljs-attr">name:</span> <span class="hljs-string">Child</span>
     <span class="hljs-attr">network:</span> <span class="hljs-string">goerli</span>
     <span class="hljs-attr">source:</span>
         <span class="hljs-attr">abi:</span> <span class="hljs-string">Child</span>
     <span class="hljs-attr">mapping:</span>
         <span class="hljs-attr">kind:</span> <span class="hljs-string">ethereum/events</span>
         <span class="hljs-attr">apiVersion:</span> <span class="hljs-number">0.0</span><span class="hljs-number">.7</span>
         <span class="hljs-attr">language:</span> <span class="hljs-string">wasm/assemblyscript</span>
         <span class="hljs-attr">entities:</span>
             <span class="hljs-bullet">-</span> <span class="hljs-string">Initialized</span>
             <span class="hljs-bullet">-</span> <span class="hljs-string">MessageUpdated</span>
         <span class="hljs-attr">abis:</span>
             <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Child</span>
               <span class="hljs-attr">file:</span> <span class="hljs-string">./abis/Child.json</span>
         <span class="hljs-attr">eventHandlers:</span>
             <span class="hljs-bullet">-</span> <span class="hljs-attr">event:</span> <span class="hljs-string">Initialized(uint8)</span>
               <span class="hljs-attr">handler:</span> <span class="hljs-string">handleInitialized</span>
             <span class="hljs-bullet">-</span> <span class="hljs-attr">event:</span> <span class="hljs-string">MessageUpdated(string,uint256)</span>
               <span class="hljs-attr">handler:</span> <span class="hljs-string">handleMessageUpdated</span>
         <span class="hljs-attr">file:</span> <span class="hljs-string">./src/child.ts</span>
</code></pre><p>The next step is to now generate your template!</p><p>Go to your terminal and enter</p><p><code>graph codegen</code></p><p>This will generate typesafety to use in our subgraph as well as a Child.ts template file based off of your subgraph.yaml updates that will be stored in your generated/templates/Child/ folder!</p><p>Lets bring that Child.ts template logic into your factory.ts mappings.</p><p>Go to your src/factory.ts file. This file is where your subgraph will handle the data emitting from the event that has occurred on the blockchain.</p><p>Here is the base factory.ts in our subgraph:</p><p><code>src/factory.ts</code></p><pre data-type="codeBlock" text="import { ChildCreated as ChildCreatedEvent } from &quot;../generated/Factory/Factory&quot;
import { ChildCreated } from &quot;../generated/schema&quot;


export function handleChildCreated(event: ChildCreatedEvent): void {
 let entity = new ChildCreated(
   event.transaction.hash.concatI32(event.logIndex.toI32())
 )
 entity.date = event.params.date
 entity.message = event.params.message
 entity.childAddress = event.params.childAddress


 entity.blockNumber = event.block.number
 entity.blockTimestamp = event.block.timestamp
 entity.transactionHash = event.transaction.hash


 entity.save()
"><code><span class="hljs-keyword">import</span> { <span class="hljs-title">ChildCreated</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">ChildCreatedEvent</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../generated/Factory/Factory"</span>
<span class="hljs-title"><span class="hljs-keyword">import</span></span> { <span class="hljs-title">ChildCreated</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../generated/schema"</span>


<span class="hljs-title">export</span> <span class="hljs-title"><span class="hljs-keyword">function</span></span> <span class="hljs-title">handleChildCreated</span>(<span class="hljs-title"><span class="hljs-keyword">event</span></span>: <span class="hljs-title">ChildCreatedEvent</span>): <span class="hljs-title">void</span> {
 <span class="hljs-title">let</span> <span class="hljs-title">entity</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">new</span></span> <span class="hljs-title">ChildCreated</span>(
   <span class="hljs-title"><span class="hljs-keyword">event</span></span>.<span class="hljs-title">transaction</span>.<span class="hljs-title">hash</span>.<span class="hljs-title">concatI32</span>(<span class="hljs-title"><span class="hljs-keyword">event</span></span>.<span class="hljs-title">logIndex</span>.<span class="hljs-title">toI32</span>())
 )
 <span class="hljs-title">entity</span>.<span class="hljs-title">date</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">event</span></span>.<span class="hljs-title">params</span>.<span class="hljs-title">date</span>
 <span class="hljs-title">entity</span>.<span class="hljs-title">message</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">event</span></span>.<span class="hljs-title">params</span>.<span class="hljs-title">message</span>
 <span class="hljs-title">entity</span>.<span class="hljs-title">childAddress</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">event</span></span>.<span class="hljs-title">params</span>.<span class="hljs-title">childAddress</span>


 <span class="hljs-title">entity</span>.<span class="hljs-title">blockNumber</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">event</span></span>.<span class="hljs-title"><span class="hljs-built_in">block</span></span>.<span class="hljs-title">number</span>
 <span class="hljs-title">entity</span>.<span class="hljs-title">blockTimestamp</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">event</span></span>.<span class="hljs-title"><span class="hljs-built_in">block</span></span>.<span class="hljs-title">timestamp</span>
 <span class="hljs-title">entity</span>.<span class="hljs-title">transactionHash</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">event</span></span>.<span class="hljs-title">transaction</span>.<span class="hljs-title">hash</span>


 <span class="hljs-title">entity</span>.<span class="hljs-title">save</span>()
</code></pre><p>Update the file with these two lines of code:</p><pre data-type="codeBlock" text="import { ChildCreated as ChildCreatedEvent } from &quot;../generated/Factory/Factory&quot;;
import { ChildCreated } from &quot;../generated/schema&quot;;
import { Child } from &quot;../generated/templates&quot;;  { THIS LINE }


export function handleChildCreated(event: ChildCreatedEvent): void {
 let entity = new ChildCreated(
   event.transaction.hash.concatI32(event.logIndex.toI32())
 );
 entity.date = event.params.date;
 entity.message = event.params.message;
 entity.childAddress = event.params.childAddress;


 entity.blockNumber = event.block.number;
 entity.blockTimestamp = event.block.timestamp;
 entity.transactionHash = event.transaction.hash;


 entity.save();


 Child.create(event.params.childAddress) { THIS LINE } 
}
"><code><span class="hljs-keyword">import</span> { <span class="hljs-title">ChildCreated</span> <span class="hljs-title"><span class="hljs-keyword">as</span></span> <span class="hljs-title">ChildCreatedEvent</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../generated/Factory/Factory"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">ChildCreated</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../generated/schema"</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title">Child</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../generated/templates"</span>;  { THIS LINE }


export <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleChildCreated</span>(<span class="hljs-params"><span class="hljs-keyword">event</span>: ChildCreatedEvent</span>): <span class="hljs-title">void</span> </span>{
 let entity <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> ChildCreated(
   <span class="hljs-keyword">event</span>.transaction.hash.concatI32(<span class="hljs-keyword">event</span>.logIndex.toI32())
 );
 entity.date <span class="hljs-operator">=</span> <span class="hljs-keyword">event</span>.params.date;
 entity.message <span class="hljs-operator">=</span> <span class="hljs-keyword">event</span>.params.message;
 entity.childAddress <span class="hljs-operator">=</span> <span class="hljs-keyword">event</span>.params.childAddress;


 entity.blockNumber <span class="hljs-operator">=</span> <span class="hljs-keyword">event</span>.block.number;
 entity.blockTimestamp <span class="hljs-operator">=</span> <span class="hljs-keyword">event</span>.block.timestamp;
 entity.transactionHash <span class="hljs-operator">=</span> <span class="hljs-keyword">event</span>.transaction.hash;


 entity.save();


 Child.create(<span class="hljs-keyword">event</span>.params.childAddress) { THIS LINE } 
}
</code></pre><p>These edits import the Child template, then pass in the <code>childAddress</code> to that Child template.</p><p>The template in subgraph.yaml now has that <code>childAddress</code> which means it can begin indexing that brand new address any time ChildCreated is run!</p><p>Now run this in terminal:</p><p><code>graph codegen &amp;&amp; graph build</code></p><p>Now you’re ready to deploy the subgraph!</p><p>Go back to your <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.thegraph.com">www.thegraph.com</a> subgraph page and copy/paste your “deploy subgraph” code into your terminal.</p><h1 id="h-youve-done-it" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">You’ve done it!</h1><p>To start playing around with your subgraph, head over to the subgraph Playground. Use the Explorer button on the right to identify the events you’d like to query.</p><p>Design your query and you’ve got your data coming from the blockchain!</p><p>You can see what your Factory is doing by looking up “childsCreated”.</p><p>You can see what your children have been doing by looking up “messageUpdateds”.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0cc590f4d14b912ddcea0dcc2745094d53cd01e4b17c869893c94bd8f5bc1136.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>These exact same steps you used in this tutorial can be used to deploy this on Ethereum mainnet if you’d like your contract and subgraph to be officially recognized on the Ethereum blockchain and not on a testnet.</p><h2 id="h-thank-you-for-taking-the-time-to-go-through-this-tutorial-and-learning-about-factory-patterns-and-dynamic-templating-within-subgraphs" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Thank you for taking the time to go through this tutorial and learning about factory patterns and dynamic templating within subgraphs.</h2><p>I hope you enjoyed learning as much as I enjoyed writing this up.</p><p>Feel free to watch the video version of this tutorial here and reach out to me on twitter if you have any further thoughts or questions:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.twitter.com/marcus_rein_">http://www.twitter.com/marcus_rein_</a></p><p>Take care!</p><p>Marcus Rein</p>]]></content:encoded>
            <author>madavre@newsletter.paragraph.com (madavre.eth)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/efbd9cccb0bc755650a66550e59cc8390f9fed38562a9ef349181b4157d27574.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Building Your First Dapp with The Graph, a Subgraph, Python, and Flask
]]></title>
            <link>https://paragraph.com/@madavre/building-your-first-dapp-with-the-graph-a-subgraph-python-and-flask</link>
            <guid>lvOO70KSoNHxjBLQQZaJ</guid>
            <pubDate>Mon, 27 Nov 2023 13:59:16 GMT</pubDate>
            <description><![CDATA[Building a powerful decentralized application (or a “dapp”) is easier than you think! Dive into this walkthrough to learn how to build using The Graph, a subgraph, Python, and Flask! TLDR? Watch the video version of this tutorial! And here is the completed repository of this projectImagine being able to see every single transaction that has gone through Bank of America. All of the pseudonymized users, all of the transaction amounts, the date, the time… all of it!Here are some analysis and dat...]]></description>
            <content:encoded><![CDATA[<p>Building a powerful decentralized application (or a “dapp”) is easier than you think! Dive into this walkthrough to learn how to build using The Graph, a subgraph, Python, and Flask!</p><p>TLDR? <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://youtu.be/UqfMQPU4H20">Watch the video version of this tutorial</a>!</p><p><em>And here is the </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/marcusrein/subgraph-to-dapp"><em>completed repository of this project</em></a></p><hr><p>Imagine being able to see <em>every single transaction</em> that has gone through Bank of America.</p><p>All of the pseudonymized users, all of the transaction amounts, the date, the time… all of it!</p><h3 id="h-here-are-some-analysis-and-datapoints-that-id-be-curious-to-see" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Here are some analysis and datapoints that I’d be curious to see:</h3><ul><li><p>What are the biggest transactions in the history of Bank of America?</p></li><li><p>What transactions typically occur the week before and after a person books a hotel room?</p></li><li><p>How does spending change after payday for people making between $50k and $75k?</p></li><li><p>When interest rates go up or down, how does that affect real-estate purchases?</p></li></ul><p><strong>Now imagine you could use that data to create your own app.</strong></p><p>Powerful stuff!</p><p>Now while we cannot access Bank of America transactional data as it is a centralized bank, we CAN do that with the decentralized Ethereum blockchain, as all of the data is public!</p><p>So let’s get to work and build a simple app based on decentralized blockchain data, also known as a “dapp.”.</p><h2 id="h-learning-objectives" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Learning Objectives</h2><p>By the end of the article, you should know how to:</p><ol><li><p>Set up a Python web server with Flask</p></li><li><p>Access blockchain data through an API known as a Subgraph - powered by The Graph Protocol</p></li><li><p>Present this blockchain data clearly in a table.</p></li><li><p>Take what you’ve learned and build your own custom dapp!</p></li></ol><h2 id="h-what-we-are-building" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">What We Are Building</h2><p><strong><em>Our dapp is going to find the biggest swaps ever performed on the token exchange, Uniswap.</em></strong></p><p><strong><em>Let’s name it Top Swaps!</em></strong></p><p>Here is what our dapp will look like when completed:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/962b15c77c9688e20823abb6e9a1cb3e736b40187a9b38927686c7476ba8b958.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><strong>What is Uniswap?</strong></p><p>Uniswap is an exchange built on the Ethereum blockchain, which means that it allows users to easily interact with blockchain transactions of tokens. This is similar to how the New York Stock Exchange allows individuals to quickly and easily exchange stocks, Uniswap allows individuals to quickly and easily exchange tokens.</p><p>Personally, I&apos;m a HUGE fan of Uniswap as it doesn’t ask its users to trust the custody of their tokens to a centralized exchange, such as with FTX (and we all saw what happens when a centralized exchange takes these private keys to do illicit things!).</p><p><em>All users retain full security within their accounts, and the code is fully open-sourced for auditing.</em></p><p>To read more about Uniswap, check out this article:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.coindesk.com/business/2021/02/04/what-is-uniswap-a-complete-beginners-guide/">https://www.coindesk.com/business/2021/02/04/what-is-uniswap-a-complete-beginners-guide/</a></p><h2 id="h-lets-build" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Lets Build!</h2><h3 id="h-set-up-your-virtual-environment" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Set Up Your Virtual Environment</h3><p>In your code editor, open up your terminal and create a virtual environment.</p><p>In python (and many other languages), it’s best practice to use virtual environments as they keep your installed packages separate from your other projects. To read more on why virtual environments are amazing, check out this article: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.geeksforgeeks.org/python-virtual-environment/">https://www.geeksforgeeks.org/python-virtual-environment/</a></p><p>Let&apos;s create a new virtual environment.</p><p><code>python3 -m venv .venv</code></p><p>Nice! <code>.venv</code> is your new virtual environment!</p><p>Now we have to activate the virtual environment.</p><p>If you are working in Linux or Mac, you’ll use this:</p><p><code>source .venv/bin/activate</code></p><p>If you’re on windows, you can activate your virtual environment using this:</p><p><code>.venv/bin/activate.bat</code></p><h3 id="h-install-dependencies" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Install Dependencies</h3><p>Our dapp requires the following items to be installed in our virtual environment.</p><ul><li><p>Flask - the python webserver we will be using</p><ul><li><p>Documentation: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://flask.palletsprojects.com/en/2.2.x/">https://flask.palletsprojects.com/en/2.2.x/</a></p></li><li><p>Short video introduction: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=2BbuB8QP1D4">https://www.youtube.com/watch?v=2BbuB8QP1D4</a></p></li></ul></li><li><p>Dotenv - allows our dapp to pass secure information around our files safely</p><ul><li><p>Documentation: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://pypi.org/project/python-dotenv/">https://pypi.org/project/python-dotenv/</a></p></li><li><p>Short video introduction: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=ryVzkQAtpKQ">https://www.youtube.com/watch?v=ryVzkQAtpKQ</a></p></li></ul></li><li><p>GraphQL Client - allows for our python app to make GraphQL queries</p><ul><li><p>Documentation: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/graphql-python/gql">https://github.com/graphql-python/gql</a></p></li></ul></li><li><p>JsonToHTML - takes a Json file and converts it to a HTML table</p><ul><li><p>Documentation: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://pypi.org/project/json2html/">https://pypi.org/project/json2html/</a></p></li></ul></li></ul><p>To install all of these at once, use this command:</p><p><code>pip install Flask python-dotenv json2html</code></p><p>As well as:</p><p><code>pip install ‘gql[all]’</code></p><h3 id="h-start-our-flask-server" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Start our Flask Server</h3><p>In your home directory of <code>subgraph-to-dapp</code>, create a file called <code>app.py</code></p><p>Copy/paste this code into the file.</p><p>This code imports what is required to run our dapp as well as starts the Flask server when Flask is run.</p><pre data-type="codeBlock" text="from flask import Flask, render_template, request
from dotenv import load_dotenv
from json2html import *
from gql import Client, gql
from gql.transport.aiohttp import AIOHTTPTransport
import os

app = Flask(__name__)
if __name__ == &apos;__main__&apos;:
   app.run()
"><code><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> <span class="hljs-title">Flask</span>, <span class="hljs-title">render_template</span>, <span class="hljs-title">request</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">dotenv</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">load_dotenv</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">json2html</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-operator">*</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">gql</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">Client</span>, <span class="hljs-title">gql</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">gql</span>.<span class="hljs-title">transport</span>.<span class="hljs-title">aiohttp</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">AIOHTTPTransport</span>
<span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">os</span>

<span class="hljs-title">app</span> <span class="hljs-operator">=</span> <span class="hljs-title">Flask</span>(<span class="hljs-title">__name__</span>)
<span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">__name__</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">'__main__'</span>:
   <span class="hljs-title">app</span>.<span class="hljs-title">run</span>()
</code></pre><p>Now let’s tell Flask that this file is the main file that should run when Flask is activated by entering this code in the terminal:</p><p><code>export FLASK_APP=app.py</code></p><p>Let&apos;s also tell Flask that it should be in Debug Mode, which means it will quickly restart the server any time we change the code so we don’t have to manually restart it.</p><p><code>export FLASK_DEBUG=1</code></p><p>We now have a server ready to run! But before we run it, let’s set up a simple landing page so we can actually see if our server is running properly.</p><h3 id="h-connecting-our-server-to-our-front-end" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Connecting our Server to Our Front End</h3><p>Add this code below the code you have previously written:</p><pre data-type="codeBlock" text="@app.route(&quot;/&quot;, methods=[&quot;GET&quot;, &quot;POST&quot;])
def index():
   return render_template(&apos;index.html&apos;)
"><code><span class="hljs-variable">@app</span>.<span class="hljs-built_in">route</span>(<span class="hljs-string">"/"</span>, methods=[<span class="hljs-string">"GET"</span>, <span class="hljs-string">"POST"</span>])
def <span class="hljs-built_in">index</span>():
   return <span class="hljs-built_in">render_template</span>(<span class="hljs-string">'index.html'</span>)
</code></pre><p>Now create a folder in your <code>subgraph-to-dapp</code> directory named <code>templates</code> and create a file called <code>index.html</code></p><p>Your project structure should look something like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2ce04a22e54de854e2ac0ea5548c1e9f1477d84603811678d8b49f9788211ab2.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Copy paste this code into <code>index.html</code>:</p><pre data-type="codeBlock" text="&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
   &lt;head&gt;
       &lt;meta charset=&quot;UTF-8&quot; /&gt;
       &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;
       &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
       &lt;title&gt;Top Swaps&lt;/title&gt;
   &lt;/head&gt;
   &lt;body&gt;
       &lt;h1&gt;Testing our server!&lt;/h1&gt;
   &lt;/body&gt;
&lt;/html&gt;
"><code><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">!</span>DOCTYPE html<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span>html lang<span class="hljs-operator">=</span><span class="hljs-string">"en"</span><span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>head<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta charset<span class="hljs-operator">=</span><span class="hljs-string">"UTF-8"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta http<span class="hljs-operator">-</span>equiv<span class="hljs-operator">=</span><span class="hljs-string">"X-UA-Compatible"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"IE=edge"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta name<span class="hljs-operator">=</span><span class="hljs-string">"viewport"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"width=device-width, initial-scale=1.0"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>title<span class="hljs-operator">></span>Top Swaps<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>title<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>head<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>body<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>h1<span class="hljs-operator">></span>Testing our server<span class="hljs-operator">!</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>body<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>html<span class="hljs-operator">></span>
</code></pre><p>We now have a basic landing page ready to connect to our Flask server.</p><p>Now let&apos;s run our Flask server!</p><p><code>flask run</code></p><p>You should see this code! Your server is running!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9923597d36ce04f8f7c21df27ad7c33747eb6fa5820c75d40b496817d51e9428.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Check the website it suggests <code>http://127.0.0.1:5000/</code> to see if your index.html is also working properly.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/da88e5b30a25cb9dc4884b129865c2411fcd91142636377a1a3f524ad189726c.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>It works!</p><h3 id="h-create-a-form-for-user-input" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Create a Form For User Input</h3><p>The users of Top Swaps will input how many Top Swaps they would like to see and Top Swaps will dynamically update to provide that data.</p><p>To do this, we need to update our index.html to have a form that will get the input that we need from the user:</p><pre data-type="codeBlock" text="&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
   &lt;head&gt;
       &lt;meta charset=&quot;UTF-8&quot; /&gt;
       &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;
       &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
       &lt;title&gt;Top Swaps&lt;/title&gt;
   &lt;/head&gt;
   &lt;body&gt;
       &lt;form method=&quot;post&quot;&gt;
           &lt;h1&gt;
               Want to see the Top Swaps in the history of Uniswap? Enter the number of Top Swaps you want to see!
           &lt;/h1&gt;
           &lt;p&gt;&lt;input type=&quot;number&quot; name=&quot;top_swap_count&quot; /&gt;&lt;/p&gt;
           &lt;p&gt;&lt;input type=&quot;submit&quot; value=&quot;submit&quot; /&gt;&lt;/p&gt;
       &lt;/form&gt;
   &lt;/body&gt;
&lt;/html&gt;
"><code><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">!</span>DOCTYPE html<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span>html lang<span class="hljs-operator">=</span><span class="hljs-string">"en"</span><span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>head<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta charset<span class="hljs-operator">=</span><span class="hljs-string">"UTF-8"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta http<span class="hljs-operator">-</span>equiv<span class="hljs-operator">=</span><span class="hljs-string">"X-UA-Compatible"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"IE=edge"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta name<span class="hljs-operator">=</span><span class="hljs-string">"viewport"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"width=device-width, initial-scale=1.0"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>title<span class="hljs-operator">></span>Top Swaps<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>title<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>head<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>body<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>form method<span class="hljs-operator">=</span><span class="hljs-string">"post"</span><span class="hljs-operator">></span>
           <span class="hljs-operator">&#x3C;</span>h1<span class="hljs-operator">></span>
               Want to see the Top Swaps in the history of Uniswap? Enter the number of Top Swaps you want to see<span class="hljs-operator">!</span>
           <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">></span>
           <span class="hljs-operator">&#x3C;</span>p<span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span>input <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"number"</span> name<span class="hljs-operator">=</span><span class="hljs-string">"top_swap_count"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>p<span class="hljs-operator">></span>
           <span class="hljs-operator">&#x3C;</span>p<span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span>input <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"submit"</span> value<span class="hljs-operator">=</span><span class="hljs-string">"submit"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>p<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>form<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>body<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>html<span class="hljs-operator">></span>
</code></pre><p>We added some context as well as created an input and submit component that is tagged with</p><p><code>name=&quot;top_swap_count&quot;</code></p><p>Which will allow our <code>app.py</code> to both recognize and import the inputted value so it can be processed.</p><p>If you check your webpage, it should update to look like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/91bc3879ce2b216488f3531deff826020f345bb88d5c1913f389c765efa2b02b.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><strong>Congratulations! You have set up your Flask server as well as your input fields for your users!</strong></p><h3 id="h-connecting-our-server-to-the-uniswap-subgraph" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Connecting our Server to the Uniswap Subgraph</h3><p>The blockchain is a HUGE public database that is not easily accessed. In the past, searching blockchain data was terribly costly and time-consuming.</p><p>Luckily, The Graph (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.thegraph.com">www.thegraph.com</a>) has done the hard work of creating a system that allows developers easy and affordable access to this data.</p><p>You access this blockchain data through an API they developed called a <strong>Subgraph</strong>.</p><p>Subgraphs can access different parts of the Ethereum blockchain depending on how the Subgraph is designed.</p><p>The Graph has two types of Subgraphs:</p><p><strong>Hosted</strong>, and <strong>Decentralized</strong>.</p><ol><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/en/deploying/hosted-service/">Hosted</a>: a centralized Subgraph that is hosted by The Graph</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/en/network/explorer/">Decentralized</a>: a Subgraph that is published on the The Graph Network, the decentralized network of indexers around the world!</p></li></ol><p>Read more about The Graph, Subgraphs, and The Graph Network at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/en/">https://thegraph.com/docs/en/</a></p><p>Lets go to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/explorer">The Graph Explorer</a> page and find the Uniswap V3 Decentralized Subgraph which allows access to Uniswap blockchain data, then design our GraphQL query for our dapp.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e69c72d4ce7b8dd638ade240f63f790981bec85866729180d995acb69c62b9dd.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-designing-our-graphql-query-using-subgraph-playground" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Designing our GraphQL Query Using Subgraph Playground</h3><p>Go to the Playground button.</p><p>This will show you a wonderful GraphQL interface that will allow you to easily query the Subgraph in small test queries that you might want to use in your dapp!</p><p>Read more about GraphQL here: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://graphql.org/">https://graphql.org/</a></p><p>Press the big “Play” button in the middle of the page to run a test query that’s prepopulated with a “tokens” and “rewardTokens” query.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c436553729eb82ad54b0ea06d115cd11925ecf0c61099c0b237053946cef99ed.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><strong>This Subgraph is reading from the Ethereum blockchain and the data is ready to be used by you! This would be impossible with current banking institutions such as Bank of America!</strong></p><p>Let’s click on this button on the right of the Playground where we can design our query to find the Top Swaps of this Subgraph:</p><p>Let’s design our Top Swaps query! We want to know:</p><ul><li><p>The value of the token transaction</p></li><li><p>Who its from and who it&apos;s going to</p></li><li><p>When it occurred</p></li><li><p>The names of the tokens swapped</p></li></ul><p>Click around the Explorer tab and create a GraphQL query that contains this information. Once completed, your GraphQL query should look like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/742f1de534e14b24579aff838f433c28de6821da7c1a894657aa617f5f4b21c1.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>You can test your GraphQL query once you’re done by clicking the big “Play” button in the middle of the Playground.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/76869671791dee5f09fb1f29e3c8c2443f1bba29746a405979c0faf2b7c7d20c.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Perfect. This is the data that we need!</p><p>Let’s copy the GraphQL query we designed and bring it into our app as a variable so we can use it!</p><p>Our <code>app.py</code> file should now look this:</p><pre data-type="codeBlock" text="app = Flask(__name__)
if __name__ == &apos;__main__&apos;:
  app.run()
  
subgraph_gql_query = &quot;&quot;&quot;
   {
   swaps(orderBy: amountInUSD, orderDirection: desc, first: 10) {
       amountInUSD
       from
       to
       timestamp
       tokenIn {
       name
       }
       tokenOut {
       name
       }
   }
   }
&quot;&quot;&quot;


@app.route(&quot;/&quot;, methods=[&quot;GET&quot;, &quot;POST&quot;])
def index():
   return render_template(&apos;index.html&apos;)
"><code><span class="hljs-attr">app</span> = Flask(__name__)
if <span class="hljs-attr">__name__</span> == <span class="hljs-string">'__main__'</span>:
  app.run()
  
<span class="hljs-attr">subgraph_gql_query</span> = <span class="hljs-string">"""
   {
   swaps(orderBy: amountInUSD, orderDirection: desc, first: 10) {
       amountInUSD
       from
       to
       timestamp
       tokenIn {
       name
       }
       tokenOut {
       name
       }
   }
   }
"""</span>


@app.route("/", <span class="hljs-attr">methods</span>=[<span class="hljs-string">"GET"</span>, <span class="hljs-string">"POST"</span>])
def index():
   return render_template('index.html')
</code></pre><p>Great! Now we have the query variable we want for our dapp.</p><h4 id="h-accessing-a-subgraphs-endpoint" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">Accessing A Subgraph’s Endpoint</h4><p>Now let’s find the Uniswap Subgraph endpoint address where we can send our beautifully designed query:</p><ol><li><p>Go to the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/explorer/subgraphs/ELUcwgpm14LKPLrBRuVvPvNKHQ9HvwmtKgKSH6123cr7?view=Playground">Uniswap V3 Ethereum Subgraph</a> found on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.thegraph.com/explorer">Subgraph Explorer</a> (at the time of writing this article, this is the most current link though it might be updated to a newer subgraph by now. Go search <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/explorer">Subgraph Explorer</a> to confirm!)</p></li><li><p>Click the “Query” button in the top right corner and bring that link into your app.py workspace.</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/711aab272ce3fb374f4d75d63e87e9bf849b53a8479ef431e0c338aa5fd9ed2a.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>3. Copy the Query URL and bring it into your <code>app.py</code> file.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9a77bc240cf13ce14292dde2113f3032a31b8e17787fb4169334738114aebfbc.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Your <code>app.py</code> should look like this:</p><pre data-type="codeBlock" text="from flask import Flask, render_template, request
from dotenv import load_dotenv
from json2html import *
import requests
import json
import os


app = Flask(__name__)
if __name__ == &apos;__main__&apos;:
  app.run()


subgraph_endpoint = &apos;https://gateway.thegraph.com/api/[api-key]/subgraphs/id/ELUcwgpm14LKPLrBRuVvPvNKHQ9HvwmtKgKSH6123cr7&apos;


query = &quot;&quot;&quot;
   {
   swaps(orderBy: amountInUSD, orderDirection: desc, first: 10) {
       amountInUSD
       from
       to
       timestamp
       tokenIn {
       name
       }
       tokenOut {
       name
       }
   }
   }
&quot;&quot;&quot;


@app.route(&quot;/&quot;, methods=[&quot;GET&quot;, &quot;POST&quot;])
def index():
   return render_template(&apos;index.html&apos;)
"><code><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, render_template, request
<span class="hljs-keyword">from</span> dotenv <span class="hljs-keyword">import</span> load_dotenv
<span class="hljs-keyword">from</span> json2html <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> os


app = Flask(__name__)
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
  app.run()


subgraph_endpoint = <span class="hljs-string">'https://gateway.thegraph.com/api/[api-key]/subgraphs/id/ELUcwgpm14LKPLrBRuVvPvNKHQ9HvwmtKgKSH6123cr7'</span>


query = <span class="hljs-string">"""
   {
   swaps(orderBy: amountInUSD, orderDirection: desc, first: 10) {
       amountInUSD
       from
       to
       timestamp
       tokenIn {
       name
       }
       tokenOut {
       name
       }
   }
   }
"""</span>


<span class="hljs-meta">@app.route(<span class="hljs-params"><span class="hljs-string">"/"</span>, methods=[<span class="hljs-string">"GET"</span>, <span class="hljs-string">"POST"</span>]</span>)</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">index</span>():
   <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>)
</code></pre><p>We now have the endpoint address of the Uniswap Subgraph to which we will be sending our Playground-designed query!</p><h3 id="h-retrieving-and-implementing-our-api-key-securely" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Retrieving and Implementing our API Key Securely</h3><p><em>The Uniswap Subgraph has a “lock” on it to keep it secure.</em></p><p><em>To open this lock and use the Subgraph, we need an API Key. Let&apos;s go get that key!</em></p><ul><li><p>Click “Manage API Keys”</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d5e3773abda5dbb3a607f8650e36397ab5547ff10a0254c8888e91104dc9494c.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Create and connect your Metamask wallet if you haven’t already. Think of this as your own personal wallet - keep it SECURE!</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://metamask.io/">https://metamask.io/</a></p></li><li><p>What is Metamask? <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/watch?v=YVgfHZMFFFQ">https://www.youtube.com/watch?v=YVgfHZMFFFQ</a></p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/338058176233492e0a015a48f8e2f0ada48c46dcfa7ff8db167763135707c00e.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-create-your-first-api-key" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Create your first API key</h3><p>The Graph gives you 1000 free queries with your first API key! Let’s use those queries to test out our new dapp.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/eb4d9b0ae5502d437efdff48f24042dd31bd64d8f59a7db77667fc18326aa9f1.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/55ea7803b2c778cd15cd3731be656d0b3291d551163e7c66cbc8abab1520e383.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Create a <code>.env</code> file in your home directory, then put your API Key in there. Your file structure should look something like this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/102d02f7a9b425454c53991042086694ef453bc1b602025ffe9b9a60dfbe20b5.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>We’ll be implementing environment variable security with this <code>.env</code> file. If you don’t know about this concept, you need to watch the video links below!</p><p>To implement this security, include these final steps to your project:</p><ul><li><p>Use <code>dotenv()</code> to secure this API Key in your <code>.env</code> file by following these video or written instructions:</p><ul><li><p>Video tutorial:<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://youtu.be/ryVzkQAtpKQ">Using Python Dotenv to Manage Environment Variables</a></p></li><li><p>Written tutorial: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://paulapivat.com/technical_notes/example_tech/python_dotenv/">https://paulapivat.com/technical_notes/example_tech/python_dotenv/</a></p></li></ul></li><li><p>After you’ve set up your <code>dotenv()</code>, lets import that key into our query url by using f-strings</p><ul><li><p>F-strings: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.geeksforgeeks.org/formatted-string-literals-f-strings-python/">https://www.geeksforgeeks.org/formatted-string-literals-f-strings-python/</a></p></li></ul></li><li><p>Your <code>app.py</code> Environment Variable code should look something like this when finished with this section.</p></li></ul><p>I’ve added a <code>print()</code> function to confirm that your API key is being imported correctly.</p><pre data-type="codeBlock" text="# Environment Variable Management
load_dotenv()
api_key = os.getenv(&apos;SUBGRAPH_API&apos;)
subgraph_endpoint = f&apos;https://gateway.thegraph.com/api/{api_key}/subgraphs/id/ELUcwgpm14LKPLrBRuVvPvNKHQ9HvwmtKgKSH6123cr7&apos;


print(&apos;This is my API key: &apos; + api_key)
"><code># Environment Variable Management
load_dotenv()
api_key <span class="hljs-operator">=</span> os.getenv(<span class="hljs-string">'SUBGRAPH_API'</span>)
subgraph_endpoint <span class="hljs-operator">=</span> f<span class="hljs-string">'https://gateway.thegraph.com/api/{api_key}/subgraphs/id/ELUcwgpm14LKPLrBRuVvPvNKHQ9HvwmtKgKSH6123cr7'</span>


print(<span class="hljs-string">'This is my API key: '</span> <span class="hljs-operator">+</span> api_key)
</code></pre><p>AMAZING!</p><p>We’ve got our API key into the dapp!</p><p>Let’s make our query accept the number that we have in our front end</p><h3 id="h-running-our-query-through-the-uniswap-subgraph" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Running our Query Through the Uniswap Subgraph</h3><p>Let’s go back to <code>app.py</code> and start building out the logic that creates Top Swaps!</p><p>To begin passing our GraphQL query, we should use the GraphQL Client we imported earlier!</p><p>As per the GraphQL Client <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/graphql-python/gql">documentation</a>, the client needs a “transport” and “client” variable written right below our Environment Variable Management.:</p><pre data-type="codeBlock" text="# Environment Variable Management
load_dotenv()
api_key = os.getenv(&apos;SUBGRAPH_API&apos;)
subgraph_endpoint = f&apos;https://gateway.thegraph.com/api/{api_key}/subgraphs/id/ELUcwgpm14LKPLrBRuVvPvNKHQ9HvwmtKgKSH6123cr7&apos;

transport = AIOHTTPTransport(
   url=subgraph_endpoint
)

client = Client(
   transport=transport,
   fetch_schema_from_transport=True,
)
"><code><span class="hljs-comment"># Environment Variable Management</span>
load_dotenv()
<span class="hljs-attr">api_key</span> = os.getenv(<span class="hljs-string">'SUBGRAPH_API'</span>)
<span class="hljs-attr">subgraph_endpoint</span> = f<span class="hljs-string">'https://gateway.thegraph.com/api/{api_key}/subgraphs/id/ELUcwgpm14LKPLrBRuVvPvNKHQ9HvwmtKgKSH6123cr7'</span>

<span class="hljs-attr">transport</span> = AIOHTTPTransport(
   <span class="hljs-attr">url</span>=subgraph_endpoint
)

<span class="hljs-attr">client</span> = Client(
   <span class="hljs-attr">transport</span>=transport,
   <span class="hljs-attr">fetch_schema_from_transport</span>=<span class="hljs-literal">True</span>,
)
</code></pre><p>Lets update our GraphQL query that we found previously to be dynamically updated by wrapping it in a function as such, written below your previous code:</p><pre data-type="codeBlock" text="load_dotenv()
api_key = os.getenv(&apos;SUBGRAPH_API&apos;)
subgraph_endpoint = f&apos;https://gateway.thegraph.com/api/{api_key}/subgraphs/id/ELUcwgpm14LKPLrBRuVvPvNKHQ9HvwmtKgKSH6123cr7&apos;

transport = AIOHTTPTransport(
   url=subgraph_endpoint
)

client = Client(
   transport=transport,
   fetch_schema_from_transport=True,
)

def update_subgraph_query(input_number):
   subgraph_gql_query = gql(
               &quot;&quot;&quot;
               {
               swaps(orderBy: amountInUSD, orderDirection: desc, first: replaceMe) {
                   amountInUSD
                   from
                   to
                   timestamp
                   tokenIn {
                   name
                   }
                   tokenOut {
                   name
                   }
               }
               }
           &quot;&quot;&quot;.replace(&apos;replaceMe&apos;, input_number))
   return subgraph_gql_query
"><code>load_dotenv()
<span class="hljs-attr">api_key</span> = os.getenv(<span class="hljs-string">'SUBGRAPH_API'</span>)
<span class="hljs-attr">subgraph_endpoint</span> = f<span class="hljs-string">'https://gateway.thegraph.com/api/{api_key}/subgraphs/id/ELUcwgpm14LKPLrBRuVvPvNKHQ9HvwmtKgKSH6123cr7'</span>

<span class="hljs-attr">transport</span> = AIOHTTPTransport(
   <span class="hljs-attr">url</span>=subgraph_endpoint
)

<span class="hljs-attr">client</span> = Client(
   <span class="hljs-attr">transport</span>=transport,
   <span class="hljs-attr">fetch_schema_from_transport</span>=<span class="hljs-literal">True</span>,
)

def update_subgraph_query(input_number):
   <span class="hljs-attr">subgraph_gql_query</span> = gql(
               """
               {
               swaps(orderBy: amountInUSD, orderDirection: desc, first: replaceMe) {
                   amountInUSD
                   from
                   to
                   timestamp
                   tokenIn {
                   name
                   }
                   tokenOut {
                   name
                   }
               }
               }
           """.replace('replaceMe', input_number))
   return subgraph_gql_query
</code></pre><p>You’ll see now that this function takes an input_number and dynamically puts that number into the GraphQL query before returning the updated query. Amazing!</p><p>Let’s take our newly updated query and query the subgraph, then save it as a new variable, ‘response’, then print its contents:</p><pre data-type="codeBlock" text="@app.route(&quot;/&quot;, methods=[&quot;GET&quot;, &quot;POST&quot;])
def index():
   if request.method == &quot;POST&quot;:
       swapInputNumberData = request.form[&quot;top_swap_count&quot;]
       subgraph_gql_query_result = update_subgraph_query(swap_input_number_data)
       response = client.execute(subgraph_gql_query_result)
       print(response)


       return render_template(&apos;index.html&apos;)
"><code>@app.route(<span class="hljs-string">"/"</span>, methods<span class="hljs-operator">=</span>[<span class="hljs-string">"GET"</span>, <span class="hljs-string">"POST"</span>])
def index():
   <span class="hljs-keyword">if</span> request.method <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">"POST"</span>:
       swapInputNumberData <span class="hljs-operator">=</span> request.form[<span class="hljs-string">"top_swap_count"</span>]
       subgraph_gql_query_result <span class="hljs-operator">=</span> update_subgraph_query(swap_input_number_data)
       response <span class="hljs-operator">=</span> client.execute(subgraph_gql_query_result)
       print(response)


       <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>)
</code></pre><p>Enter and submit a number in your webpage:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/597f39a8459315c36aed351fd4fa92dc02be1b697ec8258f970c0a3ae8014100.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Boom! You should see your data in your terminal!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/81097e0ffd2d5dfb2c4f0c2fa183d06690f8bf743371b0d168de0892d8029fb1.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Let&apos;s take our data and bring it into Top Swaps front-end!</p><p>Update your <code>index.html</code> with this code:</p><pre data-type="codeBlock" text="&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
   &lt;head&gt;
       &lt;meta charset=&quot;UTF-8&quot; /&gt;
       &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;
       &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
       &lt;title&gt;Top Swaps&lt;/title&gt;
   &lt;/head&gt;
   &lt;body&gt;
       &lt;form method=&quot;post&quot;&gt;
           &lt;h1&gt;
               Want to see the Top Swaps in the history of Uniswap? Enter the
               number of Top Swaps you want to see!
           &lt;/h1&gt;
           &lt;p&gt;&lt;input type=&quot;number&quot; name=&quot;top_swap_count&quot; /&gt;&lt;/p&gt;
           &lt;p&gt;&lt;input type=&quot;submit&quot; value=&quot;submit&quot; /&gt;&lt;/p&gt;
       &lt;/form&gt;
       &lt;div&gt;{{ response }}&lt;/div&gt;
   &lt;/body&gt;
&lt;/html&gt;
"><code><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">!</span>DOCTYPE html<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span>html lang<span class="hljs-operator">=</span><span class="hljs-string">"en"</span><span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>head<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta charset<span class="hljs-operator">=</span><span class="hljs-string">"UTF-8"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta http<span class="hljs-operator">-</span>equiv<span class="hljs-operator">=</span><span class="hljs-string">"X-UA-Compatible"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"IE=edge"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta name<span class="hljs-operator">=</span><span class="hljs-string">"viewport"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"width=device-width, initial-scale=1.0"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>title<span class="hljs-operator">></span>Top Swaps<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>title<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>head<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>body<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>form method<span class="hljs-operator">=</span><span class="hljs-string">"post"</span><span class="hljs-operator">></span>
           <span class="hljs-operator">&#x3C;</span>h1<span class="hljs-operator">></span>
               Want to see the Top Swaps in the history of Uniswap? Enter the
               number of Top Swaps you want to see<span class="hljs-operator">!</span>
           <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">></span>
           <span class="hljs-operator">&#x3C;</span>p<span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span>input <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"number"</span> name<span class="hljs-operator">=</span><span class="hljs-string">"top_swap_count"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>p<span class="hljs-operator">></span>
           <span class="hljs-operator">&#x3C;</span>p<span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span>input <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"submit"</span> value<span class="hljs-operator">=</span><span class="hljs-string">"submit"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>p<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>form<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>div<span class="hljs-operator">></span>{{ response }}<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>body<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>html<span class="hljs-operator">></span>
</code></pre><p>Enter and submit a number in your dapp. Boom! All of your data should be present on your dapp’s front-end.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/96a2c0f4de8950d56a0d74e85722ae8b1757bfa813a666cbcc582367c5cd2fc3.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Now let&apos;s take that data and make it pretty!</p><ol><li><p>Add this single line of code below our <code>response</code> variable that will first properly format, then convert our data into a nice table.</p></li><li><p>Also update the return to <code>json_table</code> to reflect we’ve converted the data into a table!</p></li></ol><pre data-type="codeBlock" text="@app.route(&quot;/&quot;, methods=[&quot;GET&quot;, &quot;POST&quot;])
def index():
   if request.method == &quot;POST&quot;:
       swap_input_number_data = request.form[&quot;top_swap_count&quot;]
       subgraph_gql_query_result = update_subgraph_query(swap_input_number_data)
       response = client.execute(subgraph_gql_query_result)
       json_table = json2html.convert(json = response)
     
       return render_template(&apos;index.html&apos;, json_table = json_table)
   else:
       return render_template(&apos;index.html&apos;)
"><code>@app.route(<span class="hljs-string">"/"</span>, methods<span class="hljs-operator">=</span>[<span class="hljs-string">"GET"</span>, <span class="hljs-string">"POST"</span>])
def index():
   <span class="hljs-keyword">if</span> request.method <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">"POST"</span>:
       swap_input_number_data <span class="hljs-operator">=</span> request.form[<span class="hljs-string">"top_swap_count"</span>]
       subgraph_gql_query_result <span class="hljs-operator">=</span> update_subgraph_query(swap_input_number_data)
       response <span class="hljs-operator">=</span> client.execute(subgraph_gql_query_result)
       json_table <span class="hljs-operator">=</span> json2html.convert(json <span class="hljs-operator">=</span> response)
     
       <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>, json_table <span class="hljs-operator">=</span> json_table)
   <span class="hljs-keyword">else</span>:
       <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>)
</code></pre><p>3. In index.html, replace <code>{{ response }}</code> with  <code>{{ json_table | safe }}</code> to allow the HTML to run properly in our dapp.</p><pre data-type="codeBlock" text="&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
   &lt;head&gt;
       &lt;meta charset=&quot;UTF-8&quot; /&gt;
       &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;
       &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
       &lt;title&gt;Top Swaps&lt;/title&gt;
   &lt;/head&gt;
   &lt;body&gt;
       &lt;form method=&quot;post&quot;&gt;
           &lt;h1&gt;
               Want to see the Top Swaps in the history of Uniswap? Enter the number of Top Swaps you want to see!
           &lt;/h1&gt;
           &lt;p&gt;&lt;input type=&quot;number&quot; name=&quot;top_swap_count&quot; /&gt;&lt;/p&gt;
           &lt;p&gt;&lt;input type=&quot;submit&quot; value=&quot;submit&quot; /&gt;&lt;/p&gt;
       &lt;/form&gt;
       &lt;div&gt;{{ json_table | safe }}&lt;/div&gt;
   &lt;/body&gt;
&lt;/html&gt;
"><code><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">!</span>DOCTYPE html<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span>html lang<span class="hljs-operator">=</span><span class="hljs-string">"en"</span><span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>head<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta charset<span class="hljs-operator">=</span><span class="hljs-string">"UTF-8"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta http<span class="hljs-operator">-</span>equiv<span class="hljs-operator">=</span><span class="hljs-string">"X-UA-Compatible"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"IE=edge"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>meta name<span class="hljs-operator">=</span><span class="hljs-string">"viewport"</span> content<span class="hljs-operator">=</span><span class="hljs-string">"width=device-width, initial-scale=1.0"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>title<span class="hljs-operator">></span>Top Swaps<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>title<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>head<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span>body<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>form method<span class="hljs-operator">=</span><span class="hljs-string">"post"</span><span class="hljs-operator">></span>
           <span class="hljs-operator">&#x3C;</span>h1<span class="hljs-operator">></span>
               Want to see the Top Swaps in the history of Uniswap? Enter the number of Top Swaps you want to see<span class="hljs-operator">!</span>
           <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>h1<span class="hljs-operator">></span>
           <span class="hljs-operator">&#x3C;</span>p<span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span>input <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"number"</span> name<span class="hljs-operator">=</span><span class="hljs-string">"top_swap_count"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>p<span class="hljs-operator">></span>
           <span class="hljs-operator">&#x3C;</span>p<span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span>input <span class="hljs-keyword">type</span><span class="hljs-operator">=</span><span class="hljs-string">"submit"</span> value<span class="hljs-operator">=</span><span class="hljs-string">"submit"</span> <span class="hljs-operator">/</span><span class="hljs-operator">></span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>p<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>form<span class="hljs-operator">></span>
       <span class="hljs-operator">&#x3C;</span>div<span class="hljs-operator">></span>{{ json_table <span class="hljs-operator">|</span> safe }}<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>div<span class="hljs-operator">></span>
   <span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>body<span class="hljs-operator">></span>
<span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>html<span class="hljs-operator">></span>
</code></pre><p>This data is now formatted in a super nice table!</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0072efb818ff3e2c06086dbde0d2cd74d77809ae47759393419da01e5df34b62.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-were-done" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">We’re done!</h2><p>You created your first dapp!</p><p>Hopefully this was helpful in getting you started in dapp development.</p><p>Here is the completed repository for you to look over: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/marcusrein/subgraph-to-dapp">https://github.com/marcusrein/subgraph-to-dapp</a></p><p>Feel free to reach out and happy developing!</p><p>–</p><p>Marcus Rein</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.twitter.com/marcus_rein_">http://www.twitter.com/marcus_rein_</a></p>]]></content:encoded>
            <author>madavre@newsletter.paragraph.com (madavre.eth)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/4ac55dcfdbf2593fc946502222c016dcfe17e83007544d13a4afe008d01986e3.png" length="0" type="image/png"/>
        </item>
    </channel>
</rss>