# Fledge Contracts — Internal Self-Review (NOT an independent audit)

_Reviewer: Claude (AI assistant), 2026-07-21. Scope: LaunchToken.sol,
BuybackBurn.sol, TokenLock.sol (the $CHIRP launch set; FledgeStaking excluded —
not needed at launch). Solidity ^0.8.24, OpenZeppelin v5._

> ⚠️ **READ THIS FIRST — what this document is and is not.**
> This is a careful line-by-line self-review by an AI, done at ElfDev's request
> to reduce cost. It is **NOT** the independent third-party audit the Chirp/Fledge
> whitepapers publicly pledge ("an independent audit before deployment").
> It found **no critical or high-severity issues**, which is reassuring — but:
> 1. A self-review cannot provide the **independent accountability** that is the
>    entire point of an audit (a named party staking its reputation).
> 2. The reviewer has blind spots and cannot fuzz, formally verify, or model
>    economic attacks the way a firm does.
> 3. **You may not tell users the contracts were "audited" on the basis of this.**
> **Before public launch, either commission the pledged audit, or amend the
> whitepaper so you are not promising something you did not do.** Treat this
> review as hardening that makes the eventual audit faster/cheaper.

---

## Summary

| Contract | Verdict | Highest finding |
|---|---|---|
| LaunchToken | Solid; anti-honeypot by construction | INFO only (N/A for $CHIRP config) |
| BuybackBurn | Solid; ownerless | LOW (accepted MEV) + deploy-time trust |
| TokenLock | Solid; non-custodial | LOW (unbounded view) |

No owner keys, no mint-after-deploy, no blacklist/pause, no admin withdrawal
anywhere. The dangerous-by-default patterns are all absent. The residual risks
are (a) one documented, bounded MEV surface in BuybackBurn, and (b) **deploy-time
correctness** — several immutables are fully trusted and must be verified at
construction (covered by launch-day gate ⑪).

---

## LaunchToken.sol

**PASS — genuinely anti-honeypot.** Fixed supply minted once in the constructor;
no `mint` afterward. Tax is `immutable`, hard-capped at `MAX_FEE_BPS = 100` (1%),
with no owner and no setter — it can never be raised to trap holders. No
blacklist, no pause. `_update` routing (None/Burn/Recipient/Split) is correct and
the Split math (`burnPart + recipPart == fee`) has no rounding leak.

- **L-1 (INFO):** On the launch-fee path, the constructor forwards the entire
  `msg.value` to `LAUNCH_TREASURY`, not just `fee` — an overpayment is not
  refunded. **N/A for $CHIRP** (deploy with `LAUNCH_TREASURY = address(0)`).
- **L-2 (INFO):** The constructor makes an external `call` to `LAUNCH_TREASURY`
  before minting. `LAUNCH_TREASURY` is a compile-time constant and the path is
  disabled for $CHIRP. No reentrancy concern in practice.
- **L-3 (NOTE):** `totalSupply_ * 10**decimals_` relies on 0.8 checked math to
  revert on overflow — fine for $CHIRP (1,000,000 × 1e18 = 1e24, far under
  uint256). No action.
- **$CHIRP deploy requirement:** launch with `feeMode = None`, `feeBps = 0`,
  `LAUNCH_TREASURY = address(0)` → a plain, ownerless, fixed-supply ERC-20.
  **Verify the constructor args on-chain after deploy** (Blockscout).

## BuybackBurn.sol

**PASS — trustless burn engine.** No owner, no admin, no withdraw; ETH can only
leave as TOKEN sent to `0x…dEaD`. `nonReentrant` guard present; CEI ordering
correct (`lastBuybackAt` set before the swap, totals after). Cap + cooldown
sandwich hardening (from the 07-19 pre-audit finding) is in place. Uses the
fee-on-transfer-safe swap variant (works whether or not TOKEN taxes transfers).

