<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Alex Kit]]></title><description><![CDATA[Alex Kit]]></description><link>https://dev.kit.eco</link><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 10:46:33 GMT</lastBuildDate><atom:link href="https://dev.kit.eco/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Safely Verify Ethereum Contract Upgrades]]></title><description><![CDATA[Here we will go through the process of contract upgrades. I assume you are already familiar with proxy patterns in Ethereum. No matter which libraries or frameworks you use, every upgrade ends with the same critical action: executing the method that ...]]></description><link>https://dev.kit.eco/how-to-safely-verify-ethereum-contract-upgrades</link><guid isPermaLink="true">https://dev.kit.eco/how-to-safely-verify-ethereum-contract-upgrades</guid><category><![CDATA[Ethereum]]></category><category><![CDATA[Solidity]]></category><dc:creator><![CDATA[Alex Kit]]></dc:creator><pubDate>Mon, 15 Dec 2025 00:06:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765755662406/058e649f-3457-4868-a25a-2823588138c7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here we will go through the process of contract upgrades. I assume you are already familiar with proxy patterns in Ethereum. No matter which libraries or frameworks you use, every upgrade ends with the same critical action: executing the method that replaces the old implementation contract address with the new one. This step must be reviewed by you, your team, and ideally by external reviewers as well.</p>
<p>Before we get to the verification flow, here is a short overview of how we develop, deploy, and upgrade our contracts.</p>
<h3 id="heading-contracts-develop-deploy-upgrade">Contracts: Develop, Deploy, Upgrade</h3>
<p>We use the 0xweb stack of libraries:
<a target="_blank" href="https://github.com/0xweb-org/0xweb">0xweb</a>, <a target="_blank" href="https://github.com/0xweb-org/hardhat">0xweb-hardhat</a>, <a target="_blank" href="https://github.com/0xweb-org/dequanto">dequanto</a></p>
<p>This gives us the following workflow:</p>
<ol>
<li>Write Solidity contracts as usual.</li>
<li>Run <code>npx hardhat compile --watch</code>.
The 0xweb plugin compiles the Solidity files and generates, for each contract, a TypeScript or JavaScript client class. Each generated class encapsulates the blockchain interaction layer and exposes a clean interface.</li>
</ol>
<blockquote>
<p>The <code>--watch</code> flag triggers recompilation as soon as you save modified Solidity files.</p>
</blockquote>
<p>Each generated class is linked to the Hardhat artifacts, which are used by the deployment factory:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { MyFooContract } <span class="hljs-keyword">from</span> <span class="hljs-string">'@0xc/hardhat/MyFooContract/MyFooContract'</span>;
<span class="hljs-keyword">import</span> { Deployments } <span class="hljs-keyword">from</span> <span class="hljs-string">'dequanto/contracts/deploy/Deployments'</span>;
<span class="hljs-keyword">import</span> { Web3ClientFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'dequanto/clients/Web3ClientFactory'</span>;

<span class="hljs-keyword">let</span> client = <span class="hljs-keyword">await</span> Web3ClientFactory.getAsync(<span class="hljs-string">'eth'</span>);
<span class="hljs-keyword">let</span> deployments = <span class="hljs-keyword">new</span> Deployments(client, deployer, {
    directory: <span class="hljs-string">'./deployments/'</span>,
    whenBytecodeChanged: <span class="hljs-string">'redeploy'</span>
});

<span class="hljs-keyword">let</span> { contract: foo } = <span class="hljs-keyword">await</span> deployments.ensure(MyFooContract, {
    <span class="hljs-built_in">arguments</span>: someConstructorArgs
});

<span class="hljs-comment">// Read method</span>
<span class="hljs-keyword">let</span> someValue = <span class="hljs-keyword">await</span> foo.getSomeValue();
<span class="hljs-comment">// Write method</span>
<span class="hljs-keyword">let</span> tx = <span class="hljs-keyword">await</span> foo.$receipt().setSomeValue(deployer, <span class="hljs-number">123</span>);
</code></pre>
<p>The <code>ensure</code> method checks whether the contract is already deployed on the selected network and whether the bytecode matches. If the bytecode is unchanged, it returns a ready-to-use instance; otherwise, it deploys the contract. After deployment it also <strong>verifies</strong> the contract on the blockchain explorer (for Ethereum this is Etherscan).</p>
<p>This works well for stateless contracts. For stateful contracts you usually need upgradeable proxies, so that the storage stays intact while the implementation changes. The deployment factory supports <code>TransparentUpgradeableProxy</code> through the <code>ensureWithProxy</code> method:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> { contract: foo } = <span class="hljs-keyword">await</span> deployments.ensureWithProxy(MyFooContract, {
    <span class="hljs-built_in">arguments</span>: someConstructorArgs,
    initialize: someInitializerArgs
});
</code></pre>
<p>Here, the factory compares the deployed bytecode with the current build. If there are changes, it redeploys the implementation contract and submits an <code>upgradeToAndCall</code> transaction.</p>
<p><strong>Important:</strong> the <code>ProxyAdmin</code> should not be your deployer account. It should be a <code>Timelock</code>, or at least a <code>Multisig</code>. A safe setup looks like this:</p>
<p><code>MyFooContractProxy</code> ← <code>Timelock</code> ← <code>Multisig</code></p>
<p>This ensures that upgrade transactions cannot be executed immediately.
Dequanto supports many account types (Timelock, Multisig, ERC-4337), but we will not go into those details here.</p>
<p>The key point is: you now have a pending upgrade transaction that will replace the implementation of your proxy. Before approving it, you must compare the old and new implementations. Below are the steps we use.</p>
<hr />
<h2 id="heading-implementation-comparison-workflow">Implementation Comparison Workflow</h2>
<h3 id="heading-1-check-out-the-exact-commit-used-for-deployment">1. Check out the exact commit used for deployment</h3>
<p>Every deployment must correspond to a specific git commit. If you don't have it locally, fetch it with minimal history:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> --no-checkout my-repo
<span class="hljs-built_in">cd</span> my-repo
git fetch --depth 1 origin &lt;commit-hash&gt;
git checkout &lt;commit-hash&gt;
</code></pre>
<p>You now have the exact sources that were used for deployment.</p>
<h3 id="heading-2-download-verified-sources-for-the-old-and-new-implementations">2. Download verified sources for the old and new implementations</h3>
<pre><code class="lang-bash">npm i 0xweb -g
0xweb i &lt;old-implementation-address&gt; --chain eth --name myFooV1
0xweb i &lt;new-implementation-address&gt; --chain eth --name myFooV2
</code></pre>
<p>After this step, you have three sets of sources:</p>
<ul>
<li>repository sources from the referenced commit,</li>
<li>verified sources for the old implementation,</li>
<li>verified sources for the new implementation.</li>
</ul>
<h3 id="heading-3-compare-the-new-implementation-against-the-old-one">3. Compare the new implementation against the old one</h3>
<pre><code class="lang-bash">git diff --no-index ./0xc/eth/myFooV1/myFooV1/contracts/ ./0xc/eth/myFooV2/myFooV2/contracts/
</code></pre>
<p>This diff shows exactly what changed between versions.</p>
<h3 id="heading-4-compare-repository-sources-against-the-new-implementation">4. Compare repository sources against the new implementation</h3>
<pre><code class="lang-bash">git diff --no-index --diff-filter=DM ./0xc/eth/myFooV2/myFooV2/contracts/ ./my-repo/contracts/
</code></pre>
<p>We use the <code>DM</code> filter to show only deleted and modified files, because the repository will often include extra files that are not part of the verified sources.</p>
<p>The goal here is simple: the <strong>output should be empty</strong>.
If there is no diff, then the verified implementation matches your codebase.</p>
<hr />
<p>These two comparisons are essential. Each party involved in the upgrade process should review them before signing and executing the upgrade transaction through the multisig.</p>
]]></content:encoded></item><item><title><![CDATA[Blockchain-as-a-Backend]]></title><description><![CDATA[This article isn’t about cryptocurrency or decentralized finance. Instead, we’ll explore public EVM blockchains and how they can be used in your next project, depending on your specific needs and goals. I’ll delve into the pros, cons, and practical e...]]></description><link>https://dev.kit.eco/blockchain-as-a-backend</link><guid isPermaLink="true">https://dev.kit.eco/blockchain-as-a-backend</guid><category><![CDATA[Blockchain]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[EVM]]></category><dc:creator><![CDATA[Alex Kit]]></dc:creator><pubDate>Wed, 25 Dec 2024 23:47:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732110417097/4fe327cc-f6fe-4d8a-94ef-48fd1450dca4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article isn’t about cryptocurrency or decentralized finance. Instead, we’ll explore public EVM blockchains and how they can be used in your next project, depending on your specific needs and goals. I’ll delve into the pros, cons, and practical examples, using the <strong>0xweb</strong> library that I’ve been working on.</p>
<h3 id="heading-pro-et-contra">§ <em>pro et contra</em></h3>
<h4 id="heading-zero-setup-time">• 🚀 Zero setup time</h4>
<p>It is already up and running. Simply define your data model as a contract and deploy it.</p>
<h4 id="heading-zero-maintenance">• ✨ Zero maintenance</h4>
<p>Once your data is uploaded, it remains accessible as long as the blockchain operates. I can assume that it will be far longer than your other hosting subscription.</p>
<h4 id="heading-100-read-uptime-close-to-100-write-uptime">• 💯 100% Read uptime; close to 100% Write uptime</h4>
<p>The separation of reading and writing processes in blockchain ensures 100% uptime for read operations, especially when leveraging multiple RPC providers for redundancy.</p>
<h4 id="heading-secure">• 🛡️ Secure</h4>
<p>Blockchains inherently provide a higher level of security than conventional hosting solutions. Data exploits are possible only if vulnerabilities exist in your data model’s logic.</p>
<h4 id="heading-open-data">• 📖 Open Data</h4>
<p>Unless encrypted, your data remains open, accessible, and verifiable by anyone, promoting transparency.</p>
<h4 id="heading-dns-free">• 🖧 DNS-Free</h4>
<p>Domain names are unnecessary for this type of backend. Instead, a list of decentralized node providers can be used, allowing client libraries to select the most efficient option for end-users.</p>
<h4 id="heading-trust">• 🤝 Trust</h4>
<p>Thanks to the features above, blockchain-based backends inherently build user trust by ensuring data security and 24/7 availability, even if project maintenance and development stops.</p>
<h4 id="heading-interepolibility-with-3rd-party-data-models">• 🧩 Interepolibility <em>with 3rd party data models</em></h4>
<p>You can integrate other data models stored on the blockchain, or other projects can build upon your data model.</p>
<h4 id="heading-extensibility">• ⚙️ Extensibility</h4>
<p>Users can leverage numerous third-party projects to monitor or automate actions, significantly expanding the possibilities of your data model.</p>
<h4 id="heading-history-and-time-travel">• 📜 History and time-travel</h4>
<p>The data can be accessed from any point in the past.</p>
<h4 id="heading-events-and-event-streams">• 📡 Events and event-streams</h4>
<p>Load historical custom events or use WebSockets to listen for real-time incoming events, enabling dynamic application responses.</p>
<h4 id="heading-built-in-user-identity">• 👤 Built-in user identity</h4>
<p>The “wallet” concept enables users to authenticate themselves by signing messages, providing seamless and decentralized user identification.</p>
<h4 id="heading-grant-users-to-modify-or-extend-data">• 📝 Grant users to modify or extend data</h4>
<p>Users can modify or extend data in your storage based on the permissions you define. Importantly, the costs of these modifications are borne by the users themselves. By selecting a low-cost blockchain, these fees can remain negligible, often amounting to only a few cents per transaction.</p>
<h4 id="heading-huge-and-continuously-evolving-ecosystem">• 🌐 Huge and continuously evolving ecosystem</h4>
<ul>
<li><p>numerous solidity modules you can use to enhance your data model's functionality.</p>
</li>
<li><p>many open-source and free services, as well as those offering free plans, are available. It is a common practice within the blockchain community to provide free plans that are often sufficient for production needs.</p>
</li>
</ul>
<h3 id="heading-contra">§ <em>contra</em></h3>
<h4 id="heading-storage-is-expensive">• 💾 Storage is expensive 😢</h4>
<p>Though it follows a true pay-as-you-go model, you pay just for the SLOTs you store in. Each SLOT has 32 bytes, it costs 20000 GAS to write new data or 5000 GAS to update the data. Let's take Polygon as an example, with a 30-gwei GAS price and a $0.60 POL price.</p>
<p>\(20000GAS <em> 30gwei = 0.008 POL </em>$0.60 = $0.00032\)</p>
<p>This is a lot, so the “Floppy Disk“ emoji represents the storage amounts in the best way, which means it is best suited for smaller datasets if you pay on your own. However, a unique advantage is that users can bear the costs of their own storage and actions, a feature not found in other technologies. While this approach might hinder the mass adoption of your app, it is widely accepted within the blockchain community.</p>
<h4 id="heading-computation-is-limited">• 🧮 Computation is limited 😢</h4>
<p>Blockchain data models support functions for interacting with the data, but their computational capabilities have constraints. These limitations depend on the RPC nodes you use for read actions and the strict GAS limits imposed on write actions (transactions). While basic operations, loops, and deeper call stacks are typically manageable, the blockchain is unsuited for heavy computational workloads.</p>
<p>That said, given the relatively small data sizes typically involved, the existing limits are usually sufficient for most use cases.</p>
<h3 id="heading-punctum-neutrum">§ <em>punctum neutrum</em></h3>
<h4 id="heading-data-structure-solidity-language-sdks">• 🧬 Data structure, Solidity language, SDKs</h4>
<p>If you're new to blockchain development, you may have heard that it’s complicated and hard to get started with. However, this is not true. Blockchain development uses familiar concepts, semantics, and syntax, making it easier to learn than it might seem.</p>
<h3 id="heading-demo-application-version-repository">§ Demo: Application Version Repository</h3>
<p><a target="_blank" href="https://github.com/0xweb-org/examples-backend">https://github.com/0xweb-org/examples-backend</a></p>
<p>For this article, let’s create an application version manager contract. Imagine you have a desktop application that requires a backend to check for new versions and retrieve the download link whenever a new version is published. Below is the final contract, demonstrating most of the key concepts:</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">import</span> { <span class="hljs-title">Ownable</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/access/Ownable.sol"</span>;

