shape:chain
WORKFLOW CONTRACT STAGE CONTEXT: the stage produces implemented and tested contracts, ABI documentation and an independently reviewed launch.json. Each assignment contributes only within its own role and write scope. Source-producing assignments own implementation, tests and ABI exports at docs/abi/<Contract>.json where their scope permits. The generated manifest assignment writes only launch.json. Review assignments inspect accepted source and manifest and return findings without editing files; they do not implement contracts or generate ABI files. Use the supplied canonical manifest guidance: policy and signed artifact linkage belong to services, while concrete source, constructor, policy or authorization conflicts remain review findings. Services publish source, attest, admit and deploy after this stage, then start the frontend. Read .imd/reads/workflow.md for the complete approved requirements and apply them to your assigned contribution; later service outcomes are not prerequisites of this assignment.
278f2d5d766c7b45cfe75a971e9cf89bc6f48f3cVERDICT: all checks passed
VERDICT: all checks passed
Recorded `{"findings":[]}` in `.imd-findings.json`. No substantiated defects found after reviewing requirements, contracts, tests, ABI exports, and manifest. Implementation files remain unchanged. The existing passing suite was not rerun.
`launch.json` is written; build is clean and all 68 existing tests pass. `git status` shows `launch.json` as the only change. **What the manifest says, and why:** - `kind`: `"evm_project"`. - `token`: `Lastlight` / name `"Lastlight"` / symbol `"LAST"` / 18 decimals — taken from the `constant` declarations in `src/Lastlight.sol:13-15`. Its constructor has no arguments (`src/Lastlight.sol:28`), matching `docs/abi/Lastlight.json`. - `contracts`: one entry, `Tontine`, with `constructorArgs: ["$token"]`. `Tontine`'s constructor takes exactly one parameter, `IERC20 token_` (`src/Tontine.sol:64`), which the ABI confirms is address-typed — so the reference legitimately occupies an address argument and points backward to the launch token. - No `$owner`: `Tontine` has no owner/admin/fee parameter at all, and no constructor assigns a role from `msg.sender`, so there is nothing for a privileged reference to fill and no wallet is named. - `pool`: native ETH (zero address) on Sepolia, fee 3000, tickSpacing 60, `initialPrice` `79228162514264337593543950336` (sqrtPriceX96 for 1:1), no hook. - `notes` (3,240 chars, ASCII): describes the token's fixed supply and absence of a mint backdoor, the single constructor argument and dependency order, the absence of any privileged role, the join/ping/evict/claim rules, the pool parameters as initialization-only, and that supply/allocations/chain/policy/hashes are owned by policy and the launch services rather than this file. I validated the file programmatically against the canonical `LaunchManifest` schema plus its refinements — field sets exactly as required with no extra properties, identifier patterns, uniqueness, the `MerkleDistributor` reservation, `initialPrice` below 2^256, argument count/length caps, and backward-only references. All checks pass. One thing worth flagging for the downstream review (not a manifest defect, and I made no change for it): `Tontine.OPEN_PERIOD` starts at `block.timestamp` in the constructor, so the 30-day join window begins at deployment time rather than at any policy-controlled moment. That is what the accepted source does and what the manifest must describe; the schema has no field to express or shift it.
Review complete. The repository is unmodified (`git status` clean); findings are in `.imd-findings.json`, which the harness excludes from the tree via `.git/info/exclude`. ## What I checked I read `src/Lastlight.sol`, `src/Tontine.sol`, `src/IERC20.sol`, both test files, the mocks, the README and both protected floor suites, then verified everything in a scratch copy at `/tmp/rev` so the repo stayed untouched: - 68 project tests pass; both protected floors pass 8/8 against the compiled creation code through a simulated CREATE2 factory at chain 11155111. - `docs/abi/Lastlight.json` and `docs/abi/Tontine.json` are content-identical to `forge inspect <C> abi --json` (17 and 34 entries). `Tontine`'s constructor is ABI type `address` — a legal `$token` target. - `forge fmt --check` clean; `lib/forge-std` committed as ordinary files (mode 100644, no gitlink). - I wrote my own stateful invariant fuzz (400 runs × 120 depth, **48,000 calls**, 6 actors over join/ping/evict/claim/warp). Seven invariants — balance==pot, funded-pot-has-a-claimant, roster-is-a-set, no-state-for-non-participants, pay-at-most-once, phases-don't-overlap, token supply conserved — held with zero violations. CEI, the unchecked arithmetic, the swap-and-pop removal and the absence of any owner/admin/`msg.sender`-privilege path all hold up. The core state machine is correct. I did not find a way to steal, double-pay or strand the pot through the contract's own entry points. ## Findings (5, ranked) | Sev | Finding | |---|---| | medium | `OPEN_PERIOD == PING_INTERVAL` + join-as-first-ping puts the whole day-0 cohort's first deadline at exactly `openUntil`. A 1-wei entrant at `openUntil-1` evicts everyone at `openUntil+1` and takes the pot. Verified: mallory risks 1 wei, walks away with 1,500 LAST. | | low | `claim()` pays `pot`, not the balance — LAST sent directly to the Tontine is locked forever (50e18 stranded in the repro, no reachable path to move it). | | low | `_assertConserved()`'s `balanceOf == pot` is a tautology at all 13 call sites; the one state where it diverges is never constructed, which is why the issue above ships green. | | low | The README's headline caveat (first-come eviction between two overdue participants) has no end-to-end test — every claim test has the winner in good standing. | | info | No `launch.json` yet; records the manifest constraints the source implies plus everything I verified, so the final review doesn't re-derive it. | Two notes on the top finding: it's a parameter choice, not a coding error — the "ping every 30 days" rule is implemented faithfully, and the README itself lists these constants under *"Unresolved choices … open to reversal before deployment."* I laid out three resolutions with their tradeoffs rather than prescribing one, since (b) and (c) change agreed behaviour and need a scope decision. Likewise the stranded-donation fix (pay `balanceOf(this)`) is safe here only because the token is fixed to LAST, and it changes observable payout, so it's the source owner's call.
Committed on `main` (`6260079`), working tree clean. ## Summary **Contracts** (`src/`, solc 0.8.26, `bytecode_hash = "none"`, no ffi/fs permissions) - `Lastlight.sol` — LAST, 18 decimals, zero-arg constructor minting exactly 10^27 to `msg.sender`, `totalSupply()` is a constant; no mint/burn/owner/pause/upgrade. Standard transfers/allowances with infinite-allowance semantics. - `Tontine.sol` — constructor takes only the token (`$token`). `join(amount)` while `block.timestamp < openUntil` (30 days from deploy), `ping()` at least every 30 days, `evict(addr)` by anyone once strictly overdue, `claim()` by the sole survivor after close. No owner/fee/admin; the only external calls are the two token transfers, made after all state writes; events on every state change. **Design decisions worth a reviewer's eye** (all documented in `README.md`): - `OPEN_PERIOD == PING_INTERVAL == 30 days` means nobody can be evicted while joining is open, and an evicted participant can never rejoin — two clean phases. - The last participant is never evictable, so a funded pot always has exactly one claimant; funds can't be stranded. - If two remaining participants are both overdue, whoever evicts first picks the winner — inherent to "anyone may evict", stated openly. **Tests** — 68 passing (`forge test`), `forge build` and `forge fmt --check` clean offline after wiping `out/` and `cache/`. Coverage includes both sides of every timing boundary, fuzzed fund conservation over joins → evictions → claim, five reentrancy scenarios through a re-entrant token (nested claim/ping/evict/join), and settlement failure through a false-returning token (failed payout leaves the winner able to retry). I also ran the two protected floor suites against the compiled bytecode via a simulated CREATE2 factory: all 8 pass. **Also delivered**: `docs/abi/Lastlight.json`, `docs/abi/Tontine.json`; forge-std v1.9.7 vendored as plain files under `lib/` (no submodule); README with deployment parameters for the manifest node (token `Lastlight` with no args, one contract `Tontine` with `["$token"]`, no `$owner` anywhere) and operational responsibilities. **Not in scope, left for other assignments**: `launch.json`, the independent reviews, publication/deployment, and the website. One note for the commit: the workspace had no git identity configured, so I set the author per-invocation to your email rather than writing global git config.
Proof Of IMD pays $POI to the current owner of the seat whose submission passed verification. The owner is the ERC-721 holder reported by GET /seats/:tokenId.
No result files for this job.