--- name: fork-test description: Generate Foundry fork tests for contracts that need real on-chain integration coverage. Use when the user asks for fork tests, mainnet or chain fork coverage, or integration tests against live protocol state. --- # Fork Test Generate Foundry fork tests for contracts whose behavior depends on real on-chain state, live liquidity, routers, gauges, or oracle reads. ## 1. Directory layout ```text contracts/tests/fork/// ├── shared/ │ └── Shared.t.sol └── concrete/ ├── Deposit.t.sol ├── Withdraw.t.sol └── Rebalance.t.sol ``` Rules: - fork tests are concrete only; do not add a `fuzz/` directory - create files only for functions with meaningful on-chain integration behavior - keep simple setters, access control checks, and pure validation in unit tests ## 2. Inheritance chain ```text forge-std/Test └─ Base └─ BaseFork └─ Fork__Shared_Test └─ Fork_Concrete___Test ``` `Base` owns shared actors, constants, IERC20 external token refs, and fork IDs. All typed contract/proxy/mock state variables are declared in each `Shared.t.sol` using interface types. `BaseFork` owns chain fork helpers. ### Interface-only testing Same rules as unit tests — use interfaces, not concrete contracts: - Import interfaces: `IVault`, `IOToken`, `IProxy`, strategy interfaces from `contracts/interfaces/strategies/` - Deploy fresh contracts with `vm.deployCode` instead of `new` (except mocks), and always reference artifact paths through `tests/utils/Artifacts.sol` (e.g. `vm.deployCode(Vaults.OETH, abi.encode(address(weth)))`); add the entry to the relevant sub-library if it does not exist yet - Cast forked addresses to interfaces: `oethVault = IVault(Mainnet.OETH_VAULT)` - Reference events from interfaces: `emit IVault.EventName(...)` ### Product-specific vault types | Product | Token | Vault | Chain | Artifacts reference | |---------|-------|-------|-------|---------------------| | OUSD | `OUSD` | `OUSDVault` | Mainnet | `Vaults.OUSD` | | OETH | `OETH` | `OETHVault` | Mainnet | `Vaults.OETH` | | OSonic | `OSonic` | `OSVault` | Sonic | `Vaults.OS` | | OETHBase | `OETHBase` | `OETHBaseVault` | Base | `Vaults.OETH_BASE` | Add the entry to `tests/utils/Artifacts.sol` if it does not exist yet. Never use `OETHVault` for Sonic tests. ## 3. Shared setup contract `shared/Shared.t.sol` should keep setup in this order: ```solidity function setUp() public virtual override { super.setUp(); _createAndSelectFork(); _deployFreshContracts(); _configureContracts(); label(); } ``` Decision rule: - deploy fresh contracts that the strategy or vault under test owns or manages - use forked addresses for external infrastructure such as routers, tokens, factories, and oracles Pull canonical addresses from `tests/utils/Addresses.sol`. ## 4. Concrete test naming File and contract naming: ```text concrete/Deposit.t.sol Fork_Concrete__Deposit_Test ``` Function naming patterns: - `test_()` - `test__()` - `test__RevertWhen_()` - `test__emits()` Casing rules: - function, behavior, and condition stay `camelCase` - `RevertWhen` is the only PascalCase token in the test name ## 5. What belongs in fork tests Fork-test these categories: - AMO pool interactions - real router swaps - oracle reads - gauge reward flows - cross-chain and bridge flows - vault rebases with real balances - zapper flows - multi-step end-to-end operations Do not fork-test: - simple setters - straightforward view functions - access control checks - constructor validation - pure math and helper logic - input-validation-only reverts Litmus test: If a mock can faithfully reproduce the behavior, keep it in unit tests. ## 6. Chain mapping Use the repository's fork helpers and address libraries consistently: - Mainnet -> `_createAndSelectForkMainnet()` - Base -> `_createAndSelectForkBase()` - Sonic -> `_createAndSelectForkSonic()` - Arbitrum if relevant -> `_createAndSelectForkArbitrum()` ## Output expectations When implementing fork tests: - keep them narrowly focused on real integration value - prefer a few strong end-to-end tests over broad but redundant coverage - label both fresh and forked contracts for readable traces - use interface-only imports; no concrete contract imports except mocks - deploy fresh contracts with `vm.deployCode`, not `new` (mocks are fine with `new`), and reference all artifact paths through `tests/utils/Artifacts.sol` — no inline `"contracts/...sol:Name"` strings - mirror existing fork test structure in the nearest comparable test suite before introducing a new pattern