Zenpower Contracts - Deployment Guide
This guide walks you through deploying the Zenpower smart contracts to Sepolia testnet and Ethereum mainnet.
Table of Contents
- Prerequisites
- Environment Setup
- Pre-Deployment Checklist
- Sepolia Testnet Deployment
- Mainnet Deployment
- Post-Deployment Steps
- Troubleshooting
Prerequisites
Required Tools
- Foundry - Install from getfoundry.sh
- Git - For version control
- Make - For running deployment commands
Required Accounts
- Deployer Wallet - Hot wallet with ETH for deployment gas
- Admin Multisig - For DEFAULT_ADMIN_ROLE (production)
- Pauser Multisig - For PAUSER_ROLE (production)
- Signer Wallet - Backend hot wallet for TheForge attestations
- Etherscan API Key - For contract verification
Required Funds
- Sepolia Testnet: ~0.1 Sepolia ETH (get from faucet)
- Mainnet: ~0.5 ETH for deployment gas (estimate, depends on gas prices)
Environment Setup
1. Clone and Setup
cd /opt/zenpower/contracts
cp .env.example .env
2. Configure .env File
Edit .env with your values:
# Deployer private key (NEVER commit this!)
PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE
# For testnet, you can use the same address for all roles
# For mainnet, use proper multisigs
ADMIN_ADDRESS=0xYOUR_ADMIN_ADDRESS
PAUSER_ADDRESS=0xYOUR_PAUSER_ADDRESS
SIGNER_ADDRESS=0xYOUR_SIGNER_ADDRESS
# RPC URLs (get from Alchemy, Infura, etc.)
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_API_KEY
MAINNET_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY
# Etherscan API key
ETHERSCAN_API_KEY=YOUR_ETHERSCAN_API_KEY
3. Verify Configuration
make check-env
This should show green checkmarks for all required variables.
Pre-Deployment Checklist
Code Quality
- All contracts compiled successfully (
make build) - All tests passing (
make test) - Code formatted (
make fmt) - Gas reports reviewed (
make test-gas) - Contract sizes under limit (
make sizes)
Security (Mainnet Only)
- Security audit completed by reputable firm
- Audit findings addressed
- Community review period completed
- Emergency procedures documented
- Multisigs tested and operational
- Backup signers identified
Configuration
- Environment variables set correctly
- Deployer wallet has sufficient ETH
- Admin/Pauser addresses are multisigs (mainnet)
- Signer wallet secured properly
- RPC endpoints tested and working
Sepolia Testnet Deployment
Step 1: Verify Environment
# Check environment configuration
make check-env
# Verify your deployer address has Sepolia ETH
cast balance $(cast wallet address $PRIVATE_KEY) --rpc-url $SEPOLIA_RPC_URL
Step 2: Dry Run
# Simulate deployment without broadcasting
make deploy-sepolia-dry
Review the output carefully:
- Check all addresses
- Verify constructor arguments
- Confirm gas estimates are reasonable
Step 3: Deploy to Sepolia
# Deploy with automatic verification
make deploy-sepolia
This will:
- Deploy ZenpowerTreasury
- Deploy ZENCOIN
- Deploy ZenpowerGovernor
- Deploy TheForge
- Grant MINTER_ROLE to TheForge
- Update Treasury roles
- Verify all contracts on Etherscan
Step 4: Save Deployed Addresses
Copy the addresses from the output and add them to your .env:
SEPOLIA_TREASURY_ADDRESS=0x...
SEPOLIA_ZENCOIN_ADDRESS=0x...
SEPOLIA_GOVERNOR_ADDRESS=0x...
SEPOLIA_FORGE_ADDRESS=0x...
Step 5: Verify Deployment
# Check all contracts are verified on Etherscan
# Visit the Etherscan links from the deployment output
# Test basic functionality
cast call $SEPOLIA_ZENCOIN_ADDRESS "name()(string)" --rpc-url $SEPOLIA_RPC_URL
cast call $SEPOLIA_ZENCOIN_ADDRESS "symbol()(string)" --rpc-url $SEPOLIA_RPC_URL
cast call $SEPOLIA_ZENCOIN_ADDRESS "totalSupply()(uint256)" --rpc-url $SEPOLIA_RPC_URL
Mainnet Deployment
WARNING: Deploying to mainnet uses real ETH and creates production contracts. Triple-check everything!
Step 1: Final Pre-Deployment Checks
# Run comprehensive checks
make pre-deploy-check
# This runs:
# - make build
# - make test
# - make check-env
All must pass before proceeding.
Step 2: Update Configuration for Production
In your .env, ensure:
# Use production multisigs, NOT hot wallets!
ADMIN_ADDRESS=0xYOUR_PRODUCTION_MULTISIG_ADDRESS
PAUSER_ADDRESS=0xYOUR_ETHICS_BOARD_MULTISIG_ADDRESS
SIGNER_ADDRESS=0xYOUR_BACKEND_SIGNER_ADDRESS
# Use reliable mainnet RPC
MAINNET_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY
Step 3: Dry Run on Mainnet
# Simulate mainnet deployment
make deploy-mainnet-dry
Review output extremely carefully:
- Verify all addresses are correct
- Check gas estimates (multiply by current gas price)
- Ensure you have enough ETH in deployer wallet
Step 4: Deploy to Mainnet
# Deploy to mainnet (requires confirmation)
make deploy-mainnet
# You will be prompted to type: yes-deploy-mainnet
This will:
- Deploy all contracts
- Wire them together
- Verify on Etherscan
- Print deployment summary
DO NOT INTERRUPT THIS PROCESS
Step 5: Save Mainnet Addresses
Copy addresses to .env:
MAINNET_TREASURY_ADDRESS=0x...
MAINNET_ZENCOIN_ADDRESS=0x...
MAINNET_GOVERNOR_ADDRESS=0x...
MAINNET_FORGE_ADDRESS=0x...
IMPORTANT: Backup these addresses securely!
Post-Deployment Steps
1. Verify All Contracts
# Should happen automatically during deployment
# If not, run manually:
make verify-mainnet # or verify-sepolia
2. Test Contract Functionality
# Check token details
cast call $MAINNET_ZENCOIN_ADDRESS "name()(string)" --rpc-url $MAINNET_RPC_URL
cast call $MAINNET_ZENCOIN_ADDRESS "symbol()(string)" --rpc-url $MAINNET_RPC_URL
cast call $MAINNET_ZENCOIN_ADDRESS "MAX_SUPPLY()(uint256)" --rpc-url $MAINNET_RPC_URL
# Check roles
cast call $MAINNET_ZENCOIN_ADDRESS "hasRole(bytes32,address)(bool)" \
$(cast keccak "MINTER_ROLE") \
$MAINNET_FORGE_ADDRESS \
--rpc-url $MAINNET_RPC_URL
# Check governor configuration
cast call $MAINNET_GOVERNOR_ADDRESS "votingDelay()(uint256)" --rpc-url $MAINNET_RPC_URL
cast call $MAINNET_GOVERNOR_ADDRESS "votingPeriod()(uint256)" --rpc-url $MAINNET_RPC_URL
3. Announce Deployment
Create announcement with:
- Contract addresses
- Etherscan links
- Deployment timestamp
- Brief description of each contract
- Links to documentation
4. Update Frontend/Backend
Update your application configuration with new contract addresses:
// Example: apps/api/config/contracts.ts
export const CONTRACTS = {
ZENCOIN: "0x...",
FORGE: "0x...",
GOVERNOR: "0x...",
TREASURY: "0x...",
};
5. Monitor Contracts
Set up monitoring for:
- Total supply changes
- Forge operations
- Governance proposals
- Role changes
- Emergency pauses
Troubleshooting
Issue: "PRIVATE_KEY not set in .env"
Solution:
cp .env.example .env
# Edit .env and add your private key
Issue: "Insufficient funds for deployment"
Solution:
# Check your balance
cast balance $(cast wallet address $PRIVATE_KEY) --rpc-url $RPC_URL
# For Sepolia: Get testnet ETH from faucet
# For Mainnet: Add more ETH to deployer wallet
Issue: "Transaction underpriced"
Solution:
# Check current gas prices
cast gas-price --rpc-url $MAINNET_RPC_URL
# Add to .env:
export GAS_PRICE_GWEI=50 # Adjust based on network conditions
Issue: "Contract verification failed"
Solution:
# Verify manually
forge verify-contract <ADDRESS> <CONTRACT_NAME> \
--constructor-args $(cast abi-encode "constructor(...)" ...) \
--chain <sepolia|mainnet> \
--etherscan-api-key $ETHERSCAN_API_KEY \
--watch
Issue: "Nonce too low"
Solution:
# Reset nonce (be careful!)
# This usually happens if a transaction was stuck
# Cancel the stuck transaction in MetaMask or similar
Issue: Deployment script fails mid-way
Solution:
- DO NOT re-run the full script - it will fail on already deployed contracts
- Note which contracts were successfully deployed
- Comment out successful deployments in the script
- Re-run to complete remaining deployments
- Or: Deploy remaining contracts manually using
forge create
Getting Help
If you encounter issues:
- Check Foundry documentation: https://book.getfoundry.sh
- Review deployment logs carefully
- Ask in Zenpower Discord: discord.gg/zenpower
- Create issue: https://github.com/zenpower-community/zenpower/issues
Security Reminders
- NEVER commit .env file to git
- NEVER share private keys with anyone
- Use hardware wallets for production multisigs
- Test thoroughly on testnet first
- Have an emergency plan ready
- Monitor contracts continuously after deployment
Good luck with your deployment!
"What if being kind was the optimal strategy?"