<span class="hljs-keyword">struct</span> <span class="hljs-title">Package</span> {
    <span class="hljs-keyword">uint</span> version;
    <span class="hljs-keyword">uint</span> timestamp;
    <span class="hljs-keyword">string</span> url;
    <span class="hljs-keyword">bytes32</span> <span class="hljs-built_in">sha256</span>;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">AppVersionManager</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Ownable</span> </span>{

    <span class="hljs-comment">// Events that are emitted on data updates</span>
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">NewApplicationInfo</span>(<span class="hljs-params"></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">NewPackage</span>(<span class="hljs-params"><span class="hljs-keyword">uint</span> version, <span class="hljs-keyword">uint</span> timestamp</span>)</span>;

    <span class="hljs-comment">// Custom error, when title for the application is empty</span>
    <span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">TitleIsEmpty</span>(<span class="hljs-params"></span>)</span>;

    <span class="hljs-comment">// Some application information</span>
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> title;
    <span class="hljs-comment">// @<span class="hljs-doctag">TODO:</span> add further application related properties if required</span>

    <span class="hljs-comment">// Latest package</span>
    Package <span class="hljs-keyword">public</span> package;

    <span class="hljs-comment">// Track all versions and their packages</span>
    <span class="hljs-keyword">mapping</span> (<span class="hljs-keyword">uint</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> Package) <span class="hljs-keyword">public</span> packages;

    <span class="hljs-comment">// List of all previous versions</span>
    <span class="hljs-keyword">uint</span>[] <span class="hljs-keyword">public</span> versions;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span> (<span class="hljs-params"></span>) <span class="hljs-title">Ownable</span>(<span class="hljs-params"><span class="hljs-built_in">msg</span>.sender</span>) </span>{
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateInfo</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">calldata</span> newTitle</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">bytes</span>(newTitle).<span class="hljs-built_in">length</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">revert</span> TitleIsEmpty();
        }
        title <span class="hljs-operator">=</span> newTitle;
        <span class="hljs-keyword">emit</span> NewApplicationInfo();
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updatePackage</span>(<span class="hljs-params">Package <span class="hljs-keyword">calldata</span> newPackage</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title">onlyOwner</span> </span>{
        <span class="hljs-built_in">require</span>(newPackage.version <span class="hljs-operator">&gt;</span> package.version, <span class="hljs-string">"Newer package already published"</span>);

        packages[package.version] <span class="hljs-operator">=</span> package;
        package <span class="hljs-operator">=</span> newPackage;
        versions.<span class="hljs-built_in">push</span>(package.version);
        <span class="hljs-keyword">emit</span> NewPackage(package.version, <span class="hljs-built_in">block</span>.<span class="hljs-built_in">timestamp</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findPackageAtTimestamp</span> (<span class="hljs-params"><span class="hljs-keyword">uint</span> timestamp</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">Package <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">if</span> (package.timestamp <span class="hljs-operator">&lt;</span><span class="hljs-operator">=</span> timestamp) {
            <span class="hljs-keyword">return</span> package;
        }
        <span class="hljs-comment">// the countdown loop to find the latest package for the timestamp</span>
        <span class="hljs-keyword">int</span> i <span class="hljs-operator">=</span> <span class="hljs-keyword">int</span>(versions.<span class="hljs-built_in">length</span>);
        <span class="hljs-keyword">while</span> (<span class="hljs-operator">-</span><span class="hljs-operator">-</span>i <span class="hljs-operator">&gt;</span> <span class="hljs-number">-1</span>) {
            Package <span class="hljs-keyword">memory</span> pkg <span class="hljs-operator">=</span> packages[versions[<span class="hljs-keyword">uint</span>(i)]];
            <span class="hljs-keyword">if</span> (pkg.timestamp <span class="hljs-operator">&lt;</span><span class="hljs-operator">=</span> timestamp) {
                <span class="hljs-keyword">return</span> pkg;
            }
        }
        <span class="hljs-keyword">revert</span>(<span class="hljs-string">"No package found"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPackage</span> (<span class="hljs-params"><span class="hljs-keyword">uint</span> version</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">Package <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">if</span> (version <span class="hljs-operator">=</span><span class="hljs-operator">=</span> package.version) {
            <span class="hljs-keyword">return</span> package;
        }
        <span class="hljs-keyword">return</span> packages[version];
    }
}
</code></pre>
<p>Every developer can read and understand this code with minimal effort. If you’re familiar with TypeScript, most of the concepts here will already make sense. To make it even clearer, I’ve created an equivalent TypeScript example: <a target="_blank" href="https://github.com/0xweb-org/examples-backend/blob/master/contracts/AppVersionManager.ts"><strong>AppVersionManager.ts</strong></a> <strong>🔗</strong>.</p>
<p>In simple terms, a contract in Solidity can be thought of as a <em>stateful class instance</em>. The concepts of properties, methods, types, and inheritance are already well-known in object-oriented programming. The main concept to explain here is the <code>onlyOwner</code> modifier (similar to a decorator in TypeScript).</p>
<p>Every blockchain account is essentially a pair of private and public keys. The account's ID, known as the <em>address</em>, is derived from the public key. When a transaction is executed, the sender’s address is passed as <code>msg.sender</code>. Using this, we can store your address in the constructor (during contract deployment). Later, the <code>onlyOwner</code> modifier ensures that only you, as the contract owner, can execute the <code>updateInfo</code> and <code>updatePackage</code> functions. If someone else attempts these actions, the transaction will be reverted. The <code>onlyOwner</code> modifier is provided by the <code>Ownable</code> contract, which is part of the widely-used <strong>OpenZeppelin</strong> library. This library includes many other useful contracts to streamline blockchain development.</p>
<p>Another important topic to discuss is the concept of <strong>Proxies</strong>, which split storage and implementation into two separate contracts. Contract implementations in Solidity are immutable, meaning you cannot add new functions or properties after deployment. To work around this, you can deploy a “Proxy” contract. The Proxy handles storage and contains only one <code>fallback</code> function, which delegates calls to the implementation contract while maintaining the storage context of the Proxy.</p>
<p>This concept may sound complex, but it’s similar to how <code>this</code> works in JavaScript. Here’s a quick analogy to help clarify:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> foo = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>({ <span class="hljs-attr">bar</span>: <span class="hljs-string">'Lorem'</span> }, {
    get (obj, prop) {
        <span class="hljs-keyword">return</span> fooImplementation[prop].bind(obj)
    },
});
<span class="hljs-keyword">const</span> fooImplementation = { logValue () { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Bar value:'</span>, <span class="hljs-built_in">this</span>.bar) } }

foo.logValue();
</code></pre>
<p>The proxy contract holds a reference to the implementation contract. If you want to add new functions, you simply deploy a new implementation contract and update the proxy to reference this new contract, forwarding function calls to the updated instance. It’s a straightforward process, but there’s an edge case to consider: constructors.</p>
<p>When deploying an implementation contract, its constructor operates within the storage of the implementation contract itself. This means that setters like <code>title = "Hello World"</code> will not modify the proxy's storage. To address this, we use the <strong>initializer function</strong> concept:</p>
<ol>
<li><p>Deploy the implementation contract with a <code>initialize</code> function.</p>
</li>
<li><p>Deploy the proxy contract, passing the address of the implementation contract in its constructor. This setup allows the <code>initialize</code> method to be called in the context of the proxy contract.</p>
</li>
</ol>
<p>As a result, updating the <code>title</code> property, for example, will correctly update it in the proxy’s storage.</p>
<p>Here’s an upgraded implementation version of our AppVersionManager: <a target="_blank" href="https://github.com/0xweb-org/examples-backend/blob/master/contracts/AppVersionManagerUpgradeable.sol"><strong>AppVersionManagerUpgradeable.sol</strong></a>.</p>
<p>The proxy contract itself is quite universal and independent of the implementation. Several well-known standards for proxies are available in the OpenZeppelin library.</p>
<p>With the knowledge of these concepts and the examples above, you’re ready to develop smart contracts for your business cases.</p>
<h3 id="heading-deployment">§ Deployment</h3>
<ol>
<li>Select the blockchain</li>
</ol>
<p>First, we need to select the blockchain where we want to deploy our contract. For this example, I’ve chosen Polygon. It offers low transaction costs, has been around for a long time, and has consistently performed well. Its stable and efficient infrastructure, combined with a Total Value Locked (TVL) of $0.9 billion, makes it a reliable choice. Deploying your contracts to public blockchains means coexisting with financial institutions. The TVL metric reflects the trust these institutions place in the blockchain’s reliability.</p>
<p>Moreover, if conditions change, you can always redeploy the contract to another blockchain in the future.</p>
<ol start="2">
<li>Deploy</li>
</ol>
<p>The demo project also serves as the CI test repository, so all the commands can be found here: <a target="_blank" href="https://github.com/0xweb-org/examples-backend/blob/master/deploy-cli.sh">https://github.com/0xweb-org/examples-backend/blob/master/deploy-cli.sh</a></p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install 0xweb library from NPM into the prject folder</span>
npm i 0xweb
<span class="hljs-comment"># Install required dependencies to compile/deploy *.sol files</span>
npx 0xweb init --hardhat --openzeppelin
<span class="hljs-comment"># Create or import the account. Private key will be encrypted with pin AND machine key.</span>
npx 0xweb accounts new --name foo --pin <span class="hljs-built_in">test</span> --login
<span class="hljs-comment"># Save the private key securly and ensure the account has some POL tokens</span>
<span class="hljs-comment"># Deploy. The foo account is selected as default.</span>
npx 0xweb deploy ./contracts/AppVersionManager.sol --chain polygon --pin <span class="hljs-built_in">test</span>
<span class="hljs-comment"># Set title</span>
npx 0xweb c write AppVersionManager updateInfo --newTitle MySuperApp --pin <span class="hljs-built_in">test</span>
<span class="hljs-comment"># Set latest package information</span>
npx 0xweb c write AppVersionManager updatePackage --arg0 <span class="hljs-string">'load(./data/package.json)'</span> --pin <span class="hljs-built_in">test</span>
</code></pre>
<p>With just a few commands, you’ve deployed the contract and updated the data. That’s it for the backend—it's now up and running “forever” without requiring any further actions from your side. The costs for this deployment, at a GAS price of 70 gwei and a POL price of $0.51, would be:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>GAS</td><td>POL</td><td><strong>$</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Deploy</td><td>850352</td><td>0.059</td><td>0.03</td></tr>
<tr>
<td>Save Title</td><td>47517</td><td>0.0033</td><td>0.001</td></tr>
<tr>
<td>Save Package Data</td><td>169549</td><td>0.0118</td><td>0.006</td></tr>
<tr>
<td>Total</td><td></td><td></td><td>0.037</td></tr>
</tbody>
</table>
</div><p>You spend just 4 cents to set up a <strong>decentralized</strong>, <strong>secure</strong>, and <strong>long-running</strong> service with <strong>no maintenance</strong> required.</p>
<h3 id="heading-query">§ Query</h3>
<p>To query your contract data, you’ll need RPC node providers. Dozens of free providers are available at <a target="_blank" href="https://chainlist.org">https://chainlist.org</a>. You can choose multiple providers, and a good Web3 library can utilize a round-robin strategy at runtime to select the most efficient one for your end users. With 0xweb, the generated TypeScript or JavaScript classes not only select the best endpoints but also abstract away all blockchain communication. The clients contain high-level methods for fetching data, making the process seamless and efficient.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># The deploy command also generates the class, but manual install is also possible</span>
npx 0xweb i 0x&lt;address&gt; --name AppVersionManager --chain polygon
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { AppVersionManager } <span class="hljs-keyword">from</span> <span class="hljs-string">'./0xc/polygon/AppVersionManager/AppVersionManager'</span>

<span class="hljs-keyword">const</span> manager = <span class="hljs-keyword">new</span> AppVersionManager();
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Title`</span>, <span class="hljs-keyword">await</span> manager.title());
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Package`</span>, <span class="hljs-keyword">await</span> manager.package());
</code></pre>
<p>For other programming languages, there are numerous libraries available to simplify querying the blockchain. After deployment, you’ll have the contract address and ABI (interface).</p>
<p>Alternatively, you can launch a middleware server to query contract data using 0xweb.</p>
<pre><code class="lang-bash">npx 0xweb server start --port 3000
curl http://localhost:3000/api/c/<span class="hljs-built_in">read</span>/AppVersionManager/package?chain=polygon
</code></pre>
<p>One advantage is that you don’t need to include any libraries in your application - raw HTTP requests. However, this approach relies on an additional server that you’ll need to manage. It’s often better to query the blockchain directly using 0xweb-generated classes or other blockchain libraries available.</p>
<h3 id="heading-summary">§ Summary 🏁</h3>
<p>This article showcased how blockchains can be both simple and powerful, offering unique advantages compared to traditional hosting solutions.</p>
<p>In the next article, I plan to explore decentralized BLOB storage networks such as Greenfield and Arweave, highlighting their features and benefits.</p>
<p>If you have any suggestions or ideas for additional features to include in the 0xweb library, feel free to share them in the comments or reach out directly at <a target="_blank" href="mailto:tnbts@0xweb.org">tnbts@0xweb.org</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Ethereum: Autogenerated TypeScript classes to read and write* contract's private state variables]]></title><description><![CDATA[* to write in the local and forked development network
In the previous article, we looked into how the EVM storage is arranged and how we can access all the contract's data relatively easily when the contract is validated or we have the source code. ...]]></description><link>https://dev.kit.eco/ethereum-autogenerated-typescript-classes-to-read-and-write-contracts-private-state-variables</link><guid isPermaLink="true">https://dev.kit.eco/ethereum-autogenerated-typescript-classes-to-read-and-write-contracts-private-state-variables</guid><category><![CDATA[Ethereum]]></category><category><![CDATA[Solidity]]></category><category><![CDATA[hardhat]]></category><category><![CDATA[0xweb]]></category><dc:creator><![CDATA[Alex Kit]]></dc:creator><pubDate>Tue, 13 Jun 2023 19:34:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682165832003/0a3d97bc-0061-4932-8f36-c16ec1eb7de3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong><em>*</em></strong> <em>to write in the local and forked development network</em></p>
<p>In the previous <a target="_blank" href="https://dev.kit.eco/ethereum-simple-deep-dive-into-evm-storage">article</a>, we looked into how the EVM storage is arranged and how we can access all the contract's data relatively easily when the contract is validated or we have the source code. To simplify it even further, there is the storage handler in the <a target="_blank" href="https://github.com/0xweb-org/dequanto">dequanto</a> library and the <a target="_blank" href="https://github.com/0xweb-org/0xweb">0xweb</a> CLI tool. I've published the storage demo repository at <a target="_blank" href="https://github.com/0xweb-org/examples-storage">github/examples-storage</a>, which is used for the 0xweb CI pipeline, and I'll go through the example in this article.</p>
<p>We start with the contract's class generation:</p>
<pre><code class="lang-bash">$ npm i 0xweb -g
$ 0xweb init --hardhat
$ 0xweb i 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 --name USDC --chain eth
</code></pre>
<p>This fetches the contract sources from <a target="_blank" href="https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#code">etherscan</a>, detects it as a proxy, and fetches the implementation at <a target="_blank" href="https://etherscan.io/address/0xa2327a938febf5fec13bacfb16ae10ecbc4cbdcf#code">0xa2327a938febf5fec13bacfb16ae10ecbc4cbdcf</a>. After the source code and the ABI are present 0xweb generates the TypeScript class for the contract: <a target="_blank" href="https://github.com/0xweb-org/examples-storage/blob/master/0xweb/eth/USDC/USDC.ts">USDC.ts</a> - that, beyond the read and write methods of the contract, also has the storage handler to read the state variables <em>and to overwrite state variables data in the hardhat environment</em>.</p>
<h3 id="heading-evm-storage-forking">EVM Storage Forking</h3>
<p>To play around with the storage we can fork the Ethereum Mainnet storage with a hardhat development server. Hardhat launches the local chain that "inherits" the complete state. Earlier I thought, this process was very time and resource-consuming, but in reality, it is a simple RPC proxy. When you call some method of the contract, for instance <code>balanceOf</code> of the <code>USDC</code> contract and the local server doesn't have any code yet for the address, it fetches this from the forked RPC endpoint with <code>getCode</code>, when the code gets executed and it reads the <code>balances[account]</code> the slot location is not yet present locally, so it will fetch the data with single <code>getStorageAt</code> to get the slot and resume contract execution. Hardhat allows you to overwrite the local storage. That is why forking is a great feature of developing, testing, and performing on-chain research.</p>
<p>Once left to mention - forking per default gets the latest block number and all proxy requests are made with the block number, but you can specify any block number you want to fork the remote chain from and perform operations as if the contract has all the state of that point of time. For this reason, when forking you should have an <strong>archive</strong> node. But, if you use <code>latest</code> block number for forking and don't have access to the archive node, your requests will still work for some time (<code>latest</code> <em>is fetched for a specific number</em>), depending on how quickly your node clears the state - for <code>geth</code> this is <code>128</code> blocks, which is around 27 minutes.</p>
<h3 id="heading-run-demo-actions">Run demo actions</h3>
<p>I use <a target="_blank" href="https://www.npmjs.com/package/atma">atma</a> and <a target="_blank" href="https://www.npmjs.com/package/atma-utest">atma-utest</a> to execute typescript actions. The actions you can see in <a target="_blank" href="https://github.com/0xweb-org/examples-storage/blob/master/actions/usdc.act.ts">actions/usdc.act.ts</a></p>
<h4 id="heading-1-create-accounts">[1] Create accounts</h4>
<pre><code class="lang-bash">atma act actions/usdc.act.ts -q <span class="hljs-string">"create-accounts"</span>
</code></pre>
<p>Prepares two accounts, which we will use to fund, overwrite and transfer balances.</p>
<h4 id="heading-2-overwrite-balance-for-account-foo">[2] Overwrite balance for account "foo"</h4>
<pre><code class="lang-bash">atma act actions/usdc.act.ts -q <span class="hljs-string">"set-balance"</span>
</code></pre>
<p>The generated TypeScript class has the <code>storage</code> field with autogenerated getters for all state variables</p>
<h4 id="heading-foreword-storage-readers"><strong>Foreword: Storage readers</strong></h4>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> usdc = <span class="hljs-keyword">new</span> USDC();
<span class="hljs-keyword">let</span> amount: bigint = <span class="hljs-keyword">await</span> usdc.storage.totalSupply_();
</code></pre>
<p>This reads the internal variable directly from the storage of the USDC contract:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FiatTokenV1</span> <span class="hljs-keyword">is</span> <span class="hljs-title">AbstractFiatTokenV1</span>, <span class="hljs-title">Ownable</span>, <span class="hljs-title">Pausable</span>, <span class="hljs-title">Blacklistable</span> </span>{
    <span class="hljs-comment">// ...</span>
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">internal</span> balances;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint256</span>)) <span class="hljs-keyword">internal</span> allowed;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">internal</span> totalSupply_ <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>Though there is an external method <code>totalSupply()</code> in the contract, but it depends on the contract developers if they decide to present getters manually or set variable visibility to <code>public</code>. That's why the contract may not have those getters, but with the storage handler, we can read <strong>all</strong> state variables of the contract.</p>
<p>So, after we generate the storage handler class, it contains methods to get all contract variables. The methods are <strong>strongly typed</strong> - with arguments and correct return types, but there is a more generic method <code>storage.$get(accessorPath)</code> to get variable chains like the JSON's paths, e.g. <code>myContract.storage.$get('foo.bar.qux')</code></p>
<p>Consider such a contract:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Foo</span> </span>{
    <span class="hljs-keyword">struct</span> <span class="hljs-title">Position</span> { 
        <span class="hljs-keyword">address</span> owner;
        <span class="hljs-keyword">uint</span> amount
    }
    Position[] positions;
}
</code></pre>
<p>We can read for example the address of the owner on the index <code>1</code> with:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> foo = <span class="hljs-keyword">new</span> Foo();
<span class="hljs-keyword">let</span> owner = <span class="hljs-keyword">await</span> foo.storage.$get(<span class="hljs-string">'positions[1].owner'</span>);
<span class="hljs-comment">// with generated method we would get the complete position struct</span>
<span class="hljs-keyword">let</span> position = <span class="hljs-keyword">await</span> foo.storage.positions(<span class="hljs-number">1</span>);
<span class="hljs-comment">// OR with $get</span>
<span class="hljs-keyword">let</span> position = <span class="hljs-keyword">await</span> foo.storage.$get(<span class="hljs-string">'positions[1]'</span>)
<span class="hljs-comment">// the position variable has the interface of IPosition</span>
<span class="hljs-keyword">interface</span> IPosition {
    owner: TAddress
    amount: bigint 
}
</code></pre>
<h2 id="heading-setters"><strong>Setters</strong></h2>
<p>Writing to the storage works only in the development environment and it can be done only via the "<strong>$set</strong>" method. Now, back to our action <code>set-balance</code> — we must set the new amount to the storage slot of the user balance.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> amount = <span class="hljs-number">50n</span> * <span class="hljs-number">10n</span>**<span class="hljs-number">6n</span> <span class="hljs-comment">// 50 USDC</span>
<span class="hljs-keyword">let</span> address = foo.address;
<span class="hljs-keyword">await</span> usdc.storage.$set(<span class="hljs-string">`balances["<span class="hljs-subst">${address}</span>"]`</span>, amount);
</code></pre>
<h4 id="heading-3-transfer-balance">[3] Transfer balance</h4>
<p>That's it - now we can use the newly updated balance, and transfer the tokens to the account "bar".</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> tx = <span class="hljs-keyword">await</span> usdc.transfer(foo <span class="hljs-keyword">as</span> ChainAccount, bar.address, fooBalance);
<span class="hljs-keyword">let</span> receipt = <span class="hljs-keyword">await</span> tx.wait();
</code></pre>
<h3 id="heading-other-hardhat-development-methods">Other hardhat development methods:</h3>
<ul>
<li><p><a target="_blank" href="https://hardhat.org/hardhat-network/docs/reference#hardhat_setbalance">hardhat_setBalance</a> - we can add any amount of ETH to the account, for example before submitting the test transaction.</p>
</li>
<li><p><a target="_blank" href="https://hardhat.org/hardhat-network/docs/reference#hardhat_setcode">hardhat_setCode</a> - we can change the contract's code</p>
</li>
<li><p><a target="_blank" href="https://hardhat.org/hardhat-network/docs/reference#hardhat_impersonateaccount">hardhat_impersonateAccount</a> - send transactions from any address</p>
</li>
</ul>
<p>🏁 Happy coding</p>
]]></content:encoded></item><item><title><![CDATA[Ethereum: Simple deep-dive into EVM Storage.]]></title><description><![CDATA[One of the greatest features of Web3 is the Open Data Principle. The Data doesn't belong just to companies, governments, groups, and individuals - it belongs to all of them and you at once. Anyone can create a twig (the contract) in global storage (t...]]></description><link>https://dev.kit.eco/ethereum-simple-deep-dive-into-evm-storage</link><guid isPermaLink="true">https://dev.kit.eco/ethereum-simple-deep-dive-into-evm-storage</guid><category><![CDATA[Ethereum]]></category><category><![CDATA[EVM]]></category><dc:creator><![CDATA[Alex Kit]]></dc:creator><pubDate>Tue, 11 Apr 2023 20:21:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672866183215/7579c640-6bcd-42ae-81aa-ce6292f27ef0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the greatest features of Web3 is the Open Data Principle. The Data doesn't belong just to companies, governments, groups, and individuals - it belongs to all of them and you at once. Anyone can create a twig (<em>the contract</em>) in global storage (<em>the tree</em>), and define the Rules on how the data (<em>the leaves</em>) gets stored and modified. Though the contract developers spend much more effort on project design now, it gives us more transparency and trust.</p>
<p>Even though the data is publicly readable, Projects can still decide how transparent they are ready to go, and this level of transparency is visible to everyone. How much data are they ready to store on the blockchain? Do they publish the ABIs, the source code? Do they encrypt data?</p>
<p>As you may know, when the ABI is published, you can query the contract's data and logs. But developers may decide to make some state variables private, so the ABI for fetching its data won't be created. This is usually done, to hide the state variables from other contracts, but for you, as an external observer, the data is open. It's just more difficult to locate its storage slot to read the value with <code>getStorageAt</code>, in comparison to reading the Data provided via the Application Binary Interface.</p>
<p>Here I briefly explain how the contract's storage works in EVM and in Part II show the tool, which can generate the <strong><em>TypeScript classes</em></strong> with <strong><em>data-getter</em></strong> <strong><em>methods</em></strong> for all state variables based on the source code. In the dev or research environment, you can even use the <strong>data-setters</strong> to overwrite the data.</p>
<h2 id="heading-storage">Storage</h2>
<p>The <strong><em>storage</em></strong> is divided into <strong><em>32</em></strong>-<strong><em>byte</em></strong> <strong><em>blocks</em></strong> <em>(the slots).</em> You can think about it, as a <strong>sparse Array</strong> of blocks. The maximum size of that array is — 2<sup>256</sup> elements. A <strong><em>sparse</em></strong> — means an array with "holes", or gaps in the sequence of their indices. For example in JavaScript:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> foo = [];
foo[<span class="hljs-number">5</span>] = <span class="hljs-string">'A'</span>;
foo[<span class="hljs-number">999000</span>] = <span class="hljs-string">'B'</span>;
</code></pre>
<p>Though the length of the Array <code>foo</code> is <code>999001</code>, it contains only two elements in the memory, so the indices are virtual memory pointers. I think this is important to know, to understand later how those indices (<em>the storage locations</em>) are calculated. But before we continue with the storage, let us go into <strong>Data-Types</strong>, and in particular their Memory Sizes.</p>
<h2 id="heading-types">Types</h2>
<h4 id="heading-1-simple-fixed-size-value-types">1. Simple fixed-size value types</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td><em>Type</em></td><td><em>Size (Bytes)</em></td></tr>
</thead>
<tbody>
<tr>
<td><code>address</code></td><td>20</td></tr>
<tr>
<td><code>bool</code></td><td>1</td></tr>
<tr>
<td><code>int{X}</code></td><td><code>Math.ceil(X/8)</code>: <code>int256=32B</code> <code>int8=1B</code> <code>int64=8B</code></td></tr>
<tr>
<td><code>bytes{X}</code> <code>byte</code></td><td><code>{X}B</code>: <code>bytes32=32B</code> <code>byte=1B</code> <code>bytes8=8B</code></td></tr>
<tr>
<td><code>enum</code></td><td><em>It depends on the number of values in the enum. •</em> <code>amount &lt; 256</code> then the <code>enum</code> is equal to <code>uint8</code> <em>•</em> <code>amount &lt; 512</code> then the <code>enum</code> is equal to <code>uint16</code> <em>•</em> <code>...</code></td></tr>
</tbody>
</table>
</div><h4 id="heading-2-complex-fixed-size-types">2. Complex fixed-size types</h4>
<table><tbody><tr><td><p><em>The fixed-size array of fixed-size elements</em></p></td><td><p></p></td></tr><tr><td><p><code>int256[3]</code></p></td><td><p><code>uint256=32B <em> 3 ≡ ∑96B</em></code></p></td></tr><tr><td><p><em>Structs</em></p></td><td><p></p></td></tr><tr><td><p><code>struct Foo { uint256 value address owner }</code></p></td><td><p><code>uint256=32B address=20B ≡ ∑52B</code></p></td></tr><tr><td><p><em>Structs array</em></p></td><td><p></p></td></tr><tr><td><p><code>Foo[2]</code></p></td><td><p><code>52B  2 ≡ ∑104B</code></p></td></tr></tbody></table>

<h4 id="heading-3-variable-size-types">3. Variable-size types</h4>
<table><tbody><tr><td><p><em>Dynamic arrays</em></p></td><td><p><em>•</em><code>int256[]</code> <em>•</em><code>int256[][]</code><em> •</em><code>Foo[]</code></p></td></tr><tr><td><p><em>Mappings</em></p></td><td><p><em>•</em><code>mapping(address =&gt; uint256)</code></p></td></tr><tr><td><p><em>Texts</em></p></td><td><p><em>•</em><code>string</code></p></td></tr><tr><td><p><em>Byte Buffers</em></p></td><td><p><em>•</em><code>bytes</code></p></td></tr></tbody></table>

<h2 id="heading-storage-layout">Storage Layout</h2>
<table><tbody><tr><td><p>0</p></td><td><p><code>32-bytes</code></p></td><td><p><code>Storage slot #0</code></p></td></tr><tr><td><p>1</p></td><td><p><code>32-bytes</code></p></td><td><p><code>Storage slot #1</code></p></td></tr><tr><td><p>...........</p></td><td><p>..................</p></td><td><p>....................</p></td></tr><tr><td><p>2<sup>256</sup>-1</p></td><td><p><code>32-bytes</code></p></td><td><p><code>Storage slot #115792089237316195423570985008687907853269984665640564039457584007913129639935</code></p></td></tr></tbody></table>

<p>From the table, it is easy to recognize, that there is a huge range of storage locations(<em>indexes</em>) and each storage slot has a fixed size - of 32bytes.</p>
<h2 id="heading-storage-locations">Storage Locations</h2>
<h3 id="heading-simple-fixed-size-value-types">Simple fixed-size value types</h3>
<p>So far we know already the required number of bytes to store different variable types, and we know how the storage is divided into slots. Now let's see where the EVM stores the data for state variables and we will start from the simple contract:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FooContract</span> </span>{
    <span class="hljs-keyword">address</span> foo;
    <span class="hljs-keyword">bool</span> isActive;
    <span class="hljs-keyword">uint256</span> amount;
}
</code></pre>
<p>From the example, we can notice the order of declared state variables: <code>foo</code> is <code>0</code>, <code>isActive</code> is <code>1</code>, <code>amound</code> is <code>2</code>. If there were more variables the order would proceed. The compiler takes this order into consideration. And so, our common sense would say each variable would occupy the slot with the index of the variable. And that's it, but with one exception: why would the <code>"isActive"</code> occupy the entire slot <code>1</code> when the data has only 1 byte, and in the previous slot, we have some space left (the <code>address</code> takes only 20bytes out of 32bytes)? Right, we can store the boolean in <code>"slot 0"</code>, then the <code>"amount"</code> goes to the next slot <code>1</code> . Another question you may have is, why the data of the <code>"amount"</code> variable moves to the next slot if we still have some space left <code>(11bytes)</code> <code>"slot 0"</code>: <code>address(20bytes)+boolean(1byte)=21</code> But, as the <code>uint256</code> takes the complete <code>32bytes</code> we would need to split the data along 2 slots, and as the EVM reads the data per WORD basis (<em>one slot at once</em>) it is much better to save the base types in one slot, therefore <code>amount</code> variable occupies one complete slot <code>1</code> and the rule is very simple:</p>
<blockquote>
<p>If we can store the complete value in the current slot, we do so, otherwise go-to the next slot and save there.</p>
</blockquote>
<h3 id="heading-complex-fixed-size-types">Complex fixed-size types</h3>
<p>Here is an example with complex fixed-size state variables</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FooContract</span> </span>{
    <span class="hljs-keyword">struct</span> <span class="hljs-title">User</span> {
        <span class="hljs-keyword">address</span> foo;
        <span class="hljs-keyword">bool</span> isActive;
        <span class="hljs-keyword">uint256</span> amount;
    }
    User user;
    User[<span class="hljs-number">3</span>] users;
}
</code></pre>
<p>I explicitly took the same simple types for the <code>User</code> struct to show, that the logic of data locations is also the same:</p>
<ul>
<li><p>when assigning slot numbers to a <code>struct</code> type, EVM assigns slot numbers to underlying slot variables.</p>
</li>
<li><p>when assigning slot numbers to a <code>fixed array</code> type, EVM assigns slot numbers to elements.</p>
</li>
</ul>
<p>So you can think about those types, as just the logical "grouping" of data, which is represented in storage with the same locations, as without the "grouping".</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FooContract</span> </span>{
    <span class="hljs-comment">// User</span>
    <span class="hljs-keyword">address</span> foo;
    <span class="hljs-keyword">bool</span> isActive;
    <span class="hljs-keyword">uint256</span> amount;

    <span class="hljs-comment">// User[3]</span>
    <span class="hljs-comment">// User0</span>
    <span class="hljs-keyword">address</span> User0_foo;
    <span class="hljs-keyword">bool</span> User0is_Active;
    <span class="hljs-keyword">uint256</span> User0_amount;
    <span class="hljs-comment">// User1</span>
    <span class="hljs-keyword">address</span> User1_foo;
    <span class="hljs-keyword">bool</span> User1_isActive;
    <span class="hljs-keyword">uint256</span> User1_amount;
    <span class="hljs-comment">// and so on ...</span>
}
</code></pre>
<p>Here we already know, how to locate and pack the data from the previous step.</p>
<h3 id="heading-variable-size-types">Variable-size types</h3>
<p>Again, let's start with the example:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FooContract</span> </span>{
    <span class="hljs-keyword">address</span>[] users;
    <span class="hljs-keyword">bool</span> isActive;
}
</code></pre>
<p>The previous logic won't work, as we don't know the number of elements in <code>users</code> array, so we can't place the data before <code>isActive</code> boolean, while the location of <code>isActive</code> would be dependent on this dynamic length of <code>users</code>.</p>
<p>The <code>isActive</code> the location must follow the previous rules: a) it is the 2nd variable b) we can't store it in the previous slot - which means, the <code>isActive</code> must stay in the slot <code>1</code> .</p>
<h4 id="heading-what-do-we-save-in-0-slot"><strong>What do we save in</strong> <code>0</code> <strong>slot?</strong></h4>
<p>In case of <code>array</code> we must save at least the length of the array, otherwise <code>users.length</code> won't be possible. So <code>length</code> of the array goes directly into the slot <code>0</code>.</p>
<h4 id="heading-where-do-we-save-the-array-items"><strong>Where do we save the array items?</strong></h4>
<p>And also we want that they are <strong>nonfragmented*</strong>, have <strong>deterministic locations*</strong>, and <strong>not collide*</strong> with other contract variables.</p>
<ul>
<li><blockquote>
<p><strong><em>Not fragmented</em></strong> — we select the location in storage of the element <code>0</code> and any other goes directly after that location:</p>
<p><code>locationOf(users[n]) === locationOf(users[0]) + n</code></p>
</blockquote>
</li>
<li><blockquote>
<p><strong>Deterministic locations</strong> — <em>if we want t</em>o access e.g. the item <code>users[14]</code> <em>we should be able to calculate the storage location without any reads from the storage.</em></p>
</blockquote>
</li>
<li><blockquote>
<p><strong>No collisions</strong> — there should be no collisions with other contracts variable states, nor they should be mixed or grouped. So the item locations must be <strong>isolated</strong>.</p>
</blockquote>
</li>
</ul>
<p>EVM solves all requirements above with a simple <em>trick</em>: they use <code>keccak256</code> function to hash the slot number of a dynamically sized state variable. The hash is the <code>uint256</code> number, which is used as a new starting position in the storage for the items. You can think about hashing as a <em>"jump"</em> in memory. So as we know, the <code>users</code> variable has the initial slot <code>0</code>, the location of the <code>users[14]</code> will be:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> stateVariableSlotNr = <span class="hljs-number">0</span>;
<span class="hljs-keyword">let</span> hash = keccak256(encodePacked({
    value: stateVariableSlotNr, 
    <span class="hljs-keyword">type</span>: <span class="hljs-string">'uint256'</span>
}));
<span class="hljs-keyword">let</span> jump = BigInt(hash); <span class="hljs-comment">// new slot number</span>
<span class="hljs-keyword">let</span> users14Location = jump + <span class="hljs-number">14n</span>;
<span class="hljs-comment">//hex: 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e571</span>
<span class="hljs-comment">//bigint:18569430475105882587588266137607568536673111973893317399460219858819262702961</span>
</code></pre>
<p>The such approach solves all requirements above:</p>
<ul>
<li><p><strong>Not fragmented:</strong> After the "jump" we can store the dynamic array in the same way as we do it with <strong><em>fixed-size arrays</em></strong> - the elements follow one after another by incrementing the slot number.</p>
</li>
<li><p><strong>Deterministic locations:</strong> From the source code, the compiler knows the initial slot number of the variable, that's why we can quickly calculate the "jump" with <code>keccak256</code></p>
</li>
<li><p><strong>Isolated:</strong> You can see in the example above how huge the "jump" number could be, with no chance for other variables to end up in the same location.</p>
</li>
</ul>
<h4 id="heading-how-do-we-save-dynamic-arrays-of-complex-types"><strong>How do we save dynamic arrays of complex types?</strong></h4>
<p>Let's go one step further and look into complex array types, not as simple <code>address[]</code> as in the previous example.</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FooContract</span> </span>{
    <span class="hljs-keyword">struct</span> <span class="hljs-title">User</span> {
        <span class="hljs-keyword">address</span> foo;
        <span class="hljs-keyword">bool</span> isActive;
        <span class="hljs-keyword">uint256</span> amount;
    }
    User[] users;
}
</code></pre>
<p>It turns out - everything works the same way, for example, to get the location of <code>users[14].amount</code></p>
<ul>
<li><p>From the source code, the compiler knows the slot index of <code>users</code> = <code>0</code></p>
</li>
<li><p>From the source code, the compiler knows that each element occupies <strong>2 slots</strong> <em>Remember packing?</em></p>
<p>  <code>0 slot = foo(20bytes) + isActive(1byte)</code></p>
<p>  <code>1 slot = amount(32bytes)</code></p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> stateVariableSlotNr = <span class="hljs-number">0</span>;
<span class="hljs-keyword">const</span> slotsPerElement = <span class="hljs-number">2n</span>;
<span class="hljs-keyword">const</span> amountPropertySlotNr = <span class="hljs-number">1n</span>;
<span class="hljs-keyword">const</span> index = <span class="hljs-number">14n</span>;
<span class="hljs-keyword">let</span> hash = keccak256(encodePacked({
    value: stateVariableSlotNr, 
    <span class="hljs-keyword">type</span>: <span class="hljs-string">'uint256'</span>
}));
<span class="hljs-keyword">let</span> jump = BigInt(hash); <span class="hljs-comment">// new slot number</span>
<span class="hljs-keyword">let</span> users14AmountLocation = jump 
    + slotsPerElement * index 
    + amountPropertySlotNr;
</code></pre>
<h4 id="heading-what-about-nested-dynamic-arrays">What about <strong><em>nested dynamic</em></strong> arrays?</h4>
<p>I hope from the previous examples, it won't be complicated for you to solve this task on your own - <code>users[5].balances[8]</code> :</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FooContract</span> </span>{
    <span class="hljs-keyword">struct</span> <span class="hljs-title">User</span> {
        <span class="hljs-keyword">address</span> foo;
        <span class="hljs-keyword">uint256</span>[] balances;
    }
    User[] users;
}
</code></pre>
<ul>
<li><p><code>users</code> is the slot <code>0</code></p>
</li>
<li><p><code>users</code>: the location of the first element in the array starts at</p>
<p>  <code>UsersCursor = BigInt(keccak256(bytes32(0)))</code></p>
</li>
<li><p><code>User</code> consists of <strong>2</strong> slots:</p>
<p>  <code>0 slot = foo-address</code></p>
<p>  <code>1 slot = balances-array-length</code></p>
</li>
<li><p><code>users[5]</code>: the location of the <strong>5th</strong> item is</p>
<p>  <code>Item5Cursor = UsersCursor + 5 * 2</code></p>
</li>
<li><p><code>users[5].balances</code>: the location of the first item in the <code>balances</code> array starts at: <code>Item5BalancesCursor = BigInt(keccak256(bytes32( Item5Cursor + 1 ))</code></p>
</li>
<li><p><code>users[5].balances[14]</code>: the location of the item is</p>
<p>  <code>SlotNumber = Item5BalancesCursor + 14</code></p>
</li>
</ul>
<h3 id="heading-mappings">Mappings</h3>
<p>Another dynamically sized type is <code>mapping</code>. Unfortunately, it is not possible to arrange the storage for "<code>Mapping</code>" in <strong><em>"Not fragmented"</em></strong> <em>and</em> <strong><em>"Deterministic locations"</em></strong> ways at once. The <code>Array</code> indices are sorted, but the <code>Mapping</code> keys are not, so here we select determinism over defragmentation, but we apply here the similar logic of <em>"jumps"</em> for <strong>every</strong> key, as for the <strong>0th item</strong> of the array. <em>You remember - the location of the 0th item was:</em> <code>keccak256(bytes32(ARRAY_SLOT_NR))</code> With mapping items, we will also use the "<code>MAPPING_SLOT_NR</code>" and combine it with the <code>key</code> for a "jump" to <strong>every</strong> value.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> jump = BigInt(keccak256(encodePacked({
    value: bytes32(key),
    <span class="hljs-keyword">type</span>: <span class="hljs-string">'bytes32'</span>
}, {
    value: bytes32(slotNr),
    <span class="hljs-keyword">type</span>: <span class="hljs-string">'bytes32'</span>
})));
</code></pre>
<blockquote>
<p>In <code>ARRAY_SLOT_NR</code> we have the array length, but in <code>MAPPING_SLOT_NR</code> we have nothing as there is no <code>mapping.length</code>, that is why we don't need any extra information in the mapping slot itself.</p>
</blockquote>
<p>It is <strong>not possible to iterate</strong> over every mapping key, as there is no place in storage where the keys are stored. You must know the key to be able to locate its storage slot. That is why, it is important for a well-implemented contract, to emit the "Log", every time a mapping item is created. <em>We know all the holders of an</em> <code>ERC20</code> <em>token, not by reading the</em> <code>balances</code> <em>mapping, but by iterating the</em> <code>Transfer</code> <em>logs.</em></p>
<h4 id="heading-complex-mapping-values">Complex mapping values</h4>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">FooContract</span> </span>{
    <span class="hljs-keyword">struct</span> <span class="hljs-title">User</span> {
        <span class="hljs-keyword">address</span> foo;
        <span class="hljs-keyword">bool</span> isActive;
        <span class="hljs-keyword">uint256</span> amount;
    }
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> User) users;
}
</code></pre>
<p>Everything works here exactly the same way: after we have calculated the location of the element by <code>address</code> key and the <code>users</code> stat variable slot number - at that index the <code>foo</code> and <code>isActive</code> are stored. The <code>amount</code> will be at the next slot (<code>+ 1</code>)</p>
<hr />
<h3 id="heading-strings-and-bytes">Strings and Bytes</h3>
<p><code>string</code> and <code>bytes</code> are not the same as <code>byte[]</code>, <code>bytes32</code> or <code>bytes32[]</code></p>
<ul>
<li><p><code>bytesX</code> are fixed-sized entities in the storage, like <code>uintX</code>, <code>address</code>, etc.</p>
</li>
<li><p><code>bytesX[]</code> are arrays of fixed-sized entities, like <code>uintX[]</code>, <code>address[]</code>, etc.</p>
</li>
<li><p><code>bytes</code> and <code>string</code> are the dynamic-sized buffers in storage, that have slightly different storage layouts, but are very similar to arrays.</p>
</li>
</ul>
<p>In the array's slot we store the <strong>number of items</strong> in the array. For bytes and strings, we store the size (<strong>bytes count</strong>) of the data.</p>
<p>EVM also applies a nice trick to pack short strings/byte buffers. If the size of the data is <strong>less then</strong> <code>32</code> <strong>bytes</strong>, we could store the size <strong>and</strong> the data in <strong>the same slot</strong>: <strong>31 bytes</strong> for data, and <strong>1 byte</strong> for the size number. Otherwise, the data is split into slots, which are stored in the same manner as arrays. For example, when we have the <code>100 bytes</code> data, it will occupy <code>Math.ceil(100/32)</code> slots.</p>
<hr />
<h3 id="heading-inheritance-and-multiple-inheritance">Inheritance and <strong>multiple</strong> inheritance</h3>
<p>This is important for the <strong>slot order</strong> of the state variables. Let's look directly into the example:</p>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Bar</span> </span>{
    <span class="hljs-keyword">uint256</span> bar;
}
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Foo</span> </span>{
    <span class="hljs-keyword">uint256</span> foo;
}
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Qux</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Foo</span>, <span class="hljs-title">Bar</span> </span>{
    <span class="hljs-keyword">uint256</span> qux;
}
</code></pre>
<p>The inheritance chain defines the order of storage variables, so the <code>qux</code> won't occupy the <code>0</code> slot. From the example:</p>
<p><code>0 slot = foo</code><br /><code>1 slot = bar</code><br /><code>2 slot = qux</code></p>
<p>For a more complex example, like the deeper inheritance chain - the rule of thumb stays the same:</p>
<blockquote>
<p>The <strong>slot number</strong> of the <strong>first</strong> <strong>variable</strong> in a contract is the incremented slot number of the <strong>last variable</strong> from the previous contract in the inheritance chain.</p>
</blockquote>
<hr />
<h2 id="heading-conclusion">Conclusion 🏁</h2>
<p>By understanding the core concepts of storage <strong>variable order</strong>, basic type <strong>sizes</strong>, <strong>packing,</strong> and the "<strong>jump</strong>"s you have a clear view of EVMs storage.</p>
<p>You also see that the calculation of the slot locations for arbitrary contracts and variables is complicated when done manually, that's why we embedded the storage reader functionality into the TypeScript contract class generator - <a target="_blank" href="https://github.com/0xweb-org/0xweb">0xweb</a>. And we'll look into it in Part II.</p>
]]></content:encoded></item><item><title><![CDATA[Ethereum: 2FA or Multi-Factor Authentication for transactions]]></title><description><![CDATA[Let's discuss security again and why you should move to a multi-signature account, even for your personal account. Many still consider multi-sigs as something for organizations to store assets, difficult to manage, or limited. None of this is true.
E...]]></description><link>https://dev.kit.eco/ethereum-2fa-or-multi-factor-authentication-for-transactions</link><guid isPermaLink="true">https://dev.kit.eco/ethereum-2fa-or-multi-factor-authentication-for-transactions</guid><category><![CDATA[Ethereum]]></category><category><![CDATA[crypto wallet]]></category><category><![CDATA[0xweb]]></category><category><![CDATA[gnosis]]></category><category><![CDATA[multisig]]></category><dc:creator><![CDATA[Alex Kit]]></dc:creator><pubDate>Sun, 17 Jul 2022 15:44:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1656787224547/J7Ljljf1l.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let's discuss security again and why you should move to a multi-signature account, even for your personal account. Many still consider multi-sigs as something for organizations to store assets, difficult to manage, or limited. None of this is true.</p>
<h1 id="heading-externally-owned-accounts-eoas">Externally owned accounts (EOAs)</h1>
<p>These are the addresses and private keys we all use to communicate with the blockchain. There is no other way to do this, but the problem is - people directly communicate with the dApps - tokens, NFTs, stacking, DAO voting, and so on. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656804341507/SRwEjQBsS.png" alt="image.png" class="image--center mx-auto" /></p>
<p>As the result, all assets are attached to that account, and it turns into a wallet, which holds all your funds. Though there are many ways you can try to secure your private 🔑KEY, all of them mainly go to checkpoints on how to secure your Operating System. Even hardware wallets can't protect your funds if your system is compromised and the malicious transactions are subscribed with the KEY. And I'm not talking about browser extensions, such as MetaMask, where in the worst case the attacker can get the seed phrase. </p>
<blockquote>
<p>We had already the case when a person in our team had downloaded the malware from a phishing website, and his funds from the accounts, he used in MetaMask, were gone. He, a technically aware person, got a victim of the <a target="_blank" href="https://www.cyberark.com/resources/threat-research-blog/meet-oski-stealer-an-in-depth-analysis-of-the-popular-credential-stealer">Oski Stealer</a>.</p>
</blockquote>
<p>But there is a much better way to secure the assets - to have <strong>multiple </strong> and <strong>rotatable </strong> 🔑KEYs with all funds on multi-sig.</p>
<h1 id="heading-multi-signature-accounts-contracts">Multi-signature accounts (Contracts)</h1>
<p>A multi-signature account is a contract - living on-chain and being a proxy between your KEY<strong>s</strong> and the dApps. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656805677005/pvW5i5ekc.png" alt="image.png" class="image--center mx-auto" /></p>
<p>And as result, this is the wallet that holds all your assets. The multi-sig is like your personal guard, which can bypass only valid transactions, there are some rules you can specify - the number of required signatures, and spending limits.</p>
<h3 id="heading-multiple-keys">🔑 Multiple Keys</h3>
<p>For example, you can create a 2-of-2 scenario - you generate one private key on your machine, and the second on your mobile phone, and you set both addresses as owners into the multi-sig, after that, to create a transaction you need both signatures to add to it so that the multi-sig passes the transaction through. And this is the 2FA for transactions:</p>
<ol>
<li>Create a transaction on your machine with the first signature.</li>
<li>Review and sign the transaction on your mobile.</li>
</ol>
<p>You still have to protect your devices, so that the KEYs stay safe, but this drastically increases the security. This mitigates even phishing attacks, as you 👀 double-check the transactions.</p>
<h3 id="heading-rotatable">🔃 Rotatable</h3>
<p>While your assets are owned by your multi-sig account and your EOAs are just the KEYs to that account, you can create new KEYs and replace them in the multi-sig at any time. So if you have any doubts you could be compromised - replace the affected address.  Or you can do this on a regular basis - once half a year - change the KEYs.</p>
<h3 id="heading-a-noncustodial-solution-and-no-vendor-locks">✳️ A noncustodial solution, and no vendor locks</h3>
<p>I saw some beliefs, that Gnosis Safe Multisig is a custodial wallet, for those people — see the section about Gnosis Safe below.</p>
<h3 id="heading-edge-cases-and-the-caveats">🔥 Edge cases and the caveats</h3>
<p>There are some situations when you can't use multi-sigs, but all of them are just limited by the dApp implementations.</p>
<ul>
<li><p>Message signing. EOAs can sign messages with their associated private keys, but currently, contracts cant.  There is a solution for this — <a target="_blank" href="https://eips.ethereum.org/EIPS/eip-1271">eip-1271</a>, but it should be implemented and supported by the dApp</p>
</li>
<li><p><code>tx.origin</code>. Not so common as the previous one, but some contracts explicitly check <code>msg.sender == tx.origin</code>, which means they restrict forwarded transactions and require the caller to be an EOA, not the contract.  <em>I've met this only once by Alpaca Finance</em>.</p>
</li>
<li><p>slightly higher ⛽GAS consumption</p>
</li>
<li><p>No easy-to-use solution yet, like the MetaMask browser extension. It is possible to connect via WalletConnect, though it is also limited to allowed dApps.</p>
</li>
</ul>
<h1 id="heading-gnosis-safe">Gnosis Safe</h1>
<p>I use <a target="_blank" href="https://gnosis-safe.io/">Gnosis Safe</a> multi-signature contracts, as the most established solutions in this area. As I've said previously, this is not a custodial multi-sig, to understand this, you should know how it works. It consists of 2 parts:</p>
<ol>
<li><p>Multisig Contract. Once you've created this on-chain, this contract belongs to you. You are the owner, and only you have access to it. Gnosis shares its implementation with you so that you could create the contract.</p>
</li>
<li><p>Off-chain Transport. Gnosis web app and Gnosis Safe mobile applications are just the clients for your multi-sig contract, but you can create multi-sig transactions and collect signatures without Gnosis Safe infrastructure. </p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658061168802/3X62ZLauU.png" alt="mermaid-diagram-2022-07-17-143244.png" class="image--center mx-auto" /></p>
<p>As an example, you can send your desired transaction data to participants via e-mail as a JSON file and collect the signatures back. The transport doesn't need to be secure, a man-in-the-middle can only see what transaction you want to send, but can't manipulate it. Also, no private keys are disclosed.</p>
<h1 id="heading-0xweb">0xWeb</h1>
<p>Here I will show, how I use the 2FA for my transactions. <a target="_blank" href="https://0xweb.org">0xWeb</a> is a CLI wallet with the ability to install validated contracts from Etherscan and other EVM blockchain explorers — it generates TypeScript client classes that can be used via CLI or API.  But to keep it simple, for an example, I will create a simple transfer transaction.</p>
<h4 id="heading-create-or-add-eoasafe-accounts">Create or Add EOA/Safe accounts</h4>
<ol>
<li>📱Create a "FooMobile" account in Gnosis Safe App.
 Go to "Settings 🠖 Owner Keys 🠖 ADD 🠖 Create new owner Key"</li>
