with one click
cli-forge
// Write Foundry-based tests and scripts. Trigger phrases - foundry testing, write test, fuzz test, fork test, invariant test, deploy script, gas benchmark, coverage, or when working in tests/ or scripts/ directories.
// Write Foundry-based tests and scripts. Trigger phrases - foundry testing, write test, fuzz test, fork test, invariant test, deploy script, gas benchmark, coverage, or when working in tests/ or scripts/ directories.
| name | cli-forge |
| description | Write Foundry-based tests and scripts. Trigger phrases - foundry testing, write test, fuzz test, fork test, invariant test, deploy script, gas benchmark, coverage, or when working in tests/ or scripts/ directories. |
Rules and patterns for Foundry tests. Find examples in the actual codebase.
| Reference | Content | When to Read |
|---|---|---|
./references/test-infrastructure.md | Constants, defaults, mocks | When setting up tests |
./references/cheat-codes.md | Common cheatcode patterns | When using vm cheatcodes |
./references/invariant-patterns.md | Handlers, stores, invariants | When writing invariant tests |
./references/formal-verification.md | Halmos, Certora, symbolic exec | When proving correctness |
./references/deployment-scripts.md | Script patterns, verification | When writing deploy scripts |
./references/deployment-checklist.md | Pre-mainnet deployment steps | Before deploying to production |
./references/gas-benchmarking.md | Snapshot, profiling, CI | When measuring gas performance |
./references/sablier-conventions.md | Sablier-specific patterns | When working in Sablier repos |
| Type | Directory | Naming | Purpose |
|---|---|---|---|
| Integration | tests/integration/concrete/ | *.t.sol | BTT-based concrete tests |
| Fuzz | tests/integration/fuzz/ | *.t.sol | Property-based testing |
| Fork | tests/fork/ | *.t.sol | Mainnet state testing |
| Invariant | tests/invariant/ | Invariant*.t.sol | Stateful protocol properties |
| Scripts | scripts/solidity/ | *.s.sol | Deployment/initialization |
| Pattern | Usage |
|---|---|
test_RevertWhen_{Condition} | Revert on input |
test_RevertGiven_{State} | Revert on state |
test_When_{Condition} | Success path |
vm.expectEmit() then call functionexpectRevert_DelegateCall, expectRevert_Null)assertEq(actual, expected, "description")tests/mocks/*Good, *Reverting, *InvalidSelector, *ReentranttestFuzz_{FunctionName}_{Scenario}
_bound() is more efficient than vm.assume()// 1. Bound independent params first
cliffDuration = boundUint40(cliffDuration, 0, MAX - 1);
// 2. Bound dependent params based on constraints
totalDuration = boundUint40(totalDuration, cliffDuration + 1, MAX);
vm.createSelectFork("ethereum")deal() to give tokens to test usersassumeNoBlacklisted() for USDC/USDTforceApprove() for non-standard tokens (USDT)| Token | Issue | Solution |
|---|---|---|
| USDC/USDT | Blacklist | assumeNoBlacklisted() |
| USDT | Non-standard | forceApprove() |
| Fee-on-transfer | Balance diff | Check actual received amount |
tests/invariant/
āāā handlers/ # State manipulation (call functions with bounded params)
āāā stores/ # State tracking (record totals, IDs)
āāā Invariant.t.sol
targetContract(address(handler))excludeSender(address(vault))BaseScript with broadcast modifierETH_FROM, MNEMONIC# Simulation
forge script scripts/Deploy.s.sol --sig "run(...)" ARGS --rpc-url $RPC
# Broadcast
forge script scripts/Deploy.s.sol --sig "run(...)" ARGS --rpc-url $RPC --broadcast --verify
# By type
forge test --match-path "tests/integration/concrete/**"
forge test --match-path "tests/fork/**"
forge test --match-contract Invariant_Test
# Specific test
forge test --match-test test_WhenCallerRecipient -vvvv
# Fuzz with more runs
forge test --match-test testFuzz_ --fuzz-runs 1000
# Coverage
forge coverage --report lcov
| Flag | Shows |
|---|---|
-v | Logs for failing tests |
-vv | Logs for all tests |
-vvv | Stack traces for failures |
-vvvv | Stack traces + setup traces |
-vvvvv | Full execution traces |
import { console2 } from "forge-std/console2.sol";
console2.log("value:", someValue);
console2.log("address:", someAddress);
console2.logBytes32(someBytes32);
# Trace specific failing test
forge test --match-test test_MyTest -vvvv
# Gas report for a test
forge test --match-test test_MyTest --gas-report
# Debug in interactive debugger
forge debug --debug tests/MyTest.t.sol --sig "test_MyTest()"
# Inspect storage layout
forge inspect MyContract storage-layout
vm.label(addr, "Recipient") for readable tracesconsole2.log before reverts--match-test--gas-report to spot unexpected costsvm.snapshot() / vm.revertTo() to isolate state changesDefaults/Constants - never hardcodetests/mocks/Modifiers.sol - centralize BTT path modifiersvm.label() for tracesvm.expectEmit() then callTest this skill with these prompts:
withdraw that expects Errors.Flow_Overdraw when amount exceeds
balance"deposit that bounds amount between 1 and type(uint128).max"deposit and withdraw functions"Write bulloak tree specifications (.tree files) for smart contract integration tests. Trigger phrases - write a tree, create test tree, BTT spec, bulloak tree, Branching Tree Technique, or when writing integration tests for contract functions.
Deploy Sablier EVM contracts (Utils, Flow, Lockup, Airdrops, Bob) with full workflow automation. This skill should be used when the user asks to "deploy", "deploy protocol", "deploy to chain", or mentions deployment-related tasks. Handles contract deployment, explorer verification, SDK updates, and initial setup through Init scripts.
This skill should be used when the user asks to "create a state machine", "add xState", "use xState with React", "implement actor-based state", "manage complex state with state machines", "use xState with Effect", "integrate Effect-ts with xState", mentions xState hooks (useMachine, useActor, useSelector), or discusses finite state machines in React applications.
This skill should be used when writing content for Sablier, including "write a blog post", "create a case study", "draft a tweet", "write X/Twitter posts", "write an announcement", "create educational content", or any marketing content task for Sablier's brand.
This skill should be used when the user asks about "Tailwind CSS", "tailwind-variants", "tv() function", "CSS-first configuration", "Tailwind breaking changes", mentions styling with Tailwind utilities, gradient syntax, or component variants with TypeScript.
This skill should be used when the user asks to "recolor the Sablier icon", "Sablier icon in orange", "Sablier logo in primary color", "generate Sablier hourglass variant", "change Sablier icon color", "export Sablier icon as PNG", or "generate Sablier favicon". Generates a gradient or flat Sablier icon SVG in any color using brand palette names, hex values, or CSS color names, with optional PNG/JPG/ICO raster export.