# FLOW — Internal Adversarial Audit Summary

**Date:** 2026-07-20
**Scope:** the direct-on-Uniswap-V4 production contract stack (below)
**Method:** six parallel adversarial reviews (one per contract + a scanner-compatibility pass), each run
"guilty-until-proven-safe", followed by a manual verification pass on every Medium/serious finding.

> **Disclaimer.** This is an **internal** adversarial review, not a third-party professional audit. It
> complements — and does not replace — the planned external audit. It reflects the code as of this date.
> Nothing here is a guarantee; smart contracts carry risk. Read the code yourself: every contract is
> verified and open-source on the block explorer.

---

## Verdict

**No Critical or High findings.** Across the whole production stack there is **no path to steal funds, no
way for buyers' ETH to get stuck, and no rug** — liquidity is provably unremovable and the protocol never
custodies buyers' ETH. The token is honeypot-scanner clean (no mint, no blacklist, no pause, no proxy, no
transfer tax, sells always work). Residual findings are Medium (bounded, or non-production), Low, and
Informational. The actionable ones have been fixed or are tracked below.

**Test status at time of writing: 119/119 passing.**

## Contracts in scope (production stack)

| Contract | Role |
|---|---|
| `FLOWv4.sol` | The basket token: reward accounting, forfeit split, redeem, permissionless buyback, anti-whale caps. |
| `v4hook/FlowHookSS.sol` | The Uniswap V4 hook: takes the tax, routes the fixed 0.25% platform cut to FLOW, anti-snipe surcharge. |
| `v4hook/FlowFactory.sol` (+ `TokenDeployer.sol`, `LauncherDeployer.sol`) | Permissionless launchpad: deploys + wires each coin. |
| `v4hook/LaunchPoolV4.sol` | Single-sided V4 launcher: seeds the locked pool, graduates (re-ranges) to deep full-range LP. |
| `v4hook/PlatformVault.sol` | Holds the 2%-per-coin stake; can only hold or redeem-to-FLOW; dead-man's switch. |

Legacy/superseded files (`FLOW.sol`, `LaunchCurve*.sol`, `FlowHook.sol`, `FlowHookMulti.sol`, `mocks/*`) are
**not** part of the production stack and were out of scope.

---

## Verified-safe invariants (the load-bearing guarantees)

- **Liquidity is unremovable (no rug).** `LaunchPoolV4` has no `withdraw`/`sweep`/`rescue`/`decreaseLiquidity`/
  `collect`/`selfdestruct`. The only `modifyLiquidity` calls are the seed add and a remove-then-re-add within a
  single graduation unlock. Raised ETH lives in the Uniswap PoolManager and only leaves via ordinary market sells.
- **Redeem is `nonReentrant` + strict CEI**, native paid last → no reentrancy, no double-claim.
- **Solvency**: all reward/forfeit/spill math floors down → Σ holder baskets ≤ ETH held; never over-credits.
- **No hidden mint / no blacklist / no pause / no proxy**; `tradingEnabled` is one-way; sells always succeed.
- **Owner cannot extract holder basket ETH**; launched (restricted) tokens have all reward/limit/exclusion
  setters permanently locked.
- **PlatformVault** exposes no transfer/withdraw/sell path; the redeem destination (FLOW) is immutable; the
  dead-man's switch reliably frees every position after 90 days of owner silence, with no cross-token DoS.
- **Cross-pool isolation** in the hook (pinned pool key + per-pool accrual); a forged key drains nothing.
- **`launch()` accepts no attacker-supplied addresses**; deployment is `CREATE` (no salt-squatting); the flow
  is atomic and hands the adversary no control, so a malicious launcher can't miswire or reenter.

---

## Findings & dispositions

Severity legend: 🟠 Medium · 🟡 Low · ⚪ Informational.

### FLOWv4.sol
- 🟠 **M-1 — `pendingLiquidity` could strand on a `curve == 0` token.** The buyback needs the V4 pool, gated
  on `graduated`. In production `graduated` is set at launch (via `LaunchPoolV4.open()` → `onGraduate()`), so
  **no production token is affected** — it is latent only for a manually-deployed `curve == 0` config.
  **FIXED:** `_forfeit` now routes the buyback slice to the project queue when `!graduated`, so nothing can
  strand (zero change to the always-graduated production path). Test updated.
- 🟠 **M-2 — buyback slippage bound is anchored to the live `slot0` price.** A same-block MEV manipulator can
  push the price and have the buyback execute near it, leaking **bounded** value (≤ `BUYBACK_MAX_SLIP_BPS`
  ≈ 2.5% per call) from the buyback queue only — never holder baskets or principal, and unspent ETH carries
  over. **DISPOSITION:** documented as an accepted, bounded risk in-code; a manipulation-resistant TWAP/oracle
  reference is tracked as dedicated future hardening (a rushed oracle in a core fund-mover is higher-risk than
  the bounded leak it addresses).
- 🟡 **L-1 — `processProject()` DoS if `treasury` reverts on receive.** Recoverable via `setTreasury()`. No fix required.
- 🟡 **L-2 — owner centralization on the unrestricted flagship** (`setLimits`/`setAMMPair`/`setExcludedFrom*`).
  Cannot mint/blacklist/pause or freeze sells. Mitigated by launch-day hygiene (below).

### FlowHookSS.sol
- 🟡 **L — exact-output sells bypass the 0.25% FLOW cut** (routed as a token burn, not ETH to baskets). Rare,
  economic-form only, no fund loss. Documented; optional future change.
