Contracts: add TimeArenaFork.t.sol (TimeArenaForkTest) for optional RPC fork smoke
Summary
Add contracts/test/TimeArenaFork.t.sol with contract TimeArenaForkTest so optional MegaETH/public-RPC fork smoke matches the runbook in docs/testing/contract-fork-smoke.md.
Context: #274 (closed) updated docs to reference TimeArenaForkTest, but the test file was never added when TimeCurveFork.t.sol was removed (#241 (closed)–#245 (closed)). The contract-fork-smoke workflow still runs --match-contract TimeCurveForkTest and fails if dispatched today.
Current state
| Artifact | Status |
|---|---|
docs/testing/contract-fork-smoke.md |
Documents TimeArenaForkTest |
docs/testing/ci.md |
Documents TimeArenaForkTest |
.github/workflows/contract-fork-smoke.yml |
Still --match-contract TimeCurveForkTest |
contracts/README.md |
Still cites TimeCurveFork.t.sol |
contracts/.env.example |
Still cites TimeCurveForkTest |
contracts/test/TimeArenaFork.t.sol |
Missing |
| Historical pattern | 451f14a — TimeCurveFork.t.sol no-oped when FORK_URL unset |
Existing fork test DoubAirdropMegaethFork.t.sol is a gas probe (requires --ffi, hardcoded mainnet addresses) — not a suitable substitute for CI connectivity smoke.
Recommended implementation
1. contracts/test/TimeArenaFork.t.sol
Mirror retired TimeCurveFork.t.sol pattern:
contract TimeArenaForkTest is Test {
function test_fork_smoke_chainIdAndBlock() public {
string memory url = vm.envOr("FORK_URL", string(""));
if (bytes(url).length == 0) return;
vm.createSelectFork(url);
assertGt(block.chainid, 0);
assertGt(block.number, 0);
}
}Optional second test (when registry address non-zero): read TimeArena head state at address from env TIME_ARENA_FORK_ADDRESS or published registry JSON — e.g. paused(), lastBuyDeadline(), proxy bytecode extcodesize > 0. Skip (return early) when address unset or zero placeholder (mainnet registry currently has TimeArena: 0x000…000 until #259 (closed) deploy).
2. Wire CI + docs
.github/workflows/contract-fork-smoke.yml:--match-contract TimeArenaForkTest; update header comment.contracts/README.md,contracts/.env.example:TimeArenaForknaming.
3. Policy (unchanged)
- Default
unit-testsworkflow:FORK_URLunset → fork test no-ops → deterministic PR gate. contract-fork-smoke:workflow_dispatchonly; requiresFORK_URLinput or secret.
Acceptance criteria
-
FOUNDRY_PROFILE=ci forge testpasses withFORK_URLunset (fork test no-ops). -
export FORK_URL=<megaeth-testnet-rpc> && FOUNDRY_PROFILE=ci forge test --match-contract TimeArenaForkTest -vvpasses locally. -
contract-fork-smokeworkflow succeeds when dispatched with valid RPC. - No references to
TimeCurveForkTest/TimeCurveFork.t.solin workflow, contracts README, or.env.example. -
docs/testing/contract-fork-smoke.mdlink target exists.
Test plan
| Step | Expected |
|---|---|
CI unit job (no FORK_URL) |
Green; TimeArenaForkTest skipped/no-op |
| Local with testnet RPC | Fork selects chain; block assertions pass |
Dispatch contract-fork-smoke |
Matches new contract name |
| After mainnet Arena deploy | Optional read test against live TimeArena proxy |
Related
- Doc follow-up from #274 (closed)
- Maintainer policy: issue #6 (closed) (opt-in fork only)
- Arena deploy registry: #259 (closed)