<li>🖥️ Create a "FooDesktop" account in 0xWeb CLI.<pre><code class="lang-bash"> $ 0xweb accounts new --name FooDesktop --pin &lt;pin&gt;
</code></pre>
</li>
<li>🖥️ Finally create the multi-sig. <em>We add to members the address of the account we've created in GnosisSafe</em><pre><code class="lang-bash">$ 0xweb safe new --name safe/foo --owner FooDesktop --members 0x&lt;...&gt; --chain eth
</code></pre>
</li>
<li>📱Add the Multisigs Address to Gnosis Safe App
Go to "Menu🠖 Add Safe 🠖 Select Chain 🠖 Enter the address"</li>
</ol>
<p>You see, I've created the keys on different devices, with different vendors, and none of the will store both private keys.</p>
<h4 id="heading-perform-arbitrary-transactions-for-example-transfers">Perform arbitrary transactions, for example, transfers</h4>
<p>Assume we sent some ETH to the safe, and later want to transfer some from the safe to another address.</p>
<pre><code class="lang-bash">$ 0xweb transfer 0.04 ETH --from safe/foo --to 0x&lt;...&gt; --pin &lt;pin&gt; --chain eth
</code></pre>
<p>After I run this command, I receive the push notification with the Tx Proposal on my mobile, I review and confirm the transaction, something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1658065993898/t__WS3-Y7.png" alt="Gno-confirm.png" class="image--center mx-auto" /></p>
<p><code>0xweb</code> tool waits until the Gnosis API Service returns the required signature and submits the Tx to the blockchain.</p>
<h3 id="heading-backend">Backend</h3>
<p>Not only for personal use but also for backends we use the multi-sig approach. There is an additional validator instance. We store all assets on multi-sigs, and for example, when a user wants to withdraw assets, in our main backend we validate the intent, create a tx proposal, and send these to the validator backend, that one validates the intent with the tx once again, and sends its confirmation back to the main server, which sends the Tx to the blockchain.</p>
<h2 id="heading-summary">Summary</h2>
<p>I'm still wondering, why the EOA wallets are still popular to store funds on when MultiSigs are much more secure. I hope browser wallets, like MetaMask, will add the MultiSig support, so we can connect to dApps with the multi-sig account, and before the transaction is submitted, we have to confirm it with our mobile app. </p>
<p>Stay safe. 🔒</p>
]]></content:encoded></item><item><title><![CDATA[A complete and straightforward guide to Node.js, Nginx, Git Deploy, and PM2 on Ubuntu.]]></title><description><![CDATA[Okay, I must admit that Terraform is not obsolete after this tutorial, neither Kubernetes, Azure Pipelines, Ansible, Pulumi nor Docker. I just want to show how you can deploy your first Node.js stack in seconds via SSH by having just a fresh or any e...]]></description><link>https://dev.kit.eco/a-complete-and-straightforward-guide-to-nodejs-nginx-git-deploy-and-pm2-on-ubuntu</link><guid isPermaLink="true">https://dev.kit.eco/a-complete-and-straightforward-guide-to-nodejs-nginx-git-deploy-and-pm2-on-ubuntu</guid><category><![CDATA[Node.js]]></category><category><![CDATA[deployment]]></category><category><![CDATA[deployment automation]]></category><dc:creator><![CDATA[Alex Kit]]></dc:creator><pubDate>Mon, 20 Jun 2022 10:20:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1655503684170/r_6j9Zlwt.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Okay, I must admit that Terraform is not obsolete after this tutorial, neither Kubernetes, Azure Pipelines, Ansible, Pulumi nor Docker. I just want to show how you can deploy your first Node.js stack in seconds via SSH by having just a fresh or any existing Ubuntu server. For middle projects, this should be enough.</p>
<p>In the first part, we'll go through the commands required to install and configure things, then you'll get a script to automate this, to be able to perform all these steps with a single command.</p>
<h2 id="heading-the-stack">The stack</h2>
<h4 id="heading-1-inlinehttpscdnhashnodecomreshashnodeimageuploadv1655507782215cw9y8fy91pngheight30-alignleft-nginx">1. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1655507782215/cW9y8Fy91.png?height=30" alt="inline" /> Nginx</h4>
<ul>
<li>as we may want to have multiple Node.js applications and domains on a single server</li>
<li>static file server</li>
<li>SSL certificates</li>
</ul>
<h4 id="heading-2-inlinehttpscdnhashnodecomreshashnodeimageuploadv1655508240744iyedgijkpngheight45-certbot">2. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1655508240744/IyE_dGIJk.png?height=45" alt="inline" /> Certbot</h4>
<ul>
<li>we will create letsencrypt certificates</li>
</ul>
<h4 id="heading-3-inlinehttpscdnhashnodecomreshashnodeimageuploadv1655715564528nkekuuxy2pngheight40-pm2">3. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1655715564528/nkEKUUXy2.png?height=40" alt="inline" /> PM2</h4>
<ul>
<li>for managing Node.js processes and clusters. Optionally, you can enable monitoring with <a target="_blank" href="https://pm2.keymetrics.io/">keymetrics</a></li>
</ul>
<h4 id="heading-4-inlinehttpscdnhashnodecomreshashnodeimageuploadv1655715605851hb8xsindrpngheight40-local-git">4. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1655715605851/Hb8XSinDR.png?height=40" alt="inline" /> Local Git</h4>
<ul>
<li>to push the code, build and restart the apps</li>
</ul>
<h4 id="heading-5-inlinehttpscdnhashnodecomreshashnodeimageuploadv16557156496995ngbkl-upngheight40-nodejs">5. <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1655715649699/5ngbkl_-U.png?height=40" alt="inline" /> Node.js</h4>
<ul>
<li><code>n</code> module helps to manage the nodejs versions</li>
</ul>
<h3 id="heading-install">Install</h3>
<pre><code class="lang-bash">apt update
apt install nginx nodejs npm certbot -y
npm install -g n
<span class="hljs-comment"># update nodejs to the latest</span>
n stable
node -v
npm -v
npm i pm2 -g
<span class="hljs-comment"># start pm2 on OS start</span>
pm2 startup
</code></pre>
<h3 id="heading-git-configuration">Git configuration</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># the server directory</span>
mkdir -p /var/www/foo
<span class="hljs-comment"># the git repository, we will push to</span>
git init --bare /var/www/foo.git
</code></pre>
<p>Then we have to create the <code>post-receive</code> hook - the script, which will be executed each time we push the changes to the git server. In the script we will <strong>a)</strong> copy the code to the server directory <strong>b)</strong> handle git submodules <strong>c)</strong> run build scripts <strong>d)</strong> restart the nodejs process:</p>
<pre><code class="lang-bash">cat &lt;&lt;EOT &gt;&gt; /var/www/foo.git/hooks/post-receive
<span class="hljs-comment">#!/bin/sh</span>
git --work-tree=/var/www/foo --git-dir=/var/www/foo.git checkout -f
<span class="hljs-built_in">cd</span> /var/www/foo
<span class="hljs-comment"># optionally, restore submodules</span>
git --git-dir=/var/www/foo.git --work-tree=. submodule init
git --git-dir=/var/www/foo.git --work-tree=. submodule update
npm i
npm run build
<span class="hljs-comment"># this will also restart foo, if already running</span>
pm2 start foo
EOT

