Deploy: TimeArenaBuyRouter on Anvil + setTimeArenaBuyRouter + default ETH E2E wiring

Summary

Automate local Anvil deployment of TimeArenaBuyRouter, wire TimeArena.setTimeArenaBuyRouter, and export VITE_KUMBAYA_TIME_ARENA_BUY_ROUTER so scripts/e2e-anvil.sh runs the ETH pay Playwright case without manual env. Closes the deploy gap left after onchain #251 (closed) and frontend #264 (closed).

Parent epic: #238 (closed). Related: #84 (closed) (registry + Vite merge), #78 (closed) (buy-router verification).


Current codebase

Onchain (done in #251 (closed))

  • TimeArenaBuyRouter.solbuyViaKumbaya (ETH / stable / CL8Y → Kumbaya exactOutput → DOUB → TimeArena.buyFor). Paths end in DOUB (not CL8Y).
  • TimeArena.soltimeArenaBuyRouter, setTimeArenaBuyRouter(address) (owner), buyFor restricted to router.

Deploy / scripts (gap)

  • DeployDev.s.sol deploys Arena v2 (TimeArena, vaults, Doubloon, etc.) and startArena() but does not deploy a buy router or call setTimeArenaBuyRouter.
  • DeployKumbayaAnvilFixtures.s.sol is referenced throughout docs and shell (scripts/lib/anvil_deploy_dev.sh, scripts/start-local-anvil-stack.sh, docs/integrations/kumbaya.md) but is not present under contracts/script/ (only DeployDev.s.sol and DeployProduction.s.sol exist today).
  • Legacy TimeCurveBuyRouter Solidity was retired; scripts still grep log lines for TimeCurveBuyRouter (single-tx and registry key TimeCurveBuyRouter (scripts/lib/kumbaya_local_anvil_env.sh).
  • scripts/e2e-anvil.sh runs DeployDev only; sets VITE_KUMBAYA_TIME_ARENA_BUY_ROUTER only when KUMBAYA_BUY_ROUTER is non-empty after optional YIELDOMEGA_DEPLOY_KUMBAYA=1 — which currently does not run in the default E2E path.
  • scripts/verify-time-arena-buy-router-anvil.sh is a stub (prints instructions, exits 0).

Frontend (done in #264 (closed))

  • ETH/USDM UI calls resolveTimeArenaBuyRouterForKumbayaSingleTx and submitArenaKumbayaSingleTxBuy when onchain timeArenaBuyRouter is set.
  • E2E anvil-arena-wallet-writes.spec.ts skips ETH pay unless VITE_KUMBAYA_TIME_ARENA_BUY_ROUTER (or legacy alias) is set at build time.

Fixtures

  • AnvilKumbayaFixture.solAnvilWETH9, AnvilMockUSDM, AnvilKumbayaRouter (swap + quoter) for local constant-product pools.

Why this is needed

  1. ETH E2E is not CI-realistic today — DOUB buy passes on Anvil; ETH pay is skipped unless operators manually deploy a router and export Vite env.
  2. Docs/scripts lie about DeployKumbayaAnvilFixtures — references assume a script that must be restored or replaced with an Arena v2 variant.
  3. Product parity — Arena v2 pay modes (docs/frontend/arena-views.md) require a non-zero timeArenaBuyRouter on devnet for integrators and agents running bash scripts/e2e-anvil.sh.

Constraints and guardrails


Relevant files

Area Files
Contracts TimeArenaBuyRouter.sol, TimeArena.sol, AnvilKumbayaFixture.sol
Deploy script (new/restore) contracts/script/DeployKumbayaAnvilFixtures.s.sol (or DeployArenaKumbayaAnvilFixtures.s.sol)
Shell scripts/lib/anvil_deploy_dev.sh, scripts/e2e-anvil.sh, scripts/lib/kumbaya_local_anvil_env.sh, scripts/start-local-anvil-stack.sh, scripts/verify-time-arena-buy-router-anvil.sh
Registry contracts/deployments/local-anvil-registry.json, contracts/deployments/kumbaya-anvil-registry.example.json
ABI export contracts/script/export_abi_hashes.sh
Tests New contracts/test/TimeArenaBuyRouter*.t.sol (local + optional fork)
E2E frontend/e2e/anvil-arena-wallet-writes.spec.ts
Docs docs/integrations/kumbaya.md, docs/testing/e2e-anvil.md, docs/testing/local-swap-testing.md, skills/play-time-arena-doub/SKILL.md

  1. Add DeployKumbayaAnvilFixtures.s.sol (Arena v2)

    • Input: deployed TimeArena proxy address (from DeployDev).
    • Deploy: AnvilWETH9, AnvilMockUSDM, AnvilKumbayaRouter, TimeArenaBuyRouter (immutable args: arena, kumbaya router, doub, reserve/CL8Y token, WETH, USDM, surplus recipient, owner).
    • Seed pools with liquidity for DOUB exactOutput paths (ETH: DOUB←WETH; USDM: DOUB←WETH←USDM).
    • TimeArena.setTimeArenaBuyRouter(router) in same broadcast (deployer = owner).
    • Log parseable lines, e.g. TimeArenaBuyRouter (single-tx): 0x….
  2. Wire anvil_deploy_dev.sh

    • Default YIELDOMEGA_DEPLOY_KUMBAYA=1 for scripts/e2e-anvil.sh (or always run fixtures after DeployDev in that script only).
    • Parse TimeArenaBuyRouter log label; set KUMBAYA_BUY_ROUTER.
    • Assert: cast call $TA "timeArenaBuyRouter()(address)" equals deployed router.
  3. Registry + Vite helpers

    • Extend yieldomega_registry_merge_* for TimeArenaBuyRouter.
    • yieldomega_frontend_merge_kumbaya_vite_full: set VITE_KUMBAYA_TIME_ARENA_BUY_ROUTER (keep legacy VITE_KUMBAYA_TIMECURVE_BUY_ROUTER only if still needed for transitional tooling).
  4. Implement verify-time-arena-buy-router-anvil.sh

    • DeployDev + fixtures → onchain router match → optional forge test --match-contract TimeArenaBuyRouter → spot-check one buyViaKumbaya (ETH) on Anvil.
  5. Forge tests

    • Local: happy path ETH + USDM (mock router), StableIngressParity, bad path, paused arena, charm bounds, expired deadline.
    • Reuse patterns from retired TimeCurve buy-router tests if any exist in git history.
  6. E2E

    • Remove skip when e2e-anvil.sh always provides router env; document that YIELDOMEGA_DEPLOY_KUMBAYA=0 opts out.

Acceptance criteria

  • DeployKumbayaAnvilFixtures (or renamed equivalent) exists, passes DevOnlyChainGuard, and broadcasts on Anvil.
  • After default bash scripts/e2e-anvil.sh: TimeArena.timeArenaBuyRouter() is non-zero and equals deployed TimeArenaBuyRouter.
  • scripts/e2e-anvil.sh exports VITE_KUMBAYA_TIME_ARENA_BUY_ROUTER without manual steps.
  • Playwright ETH pay test in anvil-arena-wallet-writes.spec.ts runs (not skipped) on CI/local when using e2e-anvil.sh.
  • local-anvil-registry.json (or merge helper) includes TimeArenaBuyRouter when fixtures run.
  • verify-time-arena-buy-router-anvil.sh performs real checks (non-stub) and exits non-zero on failure.
  • Docs updated: kumbaya integration, e2e-anvil, local-swap-testing, play-time-arena-doub skill — no stale TimeCurveBuyRouter as Arena authority.

Test plan — functional paths

# Path Steps Expected
1 Default E2E deploy bash scripts/e2e-anvil.sh DeployDev + fixtures; router set; ETH E2E executes
2 Onchain wiring cast call timeArenaBuyRouter Matches logged router address
3 ETH buyViaKumbaya Anvil account, min CHARM, ETH pay Tx succeeds; Buy / BuyViaKumbaya event
4 USDM buyViaKumbaya Same with USDM path Succeeds when USDM pool seeded
5 DOUB direct (regression) CL8Y/DOUB pay mode, no router needed for pull Still works with router set
6 Opt-out YIELDOMEGA_DEPLOY_KUMBAYA=0 bash scripts/e2e-anvil.sh DOUB E2E passes; ETH test skipped with clear message
7 Stack script YIELDOMEGA_DEPLOY_KUMBAYA=1 bash scripts/start-local-anvil-stack.sh Registry + .env.local merged
8 Verify script bash scripts/verify-time-arena-buy-router-anvil.sh All checklist steps green

Automated: forge test --match-contract TimeArenaBuyRouter; frontend build unchanged; optional indexer cargo test if registry decode extended.


Test plan — attack / abuse vectors

Vector Test Expected mitigation
Wrong router wired Deploy script points setTimeArenaBuyRouter at non-router contract Script verifies buyViaKumbaya selector or post-deploy smoke call
Router not owner-gated Only deployer/owner can call setTimeArenaBuyRouter on prod paths Anvil uses deployer key only; document prod runbook separately
Malicious setTimeArenaBuyRouter on Anvil User cannot call setTimeArenaBuyRouter without owner cast send from random key reverts
Under-liquidity pool exactOutput with empty reserves Deploy script seeds min reserves; test reverts with slippage/insufficient
Stable fee-on-transfer Mock deflationary stable (if added) StableIngressParity revert on router
Env/router mismatch Frontend env ≠ onchain #264 (closed) fail-closed in UI; deploy sets both consistently
Mainnet mistaken deploy Run fixture script against 4326 DevOnlyChainGuard reverts

Verification criteria

  • forge test green for new TimeArenaBuyRouter suite.
  • bash scripts/e2e-anvil.sh green including ETH wallet-write spec.
  • cast call spot-check: router address, paused()==false, arena live.
  • Grep: DeployKumbayaAnvilFixtures references resolve to an existing .s.sol file.
  • Manual: docs/testing/manual-qa-checklists.md Arena ETH/USDM rows (if present) pass on Anvil.
  • Production deploy explicitly out of scope — separate mainnet registry issue.