一键导入
foundry-testing
ALWAYS load before writing or modifying Foundry test files (.t.sol). Covers fuzz testing, gas benchmarks, naming conventions, and test patterns.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
ALWAYS load before writing or modifying Foundry test files (.t.sol). Covers fuzz testing, gas benchmarks, naming conventions, and test patterns.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Comprehensive smart contract development advisor based on Trail of Bits' best practices. Analyzes codebase to generate documentation/specifications, review architecture, check upgradeability patterns, assess implementation quality, identify pitfalls, review dependencies, and evaluate testing. Provides actionable recommendations.
Smart contract security review methodology. Use when auditing Solidity code, analyzing vulnerabilities, or verifying security findings.
Deep design principles for Towns Protocol smart contracts. Use when creating new facets, major refactoring, reviewing architecture decisions, or designing new abstractions.
| name | foundry-testing |
| description | ALWAYS load before writing or modifying Foundry test files (.t.sol). Covers fuzz testing, gas benchmarks, naming conventions, and test patterns. |
bound() over vm.assume - Prefer bound(value, min, max) to constrain inputs; vm.assume discards runs and wastes iterations// Good: bound with max range
amount = bound(amount, 1, type(uint96).max);
// Avoid: vm.assume wastes fuzz runs
vm.assume(amount > 0 && amount < type(uint96).max);
_gas suffix - Enables filtering with forge test --mt gastest_foo_gas() calls test_foo(fixed, values) for deterministic gas measurementfunction test_stake_gas() public returns (uint256 depositId) {
depositId = test_stake(address(this), 1 ether, OPERATOR, 0, address(this));
}
function test_stake(
address depositor,
uint96 amount,
address operator,
uint256 commissionRate,
address beneficiary
) public givenOperator(operator, commissionRate) returns (uint256 depositId) {
// Implementation...
}
givenOperator(operator, rate), givenSpaceHasPointedToOperator(space, operator)contract MyContractHarness is MyContractBase {
function internalFunction(uint256 x) external pure returns (uint256) {
return _internalFunction(x);
}
}
vm.expectEmitvm.expectRevert// Event verification
vm.expectEmit(address(contract));
emit SomeEvent(expectedArg1, expectedArg2);
contract.someFunction();
// Revert verification
vm.expectRevert(SomeError.selector);
contract.shouldRevert();
// Storage slot verification (EIP-7201)
function test_storageSlot() public pure {
bytes32 slot = keccak256(
abi.encode(uint256(keccak256("namespace.storage")) - 1)
) & ~bytes32(uint256(0xff));
assertEq(slot, MyStorage.STORAGE_SLOT);
}
| Pattern | Usage |
|---|---|
test_functionName(params) | Fuzz test (default when has parameters) |
test_functionName_gas() | Gas benchmark with fixed inputs |
test_functionName_revertIf_Condition | Revert condition tests |
test_functionName_EdgeCase | Specific edge case tests |
To compare gas usage before/after code changes:
# 1. Stash source changes (keep test changes)
git stash push -m "optimization" -- src/path/to/Changed.sol
# 2. Run baseline snapshot (--mt gas filters to _gas suffix tests)
forge snapshot --mc TestContract --mt gas
# 3. Pop stash to restore changes
git stash pop
# 4. Run diff against baseline
forge snapshot --mc TestContract --mt gas --diff
This workflow:
_gas test functions while measuring the old implementation