<span class="hljs-comment"># allow to execute</span>
chmod +x /var/www/foo.git/hooks/post-receive
</code></pre>
<h3 id="heading-nginx-configuration">Nginx configuration</h3>
<p>This one we will split into two steps:</p>
<ol>
<li>create SSL certificates for the domain </li>
<li>create the reverse proxy to the server's port</li>
</ol>
<h4 id="heading-1-ssl">1. SSL</h4>
<pre><code class="lang-bash"><span class="hljs-comment"># to remove any default websites</span>
rm /etc/nginx/sites-available/default

<span class="hljs-comment"># copy-paste simple server for the letsencrypt challange</span>
cat &lt;&lt;EOT &gt;&gt; /etc/nginx/sites-available/default
server {
    listen       80;
    server_name  foo.bar;
    root /var/www/foo;
}
EOT

<span class="hljs-comment"># start a new server</span>
service nginx restart

<span class="hljs-comment"># will generate the certificates</span>
certbot certonly --webroot -w /var/www/foo -d foo.bar --email team@foo.bar --agree-tos --no-eff-email

<span class="hljs-comment"># now create the final server</span>
rm /etc/nginx/sites-available/default

cat &lt;&lt;EOT &gt;&gt; /etc/nginx/sites-available/default
server {
    listen       80;
    listen       443 ssl;
    server_name  foo.bar;

    ssl_certificate  /etc/letsencrypt/live/foo.bar/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/foo.bar/privkey.pem;

    <span class="hljs-keyword">if</span> (<span class="hljs-variable">$scheme</span> = http) {
        <span class="hljs-built_in">return</span> 301 https://<span class="hljs-variable">$server_name</span><span class="hljs-variable">$request_uri</span>;
    }
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade <span class="hljs-variable">$http_upgrade</span>;
        proxy_set_header Connection <span class="hljs-string">'upgrade'</span>;
        proxy_set_header Host <span class="hljs-variable">$host</span>;
        proxy_cache_bypass <span class="hljs-variable">$http_upgrade</span>;
    }
}
EOT

