Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteThis first installment builds and tests only the governance-token layer of a DAO. You will compose OpenZeppelin’s ERC20Votes and ERC20Permit with Foundry, deploy the token to Anvil, and verify delegation and historical voting power. A token contract is not a complete DAO: a production system normally adds a Governor and Timelock.
The examples below target Solidity ^0.8.24 and OpenZeppelin Contracts 5-style APIs. Check the exact library tag and compiler version you install; older 4.x and newer prerelease versions may require different overrides. OpenZeppelin’s governance overview is at docs.openzeppelin.com/contracts/4.x/governance.
What a governance token must decide
An ERC-20 balance alone is not a reliable governance system. Before writing Solidity, decide who receives the initial supply, whether supply is fixed or mintable, how holders delegate, which historical timepoint a Governor will read, and whether voting uses blocks or timestamps. Also decide whether transfers remain possible during a vote, whether one token equals one vote, and what administrative powers survive deployment.
A common architecture is:
GovernanceToken → Governor → Timelock → treasury or governed contracts
The token records voting power. The Governor creates proposals and counts votes. A Timelock delays successful execution so participants can review or react. This article implements only the first component.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →#1 Best Overall
Why ERC20Votes matters
ERC20Votes stores checkpoints of delegated voting power. A Governor can therefore ask what an account controlled at a past timepoint instead of trusting its balance at the instant a vote is cast. That reduces flash-balance and transfer-timing manipulation.
getVotes(account)returns current effective voting power.getPastVotes(account, timepoint)returns the checkpointed value for an earlier valid timepoint.delegates(account)shows where an account’s voting power is delegated.- Transfers, minting, and burning update checkpoints for affected delegates.
A holder can have tokens but zero effective votes until delegating, commonly to themselves. Delegation is not automatic because it costs gas and checkpoint storage. Your eventual Governor must use the same clock mode as the token. Block-based and timestamp-based systems are not interchangeable, and the exact snapshot rule—proposal creation, activation, or another configured point—comes from the selected Governor configuration, not from ERC-20 itself. See OpenZeppelin’s governance documentation for compatibility details: https://docs.openzeppelin.com/contracts/4.x/governance.
What ERC20Permit does—and does not do
ERC20Permit implements EIP-2612 signature-based approvals. A user signs EIP-712 typed data containing the token domain, spender, amount, nonce, and deadline; a relayer submits the transaction. Nonces prevent replay, the chain ID participates in the domain separator, and an expired deadline invalidates the signature.
Permit is not automatically gasless governance. permit approves token spending; delegate is a separate state-changing call, and delegateBySig is a separate governance-signature flow when supported. Wallet support and frontend implementation also vary. Test invalid signers, expired deadlines, reused nonces, wrong-chain domains, and mismatched spender or recipient data.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #2
Supply and authority are governance decisions
| Design | Advantage | Risk or cost |
|---|---|---|
| Fixed supply | Predictable dilution and voting power | No future issuance without another mechanism |
| Capped minting | Allows planned grants within a hard limit | The cap and authorization must be governed |
| Owner minting | Simple for a tutorial | One key can dilute holders and seize governance |
| Governor-controlled minting | Issuance follows on-chain governance | Requires a secure Governor and Timelock |
| Vesting allocations | Reduces immediate insider liquidity | Additional contracts and edge cases |
| Treasury allocation | Funds future grants and operations | A concentrated treasury can dominate votes |
The baseline below uses a fixed one-million-token supply and omits an owner mint function. An unrestricted mint is acceptable only as an explicitly local-development shortcut, or when it is capped, timelocked, and controlled by carefully reviewed governance. A deployer receiving the entire initial supply is also centralized until distribution, vesting, treasury, or delegation policies change that outcome.
Install and pin the toolchain
Foundry supplies Forge (builds and tests), Cast (RPC calls), Anvil (a local EVM node), and Chisel. Install it with the official command:
curl -L https://foundry.paradigm.xyz | bash
foundryup
forge --version
cast --version
anvil --version
Foundry changes quickly; record the versions printed by these commands rather than treating any release as permanently current. The official repository is https://github.com/foundry-rs/foundry.
Create a project:
mkdir DAO
cd DAO
forge init
Foundry creates foundry.toml, lib/, script/, src/, and test/. Remove the generated Counter example. Install OpenZeppelin, then pin a release tag or commit rather than following a moving branch:
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchforge install OpenZeppelin/openzeppelin-contracts
Confirm remappings.txt contains:
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
OpenZeppelin’s repository explains its audited release channels and dependency guidance: https://github.com/OpenZeppelin/openzeppelin-contracts.
Implement the fixed-supply token
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol";
contract GovernanceToken is ERC20, ERC20Permit, ERC20Votes {
constructor()
ERC20("GovernanceToken", "MGT")
ERC20Permit("GovernanceToken")
{
_mint(msg.sender, 1_000_000 * 10 ** decimals());
}
function _update(address from, address to, uint256 amount)
internal
override(ERC20, ERC20Votes)
{
super._update(from, to, amount);
}
function nonces(address owner)
public
view
override(ERC20Permit, Nonces)
returns (uint256)
{
return super.nonces(owner);
}
}
The constructor mints 1,000,000 whole tokens. With the default 18 decimals, totalSupply() is 1_000_000 × 1018 = 1e24 raw units. The ether unit in Solidity tests is merely a convenient 10**18 multiplier; it does not mean the token is ETH.
Why the overrides are required
ERC20 and ERC20Votes both participate in balance updates, while ERC20Permit and Nonces expose overlapping nonce behavior. The overrides resolve Solidity’s multiple-inheritance graph and call parent logic through super; they are not custom tokenomics. Exact requirements depend on the OpenZeppelin major version, so copying 4.x code into a 5.x project can fail to compile.
Compile and diagnose errors
forge build
A successful build writes artifacts under out/. If it fails, inspect the first error:
Rank #4
- Brand New in box. The product ships with all relevant accessories
- Compare the contract pragma with the installed OpenZeppelin release.
- Check the remapping and that the dependency is initialized.
- Confirm whether the code expects OpenZeppelin 4.x or 5.x inheritance APIs.
- Run
forge clean, then rebuild. - Pin dependencies before updating them; do not blindly pull a development branch.
Test voting behavior, not just minting
A single balance test does not establish governance correctness. At minimum, cover the following:
function testInitialSupply() public {
assertEq(token.totalSupply(), 1_000_000 ether);
assertEq(token.balanceOf(address(this)), 1_000_000 ether);
}
function testSelfDelegation() public {
token.delegate(address(this));
assertEq(token.getVotes(address(this)), 1_000_000 ether);
}
Also test that account A delegates to A, transfers tokens to B, and loses current votes by the transferred amount; B has a balance but no active votes until delegating; and getPastVotes still returns the earlier checkpoint. Use mined blocks or controlled timepoints appropriate to the token clock.
- Name, symbol, decimals, initial allocation, and transfer behavior.
- Delegation to another account and checkpoint changes after transfers.
- Permit success, nonce increment, wrong signer, expired deadline, reused nonce, and wrong-chain domain.
- Zero-address and zero-amount edge cases.
- Fuzzed transfers and delegation invariants, including total-supply conservation.
Run the suite with:
forge test
forge test -vvv
forge test --match-test testSelfDelegation
forge test --gas-report
forge coverage
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Deploy locally with Anvil
Start the local node:
anvil
Anvil normally listens at http://127.0.0.1:8545, uses chain ID 31337, and prints prefunded accounts and private keys. Those keys are for local testing only. The local-EVM workflow is described at https://docs.openzeppelin.com/monitor/local-evm-testing.
Create script/DeployGovernanceToken.s.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {Script} from "forge-std/Script.sol";
import {GovernanceToken} from "../src/GovernanceToken.sol";
contract DeployGovernanceToken is Script {
function run() external returns (GovernanceToken token) {
vm.startBroadcast();
token = new GovernanceToken();
vm.stopBroadcast();
}
}
Broadcast it with an Anvil key:
forge script script/DeployGovernanceToken.s.sol
--rpc-url http://127.0.0.1:8545
--broadcast
--private-key <ANVIL_PRIVATE_KEY>
Query the resulting address:
cast call <DEPLOYED_CONTRACT_ADDRESS>
"totalSupply()(uint256)"
--rpc-url http://127.0.0.1:8545
cast call <DEPLOYED_CONTRACT_ADDRESS>
"balanceOf(address)(uint256)" <DEPLOYER_ADDRESS>
--rpc-url http://127.0.0.1:8545
cast call <DEPLOYED_CONTRACT_ADDRESS>
"delegates(address)(address)" <DEPLOYER_ADDRESS>
--rpc-url http://127.0.0.1:8545
cast call <DEPLOYED_CONTRACT_ADDRESS>
"getVotes(address)(uint256)" <DEPLOYER_ADDRESS>
--rpc-url http://127.0.0.1:8545
The expected raw supply is 1000000000000000000000000. Before self-delegation, the deployer’s balance can be that amount while getVotes is zero.
Recommended Free Tools
Best Value
Ownership and mainnet boundaries
Ownable(msg.sender) or an equivalent deployer authority is convenient locally, but a single externally owned account should not remain a permanent production minter or administrator. If privileged functions are necessary, transfer control to a multisig, a TimelockController, or the Governor’s execution path only after verifying addresses and recovery procedures. Transferring or renouncing ownership incorrectly can permanently remove control.
Before public deployment, pin Solidity, Foundry, OpenZeppelin, and forge-std; review allocations and dilution; test Governor/token clock compatibility; secure signing keys; deploy to a testnet; verify source through Etherscan or Sourcify; and obtain an independent security review where real funds are involved. OpenZeppelin’s preparation guidance is at https://docs.openzeppelin.com/contracts/5.x/learn/preparing-for-mainnet. Verification is useful, but neither OpenZeppelin components nor an audit guarantees that your integration is bug-free.
What this part deliberately leaves for later
- Governor quorum, proposal threshold, voting delay, and voting period.
- Timelock configuration and proposal execution.
- Treasury custody, emergency procedures, and upgrade policy.
- Delegation interfaces, indexing, and frontend wallet support.
- Public-network RPC operations, monitoring, and deployment verification.
You now have a reproducible local token layer with checkpointed voting power and signature-based approvals. Whether it becomes a credible DAO depends on distribution, authority, Governor configuration, Timelock security, and operational controls—not merely on a successful compilation.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




