<?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>0xEvan</title>
        <link>https://paragraph.com/@0xevan</link>
        <description>Old mirror - https://mirror.xyz/evandekim.eth

https://mirror.xyz/evandekim.eth/kowg_VFD7lp5p12C4wcytc2rooVXgKnUwBd-KUKtndQ</description>
        <lastBuildDate>Sun, 24 May 2026 05:00:17 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[Fetching Uniswap Historical Swap Data With Python and Subgrounds]]></title>
            <link>https://paragraph.com/@0xevan/fetching-uniswap-historical-swap-data-with-python-and-subgrounds</link>
            <guid>7zGuBiYQBDtCJ4ZYoBLE</guid>
            <pubDate>Thu, 30 Nov 2023 22:25:23 GMT</pubDate>
            <description><![CDATA[IntroductionSubgraphs provide a highly curated source of data that can be used for historical data analytics compared to archive nodes. While historically used primarily to power frontend dashboards with recent data, subgraphs are similar to archive nodes because they contain all historical data for a protocols set of contracts. We query historical Uniswap swap data from two subgraphs on The Graphs decentralized network with Subgrounds:streamingfast univ3univ2Use these links to find a list of...]]></description>
            <content:encoded><![CDATA[<h2 id="h-introduction" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Introduction</h2><p>Subgraphs provide a highly curated source of data that can be used for historical data analytics compared to archive nodes. While historically used primarily to power frontend dashboards with recent data, subgraphs are similar to archive nodes because they contain all historical data for a protocols set of contracts.</p><p>We query historical Uniswap swap data from two subgraphs on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/explorer">The Graphs decentralized network</a> with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/0xPlaygrounds/subgrounds">Subgrounds</a>:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/explorer/subgraphs/HUZDsRpEVP2AvzDCyzDHtdc64dyDxx8FQjzsmqSg4H3B?view=Playground&amp;chain=arbitrum-one">streamingfast univ3</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/explorer/subgraphs/A3Np3RQbaBA6oKJgiwDJeo5T3zrYfGHPWFYayMwtNDum?view=Overview&amp;chain=arbitrum-one">univ2</a></p></li></ul><p>Use these links to find a list of available query fields and schemas.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Evan-Kim2028/uniswap_subgraph_downloader">This example repository</a> provides example scripts to get started. The repository wraps additional functionality to:</p><ul><li><p>control the query date range</p></li><li><p>pre-defined query fields for a complete swaps dataset</p></li><li><p>asynchronous query per day</p></li><li><p>idempotent local data storage</p></li></ul><p>Currently playgrounds gives 5000 free query credits to start with when signing up for their API key. Each query credit is equivalent to 1000 rows queried. You can sign up for an <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.playgrounds.network/api/key/">API key here</a>.</p><h1 id="h-data-exploration-with-polars" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Data Exploration with Polars</h1><p>The pre-defined query fields contain the following columns with respective types. These schemas are defined using polars types, which leverages the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Apache_Arrow">apache arrow columnar data format</a>.</p><pre data-type="codeBlock" text="univ3_schema = {
    &apos;&apos;: pl.Int64,
    &apos;protocol&apos;: pl.Utf8,
    &apos;swaps_timestamp&apos;: pl.Int64,
    &apos;swaps_transaction_id&apos;: pl.Utf8,
    &apos;swaps_transaction_blockNumber&apos;: pl.Int64,
    &apos;swaps_transaction_timestamp&apos;: pl.Int64,
    &apos;swaps_transaction_gasPrice&apos;: pl.Float64,
    &apos;swaps_transaction_gasUsed&apos;: pl.Int64,
    &apos;swaps_logIndex&apos;: pl.Int64,
    &apos;swaps_sqrtPriceX96&apos;: pl.Float64,
    &apos;swaps_pool_id&apos;: pl.Utf8,
    &apos;swaps_pool_feeTier&apos;: pl.Int64,
    &apos;swaps_pool_liquidity&apos;: pl.Float64,
    &apos;swaps_pool_token0Price&apos;: pl.Float64,
    &apos;swaps_pool_token1Price&apos;: pl.Float64,
    &apos;swaps_recipient&apos;: pl.Utf8,
    &apos;swaps_sender&apos;: pl.Utf8,
    &apos;swaps_origin&apos;: pl.Utf8,
    &apos;swaps_amount0&apos;: pl.Float64,
    &apos;swaps_amount1&apos;: pl.Float64,
    &apos;swaps_token0_name&apos;: pl.Utf8,
    &apos;swaps_token0_decimals&apos;: pl.Int64,
    &apos;swaps_token0_symbol&apos;: pl.Utf8,
    &apos;swaps_token1_name&apos;: pl.Utf8,
    &apos;swaps_token1_decimals&apos;: pl.Int64,
    &apos;swaps_token1_symbol&apos;: pl.Utf8,
}
"><code>univ3_schema <span class="hljs-operator">=</span> {
    <span class="hljs-string">''</span>: pl.Int64,
    <span class="hljs-string">'protocol'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_timestamp'</span>: pl.Int64,
    <span class="hljs-string">'swaps_transaction_id'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_transaction_blockNumber'</span>: pl.Int64,
    <span class="hljs-string">'swaps_transaction_timestamp'</span>: pl.Int64,
    <span class="hljs-string">'swaps_transaction_gasPrice'</span>: pl.Float64,
    <span class="hljs-string">'swaps_transaction_gasUsed'</span>: pl.Int64,
    <span class="hljs-string">'swaps_logIndex'</span>: pl.Int64,
    <span class="hljs-string">'swaps_sqrtPriceX96'</span>: pl.Float64,
    <span class="hljs-string">'swaps_pool_id'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_pool_feeTier'</span>: pl.Int64,
    <span class="hljs-string">'swaps_pool_liquidity'</span>: pl.Float64,
    <span class="hljs-string">'swaps_pool_token0Price'</span>: pl.Float64,
    <span class="hljs-string">'swaps_pool_token1Price'</span>: pl.Float64,
    <span class="hljs-string">'swaps_recipient'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_sender'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_origin'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_amount0'</span>: pl.Float64,
    <span class="hljs-string">'swaps_amount1'</span>: pl.Float64,
    <span class="hljs-string">'swaps_token0_name'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_token0_decimals'</span>: pl.Int64,
    <span class="hljs-string">'swaps_token0_symbol'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_token1_name'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_token1_decimals'</span>: pl.Int64,
    <span class="hljs-string">'swaps_token1_symbol'</span>: pl.Utf8,
}
</code></pre><pre data-type="codeBlock" text="univ2_schema = {
    &apos;&apos;: pl.Int64,
    &apos;protocol&apos;: pl.Utf8,
    &apos;swaps_transaction_id&apos;: pl.Utf8,
    &apos;swaps_transaction_blockNumber&apos;: pl.Int64,
    &apos;swaps_transaction_timestamp&apos;: pl.Int64,
    &apos;swaps_logIndex&apos;: pl.Int64,
    &apos;swaps_amount0In&apos;: pl.Float64,
    &apos;swaps_amount0Out&apos;: pl.Float64,
    &apos;swaps_amount1In&apos;: pl.Float64,
    &apos;swaps_amount1Out&apos;: pl.Float64,
    &apos;swaps_amountUSD&apos;: pl.Float64,
    &apos;swaps_from&apos;: pl.Utf8,
    &apos;swaps_id&apos;: pl.Utf8,
    &apos;swaps_sender&apos;: pl.Utf8,
    &apos;swaps_to&apos;: pl.Utf8,
    &apos;swaps_pair_id&apos;: pl.Utf8,
    &apos;swaps_pair_reserve0&apos;: pl.Float64,
    &apos;swaps_pair_reserve1&apos;: pl.Float64,
    &apos;swaps_pair_token0_decimals&apos;: pl.Int64,
    &apos;swaps_pair_token0_id&apos;: pl.Utf8,
    &apos;swaps_pair_token0_name&apos;: pl.Utf8,
    &apos;swaps_pair_token0_symbol&apos;: pl.Utf8,
    &apos;swaps_pair_token1_decimals&apos;: pl.Int64,
    &apos;swaps_pair_token1_id&apos;: pl.Utf8,
    &apos;swaps_pair_token1_name&apos;: pl.Utf8,
    &apos;swaps_pair_token1_symbol&apos;: pl.Utf8,
}
"><code>univ2_schema <span class="hljs-operator">=</span> {
    <span class="hljs-string">''</span>: pl.Int64,
    <span class="hljs-string">'protocol'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_transaction_id'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_transaction_blockNumber'</span>: pl.Int64,
    <span class="hljs-string">'swaps_transaction_timestamp'</span>: pl.Int64,
    <span class="hljs-string">'swaps_logIndex'</span>: pl.Int64,
    <span class="hljs-string">'swaps_amount0In'</span>: pl.Float64,
    <span class="hljs-string">'swaps_amount0Out'</span>: pl.Float64,
    <span class="hljs-string">'swaps_amount1In'</span>: pl.Float64,
    <span class="hljs-string">'swaps_amount1Out'</span>: pl.Float64,
    <span class="hljs-string">'swaps_amountUSD'</span>: pl.Float64,
    <span class="hljs-string">'swaps_from'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_id'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_sender'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_to'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_pair_id'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_pair_reserve0'</span>: pl.Float64,
    <span class="hljs-string">'swaps_pair_reserve1'</span>: pl.Float64,
    <span class="hljs-string">'swaps_pair_token0_decimals'</span>: pl.Int64,
    <span class="hljs-string">'swaps_pair_token0_id'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_pair_token0_name'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_pair_token0_symbol'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_pair_token1_decimals'</span>: pl.Int64,
    <span class="hljs-string">'swaps_pair_token1_id'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_pair_token1_name'</span>: pl.Utf8,
    <span class="hljs-string">'swaps_pair_token1_symbol'</span>: pl.Utf8,
}
</code></pre><p>The notebook in the repository demonstrates some basic joins and charts to get started analyzing data between the two protocols. Note the query size is set at <code>2,500</code> so there are only <code>17,500</code> rows for each protocol in the sample data.</p><p>The main benefit from using subgraphs for historical analysis is that the data is already nicely curated. To concat the dataframes together, only the column names need to be standardized. Below shows an example of the nicely curated dataset.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/456d02a7c15bd68afe3b2f86244cff01ba9c9c83b70071357f9a154c39025c76.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>From this dataset, a simple scatterplot is made to show the number of swaps in a pool and the total volume from those number of swaps. Each dot represents a unique pool.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/82390ed21ca9b84b26adcc1f4626be9ca9cdae3ffab9e4c4ba70675a88a101e2.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><h1 id="h-limitations-and-conclusion" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Limitations and Conclusion</h1><p>The main benefit from querying a subgraph for historical data is access to a curated dataset, full of information. In contrast with an archive node, schemas and metadata (such as USD volume and token data) must be written from scratch.</p><p>While subgraphs provide an easy means to access curated datasets with minimal effort, they come with limitations. The decentralized graph network is currently undergoing growth challenges, and the technology stack is not fully matured. Query performance depends on the indexers, and optimizing their stacks and establishing sustainable businesses around the decentralized network is an ongoing process.</p>]]></content:encoded>
            <author>0xevan@newsletter.paragraph.com (0xEvan)</author>
        </item>
        <item>
            <title><![CDATA[Free Historical Blockchain Extraction with Cryo + Merkle Reth Nodes]]></title>
            <link>https://paragraph.com/@0xevan/free-historical-blockchain-extraction-with-cryo-merkle-reth-nodes</link>
            <guid>iIN2Gy13PqZ9mNW1zmaT</guid>
            <pubDate>Thu, 23 Nov 2023 15:12:39 GMT</pubDate>
            <description><![CDATA[IntroductionHistorical blockchain data poses challenges for analysis. Despite its general accessibility, obtaining and analyzing such data has been historically hindered by paywalls and restrictions imposed by node service providers. Setting up a personal archive node is also a non-trivial task, introducing extra steps before data analysis becomes feasible. By leveraging Cryo to extract historical data and utilizing the free Merkle RPC with archive node support, researchers can now easily acc...]]></description>
            <content:encoded><![CDATA[<h3 id="h-introduction" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>Introduction</strong></h3><p>Historical blockchain data poses challenges for analysis. Despite its general accessibility, obtaining and analyzing such data has been historically hindered by paywalls and restrictions imposed by node service providers. Setting up a personal archive node is also a non-trivial task, introducing extra steps before data analysis becomes feasible.</p><p>By leveraging <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/paradigmxyz/cryo">Cryo to extract historical data</a> and utilizing the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://freerpc.merkle.io/">free Merkle RPC with archive node support</a>, researchers can now easily access Ethereum historical data at no cost. This breakthrough provides quantitative researchers with production-grade access, allowing more time for data exploration and less time spent on building data pipelines.</p><h2 id="h-cryo" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/paradigmxyz/cryo">Cryo</a></h2><p>Cryo, a recent addition to data extraction tools, was announced in <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/notnotstorm/status/1687517038305308672">July 2023</a>. It employs <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gakonst/ethers-rs">ethers.rs</a> for JSON-RPC requests, making it compatible with various chains, including Ethereum, Optimism, Arbitrum, Polygon, BNB, and Avalanche. Since Cryo is built in rust, querying data is <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Embarrassingly_parallel">embarassingly parallel</a>. This actually makes Cryo so fast that by default, it will be too fast to use with most node providers.</p><p>When extracting data from a historical node, a common challenge involves preprocessing raw blockchain data to make it human-usable. Cryo takes care of this and standardizes the dataset across a wide variety of datasets. y default, data is saved into Apache&apos;s free, universal, and open-source column-oriented storage format—parquet files. These files use the <code>lz4</code> compression method by default (modifiable with the <code>--compression</code> syntax).</p><p>Some example datasets that are available in Cryo already:</p><ul><li><p>balance_diffs</p></li><li><p>balances</p></li><li><p>blocks</p></li><li><p>erc20_balances</p></li><li><p>erc20_supplies</p></li><li><p>erc20_transfers</p></li><li><p>erc721_transfers</p></li><li><p>eth_calls</p></li><li><p>geth_calls</p></li><li><p>geth_code_diffs</p></li><li><p>geth_balance_diffs</p></li><li><p>geth_opcodes</p></li><li><p>logs (alias = events)</p></li><li><p>native_transfers</p></li><li><p>slots (alias = storages)</p></li><li><p>storage_diffs (alias = slot_diffs)</p></li><li><p>storage_reads (alias = slot_reads)</p></li><li><p>traces</p></li><li><p>trace_calls</p></li><li><p>transactions (alias = txs)</p></li></ul><p>Cryo is user-friendly, accessible through the CLI or Python bindings, significantly simplifying the process of extracting and curating historical data for research. The <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/paradigmxyz/cryo">Cryo GitHub readme</a> provides a set of starter commands. Additionally, Cryo is <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.fivetran.com/blog/what-is-idempotence">idempotent</a>, enabling researchers to resume interrupted pipelines without duplicating queried data.</p><h3 id="h-merkle-rpc" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://freerpc.merkle.io/">Merkle RPC</a></h3><p>Cryo&apos;s efficiency is limited by rate limits and throttling from various node endpoints or personal node hardware. Merkle addresses this bottleneck by offering a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.merkle.io/blog/improving-reth">free RPC with no throttling and unlimited requests</a>. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://freerpc.merkle.io/">The endpoint can be found here</a>. How is this possible?</p><p>Merkle is a private mempool provider and operates a group of RETH nodes, allowing them to save ~$250,000 annually on expenses (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.merkle.io/blog/building-a-eth-load-balancer">source</a>) and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.paradigm.xyz/2022/12/reth">improve performance</a> compared to other mempool services like Kolibrio and Bloxroute. Of equal importance, their cloud provider, OVH, grants them <strong>unlimited outgoing/incoming bandwidth</strong> so don’t feel guilty using the node!</p><p>While Cryo currently supports BSC and Polygon, Reth does not. However, Merkle plans to offer similar public endpoints for BSC and Polygon once they support them.</p><h3 id="h-short-example" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Short Example</h3><p>Here is an example of how I am using Cryo CLI to build a dataset with blocks, transactions, and intra-block balance changes. Two lines of code downloads ~50gb of historical data for the month of September. The limiting factor was my internet speed! The pipeline is largely self managed because of the idempotent nature of Cryo so the only thing I needed to do was create a data folder, Cryo takes care of the subfolder management with <code>--subdirs datatype</code></p><pre data-type="codeBlock" text="`cryo blocks_and_transactions -b 18039828:18251969 -o /home/evan/Documents/blockspace/data/cryo_september/ --rpc &quot;https://eth.merkle.io&quot; --subdirs datatype --hex`

`cryo balance_diffs -b 18039828:18251969 -o /home/evan/Documents/blockspace/data/cryo_september/ --rpc &quot;https://eth.merkle.io&quot; --subdirs datatype --hex`
"><code>`cryo blocks_and_transactions <span class="hljs-operator">-</span>b <span class="hljs-number">18039828</span>:<span class="hljs-number">18251969</span> <span class="hljs-operator">-</span>o <span class="hljs-operator">/</span>home<span class="hljs-operator">/</span>evan<span class="hljs-operator">/</span>Documents<span class="hljs-operator">/</span>blockspace<span class="hljs-operator">/</span>data<span class="hljs-operator">/</span>cryo_september<span class="hljs-operator">/</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc <span class="hljs-string">"https://eth.merkle.io"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>subdirs datatype <span class="hljs-operator">-</span><span class="hljs-operator">-</span>hex`

`cryo balance_diffs <span class="hljs-operator">-</span>b <span class="hljs-number">18039828</span>:<span class="hljs-number">18251969</span> <span class="hljs-operator">-</span>o <span class="hljs-operator">/</span>home<span class="hljs-operator">/</span>evan<span class="hljs-operator">/</span>Documents<span class="hljs-operator">/</span>blockspace<span class="hljs-operator">/</span>data<span class="hljs-operator">/</span>cryo_september<span class="hljs-operator">/</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc <span class="hljs-string">"https://eth.merkle.io"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>subdirs datatype <span class="hljs-operator">-</span><span class="hljs-operator">-</span>hex`
</code></pre>]]></content:encoded>
            <author>0xevan@newsletter.paragraph.com (0xEvan)</author>
        </item>
        <item>
            <title><![CDATA[Cross-Chain NFT Marketplace MEV Strategy with Artemis: A Technical Commentary]]></title>
            <link>https://paragraph.com/@0xevan/cross-chain-nft-marketplace-mev-strategy-with-artemis-a-technical-commentary</link>
            <guid>4ks5i5GKmR6pA2LjMj6w</guid>
            <pubDate>Thu, 04 May 2023 22:10:28 GMT</pubDate>
            <description><![CDATA["A strategy implementing atomic, cross-market NFT arbitrage between Seaport and Sudoswap. At a high level, we listen to a stream of new seaport orders, and compute whether we can atomically fulfill the order and sell the NFT into a sudoswap pool while making a profit." Paradigm recently released Artemis: An Open-Sourced MEV Bot Framework with a cross-market NFT arbitrage strategy implementation included. This is a brief technical commentary focusing on how the initial strategy is setup and ho...]]></description>
            <content:encoded><![CDATA[<p><strong>&quot;A strategy implementing atomic, cross-market NFT arbitrage between Seaport and Sudoswap. At a high level, we listen to a stream of new seaport orders, and compute whether we can atomically fulfill the order and sell the NFT into a sudoswap pool while making a profit.&quot;</strong></p><p>Paradigm recently released <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.paradigm.xyz/2023/05/artemis">Artemis: An Open-Sourced MEV Bot Framework</a> with a cross-market NFT arbitrage strategy implementation included. This is a brief technical commentary focusing on how the initial strategy is setup and how all of the pieces of the library come together.</p><h2 id="h-artemis-core" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Artemis-core</h2><p>Artemis-core provides a shared codebase in which strategies can be executed on. Artemis-core contains a lot of boilerplate overhead. The boilerplate is split into three folders:</p><ul><li><p><code>collectors</code> - provides boilerplate for streaming general events for every new block from the blockchain and transactions in the mempool.</p></li><li><p><code>executors</code> - contains execution logic to send transactions (strategy <code>actions</code>) to the mempool or flashbots relay.</p></li><li><p><code>utilities</code> - contains logic to update and maintain the internal state for a given strategy</p></li><li><p><code>engine.rs</code> - not a folder, but contains the core logic (aka the engine) of Artemis. <code>engine.rs</code> is used to orchestrate the dataflow between the data stream, the internal state, and sending transactions back on-chain for execution.</p></li></ul><h2 id="h-smart-contracts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Smart Contracts</h2><p><code>strategy.rs</code> utilizes two smart contracts - <code>SudoOpenseaArb.sol</code> and <code>SudoPairQuoter.sol</code>.</p><ul><li><p><code>SudoOpenseaArb.sol</code> contains the <code>executeArb</code> and <code>withdraw</code>.</p></li><li><p><code>SudoPairQuoter.sol</code> contains <code>getSellQuote</code> and <code>getMultipleSellQuotes</code>. These are both view functions that return the on-chain Sudo pool quote price.</p></li></ul><h2 id="h-strategyrs-logic" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">strategy.rs logic</h2><p>In the opensea-sudo-arb folder, <code>strategy.rs</code> holds the bulk of the code for executing this arbitrage strategy. The logic for the strategy can be broken down into these core async functions:</p><ul><li><p><code>sync_state</code> gets the on-chain state of all Sudo pools. The list of Sudo pool addresses are retrieved by searching within a block range for all pools deployed. This set of addresses is used to initialize an empty internal state.</p></li><li><p><code>process_event</code> updates the internal state with Opensea orders from the API and sudo pool offers. Sudo pool offers are retrieved by using the <code>view</code> functions in <code>SudoPairQuoter.sol</code></p></li><li><p><code>process_order_event</code> filters out the state space for orders that are not on ethereum, not denominated in eth, and are not profitable. This leaves the only remaining pool addresses as the profitable arb transactions to submit for execution.</p></li><li><p><code>process_new_block_event</code> updates the internal state space with new Sudo pools created in the last block and retrieves updated quotes for Sudo pools that have changed price since the last block.</p></li></ul><h2 id="h-conclusion" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Conclusion</h2><p>Paradigm has done the heavy lifting for taking a bot project from 0 to 1. New strategies that are added benefit from <code>Artemis-core</code>, which contains a lot of boilerplate code for retrieving blockchain data, building a strategy around the inputs, and executing transactions.</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"></h2>]]></content:encoded>
            <author>0xevan@newsletter.paragraph.com (0xEvan)</author>
        </item>
        <item>
            <title><![CDATA[Streamline Subgraph Pipeline Creation With DataStreams]]></title>
            <link>https://paragraph.com/@0xevan/streamline-subgraph-pipeline-creation-with-datastreams</link>
            <guid>Fx0pbT6uPTKTkYAix0Gu</guid>
            <pubDate>Mon, 16 Jan 2023 23:14:33 GMT</pubDate>
            <description><![CDATA[DataStreams a Subgraph query utility package that allows users to execute complex Subgraph queries. It provides extended functionality on top of The Graph data access python package Subgrounds. The main benefit is that now anyone can query Subgraph data, save it to their local storage as csv files, and perform data analytics immediately. DataStreams creates a reproducible data pipeline creation process in a transparent, lightweight manner. No database needed! The main package in DataStreams i...]]></description>
            <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Evan-Kim2028/DataStreams">DataStreams</a> a Subgraph query utility package that allows users to execute complex Subgraph queries. It provides extended functionality on top of The Graph data access python package <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Protean-Labs/subgrounds">Subgrounds</a>. The main benefit is that now anyone can query Subgraph data, save it to their local storage as csv files, and perform data analytics immediately. DataStreams creates a reproducible data pipeline creation process in a transparent, lightweight manner. No database needed!</p><p>The main package in DataStreams is the <code>Streamer</code> class. <code>Streamer</code> streamlines the Subgraph query process in Python, exposing key information such as the queryable Subgraph schemas and filter clauses. In v1.0.0, functionality includes:</p><ul><li><p>DRY Subgraph Query Code - reuse code to reduce complexity of Subgraph queries</p></li><li><p>Parallelized Subgraph Queries - Leverage the standard Python package <code>concurrent</code> to unlock concurrency at the Subgraph query level</p></li></ul><h3 id="h-example-1-access-historical-chainlink-node-data" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Example #1 - Access Historical Chainlink Node Data</h3><p>Query the Chainlink Subgraph node for multiple token prices over a customized ranged period. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Evan-Kim2028/DataStreams/blob/master/examples/chainlink_historical_price.ipynb">Example notebook found here</a></p><h3 id="h-example-2-parallelized-multi-schema-query" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Example #2 - Parallelized Multi Schema Query</h3><p>Query the Cowswap Subgraph node for four specific schemas with parallelization support. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Evan-Kim2028/DataStreams/blob/master/examples/cowswap_schemas.ipynb">Example notebook found here</a></p>]]></content:encoded>
            <author>0xevan@newsletter.paragraph.com (0xEvan)</author>
        </item>
    </channel>
</rss>