service nginx restart
</code></pre>
<h2 id="heading-project">Project</h2>
<ol>
<li>Add <code>ecosystem.config.js</code> file to configure the <code>pm2</code></li>
</ol>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
    <span class="hljs-string">"apps"</span>: [
        {
            <span class="hljs-string">"name"</span>: <span class="hljs-string">"foo"</span>,
            <span class="hljs-string">"script"</span>: <span class="hljs-string">"index.js"</span>,
            <span class="hljs-string">"args"</span>: [
                <span class="hljs-string">"--SERVER"</span>, <span class="hljs-string">"--port 3000"</span>,
            ],
            <span class="hljs-string">"node_args"</span>: [
                <span class="hljs-string">"--max-old-space-size=12000"</span>
            ],
            <span class="hljs-string">"timestamp"</span>: <span class="hljs-string">"MM-DD HH:mm Z"</span>,
            <span class="hljs-string">"instances"</span>: <span class="hljs-string">"max"</span>,
            <span class="hljs-string">"exec_mode"</span>: <span class="hljs-string">"cluster"</span>,
            <span class="hljs-string">"env"</span>: {}
        }
    ]
};
</code></pre>
<ol>
<li>Add the upstream repository </li>
</ol>
<pre><code>git init
git remote add prod root@SERVER_IP_DOMAIN<span class="hljs-symbol">:/var/www/foo</span>.git/
</code></pre><p>You can extend and install any other software you need, which is beneficial by using plain SSH access directly to your Ubuntu instance - there are dozens of other tutorials and configurations.</p>
<h2 id="heading-execute-the-commands-with-a-single-nodejs-script">Execute the commands with a single Node.js script</h2>
<p>The commands above are simple copy-paste-enter commands, which means you can submit them one by one, but I'm using <a target="_blank" href="https://www.npmjs.com/package/ssh2">ssh2</a> module to submit commands over the ssh client. </p>
<p>I've also published the ssh2 wrapper class to make the client easier to use - <a target="_blank" href="https://github.com/tenbits/sshly">sshly</a></p>
<pre><code><span class="hljs-keyword">import</span> { <span class="hljs-title">Ssh</span> } <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">'sshly'</span>

