Comprehensive Foundry smart contract development skill with code style, naming conventions, contract structure, security guidelines, testing standards, and gas optimization. Use when working with .sol files, Foundry projects (foundry.toml), test files (.t.sol), or deployment scripts. Triggers on "smart contract", "Solidity", "Foundry", "forge", "deploy contract", "write test", "security audit".
Skill for professional Solidity smart contract development using Foundry framework. Provides code standards, security-first practices, and comprehensive testing patterns.
Activate when:
.sol (Solidity) filesfoundry.toml present)| Category | Key Rules |
|---|---|
| Version | pragma solidity ^0.8.23; with MIT license |
| Imports | Named imports , grouped by source |
{Contract}| Private vars | Underscore prefix: _variableName |
| Constants | SCREAMING_SNAKE_CASE: MAX_SUPPLY |
| Interfaces | Define ALL errors, events, structs in interface |
| Functions | Internal/private use _functionName prefix |
| NatSpec | @notice + @param + @return on all external functions |
| Coverage | Minimum 95% line coverage required |
Use decorative ASCII headers for contract organization:
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SECTION NAME */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Section order: LIBRARIES → CUSTOM ERRORS → EVENTS → STORAGE → CONSTANTS → MODIFIERS → CONSTRUCTOR → PUBLIC UPDATE FUNCTIONS → ADMIN FUNCTIONS → PUBLIC READ FUNCTIONS → INTERNAL FUNCTIONS → PRIVATE FUNCTIONS
# Initialize new Foundry project
forge init my-project
cd my-project
# Initialize in existing directory
forge init --force
# Initialize with specific template
forge init --template transmissions11/solmate my-project
# Install OpenZeppelin contracts
forge install OpenZeppelin/openzeppelin-contracts
# Install Solady (gas-optimized utilities)
forge install Vectorized/solady
# Install specific version
forge install OpenZeppelin/[email protected]
# Update dependencies
forge update
| Library | Install Command | Use For |
|---|---|---|
| OpenZeppelin | forge install OpenZeppelin/openzeppelin-contracts | ERC20/721/1155, Access Control, Proxies, Security |
| Solady | forge install Vectorized/solady | Gas-optimized ERC20/721, Utilities, Math |
| Solmate | forge install transmissions11/solmate | Minimal, gas-efficient implementations |
| PRBMath | forge install PaulRBerg/prb-math | Fixed-point math (UD60x18, SD59x18) |
| forge-std | (included by default) | Testing utilities, console.log, vm cheats |
OpenZeppelin
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
Solady
import {ERC721} from "solady/tokens/ERC721.sol";
import {ERC20} from "solady/tokens/ERC20.sol";
import {Ownable} from "solady/auth/Ownable.sol";
import {LibString} from "solady/utils/LibString.sol";
import {LibPRNG} from "solady/utils/LibPRNG.sol";
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc = "0.8.23"
optimizer = true
optimizer_runs = 200
# Remappings
remappings = [
"@openzeppelin/=lib/openzeppelin-contracts/",
"solady/=lib/solady/src/",
]
# Formatter
[fmt]
line_length = 120
tab_width = 4
bracket_spacing = true
# Testing
[fuzz]
runs = 256
[invariant]
runs = 256
depth = 15
Foundry supports two ways to configure import remappings:
Option 1: In foundry.toml (shown above)
Option 2: remappings.txt file (recommended for IDE compatibility)
# Auto-generate remappings.txt from installed dependencies
forge remappings > remappings.txt
remappings.txt format:
@openzeppelin/=lib/openzeppelin-contracts/
solady/=lib/solady/src/
forge-std/=lib/forge-std/src/
Best practice:
remappings.txt for IDE compatibilityforge remappings > remappings.txt after installing new dependenciesremappings.txt to version controlmy-project/
├── foundry.toml # Configuration
├── remappings.txt # Import remappings (for IDE)
├── src/ # Contract source files
│ ├── interfaces/ # Interface definitions
│ └── libraries/ # Shared libraries
├── test/ # Test files (.t.sol)
│ ├── unit/
│ ├── integration/
│ └── security/
├── script/ # Deployment scripts (.s.sol)
└── lib/ # Dependencies (git submodules)
Follow security-first patterns:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {IMyContract} from "./interfaces/IMyContract.sol";
/// @title MyContract
/// @notice Brief description
/// @author Development Team
contract MyContract is IMyContract, Ownable, ReentrancyGuard {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
mapping(address => uint256) private _balances;
uint256 private _nextTokenId;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTRUCTOR */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
constructor() Ownable(msg.sender) {
_nextTokenId = 1;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
function deposit() external payable nonReentrant {
// CEI Pattern
if (msg.value == 0) revert InvalidAmount();
_balances[msg.sender] += msg.value;
emit Deposited(msg.sender, msg.value);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import {Test} from "forge-std/Test.sol";
import {MyContract} from "../src/MyContract.sol";
contract MyContractTest is Test {
MyContract public myContract;
address constant ALICE = address(0x1);
function setUp() public {
myContract = new MyContract();
}
function test_Deposit_Success() public {
vm.deal(ALICE, 1 ether);
vm.prank(ALICE);
myContract.deposit{value: 0.1 ether}();
// assertions
}
function test_Deposit_RevertWhen_ZeroAmount() public {
vm.prank(ALICE);
vm.expectRevert(IMyContract.InvalidAmount.selector);
myContract.deposit{value: 0}();
}
function testFuzz_Deposit(uint256 amount) public {
amount = bound(amount, 1, 100 ether);
vm.deal(ALICE, amount);
vm.prank(ALICE);
myContract.deposit{value: amount}();
}
}
forge test -vvv # Run all tests verbose
forge test --gas-report # Include gas costs
forge coverage # Coverage report (target ≥95%)
forge snapshot # Gas snapshot
# Static analysis
slither . --exclude-optimization --exclude-informational
# Linting
solhint 'src/**/*.sol' 'test/**/*.sol'
# Build with optimization
forge build --optimize --optimizer-runs 200
# Simulate deployment
forge script script/Deploy.s.sol --rpc-url $RPC_URL
# Deploy to testnet
forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast --verify
# Verify contract
forge verify-contract $ADDRESS src/MyContract.sol:MyContract --chain-id 1
Consult these for detailed standards:
| File | Use When |
|---|---|
| code-style.md | SPDX, pragma, imports, formatting |
| naming-conventions.md | Naming contracts, variables, functions, events |
| contract-structure.md | Organizing sections, interface architecture |
| documentation-standards.md | NatSpec comments for contracts, functions, events, errors |
| security-guidelines.md | Access control, CEI, reentrancy, hooks |
| testing-standards.md | Unit, integration, fuzz, gas tests |
| gas-optimization.md | Storage packing, loops, unchecked |
MUST define errors, events, and structs in interface:
// Interface - defines everything
interface IMyContract {
error InvalidAmount();
error Unauthorized();
event Deposited(address indexed user, uint256 amount);
struct UserInfo { uint256 balance; uint64 lastUpdate; }
function deposit() external payable;
}
// Contract - inherits and uses
contract MyContract is IMyContract {
// DO NOT re-define errors, events, or structs here
// Use inherited ones directly
function deposit() external payable {
if (msg.value == 0) revert InvalidAmount(); // ✓ Uses interface error
emit Deposited(msg.sender, msg.value); // ✓ Uses interface event
}
}
# Project Setup
forge init my-project # New project
forge init --force # Init in existing dir
forge install org/repo # Install dependency
forge update # Update dependencies
# Development
forge build # Compile
forge test # Test
forge fmt # Format
forge clean # Clean
# Testing
forge test -vvv # Verbose
forge test --match-test NAME # Specific test
forge test --fork-url $RPC # Fork testing
forge coverage # Coverage
# Deployment
forge script script/Deploy.s.sol --broadcast
forge verify-contract $ADDR src/Contract.sol:Contract
# Local node
anvil # Start local node
anvil --fork-url $RPC # Fork mainnet