<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>TechExplorer</title>
        <link>https://paragraph.com/@techexplorer</link>
        <description>undefined</description>
        <lastBuildDate>Sun, 09 Aug 2026 14:13:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>TechExplorer</title>
            <url>https://storage.googleapis.com/papyrus_images/37b940d5f59d283287ee0a95f503dd252c9b649a3b5fae3cae6da7b268aab5fb.jpg</url>
            <link>https://paragraph.com/@techexplorer</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[Building a DAO from Scratch with Solidity & Foundry — Part 1]]></title>
            <link>https://paragraph.com/@techexplorer/building-a-dao-from-scratch-with-solidity-and-foundry-—-part-1</link>
            <guid>OPQXzh26L3bMlsAxW8CQ</guid>
            <pubDate>Thu, 08 Jan 2026 13:46:03 GMT</pubDate>
            <description><![CDATA[IntroductionA DAO (Decentralized Autonomous Organization) is a system that enables collective decision-making through code, without relying on traditional organizational hierarchies such as boards of directors, CEOs, or CTOs. Instead of trust in individuals or institutions, DAOs rely on smart contracts deployed on a blockchain. At its core, a DAO allows participants to propose, vote, and execute decisions in a transparent and verifiable way. Voting power is typically derived from tokens held ...]]></description>
            <content:encoded><![CDATA[<h2 id="h-introduction" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Introduction</strong></h2><p>A <strong>DAO (Decentralized Autonomous Organization)</strong> is a system that enables collective decision-making through code, without relying on traditional organizational hierarchies such as boards of directors, CEOs, or CTOs. Instead of trust in individuals or institutions, DAOs rely on <strong>smart contracts</strong> deployed on a blockchain.</p><p>At its core, a DAO allows participants to <strong>propose</strong>, <strong>vote</strong>, and <strong>execute decisions</strong> in a transparent and verifiable way. Voting power is typically derived from <strong>tokens</strong> held by participants, where each token represents a unit of voting weight.</p><p>A typical on-chain DAO is composed of three main smart contracts:</p><ol><li><p><strong>Token contract</strong><br>Defines the governance token and tracks voting power.</p></li><li><p><strong>Governor contract</strong><br>Manages proposals and voting logic: who can propose, how votes are counted, quorum requirements, and proposal outcomes.</p></li><li><p><strong>Timelock contract</strong><br>Acts as a security layer by enforcing a delay between proposal approval and execution, giving participants time to react to potentially harmful decisions.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/08141d776c7a1b85f8b8494a8b5bf1c9e4fe309fc9dc6aff53086f35a3a25ddd.png" blurdataurl="data:image/png;base64,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" nextheight="333" nextwidth="546" class="image-node embed"><figcaption htmlattributes="[object Object]" class="hide-figcaption"></figcaption></figure></li></ol><p>In this article series, we will build a DAO from the ground up using <a target="_blank" rel="noopener ugc nofollow" class="dont-break-out ah pd" href="https://www.openzeppelin.com/"><u>OpenZeppelin</u></a> model. In <strong>Part 1</strong>, we will focus on writing, deploying, and testing the <strong>governance token</strong>, which we will call <code>GovernanceToken</code>. This token will later be used to enable on-chain voting and decision-making in the DAO.</p><h2 id="h-the-token-code" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>The Token Code</strong></h2><p>Without further ado, here is the code:</p><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {ERC20} from &quot;@openzeppelin/contracts/token/ERC20/ERC20.sol&quot;;
import {ERC20Permit} from &quot;@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol&quot;;
import {ERC20Votes} from &quot;@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol&quot;;
import {Ownable} from &quot;@openzeppelin/contracts/access/Ownable.sol&quot;;
import {Nonces} from &quot;@openzeppelin/contracts/utils/Nonces.sol&quot;;

contract GovernanceToken is ERC20, ERC20Permit, ERC20Votes, Ownable {
    constructor()
        ERC20(&quot;GovernanceToken&quot;, &quot;MGT&quot;)
        ERC20Permit(&quot;GovernanceToken&quot;)
        Ownable(msg.sender)
    {
        _mint(msg.sender, 1_000_000 * 10 ** decimals());
    }

    // Optional: Add controlled minting
    function mint(address to, uint256 amount) external {
        require(msg.sender == owner(), &quot;Only owner can mint&quot;);
        _mint(to, amount);
    }

    // ── Conflict resolution ──

    // Both ERC20 and ERC20Votes define _update
    function _update(address from, address to, uint256 amount)
        internal
        override(ERC20, ERC20Votes)
    {
        super._update(from, to, amount);
    }

    // Both ERC20Permit and Nonces define nonces()
    function nonces(address owner)
        public
        view
        override(ERC20Permit, Nonces)
        returns (uint256)
    {
        return super.nonces(owner);
    }
}"><code><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">ERC20</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/ERC20.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">ERC20Permit</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">ERC20Votes</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"</span>;
<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">import</span> {<span class="hljs-title">Nonces</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"@openzeppelin/contracts/utils/Nonces.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">GovernanceToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">ERC20</span>, <span class="hljs-title">ERC20Permit</span>, <span class="hljs-title">ERC20Votes</span>, <span class="hljs-title">Ownable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>)
        <span class="hljs-title">ERC20</span>(<span class="hljs-params"><span class="hljs-string">"GovernanceToken"</span>, <span class="hljs-string">"MGT"</span></span>)
        <span class="hljs-title">ERC20Permit</span>(<span class="hljs-params"><span class="hljs-string">"GovernanceToken"</span></span>)
        <span class="hljs-title">Ownable</span>(<span class="hljs-params"><span class="hljs-built_in">msg</span>.sender</span>)
    </span>{
        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-number">1_000_000</span> <span class="hljs-operator">*</span> <span class="hljs-number">10</span> <span class="hljs-operator">*</span><span class="hljs-operator">*</span> decimals());
    }

    <span class="hljs-comment">// Optional: Add controlled minting</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mint</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-built_in">require</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> owner(), <span class="hljs-string">"Only owner can mint"</span>);
        _mint(to, amount);
    }

    <span class="hljs-comment">// ── Conflict resolution ──</span>

    <span class="hljs-comment">// Both ERC20 and ERC20Votes define _update</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_update</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>)
        <span class="hljs-title"><span class="hljs-keyword">internal</span></span>
        <span class="hljs-title"><span class="hljs-keyword">override</span></span>(<span class="hljs-params">ERC20, ERC20Votes</span>)
    </span>{
        <span class="hljs-built_in">super</span>._update(<span class="hljs-keyword">from</span>, to, amount);
    }

    <span class="hljs-comment">// Both ERC20Permit and Nonces define nonces()</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">nonces</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> owner</span>)
        <span class="hljs-title"><span class="hljs-keyword">public</span></span>
        <span class="hljs-title"><span class="hljs-keyword">view</span></span>
        <span class="hljs-title"><span class="hljs-keyword">override</span></span>(<span class="hljs-params">ERC20Permit, Nonces</span>)
        <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>)
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">super</span>.nonces(owner);
    }
}</code></pre><p>Compared to a traditional ERC20 token, <code>GovernanceToken</code> integrates two additional OpenZeppelin modules: <strong>ERC20Permit</strong> and <strong>ERC20Votes</strong>.</p><ul><li><p><strong>ERC20Votes</strong> adds governance-specific functionality, most notably <code>getPastVotes(account, blockNumber)</code>. This function returns an account’s voting power at a specific block, rather than its current balance. In a DAO context, this snapshot mechanism is critical: voting power is fixed at the moment a proposal is created, preventing users from manipulating votes by buying or transferring tokens after the fact.</p></li><li><p><strong>ERC20Permit</strong> enables gasless approvals via signatures (EIP-2612), allowing users to delegate or approve voting power without sending an on-chain transaction.</p></li></ul><p>The most important logic resides in the <strong>constructor</strong>, which initializes all inherited modules and mints one million governance tokens to the deployer. We also define an optional <code>mint</code> function, restricted to the contract owner, to allow controlled token issuance after deployment (useful for testing or future governance decisions).</p><p>Finally, two functions — <code>_update</code> and <code>nonces</code>—must be explicitly overridden. This is required because they are defined in multiple parent contracts. The overrides simply delegate execution to <code>super</code>, ensuring that all inherited behaviors are correctly composed and that the compiler’s inheritance conflicts are resolved cleanly.</p><h2 id="h-building-the-token" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Building the Token</strong></h2><p>To build our governance token, we will use <strong>Foundry</strong>, a fast and modern Ethereum development toolkit. The following steps assume a Linux environment, but the workflow is similar on macOS.</p><p>We start by installing Foundry using the official installation script:</p><pre data-type="codeBlock" text="curl -L https://foundry.paradigm.xyz | bash"><code>curl <span class="hljs-operator">-</span>L https:<span class="hljs-comment">//foundry.paradigm.xyz | bash</span></code></pre><p>After installation, the script instructs us to update our shell environment and install the Foundry binaries:</p><pre data-type="codeBlock" text="source ~/.bashrc   # path may vary depending on your system foundryup"><code><span class="hljs-built_in">source</span> ~/.bashrc   <span class="hljs-comment"># path may vary depending on your system foundryup</span></code></pre><p>This installs the full Foundry toolchain: <strong>forge</strong> (build &amp; test), <strong>cast</strong> (CLI interactions), <strong>anvil</strong> (local node), and <strong>chisel</strong> (REPL).</p><p>Next, we initialize a new Foundry project in an empty directory:</p><pre data-type="codeBlock" text="mkdir DAO
cd DAO
forge init"><code><span class="hljs-built_in">mkdir</span> DAO
<span class="hljs-built_in">cd</span> DAO
forge init</code></pre><p>This generates a complete project scaffold, including <code>src/</code>, <code>script/</code>, and <code>test/</code> directories. By default, Foundry creates example <em>Counter</em> contracts and tests. Since we only want the project structure, we can safely remove these example files and replace them with our own contracts.</p><p>For now, we add our governance token under <code>src/</code>:</p><pre data-type="codeBlock" text="src/
└── GovernanceToken.sol"><code><span class="hljs-attribute">src</span>/
└── GovernanceToken<span class="hljs-selector-class">.sol</span></code></pre><p>(Containing the <code>GovernanceToken</code> contract defined in the previous section.)</p><p>Because our token relies on OpenZeppelin modules, we must install the OpenZeppelin Contracts library:</p><pre data-type="codeBlock" text="forge install OpenZeppelin/openzeppelin-contracts"><code>forge install OpenZeppelin<span class="hljs-operator">/</span>openzeppelin<span class="hljs-operator">-</span>contracts</code></pre><p>This command vendors OpenZeppelin into the <code>lib/</code> directory and makes its contracts available for import within our project.</p><p>Finally, we compile the project:</p><pre data-type="codeBlock" text="forge build"><code></code></pre><p>If everything is set up correctly, the compilation completes successfully and generates an <code>out/</code> directory. This folder contains the compiled artifacts (ABIs and bytecode) for <code>GovernanceToken</code> as well as all inherited OpenZeppelin dependencies.</p><p>At this point, our governance token is fully compiled and ready to be deployed and tested — steps we will cover in the next sections.</p><h2 id="h-deploying-the-token" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Deploying the Token</strong></h2><p>With the governance token compiled, we can now deploy it to a local blockchain. Foundry makes this process straightforward through <strong>deployment scripts</strong>.</p><p>We start by creating a deployment script <code>DeployGovernanceToken.s.sol</code> under the <code>script/</code> directory:</p><pre data-type="codeBlock" text="// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script} from &quot;forge-std/Script.sol&quot;;
import {GovernanceToken} from &quot;../src/GovernanceToken.sol&quot;;
contract DeployGovernanceToken is Script {
    function run() external {
        vm.startBroadcast();
        new GovernanceToken();
        vm.stopBroadcast();
    }
}"><code><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>
<span class="hljs-keyword">import</span> {<span class="hljs-title">Script</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Script.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">GovernanceToken</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/GovernanceToken.sol"</span>;
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">DeployGovernanceToken</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Script</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        vm.startBroadcast();
        <span class="hljs-keyword">new</span> GovernanceToken();
        vm.stopBroadcast();
    }
}</code></pre><p>This script defines a <code>run</code> function that Foundry will execute. The <code>vm.startBroadcast()</code> / <code>vm.stopBroadcast()</code> pair tells Foundry to send transactions to the network, rather than simulating them.</p><p>Next, we launch a local Ethereum network using <strong>Anvil</strong> (in a separate terminal):</p><pre data-type="codeBlock" text="anvil"><code></code></pre><p>Anvil starts a local node on <code>http://127.0.0.1:8545</code> and prints a list of pre-funded accounts along with their private keys. These accounts are intended for development and testing only.</p><p>With Anvil running, we can deploy the contract using <code>forge script</code>:</p><pre data-type="codeBlock" text="forge script script/DeployGovernanceToken.s.sol \
  --rpc-url http://127.0.0.1:8545 \
  --broadcast \
  --private-key &lt;ANVIL_PRIVATE_KEY&gt;"><code>forge script script<span class="hljs-operator">/</span>DeployGovernanceToken.s.sol \
  <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url http:<span class="hljs-comment">//127.0.0.1:8545 \</span>
  <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast \
  <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-keyword">private</span><span class="hljs-operator">-</span>key <span class="hljs-operator">&lt;</span>ANVIL_PRIVATE_KEY<span class="hljs-operator">&gt;</span></code></pre><p>The RPC URL and private key are taken directly from Anvil’s output. When the command succeeds, Foundry prints the transaction hash, deployed contract address, gas usage, and the block number in which the contract was created.</p><p>To quickly verify that the deployment worked, we can query the deployed contract using <strong>cast</strong>. For example, calling <code>totalSupply()</code> confirms that the initial mint occurred as expected:</p><pre data-type="codeBlock" text="cast call &lt;DEPLOYED_CONTRACT_ADDRESS&gt; \
  &quot;totalSupply()(uint256)&quot; \
  --rpc-url http://127.0.0.1:8545"><code>cast call <span class="hljs-operator">&lt;</span>DEPLOYED_CONTRACT_ADDRESS<span class="hljs-operator">&gt;</span> \
  <span class="hljs-string">"totalSupply()(uint256)"</span> \
  <span class="hljs-operator">-</span><span class="hljs-operator">-</span>rpc<span class="hljs-operator">-</span>url http:<span class="hljs-comment">//127.0.0.1:8545</span></code></pre><p>The returned value corresponds to <strong>1,000,000 tokens with 18 decimals (</strong>1000000000000000000000000 [1e24]<strong>)</strong>, matching the amount minted in the constructor.</p><p>At this stage, our governance token is live on a local network and ready to be used for testing voting, delegation, and — eventually — DAO governance.</p><h2 id="h-testing-the-token" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Testing the Token</strong></h2><p>To validate our governance token’s behavior, we can write unit tests using <strong>forge-std</strong>, Foundry’s testing framework. Tests live in the <code>test/</code> directory and are written in Solidity.</p><p>Below is a simple test that verifies the <code>mint</code> function works as expected:</p><pre data-type="codeBlock" text="// test/GovernanceToken.t.sol