<span class="hljs-title">const</span> <span class="hljs-title">script</span> <span class="hljs-operator">=</span> `
<span class="hljs-title">apt</span> <span class="hljs-title">update</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">apt</span> <span class="hljs-title">install</span> <span class="hljs-title">nodejs</span> <span class="hljs-title">npm</span> <span class="hljs-title">certbot</span> <span class="hljs-operator">-</span><span class="hljs-title">y</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">npm</span> <span class="hljs-title">install</span> <span class="hljs-operator">-</span><span class="hljs-title">g</span> <span class="hljs-title">n</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">n</span> <span class="hljs-title">stable</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">npm</span> <span class="hljs-title">i</span> <span class="hljs-title">pm2</span> <span class="hljs-operator">-</span><span class="hljs-title">g</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">pm2</span> <span class="hljs-title">startup</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">mkdir</span> <span class="hljs-operator">-</span><span class="hljs-title">p</span> <span class="hljs-operator">/</span><span class="hljs-title"><span class="hljs-keyword">var</span></span><span class="hljs-operator">/</span><span class="hljs-title">www</span><span class="hljs-operator">/</span><span class="hljs-title">foo</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">git</span> <span class="hljs-title">init</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-title">bare</span> <span class="hljs-operator">/</span><span class="hljs-title"><span class="hljs-keyword">var</span></span><span class="hljs-operator">/</span><span class="hljs-title">www</span><span class="hljs-operator">/</span><span class="hljs-title">foo</span>.<span class="hljs-title">git</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">cat</span> <span class="hljs-operator">&lt;</span><span class="hljs-operator">&lt;</span><span class="hljs-title">EOT</span> <span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span> <span class="hljs-operator">/</span><span class="hljs-title"><span class="hljs-keyword">var</span></span><span class="hljs-operator">/</span><span class="hljs-title">www</span><span class="hljs-operator">/</span><span class="hljs-title">foo</span>.<span class="hljs-title">git</span><span class="hljs-operator">/</span><span class="hljs-title">hooks</span><span class="hljs-operator">/</span><span class="hljs-title">post</span><span class="hljs-operator">-</span><span class="hljs-title"><span class="hljs-keyword">receive</span></span>
#<span class="hljs-operator">!</span><span class="hljs-operator">/</span><span class="hljs-title">bin</span><span class="hljs-operator">/</span><span class="hljs-title">sh</span>
<span class="hljs-title">git</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-title">work</span><span class="hljs-operator">-</span><span class="hljs-title">tree</span><span class="hljs-operator">=</span><span class="hljs-operator">/</span><span class="hljs-title"><span class="hljs-keyword">var</span></span><span class="hljs-operator">/</span><span class="hljs-title">www</span><span class="hljs-operator">/</span><span class="hljs-title">foo</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-title">git</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"><span class="hljs-keyword">var</span></span><span class="hljs-operator">/</span><span class="hljs-title">www</span><span class="hljs-operator">/</span><span class="hljs-title">foo</span>.<span class="hljs-title">git</span> <span class="hljs-title">checkout</span> <span class="hljs-operator">-</span><span class="hljs-title">f</span>
<span class="hljs-title">cd</span> <span class="hljs-operator">/</span><span class="hljs-title"><span class="hljs-keyword">var</span></span><span class="hljs-operator">/</span><span class="hljs-title">www</span><span class="hljs-operator">/</span><span class="hljs-title">foo</span>
<span class="hljs-title">git</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-title">git</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"><span class="hljs-keyword">var</span></span><span class="hljs-operator">/</span><span class="hljs-title">www</span><span class="hljs-operator">/</span><span class="hljs-title">foo</span>.<span class="hljs-title">git</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-title">work</span><span class="hljs-operator">-</span><span class="hljs-title">tree</span><span class="hljs-operator">=</span>. <span class="hljs-title">submodule</span> <span class="hljs-title">init</span>
<span class="hljs-title">git</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-title">git</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"><span class="hljs-keyword">var</span></span><span class="hljs-operator">/</span><span class="hljs-title">www</span><span class="hljs-operator">/</span><span class="hljs-title">foo</span>.<span class="hljs-title">git</span> <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-title">work</span><span class="hljs-operator">-</span><span class="hljs-title">tree</span><span class="hljs-operator">=</span>. <span class="hljs-title">submodule</span> <span class="hljs-title">update</span>
<span class="hljs-title">npm</span> <span class="hljs-title">i</span>
<span class="hljs-title">npm</span> <span class="hljs-title">run</span> <span class="hljs-title">build</span>
<span class="hljs-title">pm2</span> <span class="hljs-title">start</span> <span class="hljs-title">foo</span>
<span class="hljs-title">EOT</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">chmod</span> <span class="hljs-operator">+</span><span class="hljs-title">x</span> <span class="hljs-operator">/</span><span class="hljs-title"><span class="hljs-keyword">var</span></span><span class="hljs-operator">/</span><span class="hljs-title">www</span><span class="hljs-operator">/</span><span class="hljs-title">foo</span>.<span class="hljs-title">git</span><span class="hljs-operator">/</span><span class="hljs-title">hooks</span><span class="hljs-operator">/</span><span class="hljs-title">post</span><span class="hljs-operator">-</span><span class="hljs-title"><span class="hljs-keyword">receive</span></span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">rm</span> <span class="hljs-operator">/</span><span class="hljs-title">etc</span><span class="hljs-operator">/</span><span class="hljs-title">nginx</span><span class="hljs-operator">/</span><span class="hljs-title">sites</span><span class="hljs-operator">-</span><span class="hljs-title">available</span><span class="hljs-operator">/</span><span class="hljs-title">default</span>
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
<span class="hljs-title">cat</span> <span class="hljs-operator">&lt;</span><span class="hljs-operator">&lt;</span><span class="hljs-title">EOT</span> <span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span> <span class="hljs-operator">/</span><span class="hljs-title">etc</span><span class="hljs-operator">/</span><span class="hljs-title">nginx</span><span class="hljs-operator">/</span><span class="hljs-title">sites</span><span class="hljs-operator">-</span><span class="hljs-title">available</span><span class="hljs-operator">/</span><span class="hljs-title">default</span>
<span class="hljs-title">server</span> {
    <span class="hljs-title">listen</span>       80;
    server_name  foo.bar;

    location <span class="hljs-operator">^</span><span class="hljs-operator">~</span> <span class="hljs-operator">/</span>.well-known<span class="hljs-operator">/</span>acme<span class="hljs-operator">-</span>challenge<span class="hljs-operator">/</span> {
        root <span class="hljs-operator">/</span><span class="hljs-keyword">var</span><span class="hljs-operator">/</span>www<span class="hljs-operator">/</span>foo
        allow all;
        default_type <span class="hljs-string">"text/plain"</span>;
    }
}
EOT
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
service nginx restart
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
certbot certonly <span class="hljs-operator">-</span><span class="hljs-operator">-</span>webroot <span class="hljs-operator">-</span>w <span class="hljs-operator">/</span><span class="hljs-keyword">var</span><span class="hljs-operator">/</span>www<span class="hljs-operator">/</span>foo <span class="hljs-operator">-</span>d foo.bar <span class="hljs-operator">-</span><span class="hljs-operator">-</span>email team@foo.bar <span class="hljs-operator">-</span><span class="hljs-operator">-</span>agree<span class="hljs-operator">-</span>tos <span class="hljs-operator">-</span><span class="hljs-operator">-</span>no<span class="hljs-operator">-</span>eff<span class="hljs-operator">-</span>email
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
rm <span class="hljs-operator">/</span>etc<span class="hljs-operator">/</span>nginx<span class="hljs-operator">/</span>sites<span class="hljs-operator">-</span>available<span class="hljs-operator">/</span>default
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
cat <span class="hljs-operator">&lt;</span><span class="hljs-operator">&lt;</span>EOT <span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span> <span class="hljs-operator">/</span>etc<span class="hljs-operator">/</span>nginx<span class="hljs-operator">/</span>sites<span class="hljs-operator">-</span>available<span class="hljs-operator">/</span>default
server {
    listen       <span class="hljs-number">80</span>;
    listen       <span class="hljs-number">443</span> ssl;
    server_name  foo.bar;

    ssl_certificate  <span class="hljs-operator">/</span>etc<span class="hljs-operator">/</span>letsencrypt<span class="hljs-operator">/</span>live<span class="hljs-operator">/</span>foo.bar/fullchain.pem;
    ssl_certificate_key <span class="hljs-operator">/</span>etc<span class="hljs-operator">/</span>letsencrypt<span class="hljs-operator">/</span>live<span class="hljs-operator">/</span>foo.bar/privkey.pem;

    <span class="hljs-keyword">if</span> ($scheme <span class="hljs-operator">=</span> http) {
        <span class="hljs-keyword">return</span> <span class="hljs-number">301</span> https:<span class="hljs-comment">//$server_name$request_uri;</span>
    }
    location <span class="hljs-operator">/</span> {
        proxy_pass http:<span class="hljs-comment">//localhost:3000;</span>
        proxy_http_version <span class="hljs-number">1.1</span>;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection <span class="hljs-string">'upgrade'</span>;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}
EOT
<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
service nginx restart
`

const client <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Ssh({
  host: <span class="hljs-string">'IP'</span>,
  privateKeyPath: <span class="hljs-string">'path/to/file'</span>
});
const commands <span class="hljs-operator">=</span> script
  .split(<span class="hljs-string">'---'</span>)
  .filter(x <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> x.trim().replace(<span class="hljs-operator">/</span>\r<span class="hljs-operator">/</span>g, <span class="hljs-string">''</span>))
  .filter(Boolean);
<span class="hljs-keyword">for</span> (let command of commands) {
    await client.exec(command);
}
</code></pre><h3 id="heading-publish-the-app">Publish the app</h3>
<p>Push your code to the repository</p>
<pre><code>git add <span class="hljs-operator">-</span>A
git commit <span class="hljs-operator">-</span>am <span class="hljs-string">"init"</span>
git push <span class="hljs-operator">-</span>u prod master
</code></pre><h2 id="heading-summary">Summary</h2>
<p>You can create your own setup, using apache2 for example, or separate roles. After all, these are plain *nix commands with Node.js scripting, and it is a huge advantage over using some additional deployment tools or platforms.</p>
<p>Adjust and save the server creation script as a template, so that later you can deploy Node.js servers with ease.</p>
<p>Happy deploying.</p>
]]></content:encoded></item><item><title><![CDATA[Selenium webdriver for Chrome: how to change the proxy at runtime (a workaround)]]></title><description><![CDATA[Recently, I got a question from a user of selenium-query about how to change the proxy after the chrome instance is launched. Additionally, the solution should support proxy authorization.
To set a proxy in chrome with selenium driver is not a big de...]]></description><link>https://dev.kit.eco/selenium-webdriver-for-chrome-how-to-change-the-proxy-at-runtime-a-workaround</link><guid isPermaLink="true">https://dev.kit.eco/selenium-webdriver-for-chrome-how-to-change-the-proxy-at-runtime-a-workaround</guid><category><![CDATA[selenium]]></category><category><![CDATA[selenium-webdriver]]></category><category><![CDATA[proxy]]></category><category><![CDATA[Google Chrome]]></category><dc:creator><![CDATA[Alex Kit]]></dc:creator><pubDate>Tue, 12 Apr 2022 23:23:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649805614045/MxG67Bsfb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I got a question from a user of <a target="_blank" href="https://github.com/tenbits/selenium-query"><code>selenium-query</code></a> about how to change the proxy after the chrome instance is launched. Additionally, the solution should support proxy authorization.</p>
<p>To set a proxy in chrome with selenium driver is not a big deal, there are even two options - through the API, the example <a target="_blank" href="https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/proxy.html">here</a> or with the command line argument <code>--proxy-server=http://foo.bar</code>. But, after the instance is launched, the reconfiguration of the capabilities has no effect. 
So here, I'll show a very simple workaround to the issue. We'll go through the theoretical part, and then the small implementation. <em>The examples will contain a couple of Windows-specific things, but for macOS and Linux it would work similar.</em></p>
<h3 id="heading-1-use-additional-local-proxy-like-squidhttpwwwsquid-cacheorg">1. Use additional local proxy, like <a target="_blank" href="http://www.squid-cache.org/">squid</a></h3>
<p>Okay, if we can set a proxy for chrome, at least at startup, then our requirement of "changing the proxy" we should move out of the chrome context. For this, we can create an additional local proxy, which supports parent proxies. The ideal option here will be the cross-platform tool - the <code>squid cache</code>(http://www.squid-cache.org/). Installing the package with <a target="_blank" href="https://community.chocolatey.org/packages/squid">choco</a> and configuration with <a target="_blank" href="https://code.visualstudio.com/">vscode</a> is quite simple</p>
<pre><code class="lang-bash">$ choco install squid
$ code c:/Squid/etc/squid/squid.conf
</code></pre>
<p>Here we need to configure the parent proxy with <code>cache_peer</code>, it supports also the authorization.</p>
<pre><code class="lang-javascript">cache_peer PARENT_IP parent PARENT_PORT <span class="hljs-number">0</span>  no-query <span class="hljs-keyword">default</span> login=USERNAME:PASSWORD connect-fail-limit=<span class="hljs-number">99999999</span>  proxy-only
never_direct allow all
</code></pre>
<p>Now, to change the proxy, we need a) to read the configuration, b) to edit those two lines, c) to write the file back, and d) to reconfigure the squid with the command</p>
<pre><code class="lang-bash">$ squid -d 0 -k reconfigure
</code></pre>
<blockquote>
<p>⚠️ The terminal should be launched with admin privileges.</p>
</blockquote>
<p>All of these are easily scriptable. We'll go into details later.</p>
<h3 id="heading-2-keep-alive-sessions">2. <code>Keep-Alive</code> sessions.</h3>
<p>So now we know, how to change the proxy servers at runtime, but there is a caveat ❗❗— the requests can still go through the old proxy, as the agent can reuse connections and will <strong>hold the sockets opened</strong>, even in the idle state. </p>
<p>I looked for an API to close all idle connections via selenium, but haven't found it: if anybody has some hints for me, it would be great. But there is another way, we can do it via <code>chrome://net-internals/#sockets</code>, by evaluating the script </p>
<pre><code class="lang-js">chrome.send(<span class="hljs-string">'closeIdleSockets'</span>)
</code></pre>
<h3 id="heading-3-implementation">3. Implementation</h3>
<h4 id="heading-part-1">Part 1.</h4>
<p>For modifying the squid config, I will use:</p>
<ul>
<li><a target="_blank" href="https://github.com/atmajs/atma-io"><code>atma-io</code></a> for the FileSystem IO</li>
<li><a target="_blank" href="https://github.com/atmajs/shellbee"><code>shellbee</code></a> for the CLI</li>
</ul>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> { File } <span class="hljs-keyword">from</span> <span class="hljs-string">'atma-io'</span>
<span class="hljs-keyword">import</span> { run } <span class="hljs-keyword">from</span> <span class="hljs-string">'shellbee'</span>;
<span class="hljs-keyword">import</span> { URL } <span class="hljs-keyword">from</span> <span class="hljs-string">'url'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">namespace</span> SquidConfig {
    <span class="hljs-keyword">const</span> SQUID_CONFIG_PATH = <span class="hljs-string">'file://c:/Squid/etc/squid/squid.conf'</span>;

    <span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setProxy</span> (<span class="hljs-params">httpProxy: <span class="hljs-built_in">string</span></span>) </span>{
        <span class="hljs-keyword">let</span> { hostname, port, username, password} = <span class="hljs-keyword">new</span> URL(httpProxy);

        <span class="hljs-keyword">let</span> content = <span class="hljs-keyword">await</span> File.readAsync&lt;<span class="hljs-built_in">string</span>&gt;(SQUID_CONFIG_PATH);
        <span class="hljs-keyword">let</span> rgxCheckExists = <span class="hljs-regexp">/^cache_peer .+/m</span>;
        <span class="hljs-keyword">let</span> line = <span class="hljs-string">`cache_peer <span class="hljs-subst">${hostname}</span> parent <span class="hljs-subst">${port}</span> 0  no-query default login=<span class="hljs-subst">${username}</span>:<span class="hljs-subst">${password}</span>  connect-fail-limit=99999999  proxy-only`</span>;
        <span class="hljs-keyword">if</span> (rgxCheckExists.test(content)) {
            content = content.replace(rgxCheckExists, line);
        } <span class="hljs-keyword">else</span> {
            content += <span class="hljs-string">`<span class="hljs-subst">${line}</span> \n never_direct allow all`</span>;
        }

        <span class="hljs-keyword">await</span> File.writeAsync(SQUID_CONFIG_PATH, content);
        <span class="hljs-comment">// re-read the configuration</span>
        <span class="hljs-keyword">let</span> { stderr } = <span class="hljs-keyword">await</span> run(<span class="hljs-string">`squid -d 0 -k reconfigure`</span>);
        <span class="hljs-keyword">if</span> (stderr.length &gt; <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(stderr.join(<span class="hljs-string">'\n'</span>));
        }
    }
}
</code></pre>
<h4 id="heading-part-2">Part 2.</h4>
<p>I'll show how to close the sockets using the <a target="_blank" href="https://github.com/tenbits/selenium-query"><code>selenium-query</code></a> itself.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> SQuery <span class="hljs-keyword">from</span> <span class="hljs-string">'selenium-query'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">namespace</span> ChromeSockets {
    <span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">closeIdleSockets</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">let</span> $internalsPage: SQuery = <span class="hljs-keyword">await</span> SQuery.load(<span class="hljs-string">'chrome://net-internals/#sockets'</span>);
        <span class="hljs-keyword">await</span> $internalsPage.eval(<span class="hljs-string">`chrome.send('closeIdleSockets')`</span>)
    }
}
</code></pre>
<h3 id="heading-4-testing">4. Testing</h3>
<p>I use <a target="_blank" href="https://github.com/atmajs/utest"><code>atma-utest</code></a> module to run the test.</p>
<p>Bootstrap the demo project in some folder:</p>
<pre><code class="lang-bash">npm i atma -g
<span class="hljs-comment"># repair default packages and TS runners</span>
atma init
<span class="hljs-comment"># install additional packages</span>
npm i selenium-query shellbee
</code></pre>
<p>After you've created the files with snippets provided earlier, you can create the test, e.g. <code>./tests/proxies.spec.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> SQuery <span class="hljs-keyword">from</span> <span class="hljs-string">'selenium-query'</span>;
<span class="hljs-keyword">import</span> { ChromeSockets } <span class="hljs-keyword">from</span> <span class="hljs-string">'../src/ChromeSockets'</span>;
<span class="hljs-keyword">import</span> { SquidConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'../src/SquidConfig'</span>;
<span class="hljs-keyword">import</span> { URL } <span class="hljs-keyword">from</span> <span class="hljs-string">'url'</span>;

<span class="hljs-comment">// remote proxy servers</span>
<span class="hljs-keyword">const</span> PROXY1 = process.env.PROXY1;
<span class="hljs-keyword">const</span> PROXY2 = process.env.PROXY2;
<span class="hljs-keyword">const</span> IP_PROVIDER = <span class="hljs-string">`https://api.ipify.org?format=json`</span>;

UTest({
    <span class="hljs-keyword">async</span> <span class="hljs-string">'should visit both proxies'</span> () {

        <span class="hljs-keyword">await</span> SquidConfig.setProxy(PROXY1);
        <span class="hljs-comment">// opens new chrome instance</span>
        <span class="hljs-keyword">let</span> { data: server1 } = <span class="hljs-keyword">await</span> SQuery.fetch(IP_PROVIDER, {
            args: [
                <span class="hljs-string">'--log-level=3'</span>,
                <span class="hljs-comment">// the local squid proxy</span>
                <span class="hljs-string">'--proxy-server=http://localhost:3128'</span>
            ]
        });

        eq_(server1.ip, <span class="hljs-keyword">new</span> URL(PROXY1).hostname);

        <span class="hljs-keyword">await</span> SquidConfig.setProxy(PROXY2);
        <span class="hljs-keyword">await</span> ChromeSockets.closeIdleSockets();
        <span class="hljs-comment">// reuses chrome instance</span>
        <span class="hljs-keyword">let</span> { data: server2 } = <span class="hljs-keyword">await</span> SQuery.fetch(IP_PROVIDER);

        eq_(server2.ip, <span class="hljs-keyword">new</span> URL(PROXY2).hostname);
    }
});
</code></pre>
<p>Finally, run the test</p>
<pre><code class="lang-bash">$ atma <span class="hljs-built_in">test</span> tests/proxies.spec.ts
</code></pre>
<blockquote>
<p>Both servers should be in Environment as strings like, <code>http://USERNAME:PASSWORD@IP:PORT</code></p>
</blockquote>
<hr />
]]></content:encoded></item><item><title><![CDATA[Alot - turns your arrays into lazy and async streams]]></title><description><![CDATA[Here I will go through the 📦 alot 🔗 library, which I use to work with arrays in JavaScript/TypeScript. Though there are already dozens of utility libraries for arrays, there was always something I've missed there. 
To position the alot library on a...]]></description><link>https://dev.kit.eco/alot-turns-your-arrays-into-lazy-and-async-streams</link><guid isPermaLink="true">https://dev.kit.eco/alot-turns-your-arrays-into-lazy-and-async-streams</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[array methods]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Alex Kit]]></dc:creator><pubDate>Tue, 05 Apr 2022 00:14:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649151996245/nkUfKAZkh.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here I will go through the 📦 <a target="_blank" href="https://github.com/atmajs/alot">alot 🔗</a> library, which I use to work with arrays in JavaScript/TypeScript. Though there are already dozens of utility libraries for arrays, there was always something I've missed there. </p>
<p>To position the <code>alot</code> library on a "map" and give you the orientation - I would say, it is somewhere between JavaScript native array methods and <a target="_blank" href="https://rxjs.dev/"><code>Rx</code></a>, and in no way completely replaces both of them. <code>Alot</code> is highly inspired by <strong><code>LINQ</code></strong> methods from <code>.NET</code>.</p>
<h3 id="heading-typescript-and-installation">TypeScript and installation</h3>
<p>The library is implemented in TypeScript and has complete typings support out of the box, but can be used also in the plain js environment.</p>
<pre><code class="lang-ts">$ npm i alot
</code></pre>
<blockquote>
<p>If you, the reader, still do not use TS on your daily dev basis, I would highly encourage you to switch to typescript. In later articles, I will show how I use TypeScript with no configuration and compilation hassle, and use it as it were a JavaScript (<em>as it actually is, but with sweet additions.</em>)</p>
</blockquote>
<h3 id="heading-laziness">🌱 Laziness</h3>
<p>Similar to <code>rx</code> cold observables,  the chained methods won't be evaluated until you call <code>subscribe</code> method - the equivalents in <code>alot</code> library: <code>toArray</code>, <code>toArrayAsync</code>, <code>first</code>, <code>firstAsync</code> etc. But let's compare these two examples:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> alot <span class="hljs-keyword">from</span> <span class="hljs-string">'alot'</span>

