Prerequisites
Before you begin, ensure you have the following installed:
Install Node.js v24+
Download and install from nodejs.orgnode --version # Should be v24 or higher
Install Foundry v1.3.2+
Follow the official installation guidecurl -L https://foundry.paradigm.xyz | bash
foundryup
forge --version # Should be v1.3.2 or higher
Install Bun v1.2+
Install from bun.shcurl -fsSL https://bun.sh/install | bash
bun --version # Should be v1.2 or higher
(Optional) Install lcov for coverage
Required only if you plan to run test coverage reports.
Installation
Clone the repository
git clone https://github.com/ensdomains/contracts-v2.git
cd contracts-v2
Install root dependencies
Install Forge dependencies
Compile ens-contracts library
This is required before running tests.cd lib/ens-contracts
bun run compile
cd ../..
Build
ENS v2 uses both Foundry and Hardhat for compilation:
Build Configuration
Foundry (foundry.toml)
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
gas_reports = ["*"]
evm_version = "cancun"
optimizer = true
optimizer_runs = 200
[fuzz]
runs = 4096
Hardhat (hardhat.config.ts)
solidity: {
compilers: [
{
version: "0.8.25",
settings: {
optimizer: {
enabled: true,
runs: 1000,
},
evmVersion: "cancun",
},
},
],
}
Do not use --via-ir when compiling contracts. If you encounter “stack too deep” errors, fix them through code refactoring instead.
Project Structure
contracts/
├── src/ # Smart contract source files
│ ├── registry/ # Registry contracts
│ ├── erc1155/ # ERC1155 implementation
│ ├── migration/ # Migration controllers
│ ├── universalResolver/ # Resolution contracts
│ └── access/ # Access control
├── test/ # Test files
│ ├── integration/ # Hardhat integration tests
│ ├── e2e/ # End-to-end tests
│ └── *.t.sol # Forge unit tests
├── deploy/ # Deployment scripts
├── script/ # Utility scripts
├── lib/ # External dependencies
│ └── ens-contracts/ # ENS v1 contracts
├── foundry.toml # Foundry configuration
├── hardhat.config.ts # Hardhat configuration
└── package.json # Node.js dependencies
Foundry provides additional tools for development:
Lint Solidity Code
Gas Snapshots
Generate gas usage snapshots for all tests:
Cast is a command-line tool for interacting with Ethereum:
# Get block number
cast block-number
# Call a contract
cast call <CONTRACT_ADDRESS> "symbol()" --rpc-url http://localhost:8545
# Send a transaction
cast send <CONTRACT_ADDRESS> "mint(address,uint256)" <ADDRESS> 100 --rpc-url http://localhost:8545
See the Cast documentation for more commands.
Anvil (Local Node)
Anvil is a local Ethereum node for testing:
# Start Anvil on default port (8545)
anvil
# Start with custom chain ID
anvil --chain-id 31337
# Fork mainnet
anvil --fork-url https://eth-mainnet.alchemyapi.io/v2/YOUR_KEY
Chisel (Solidity REPL)
Chisel is an interactive Solidity shell:
Common Issues
Stack Too Deep Errors
If you encounter “stack too deep” errors during compilation, refactor your code instead of using --via-ir. Common solutions:
- Extract logic into separate internal functions
- Use structs to group related parameters
- Reduce the number of local variables
Compilation Errors in ens-contracts
If you see errors related to lib/ens-contracts, ensure you’ve compiled it:
cd lib/ens-contracts
bun run compile
Missing Dependencies
If Forge can’t find dependencies, reinstall them:
Next Steps
Testing
Learn how to run and write tests
Local Devnet
Set up a local development network
Deployment
Deploy contracts to testnets and mainnet
Contract Architecture
Understand the ENS v2 architecture