pragma solidity ^0.8.20;
import {Test} from &quot;forge-std/Test.sol&quot;;
import {GovernanceToken} from &quot;../src/GovernanceToken.sol&quot;;
contract TokenTest is Test {
    GovernanceToken token;
    function setUp() public {
        token = new GovernanceToken();
    }
    function testMint() public {
        uint256 before = token.balanceOf(address(this));
        token.mint(address(this), 100);
        uint256 after_ = token.balanceOf(address(this));
        assertEq(after_ - before, 100);
    }
}"><code><span class="hljs-comment">// test/GovernanceToken.t.sol</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.20;</span>
<span class="hljs-keyword">import</span> {<span class="hljs-title">Test</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"forge-std/Test.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">GovernanceToken</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"../src/GovernanceToken.sol"</span>;
<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">TokenTest</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Test</span> </span>{
    GovernanceToken token;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setUp</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        token <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> GovernanceToken();
    }
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testMint</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-keyword">uint256</span> before <span class="hljs-operator">=</span> token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
        token.mint(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), <span class="hljs-number">100</span>);
        <span class="hljs-keyword">uint256</span> after_ <span class="hljs-operator">=</span> token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
        assertEq(after_ <span class="hljs-operator">-</span> before, <span class="hljs-number">100</span>);
    }
}</code></pre><p>The <code>setUp</code> function is executed before each test and deploys a fresh instance of <code>GovernanceToken</code>, ensuring isolation between test cases. The <code>testMint</code> function then checks that calling <code>mint</code> increases the recipient’s balance by the expected amount.</p><p>Running the test suite is as simple as:</p><pre data-type="codeBlock" text="forge test"><code>forge <span class="hljs-built_in">test</span></code></pre><p>Foundry compiles the contracts, executes the test, and reports the results. A passing test confirms that our token’s minting logic behaves correctly.</p><h2 id="h-conclusion" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Conclusion</strong></h2><p>In this article, we tackled the first building block of a DAO: the <strong>governance token</strong>. We began by examining the token contract itself, with particular attention to the OpenZeppelin modules it inherits from and the additional governance-related features they provide.</p><p>We then walked through the full development workflow using <strong>Foundry</strong> — from initializing a project, to deploying the token on a local Anvil network, and finally validating its behavior with unit tests.</p><p>This governance token will serve as the foundation for everything that follows. In the next parts of this series, we will build on top of it by introducing delegation, voting mechanics, and the core governance contracts that transform this token into a fully functional on-chain DAO.</p><p>I hope you found this article useful. Feel free to like, share, and subscribe for more content in the series.</p><h2 id="h-miscellaneous-extra-commands" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Miscellaneous: Extra Commands</strong></h2><p>All commands shown in this article were executed inside a Docker container created with the following command:</p><pre data-type="codeBlock" text="docker run -it ubuntu:ubuntu@sha256:72297848456d5d37d1262630108ab308d3e9ec7ed1c3286a32fe09856619a782"><code>docker run <span class="hljs-operator">-</span>it ubuntu:ubuntu@<span class="hljs-built_in">sha256</span>:72297848456d5d37d1262630108ab308d3e9ec7ed1c3286a32fe09856619a782</code></pre><p>Using a pinned image digest ensures <strong>full reproducibility</strong>, as the environment will always be identical regardless of when or where the container is launched.</p><p>To run <strong>Anvil</strong> in a separate terminal, we simply attached to the same container:</p><pre data-type="codeBlock" text="docker exec -it &lt;CONTAINER_NAME&gt; bashanvil"><code>docker exec <span class="hljs-operator">-</span>it <span class="hljs-operator">&lt;</span>CONTAINER_NAME<span class="hljs-operator">&gt;</span> bashanvil</code></pre><p>The variable <em>&lt;CONTAINER_NAME&gt;</em> can be found through the command:</p><pre data-type="codeBlock" text="$ docker ps"><code><span class="hljs-variable">$ </span>docker ps</code></pre><p>Foundry also allows you to run deployment scripts <strong>without</strong> a live network. The following command executes the script in a simulated environment and reports gas usage, without broadcasting any transactions:</p><pre data-type="codeBlock" text="forge script script/DeployGovernanceToken.s.sol --broadcast"><code>forge script script<span class="hljs-operator">/</span>DeployGovernanceToken.s.sol <span class="hljs-operator">-</span><span class="hljs-operator">-</span>broadcast</code></pre><p>This mode is useful for quickly validating deployment logic and estimating gas costs. If you want to simulate or execute transactions against an actual network (local or remote), simply provide an RPC URL using the <code>--rpc-url</code> flag.</p><h2 id="h-miscellaneous-warnings" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0"><strong>Miscellaneous: Warnings</strong></h2><p>During development, you may encounter warnings related to dependencies rather than your own contracts. In our case, the compiler emitted warnings originating from the <code>lib/forge-std</code> library:</p><pre data-type="codeBlock" text="Warning (2424): Natspec memory-safe-assembly special comment for inline assembly is deprecated
and scheduled for removal. Use the memory-safe block annotation instead.
   --&gt; lib/forge-std/src/StdStorage.sol:301:13"><code>Warning (<span class="hljs-number">2424</span>): Natspec <span class="hljs-keyword">memory</span><span class="hljs-operator">-</span>safe<span class="hljs-operator">-</span><span class="hljs-keyword">assembly</span> special comment for inline <span class="hljs-keyword">assembly</span> is deprecated