<span class="hljs-keyword">let</span> arr1 = users
    .filter(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.score &gt; <span class="hljs-number">10</span>)
    .map(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.name.toUpperCase())
    .slice(<span class="hljs-number">0</span>, <span class="hljs-number">5</span>);

<span class="hljs-keyword">let</span> arr2 = alot(users)
    .filter(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.score &gt; <span class="hljs-number">10</span>)
    .map(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.name.toUpperCase())
    .take(<span class="hljs-number">5</span>)
    .toArray()
</code></pre>
<p>Though the code here does the same things and looks similar, the <strong>flow</strong> is <strong>different</strong>. JavaScript methods do the following:</p>
<ol>
<li><code>filter</code> all users by some <code>score</code> field</li>
<li><code>map</code> all previously filtered users to their uppercased names and create a new array of strings</li>
<li><code>take</code>(slice) the first <code>5</code> usernames.</li>
</ol>
<p>As you may already have noticed, the caveat here is when the <code>users</code> array has lots of items - the engine goes through all the users to create a new filtered array, then goes over each item to pick the username and create the new array with names.</p>
<p>The example with <code>alot</code> library has the <strong>reversed direction flow</strong>. When the js engine evaluates <code>filter</code>, <code>map</code>, and <code>take</code> methods, it builds the query that gets executed when we call the <code>toArray()</code> method and the flow is:</p>
<ol>
<li><code>take</code> 5 elements from the underlying <code>map</code> stream</li>
<li><code>map</code> users to their uppercased names from the underlying <code>filter</code> stream. As only 5 elements were requested it takes and maps also only 5 elements</li>
<li><code>filter</code> users by some <code>score</code> field. As only 5 elements were requested, it processes filtering only until 5 elements are matched</li>
</ol>
<blockquote>
<p>When I'm writing code I still think in forward-flow <code>filter&gt;map&gt;take</code>, but understanding how laziness works under the hood is beneficial.</p>
</blockquote>
<p>So, in the best case, if the first 5 users have a score greater than 10, then the js engine visits only those 5 elements for filtering and mapping.</p>
<p>I have to mention, that it works great for this example. If we wouldn't have <code>slice/take</code> methods, then in <code>alot</code> example we would obviously <code>map</code> <strong>all</strong> filtered users and we wouldn't benefit from the laziness nature of <code>alot</code> lib. That's why I still often use js native array methods, and the <code>alot</code> API allows me quickly switch between different flows.</p>
<p>The laziness brings us to another feature, which was easy to implement - the asynchronous.</p>
<h3 id="heading-asynchronous">⛓️ Asynchronous</h3>
<p>All methods in <code>alot</code> library have also there asynchronous variations, which accept async methods. 
From the previous example, what if we would want to load also user's comments along with uppercased username - for native js methods we have a huge headache, how to accomplish this. I have seen such <strong>wrong</strong> ❌ solution:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> promises = users
    .filter(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.score &gt; <span class="hljs-number">10</span>)
    .map(<span class="hljs-keyword">async</span> user =&gt; {
        <span class="hljs-keyword">return</span> {
            username: user.name.toUpperCase(),
            comments: <span class="hljs-keyword">await</span> Api.loadComments(user.id)
        };
    })
    .slice(<span class="hljs-number">0</span>, <span class="hljs-number">5</span>);
<span class="hljs-keyword">let</span> arr1 = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(promises);
</code></pre>
<p>Wrong things about this could be:</p>
<ul>
<li>here we load comments for <strong>all filtered</strong> users, even though we need only 5.</li>
<li>even, if we would need all users, not only 5, we make anyway all requests parallel - which means if we have an array with <code>1000</code> elements - we make <code>1000</code> requests simultaneously. (<em>Though browsers and nodejs have max number for open connections, not all requests go immediately to the server, but it could cause timeout errors anyway</em>)</li>
</ul>
<p>With <code>alot</code> library it would be almost similar and ✅</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> arr2 = <span class="hljs-keyword">await</span> alot(users)
    .filter(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.score &gt; <span class="hljs-number">10</span>)
    .mapAsync(<span class="hljs-keyword">async</span> user =&gt; {
        <span class="hljs-keyword">return</span> {
            username: user.name.toUpperCase(),
            comments: <span class="hljs-keyword">await</span> Api.loadComments(user.id)
        };
    })
    .takeAsync(<span class="hljs-number">5</span>)
    .toArrayAsync({ threads: <span class="hljs-number">2</span>})
</code></pre>
<p>And the previous issues are solved:</p>
<ul>
<li>due to the <code>take</code> method, we <code>map</code> only 5 elements, which means we make only 5 api requests to load the comments.</li>
<li><code>alot</code> library can handle the <strong>async queue</strong> - in this example, we make <code>2</code> requests to the server at once (<em>this number is just an example, you can set any number of simultaneous async tasks, default is <code>4</code></em>)</li>
</ul>
<p>So with little code change, we managed to create a <strong>lazy asynchronous stream</strong></p>
<p>We can also make our <code>filter</code> async, in case we have to get the data for filtering also async.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> arr2 = <span class="hljs-keyword">await</span> alot(users)
    .filterAsync(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> Api.isActive(user))
    .mapAsync(<span class="hljs-keyword">async</span> user =&gt; {
        <span class="hljs-keyword">return</span> {
            username: user.name.toUpperCase(),
            comments: <span class="hljs-keyword">await</span> Api.loadComments(user.id)
        };
    })
    .takeAsync(<span class="hljs-number">5</span>)
    .toArrayAsync({ threads: <span class="hljs-number">2</span> })
</code></pre>
<blockquote>
<p>Аttentive reader could notice, that such data loading is not optimal. Batch load by providing the array of userIds to the backend would be better. This example just demonstrates the async tasks. This is just a tool, how and when to use it depends on you.</p>
</blockquote>
<h3 id="heading-additional-array-methods">⚙️ Additional array methods.</h3>
<p>There are some other convenient methods to work with arrays. Check the <a target="_blank" href="https://github.com/atmajs/alot">Documentation</a></p>
<p>The methods I use often are:</p>
<ul>
<li><p><code>groupBy(user =&gt; user.score)</code>
  Returns stream of groups (<code>{ key, values: T[] }[]</code>)  grouped by the same value, by the score in this example.</p>
</li>
<li><p><code>distinctBy(user =&gt; user.city)</code>
  Returns stream of unique items by the field value. In this example: a user per city.</p>
</li>
<li><p><code>sortBy(user =&gt; user.age, 'asc')</code>
  Returns sorted stream. Possible directions <code>asc</code> and <code>desc</code>. For better text sorting there is <code>sortByLocalCompare</code> method.</p>
</li>
<li><p><code>toMap(user =&gt; user.id, user =&gt; user.name)</code>
  Returns an <code>Map</code>. From the example, the keys would be the ID of a user, and the value would be the name. </p>