- **B-1 (LOW, ACCEPTED):** `minTokensOut` is caller-supplied and **anyone** may
  call `buybackAndBurn`. A sandwicher can call with `minTokensOut = 0` and
  extract value; the loss per call is bounded by `maxEthPerCall`'s price impact
  and the rate is bounded by `cooldownSec`. This is the documented, accepted
  residual. **Mitigation (gate ⑩):** run the keeper cron passing a sane
  `minTokensOut` from `quote()`, keep the contract near-empty (frequent small
  burns), and randomize timing. Do **not** advertise the address as a place to
  park large ETH balances.
- **B-2 (MEDIUM — DEPLOY-TIME, not code):** `token`, `router`, `weth` are
  immutable and **fully trusted**. A wrong or malicious `router` at construction
  = total loss of deposited ETH. **This is the single most important launch
  check:** confirm `router` == the canonical Uniswap V2 router on Robinhood
  Chain (`0x89e5db8b…` per config) and `token` == the real $CHIRP address, and
  read them back from chain before funding. Covered by gate ⑪ dry-run.
- **B-3 (INFO):** `quote()` reverts if the CHIRP/WETH pool doesn't exist yet —
  the keeper must not call before LP is seeded. Operational note only.

## TokenLock.sol

**PASS — non-custodial and safe.** OZ `ReentrancyGuard` + `SafeERC20`. No owner,
no admin withdrawal, no early exit — once locked, no one (not even the creator)
can pull tokens; only the beneficiary claims, only what has vested. `claim` is
CEI (`claimed += amt` before transfer). `lock` measures the actually-received
amount, so it's fee-on-transfer-safe. Vesting math is overflow-safe for realistic
supply × duration.

- **T-1 (LOW):** `totalLocked(token)` loops over all locks for a token, and
  `_byToken` / `_byBeneficiary` arrays grow unbounded. A token with a very large
  number of locks could make the `totalLocked` **view** exceed an eth_call gas
  limit. **View-only, no fund risk**; fine at launchpad scale. If you ever expect
  thousands of locks per token, maintain a running per-token total instead.
- **T-2 (INFO):** Pure-lock case (`cliffDuration == duration`) behaves correctly
  (0 before cliff, full at end, empty linear window in between).

---

## Slither static analysis (run 2026-07-21)

Ran `contracts/run-slither.sh` (Slither over all four). Substantive detectors
fired 3 times across the launch set — **all three are benign false positives**,
which corroborates the manual review (nothing critical/high):

- **LaunchToken — `divide-before-multiply`** (`fee`, then `burnPart`): FALSE
  POSITIVE. `fee` is the final tax; `burnPart` is a share OF it, and
  `recipPart = fee - burnPart` makes the split **exact** (no leaked wei). The
  floor-rounding of `fee` is intentional and standard. No change.
- **BuybackBurn — `incorrect-equality` (`ethIn == 0`)**: FALSE POSITIVE. Just
  "is there anything to spend" on `min(balance, cap)` — not a manipulable
  equality guard. No change.
- **BuybackBurn — `reentrancy-benign`** (totals written after the swap):
  Slither's own **benign** class. `nonReentrant` guards the function, and the
  security-critical `lastBuybackAt` is written BEFORE the external call (correct
  CEI); the post-call writes are accounting-only. No change.

The remaining Slither output was style noise (pragma version spread from OZ
imports, naming conventions, low-level-call in the launch-fee path). Full logs:
`/tmp/slither-{LaunchToken,BuybackBurn,TokenLock,FledgeStaking}.txt` on WSL.

## Cross-cutting recommendations before deployment

1. **Slither: done (above)** — clean apart from explained false positives.
2. **Confirm 0 compiler warnings** on all three (only BuybackBurn was noted as
   "0 warnings" — verify LaunchToken + TokenLock too).
3. **Deploy-time verification is the real risk surface**, not the code logic:
   verify every constructor immutable on-chain (token, router, treasury, fee
   params, lock schedules) before any real value flows. Gate ⑪'s "tiny test
   transfer to every address + read params back" is exactly right.
4. **Decide the audit question explicitly** (see the banner at top): commission
   it, or change the public pledge. Do not deploy while the whitepaper says
   "audited" and it isn't.