and scheduled for removal. Use the memory-safe block annotation instead.
   --&gt; lib/forge-std/src/StdStorage.sol:301:13</code></pre><p>These warnings are caused by a <strong>version mismatch</strong> between the Solidity compiler and the installed version of <code>forge-std</code>. Newer Solidity versions deprecate the <code>@memory-safe-assembly</code> NatSpec comment in favor of the <code>memory-safe</code> block annotation, while older library versions may still use the deprecated syntax.</p><p>Since the issue originates in a dependency, the simplest fix is to update <code>forge-std</code> to the latest version:</p><pre data-type="codeBlock" text="cd lib/forge-std
git pull origin master
git checkout mastercd -"><code>cd lib<span class="hljs-operator">/</span>forge<span class="hljs-operator">-</span>std
git pull origin master
git checkout mastercd <span class="hljs-operator">-</span></code></pre><p>After updating the library, the warnings disappear and the project compiles cleanly again.</p><p>This is a good reminder that compiler warnings are not always caused by your own code. When working with fast-evolving toolchains like Foundry and Solidity, keeping dependencies up to date is often necessary to avoid noisy or misleading warnings.</p>]]></content:encoded>
            <author>techexplorer@newsletter.paragraph.com (TechExplorer)</author>
            <category>dao</category>
            <category>smart-contracts</category>
            <category>ethereum</category>
            <category>crypto</category>
            <category>web3</category>
            <enclosure url="https://storage.googleapis.com/papyrus_images/4eacdd2335ef1914651ee2952544b3f56b10450b7a5c1cb14ab417824b9e8ac3.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>