<p>  I use this also to improve performance. Imagine, you need to query the name of a user by id often. Then instead of <code>users.find(x =&gt;x.id === id)?.name</code> I create a <code>Map</code> of <code>id:name</code> and then simply get the name: <code>map.get(id)</code> </p>
<p>  <em><code>toDictionary</code> method returns <code>object</code> instead of <code>Map</code>, just in case it is more convinient for you</em></p>
</li>
</ul>
<hr />
<p><em>Happy coding</em></p>
<p>🏁</p>
]]></content:encoded></item><item><title><![CDATA[Use private domains with ssl certificates instead of localhost:port]]></title><description><![CDATA[If you develop several projects you should consider to use private domains, e.g. https://foo.local , instead of e.g. http://localhost:12345.


Why?

Obviously: you don't have to remember ports.
Passwords: as you don't mess with ports, your dev passwo...]]></description><link>https://dev.kit.eco/use-private-domains-with-ssl-certificates-instead-of-localhostport</link><guid isPermaLink="true">https://dev.kit.eco/use-private-domains-with-ssl-certificates-instead-of-localhostport</guid><category><![CDATA[webdev]]></category><category><![CDATA[domain]]></category><category><![CDATA[SSL]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Alex Kit]]></dc:creator><pubDate>Fri, 01 Apr 2022 10:54:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1648810281977/koau5O0Fd.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>If you develop several projects you should consider to use private domains, e.g. <code>https://foo.local</code> , instead of e.g. <code>http://localhost:12345</code>.</p>
</blockquote>
<hr />
<h2 id="heading-why">Why?</h2>
<ul>
<li><em>Obviously</em>: you don't have to remember ports.</li>
<li><em>Passwords</em>: as you don't mess with ports, your dev passwords always stick to specific domains and is much better to manage them in password manager.</li>
<li><em>Bookmarks</em>: if you save links to fast-access them on your needs, you have much better meaningful links.</li>
<li><em>Further more</em>: by separation naming and deployment you are on a good way, therefor you may find other useful cases in your dev env.</li>
<li><em>Certificates</em>: you can setup this also with localhost, but anyways this step is a must, as many of browser features are HTTPS-only, like: WebRTC, Geolocation, Service Worker.</li>
</ul>
<p>Is cross-platform: window, linux, mac. But was tested on windows. Required preinstalls: <strong>node</strong>, <strong>openssl</strong>, <strong>nginx</strong>.</p>
<blockquote>
<p><em>On windows I would suggest to use https://community.chocolatey.org/packages to install all this dependencies.</em></p>
</blockquote>
<hr />
<h2 id="heading-1-hosts">1. Hosts</h2>
<p>To make it simple, use <a target="_blank" href="http://npmjs.com/package/hostile">npm:hostile</a></p>
<pre><code class="lang-bash"><span class="hljs-comment"># install globally </span>
npm i hostile -g
<span class="hljs-comment"># define your custom private domain</span>
hostile <span class="hljs-built_in">set</span> 127.0.0.1 foo.local

<span class="hljs-comment"># view list</span>
hostile list
</code></pre>
<hr />
<h2 id="heading-2-self-signed-certificate">2. Self-signed certificate</h2>
<p>2.1 Create a certificate authority. <em>This could be one time action - for any further domains it can be reused</em></p>
<pre><code class="lang-bash"><span class="hljs-comment"># Generate private key</span>
openssl genrsa -des3 -out myCA.key 2048
<span class="hljs-comment"># Generate root certificate</span>
openssl req -x509 -new -nodes -key myCA.key -sha256 -days 825 -out myCA.pem
</code></pre>
<p>2.2 Create a certificate for the domain.</p>
<p>Create a configuration file <code>foo.local.ext</code></p>
<pre><code class="lang-ini"><span class="hljs-attr">authorityKeyIdentifier</span>=keyid,issuer
<span class="hljs-attr">basicConstraints</span>=CA:<span class="hljs-literal">FALSE</span>
<span class="hljs-attr">keyUsage</span> = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
<span class="hljs-attr">subjectAltName</span> = @alt_names
<span class="hljs-section">[alt_names]</span>
<span class="hljs-attr">DNS.1</span> = foo.local
</code></pre>
<p>Now you can create the cert using certificate authority keys:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Generate a private key</span>
openssl genrsa -out foo.local.key 2048
<span class="hljs-comment"># Create a certificate-signing request</span>
openssl req -new -key foo.local.key -out foo.local.csr
<span class="hljs-comment"># Create the signed certificate</span>
openssl x509 -req -<span class="hljs-keyword">in</span> foo.local.csr -CA myCA.pem -CAkey myCA.key -CAcreateserial -out foo.local.crt -days 825 -sha256 -extfile foo.local.ext
</code></pre>
<hr />
<h2 id="heading-3-install-self-signed-certificate">3. Install self-signed certificate</h2>
<p>You can use Chrome to install those certificates, go to: <code>chrome://settings/security</code></p>
<ol>
<li>Import foo.local.crt to the <strong>Trusted Root Certification</strong>.</li>
<li>Import myCA.pem to the <strong>Trusted Publishers</strong>, <em>if not already done</em></li>
</ol>
<hr />
<h2 id="heading-4-nginx">4. Nginx</h2>
<p>Locate the configuration file, and add reverse proxy to your localhost development instance.</p>
<pre><code class="lang-nginx"><span class="hljs-section">server</span> {
    <span class="hljs-attribute">listen</span> <span class="hljs-number">443</span> ssl;
    <span class="hljs-attribute">server_name</span>  foo.local;

    <span class="hljs-attribute">ssl_certificate</span>      /path/to/foo.local.crt;
    <span class="hljs-attribute">ssl_certificate_key</span>  /path/to/foo.local.key;

    <span class="hljs-attribute">location</span> / {
        <span class="hljs-attribute">proxy_pass</span>       http://localhost:5003;
        <span class="hljs-attribute">proxy_set_header</span> Host <span class="hljs-variable">$host</span>;
    }
}
<span class="hljs-section">server</span> {
    <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;
    <span class="hljs-attribute">server_name</span>  foo.local;
    <span class="hljs-attribute">return</span> <span class="hljs-number">301</span> https://foo.local;
}
</code></pre>
<blockquote>
<p>This also forces redirects to <code>https</code>.</p>
</blockquote>
<hr />
<p><em>Looking forward to improve:</em></p>
<p>It would be nice to have a tool which can automate all this steps and display better overview of already created projects. Also I would wish this tool to be able to launch my development environment for a project.</p>
]]></content:encoded></item><item><title><![CDATA[Ethereum: Get token price at a specific block number (onchain)]]></title><description><![CDATA[After trying to answer the question at stackexchange I've decided to write this short article, as the topic is indeed quite interesting.

1. Archive Node
The most simple is the last part of the question: at a specific block (onchain). As you may know...]]></description><link>https://dev.kit.eco/ethereum-get-token-price-at-a-specific-block-onchain</link><guid isPermaLink="true">https://dev.kit.eco/ethereum-get-token-price-at-a-specific-block-onchain</guid><category><![CDATA[Ethereum]]></category><category><![CDATA[Web3]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Smart Contracts]]></category><dc:creator><![CDATA[Alex Kit]]></dc:creator><pubDate>Sun, 27 Mar 2022 21:37:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1648254754147/wxn0h_b6Q.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>After trying to answer the question at <a target="_blank" href="https://ethereum.stackexchange.com/questions/120309/how-can-i-get-access-to-token-price-data-at-a-specific-block">stackexchange</a> I've decided to write this short article, as the topic is indeed quite interesting.</p>
</blockquote>
<h2 id="heading-1-archive-node">1. Archive Node</h2>
<p>The most simple is the last part of the question: <code>at a specific block (onchain)</code>. As you may know, ethereum's <code>geth</code> node can be launched with various <code>--gcmode</code> values: <code>full</code> or <code>archive</code>.  The <code>archive</code> mode doesn't remove any historical state data, it means - we can perform read queries specifying the <code>blockNumber</code> and getting the result back, as it was at that block.</p>
<h4 id="heading-node-as-a-service">Node-as-a-Service</h4>
<p>All popular node providers, like <a target="_blank" href="https://infura.io">infura.io</a>, <a target="_blank" href="https://quicknode.com">quicknode.com</a>, <a target="_blank" href="https://www.alchemy.com/">alchemy.com</a> can give you access to the archive node, but it won't be free of charge.</p>
<h4 id="heading-self-hosting">Self Hosting</h4>
<p>As already mentioned, if you use <code>geth</code> include additionally <code>--syncmode full --gcmode archive</code> flags. But you have to be patient - it takes time to full sync the node, and it will occupy <code>&gt;10.2TB</code> storage: <a target="_blank" href="https://etherscan.io/chartsync/chainarchive">etherscan/chainarchive</a></p>
<p><a target="_blank" href="https://github.com/ledgerwatch/erigon"><strong>Erigon 🔗</strong></a></p>
<p>I use <code>erigon</code> as it allows us to specify the number of blocks we want to keep with the historical state data</p>
<pre><code class="lang-bash">./erigon.exe --datadir D:/Erigon --chain mainnet --private.api.addr=127.0.0.1:9090 --prune=hrtc --prune.h.older=400000 --prune.r.older=400000 --prune.t.older=400000 --prune.c.older=400000
</code></pre>
<p>This will keep <code>400000</code> blocks, which with the average blocktime of <code>13s</code> will keep the data for 2 months, and it takes <code>680GB</code> of storage.</p>
<h5 id="heading-intermediate-summary">Intermediate summary</h5>
<blockquote>
<p>When you perform <code>READ</code> actions at blockchain you always get the result back which refers to some <code>blockNumber</code>. Even if you don't specify the block number, you get the result just for the latest block, but you can set any previous block your node supports.</p>
</blockquote>
<h2 id="heading-2-token-price">2. Token Price</h2>
<p>To retrieve the price onchain, there are 2 options - <code>a)</code> oracles: 3rd party contracts, which accumulate the prices in the correct way, and <code>b)</code> direct DEX sources - like Uniswap.</p>
<h3 id="heading-21-oracles">2.1 Oracles</h3>
<p>The <strong>most convenient</strong> way, as it provides direct <em><code>TOKEN/USD</code></em> pair access, and <strong>most correct</strong> way, as it provides the most accurate price information at a given time point (<code>blockNumber</code>).</p>
<p>I suggest the <strong>⬡ Chainlink</strong> price feed contracts: <a target="_blank" href="https://data.chain.link/ethereum/mainnet/crypto-usd">data.chain.link/crypto-usd</a>. For an example,  lets get the <code>ETH</code> price from the feed: </p>
<p><a target="_blank" href="https://data.chain.link/ethereum/mainnet/crypto-usd/eth-usd">data.chain.link/eth-usd</a> 
 (<a target="_blank" href="https://etherscan.io/address/0x5f4ec3df9cbd43714fe2740f5e3616155c5b8419"><code>0x5f4ec3df9cbd43714fe2740f5e3616155c5b8419</code></a>)</p>
<blockquote>
<p>Here I will use <a target="_blank" href="https://0xweb.org"><code>0xweb</code></a> 📦 package manager to create contract classes and to read data from the blockchain.</p>
</blockquote>
<pre><code class="lang-bash"><span class="hljs-comment"># install 0xweb as global util</span>
$ npm i 0xweb -g
<span class="hljs-comment"># initialize dependencies in the current folder, for API usage. For CLI not required </span>
$ 0xweb init

<span class="hljs-comment"># download and generate classes for the contract</span>
$ 0xweb install 0x5f4ec3df9cbd43714fe2740f5e3616155c5b8419 --name chainlink/oracle-eth
</code></pre>
<p>After the contract classes are generated, you can access onchain data via CLI or API</p>
<blockquote>
<p>❗❣️❗ There are default KEYs for etherscan/co and infura. They are rate-limited. Please, create and insert your keys: <code>0xweb config -e</code>, replace Node URLs for <code>eth</code>.</p>
</blockquote>
<ul>
<li><code>cli</code></li>
</ul>
<pre><code class="lang-bash">$ 0xweb contract <span class="hljs-built_in">read</span> chainlink/oracle-eth latestAnswer
</code></pre>
<ul>
<li><code>api</code></li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ChainlinkOracleEth } <span class="hljs-keyword">from</span> <span class="hljs-string">'./0xweb/eth/chainlink/oracle-eth/oracle-eth'</span>;
<span class="hljs-keyword">import</span> { Config } <span class="hljs-keyword">from</span> <span class="hljs-string">'@dequanto/Config'</span>;
<span class="hljs-keyword">import</span> { $bigint } <span class="hljs-keyword">from</span> <span class="hljs-string">'@dequanto/utils/$bigint'</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">example</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">await</span> Config.fetch();

    <span class="hljs-keyword">const</span> oracle = <span class="hljs-keyword">new</span> ChainlinkOracleEth();
    <span class="hljs-keyword">const</span> decimals = <span class="hljs-keyword">await</span> oracle.decimals();
    <span class="hljs-keyword">const</span> price: bigint = <span class="hljs-keyword">await</span> oracle.latestAnswer();

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`ETH Price: <span class="hljs-subst">${ $bigint.toEther(price, decimals) }</span> USD`</span>);
}
example();
</code></pre>
<hr />
<p>These examples return current <code>ETH</code> price. How to get the price <strong>at a specific block</strong>? Easy, by defining the <code>block</code> number.</p>
<pre><code class="lang-bash">$ 0xweb contract <span class="hljs-built_in">read</span> chainlink/oracle-eth latestAnswer --block 14450000
</code></pre>
<pre><code class="lang-typescript"> <span class="hljs-keyword">const</span> price: bigint = <span class="hljs-keyword">await</span> oracle.forBlock(<span class="hljs-number">14450000</span>).latestAnswer();
</code></pre>
<blockquote>
<p>⚠️ Ethereum 🗄️node URLs in default configuration are not archive nodes, so it won't work, you should replace them with archive node URLs.</p>
</blockquote>
<h5 id="heading-intermediate-summary">Intermediate summary</h5>
<blockquote>
<p>Though ⬡ Chainlink is the most accurate and easy way to get the prices, but it doesn't contain all those thousands of tokens out there. That's why let's have a look at DEXes.</p>
</blockquote>
<h3 id="heading-22-dex">2.2 DEX</h3>
<p>If a token is traded, that means we can get the price from there. Looks simple, but has its caveats. First of all, I'll show how to get the prices from <code>UniswapV2</code> using <code>0xweb</code> cli and <code>dequanto</code> libraries, and afterward, I briefly explain how it works under the hood.</p>
<ul>
<li><code>cli</code></li>
</ul>
<p>0xweb has already the built-in token command, which can retrieve prices from <code>UniswapV2</code></p>
<pre><code class="lang-bash">$ 0xweb token price LINK
<span class="hljs-comment"># or with block number (archive node required)</span>
$ 0xweb token price LINK --block 14450000
<span class="hljs-comment"># or by address</span>
$ 0xweb token price 0x514910771af9ca656af840dff83e8264ecf986ca
<span class="hljs-comment"># example of the command return  </span>
Symbol   LINK
Address  0x514910771af9ca656af840dff83e8264ecf986ca
Decimals 18
Price    15.715912
</code></pre>
<ul>
<li><code>api</code></li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> di <span class="hljs-keyword">from</span> <span class="hljs-string">'a-di'</span>;
<span class="hljs-keyword">import</span> { Config } <span class="hljs-keyword">from</span> <span class="hljs-string">'@dequanto/Config'</span>;
<span class="hljs-keyword">import</span> { PlatformFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'@dequanto/chains/PlatformFactory'</span>;
<span class="hljs-keyword">import</span> { TokenPriceService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@dequanto/tokens/TokenPriceService'</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">example</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// we need this once: to find and read all configurations</span>
    <span class="hljs-keyword">await</span> Config.fetch();

    <span class="hljs-keyword">let</span> token = <span class="hljs-string">'LINK'</span>;
    <span class="hljs-comment">// any unknown tokens are also supported</span>
    <span class="hljs-keyword">let</span> token = { address: <span class="hljs-string">"0x12345abcd"</span>, decimals: <span class="hljs-number">18</span> };
    <span class="hljs-keyword">let</span> chain = <span class="hljs-keyword">await</span> di.resolve(PlatformFactory).get(<span class="hljs-string">'eth'</span>)
    <span class="hljs-keyword">let</span> service = <span class="hljs-keyword">new</span> TokenPriceService(chain.client, chain.explorer);
    <span class="hljs-keyword">let</span> { price } = <span class="hljs-keyword">await</span> service.getPrice(token, {
        block: <span class="hljs-number">14450000</span>
    });
    <span class="hljs-built_in">console</span>.log(price);
}
example();
</code></pre>
<hr />
<p><em>A couple of words about how to run the scripts from api examples.</em> I use <a target="_blank" href="https://www.npmjs.com/package/atma">atma</a> global package to run the scripts. It supports file middlewares, in particular the <a target="_blank" href="https://www.npmjs.com/package/atma-loader-ts">atma-loader-ts</a>, it will compile, cache and execute the TS files on the fly: <code>atma run ./example.ts</code>. All required packages and loader configuration will be created on <code>0xweb init</code>. <strong>But</strong> you can use any other loader/builder you already use for TypeScript.</p>
<hr />
<p><strong>⚙️ How it works</strong></p>
<h3 id="heading-221-uniswapv2-interfaces">2.2.1 <code>UniswapV2</code> interfaces</h3>
<pre><code class="lang-solidity"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IUniswapV2Factory</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPair</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> tokenA, <span class="hljs-keyword">address</span> tokenB</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">address</span> pair</span>)</span>;
}
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IUniswapV2Pair</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">token0</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">token1</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">address</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getReserves</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">uint112</span> reserve0, <span class="hljs-keyword">uint112</span> reserve1, <span class="hljs-keyword">uint32</span> blockTimestampLast</span>)</span>;
}
</code></pre>
<h4 id="heading-1-how-to-get-the-price-of-a-token-egweth-from-the-pair-wethusdc">1. How to get the price of a token e.g.<code>WETH</code> from the pair <code>WETH/USDC</code>?</h4>
<p>This step is trivial, the <a target="_blank" href="https://etherscan.io/address/0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc#readContract">pair</a>, has reserves of each token - amount of tokens in the pool. And the price is just a ratio of these amounts. <code>price(WETH) = totalEther(USDC)/totalEther(WETH)</code>. </p>
<ul>
<li>⚠️ Be aware, that each <code>ERC20</code> token can have different values for <strong><code>decimals</code></strong>, so just convert values to <code>ether</code></li>
<li><p>✨ By having two tokens, e.g. <code>0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48</code>(<code>USDC</code>)/<code>0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2</code>(<code>WETH</code>) which one is <code>reserve0</code> and <code>reserve1</code>? Uniswap stores the tokens in a sorted way: <code>token0 &lt; token1</code></p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">const</span> USDC = <span class="hljs-string">'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'</span>;
  <span class="hljs-keyword">const</span> WETH = <span class="hljs-string">'0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'</span>;
  <span class="hljs-keyword">const</span> lpReserves = <span class="hljs-keyword">await</span> poolPair
      .forBlock(opts?.block ?? opts?.date)
      .getReserves();

  <span class="hljs-keyword">let</span> reserves = [lpReserves.reserve0, lpReserves.reserve1];
  <span class="hljs-keyword">let</span> sorted = BigInt(USDC) &lt; BigInt(WETH);
  <span class="hljs-keyword">if</span> (sorted === <span class="hljs-literal">false</span>) {
      reserves.reverse();
  }
  <span class="hljs-keyword">let</span> [ usdc, weth ] = reserves;
</code></pre>
</li>
<li>✨ From the previous example, you have noticed the <code>.fromBlock(opts?.block ?? opts?.date)</code> method - so yes, you can specify the <code>BlockNumber</code> or <code>Date</code>(<em>which will be resolved to the <code>BlockNumber</code></em>).</li>
</ul>
<h4 id="heading-2-okay-but-how-do-i-find-out-the-address-of-the-pair-contract">2. Okay, but how do I find out the address of the pair contract?</h4>
<p>The <code>UniswapV2Factory</code> contract has the method <code>getPair</code>, which accepts any two tokens, and returns the pair contract (<em>if exists ❗</em>).</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// tokens order doesn't matter here</span>
factoryContract.getPair(USDC, WETH)
</code></pre>
<h4 id="heading-3-what-if-i-want-to-get-the-price-for-a-token-but-there-is-no-tokenusdc-pair">3. What if I want to get the price for a token, but there is no <code>TOKEN/USDC</code> pair?</h4>
<p>If we stick to on-chain solution only, you could index all pairs in the <code>Factory</code>, then you have the list of all pairs for a token. But this is unnecessary, as it is enough to check all major stable coins and the wrapped eth with that token: <code>USDC, USDT, DAI, WETH</code>. </p>
<ul>
<li>⚠️ Often only <code>TOKEN/WETH</code> pair is present, or stable pairs have small liquidity, but as we already know - we can get the price for <code>WETH</code> from Chainlink or any of <code>WETH/STABLE</code> pairs</li>
</ul>
<hr />
<p>Following points you have to think about:</p>
<ul>
<li>✨ to get the price from the pool with the most liquidity</li>
<li>✨ to get the price for one or two nearby blocks and take the average</li>
<li>✨ this gives the price in stable coins, those are not always equal to <code>1$</code></li>
</ul>
<hr />
<p>🏁</p>
]]></content:encoded></item></channel></rss>