- ⚪ Comment "cut is exactly 0.25%" is really "≤ 0.25%" (double flooring always favors holders — safe).
- ⚪ Swap liveness depends on `fundBaskets` never reverting — safe today (immutable one-shots); flag for any
  future FLOWv4 change.

### FlowFactory.sol / TokenDeployer.sol / LauncherDeployer.sol
- 🟡 **L-1 — deployer access-control guards (`only factory`, one-shot `setFactory`) are untested.** Code is
  correct; a regression would be serious. **TODO:** add negative tests.
- 🟡 **L-2 — no `nonReentrant` on `launch()`.** Safe today (adversary never gets control); recommended as
  cheap defense-in-depth for future edits.
- ⚪ Comment says "2% of supply"; actual is 2% of `curveSupply` (capped to the vault's maxWallet room).

### LaunchPoolV4.sol
- 🟠 **M-1 — graduation can brick / `gradReserve` (tokens, not ETH) can be stranded on bad parameters.** Not a
  theft or rug (the pool stays tradeable; buyer ETH is always pool-side). The runtime guard
  `require(residEth*50 <= ethBack, "eth not paired")` already makes a bad-param graduation **fail-safe**
  (revert, no loss). **DISPOSITION:** we deliberately did **not** add an immutable constructor math-check — a
  correct one must account for the dynamic unsold `tokBack` (`tokenAvail = tokBack + gradReserve`), and a naive
  check would wrongly reject valid configs (including the real deploy). Requirement is documented in-code and
  locked in by the graduation tests + deploy-script params.
- 🟡 **L-1/L-2 — transient, self-costing graduation DoS / theoretical 1-wei brick.** Retryable; no funds lost.
- ⚪ "graduates to **deep** full-range liquidity" — the full-range pool is actually ~1.5× *thinner* near price
  than the concentrated seed (protective against the graduation sandwich, but "deep" ≠ lower slippage).
- ⚪ "the ETH never touches this contract" — a **bounded** dust amount (≤ 2% of the raise) transits during
  graduate() en route to baskets. Not custody of principal.

### PlatformVault.sol
- 🟡 **F-1 — `renounceOwnership()` was not disabled.** Renouncing would freeze `lastActive` and kill
  owner-timed + partial redeems (funds still safe via the dead-man's switch). **FIXED:** `renounceOwnership()`
  now reverts; `transferOwnership` (to a multisig) stays available. Test added.
- ⚪ Header comment "WORK IN PROGRESS — NOT AUDITED" — update on external-audit completion.

---

## Automated-scanner (GoPlus / honeypot.is / DexScreener) assessment

**Structurally clean:** no mint, no blacklist, no pausable, no proxy, no owner-settable transfer tax, no
"max-tx = 0" trap; LP locked; buy→sell round-trip succeeds; the token contract has **0% transfer tax** (forfeit
touches only the ETH reward basket). Watch-items are launch-day hygiene, not code defects:

- **P1 — anti-snipe surcharge — TUNED.** Reduced from +20%/120s to **+4%/60s**
  (`SNIPE_MAX_BPS 2000 → 400`, `SNIPE_GUARD 120 → 60`), so a launch-window scan of a ≤5%-base token reads
  ≤ ~10% (under the common flag line) and self-corrects within a minute. The 1%/2% caps remain the primary
  anti-snipe; peak deterrence is intentionally lower. Keep base fees ≤ 5% (P2).
- **P2 — base fee ≤ 5%.** 10% sits on the common flag threshold; keep FLOW + presets comfortably under it.
- **P3 — flagship ownership.** Post-launch, call `removeLimits()` then move ownership to a multisig/timelock (or
  renounce) to clear the anti-whale / trading-restriction WARNs. Launched (restricted) tokens already pass.
- **P4/P5 — holder-concentration optics** (label the launcher as "Locked Liquidity" and the vault as
  "Protocol (locked)") and **verify honeypot.is / Token Sniffer support chain 4663** before launch.

---

## Fixes applied in this pass (changelog)

| # | Contract | Change |
|---|---|---|
| 1 | `PlatformVault.sol` | `renounceOwnership()` disabled (reverts); `transferOwnership` retained. + test. |
| 2 | `LaunchPoolV4.sol` | Documented the `gradReserve` requirement + the runtime fail-safe guard (no risky immutable check). |
| 3 | `FLOWv4.sol` | Documented the bounded buyback MEV (M-2) as accepted risk; TWAP tracked as future hardening. |
| 4 | `FLOWv4.sol` | `_forfeit` routes the buyback slice to the project queue when `!graduated` (kills the latent strand). + test. |
| P1 | `FlowHookSS.sol` | Anti-snipe surcharge tuned to +4% / 60s (`SNIPE_MAX_BPS 2000→400`, `SNIPE_GUARD 120→60`) for scanner-clean launch-window tax. Tests updated. |

## Open items (not code-blocking)

- Launch-day scanner hygiene P2–P5 above (P1 tuned in this pass; see also `docs/LAUNCH-DAY-SCANNER-HYGIENE.md`).
- Test-coverage additions: deployer access-control negatives; vault reentrancy/boundary; buyback-MEV; `curve==0` strand.
- Future hardening: TWAP-referenced buyback min-out; optional `nonReentrant` on `launch()`.
- Third-party professional audit (planned milestone).
