evm-foundry
Skill8 starsChanged 2 months agoApache-2.0View on GitHub
Foundry development for EVM chains including Celo. Use when working with forge, cast, anvil, writing Solidity contracts, testing, deploying, or verifying contracts with Foundry.
- Pipes a download into a shell
- Reads credentials
In this repository15 other files it gives its agents.
- 8004Skill
- bridgingSkill
- celo-composerSkill
- celo-defiSkill
- celo-rpcSkill
- celo-stablecoinsSkill
- contract-verificationSkill
- evm-hardhatSkill
- evm-wallet-integrationSkill
- fee-abstractionSkill
- minipay-integrationSkill
- thirdwebSkill
- viemSkill
- wagmiSkill
- x402Skill
The file
Files
Foundry Development for EVM Chains
This skill covers Foundry setup and development for EVM-compatible chains with emphasis on Celo.
When to Use
- Setting up a new Foundry project
- Writing and compiling Solidity smart contracts with forge
- Testing contracts with forge test
- Deploying contracts to Celo or other EVM chains
- Verifying contracts on block explorers
- Interacting with contracts using cast
Foundry Tools
| Tool | Purpose |
| forge | Build, test, debug, deploy, and verify smart contracts |
| cast | Interact with contracts and retrieve chain data from CLI |
| anvil | Run a local Ethereum development node with forking support |
| chisel | Fast Solidity REPL for interactive development |
Installation
# Install Foundryup (the Foundry installer)
curl -L https://foundry.paradigm.xyz | bash
# Install Foundry tools
foundryupFor Windows, use Git BASH or WSL (Foundryup doesn't support PowerShell or Command Prompt).
Quick Start
Initialize Project
forge init my-project
cd my-projectProject Structure
my-project/
├── foundry.toml # Configuration
├── src/ # Contract source files
│ └── Counter.sol
├── test/ # Test files
│ └── Counter.t.sol
├── script/ # Deployment scripts
│ └── Counter.s.sol
└── lib/ # DependenciesCelo Network Information
| Network | Chain ID | RPC Endpoint |
| Celo Mainnet | 42220 | https://forno.celo.org |
| Celo Sepolia | 11142220 | https://forno.celo-sepolia.celo-testnet.org |
Configuration
foundry.toml for Celo
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc = "0.8.28"
optimizer = true
optimizer_runs = 200
[rpc_endpoints]
celo = "https://forno.celo.org"
celo_sepolia = "https://forno.celo-sepolia.celo-testnet.org"
localhost = "http://127.0.0.1:8545"
[etherscan]
celo = { key = "${CELOSCAN_API_KEY}", chain = 42220, url = "https://api.celoscan.io/api" }
celo_sepolia = { key = "${CELOSCAN_API_KEY}", chain = 11142220, url = "https://api.etherscan.io/v2/api" }Environment Variables (.env)
PRIVATE_KEY=your_private_key_here
CELOSCAN_API_KEY=your_celoscan_api_key_hereLoad environment variables:
source .envWriting Contracts
Basic Contract
// src/MyContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
contract MyContract {
string public name;
address public owner;
event NameChanged(string oldName, string newName);
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
constructor(string memory _name) {
name = _name;
owner = msg.sender;
}
function setName(string memory _newName) external onlyOwner {
string memory oldName = name;
name = _newName;
emit NameChanged(oldName, _newName);
}
}Using OpenZeppelin
forge install OpenZeppelin/openzeppelin-contractsAdd to remappings.txt:
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/// src/MyToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20, Ownable {
constructor() ERC20("MyToken", "MTK") Ownable(msg.sender) {
_mint(msg.sender, 1000000 * 10 ** decimals());
}
function mint(address to, uint256 amount) external onlyOwner {
_mint(to, amount);
}
}Compilation
# Compile all contracts
forge build
# Clean and rebuild
forge clean && forge build
# Check contract sizes
forge build --sizesTesting
Test File Structure
// test/MyContract.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {Test, console} from "forge-std/Test.sol";
import {MyContract} from "../src/MyContract.sol";
contract MyContractTest is Test {
MyContract public myContract;
address public owner;
address public user;
function setUp() public {
owner = address(this);
user = makeAddr("user");
myContract = new MyContract("Initial Name");
}
function test_InitialName() public view {
assertEq(myContract.name(), "Initial Name");
}
function test_Owner() public view {
assertEq(myContract.owner(), owner);
}
function test_SetName() public {
myContract.setName("New Name");
assertEq(myContract.name(), "New Name");
}
function test_SetNameEmitsEvent() public {
vm.expectEmit(true, true, true, true);
emit MyContract.NameChanged("Initial Name", "New Name");
myContract.setName("New Name");
}
function test_RevertWhen_NonOwnerSetsName() public {
vm.prank(user);
vm.expectRevert("Not owner");
myContract.setName("Hacked");
}
function testFuzz_SetName(string memory newName) public {
myContract.setName(newName);
assertEq(myContract.name(), newName);
}
}Running Tests
# Run all tests
forge test
# Run with verbosity (show logs)
forge test -vvv
# Run specific test
forge test --match-test test_SetName
# Run specific contract
forge test --match-contract MyContractTest
# Run with gas reporting
forge test --gas-report
# Run with coverage
forge coverage
# Fork testing against Celo mainnet
forge test --fork-url https://forno.celo.orgDeployment
Deployment Script
// script/Deploy.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {Script, console} from "forge-std/Script.sol";
import {MyContract} from "../src/MyContract.sol";
contract DeployScript is Script {
function setUp() public {}
function run() public {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
MyContract myContract = new MyContract("My Contract Name");
console.log("Contract deployed to:", address(myContract));
vm.stopBroadcast();
}
}Deploy Commands
# Deploy to local Anvil
forge script script/Deploy.s.sol --rpc-url http://127.0.0.1:8545 --broadcast
# Deploy to Celo Sepolia
forge script script/Deploy.s.sol --rpc-url https://forno.celo-sepolia.celo-testnet.org --broadcast --private-key $PRIVATE_KEY
# Deploy to Celo Mainnet
forge script script/Deploy.s.sol --rpc-url https://forno.celo.org --broadcast --private-key $PRIVATE_KEY
# Deploy with verification
forge script script/Deploy.s.sol --rpc-url https://forno.celo-sepolia.celo-testnet.org --broadcast --verify --private-key $PRIVATE_KEYQuick Deploy with forge create
# Deploy to Celo Sepolia
forge create src/MyContract.sol:MyContract \
--rpc-url https://forno.celo-sepolia.celo-testnet.org \
--private-key $PRIVATE_KEY \
--constructor-args "My Contract Name"
# Deploy with verification
forge create src/MyContract.sol:MyContract \
--rpc-url https://forno.celo-sepolia.celo-testnet.org \
--private-key $PRIVATE_KEY \
--constructor-args "My Contract Name" \
--verify \
--etherscan-api-key $CELOSCAN_API_KEYVerification
Verify Existing Contract
# Verify on Celo Sepolia
forge verify-contract \
--chain-id 11142220 \
<CONTRACT_ADDRESS> \
src/MyContract.sol:MyContract \
--etherscan-api-key $CELOSCAN_API_KEY \
--watch
# Verify on Celo Mainnet
forge verify-contract \
--chain-id 42220 \
<CONTRACT_ADDRESS> \
src/MyContract.sol:MyContract \
--etherscan-api-key $CELOSCAN_API_KEY \
--watch
# With constructor arguments
forge verify-contract \
--chain-id 11142220 \
<CONTRACT_ADDRESS> \
src/MyContract.sol:MyContract \
--etherscan-api-key $CELOSCAN_API_KEY \
--constructor-args $(cast abi-encode "constructor(string)" "My Contract Name") \
--watchCast Commands
Reading Data
# Get balance
cast balance <ADDRESS> --rpc-url https://forno.celo.org
# Call view function
cast call <CONTRACT_ADDRESS> "name()(string)" --rpc-url https://forno.celo.org
# Get storage slot
cast storage <CONTRACT_ADDRESS> 0 --rpc-url https://forno.celo.org
# Get block number
cast block-number --rpc-url https://forno.celo.orgWriting Data
# Send transaction
cast send <CONTRACT_ADDRESS> "setName(string)" "New Name" \
--rpc-url https://forno.celo.org \
--private-key $PRIVATE_KEY
# Transfer CELO
cast send <TO_ADDRESS> --value 1ether \
--rpc-url https://forno.celo.org \
--private-key $PRIVATE_KEYUtility Commands
# Encode function call
cast calldata "setName(string)" "New Name"
# Decode function call
cast 4byte-decode <CALLDATA>
# Convert units
cast to-wei 1 ether
cast from-wei 1000000000000000000
# Get ABI-encoded constructor args
cast abi-encode "constructor(string)" "My Contract Name"Anvil (Local Node)
# Start local node
anvil
# Start with fork of Celo mainnet
anvil --fork-url https://forno.celo.org
# Start with specific block
anvil --fork-url https://forno.celo.org --fork-block-number 12345678Block Explorers
- Celo Mainnet: https://celoscan.io
- Celo Sepolia: https://sepolia.celoscan.io
Additional Resources
- foundry-config.md - Detailed configuration options
- testing-patterns.md - Advanced testing patterns
- security-checklist.md - Security best practices
Source of truth: Celopedia
These skills are focused, task-level references. For anything broader — verified contract addresses, ecosystem and protocol data, listing requirements, grants, governance, migration guides, or cross-cutting Celo questions — Celopedia is the canonical source and is kept current. Where this skill and Celopedia disagree, Celopedia wins.
npx skills add celo-org/celopedia-skillsDoes it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

