shape:chain
Release TOLLGATE (symbol TOLL), a Uniswap v4 token+hook launched as univ4_hook. TollgateHook charges a 2% fee in NATIVE ETH on every buy and every sell of the pool. 100% of hook fees are owed to a fixed CREATOR wallet until exactly 1 ETH has accrued (CREATOR_CAP); a permissionless payCreator() pays what is owed. After the cap every fee is burnable: a permissionless burnEth() sends it to 0x000000000000000000000000000000000000dEaD. Context: this is a technical rehearsal of the fee-and-cap mechanics (flags 0x00CC with both swap return deltas, a capped fee to a fixed wallet, a permissionless burn) ahead of a later production launch by the same requester; it is not a consumer product and makes no claims beyond what the code does. The creator fee is intentional and must be disclosed in README, launch.json notes and NatSpec; the reviewer must verify its cap, recipient and immutability. MANDATORY: 1) Token: self-contained ERC-20, zero-argument constructor, mints EXACTLY 10^27 (1e27) to msg.sender (the LaunchFactory), 18 decimals, no owner, no mint, no pause, no proxy; burn/burnFrom allowed. NEVER 10^24 (launch 123 was parked on SupplyMismatch). 2) Hook permissions exactly: beforeSwap, afterSwap, beforeSwapReturnDelta, afterSwapReturnDelta (flags 0x00CC). NO beforeInitialize (launch 138 was parked on an initialize guard). Constructor calls Hooks.validateHookPermissions. The ONLY constructor argument is the PoolManager address (a literal address). Everything else is a compile-time constant in source. 3) Constants: BUY_FEE_BPS=200, SELL_FEE_BPS=200, CREATOR_CAP=1 ether, CREATOR=0x70c6C4fcaAb11151FCEDb32eaaC3431547193A0a, BURN_SINK=0x000000000000000000000000000000000000dEaD, MIN_BURN=0.01 ether, MIN_BLOCKS_BETWEEN_BURNS=5. 4) Fee always in ETH (currency0): exact-in buy and exact-out sell take it in beforeSwap as a positive specified BeforeSwapDelta; exact-out buy and exact-in sell take it in afterSwap as a positive unspecified int128. Collect with poolManager.mint(address(this), 0, fee) (ERC-6909 claim); never push ETH or call external contracts inside swap callbacks. Revert PartialFill if the raw pool delta != amountSpecified + fee. In a pool whose currency0 is not native ETH (e.g. foreign MockERC20 pools of the protected suite) charge nothing and return zero deltas. 5) Lazy ledger: the swap path only increments totalFees. creatorEntitlement = min(CREATOR_CAP, totalFees); burnable = totalFees - creatorEntitlement - burned. Invariant: PoolManager.balanceOf(hook, 0) >= totalFees - creatorPaid - burned (anyone may transfer ERC-6909 claims to the hook; they stay stuck, there is no sweep). Emit CapReached(totalFees, block.number) exactly once, in the swap that crosses the cap. 6) payCreator(): permissionless, nonReentrant; pays creatorEntitlement - creatorPaid to CREATOR via unlock -> burn claims -> take; reverts NothingDue when nothing is owed; never more than CREATOR_CAP in total. 7) burnEth(): permissionless top-level call (separate unlock, never inside a swap), nonReentrant, 5-block cooldown counted from deployment (TooSoon), amount = burnable, revert NothingToBurn below MIN_BURN; via unlock -> burn claims -> take to BURN_SINK. No external contracts other than the PoolManager. 8) Reentrancy lock on a literal transient slot (1), as PvPadHook, so no hashed constant lands in a data section. A linear opcode walk of every compiled contract must find 0 bytes F2/F4/FF. 9) Toolchain: solc 0.8.26, evm cancun, optimizer 200, via_ir false, bytecode_hash none, cbor_metadata false, dependencies vendored under lib/ (v4-core 1.0.2). 10) Tests run OFFLINE (worker checks get no RPC) with a locally deployed PoolManager and routers. FORBIDDEN: owner, admin, pause, upgrade, fee setter, recipient setter, sweep; beforeInitialize or any initialize gating; SELFDESTRUCT, DELEGATECALL, CALLCODE in any compiled contract; non-literal constructor args such as $token or $pad (launch 137); dynamic LP fee; fees in the token; fee-on-transfer token; any payout to CREATOR beyond 1 ETH in total; putting supply, bps or fees into launch.json; launch.json notes over 4000 characters.
86bed3022c77e03402cd8e333e809563a1eeaef2VERDICT: all checks passed
VERDICT: all checks passed
Wrote [`.imd-findings.json`](/root/.identitymd/work/722cdd8b-4f02-45d3-a11e-27973c377122/c8d30134-62a5-4254-83cd-fe6e715a0ddf/.imd-findings.json) containing `{"findings":[]}`. No substantiated defects found: - No path pays CREATOR over 1 ETH or changes fees, recipients, or sink. Required disclosures are present. - No third-party payout griefing, successful reentrancy, or unauthorized extraction found. CREATOR rejecting ETH blocks its own payout; burns remain available. - All four swap modes match the documented 2% calculation and rounding. Exact-output price limits cannot bypass fees; partial fills revert without changing the ledger. Seven temporary adversarial checks passed offline, including 1,000 fuzz cases. The opcode scan passed. Implementation and repository tests remain unchanged.
The manifest is rewritten, validated, and committed. Only launch.json changed. **What was wrong.** The previous launch.json carried fields the schema rejects at every level: `name`, `chainId`, `hook.source`, `hook.flags` and `token.source`. Because the schema sets `additionalProperties: false`, the whole manifest would have failed to parse. Its notes were also within 19 characters of the cap. **What the new manifest says.** It keeps `"kind": "univ4_hook"` as the first field and uses only schema fields. - Hook `TollgateHook`, one constructor argument, the literal canonical mainnet PoolManager address, and the four permissions beforeSwap, afterSwap, beforeSwapReturnDelta, afterSwapReturnDelta. - Token `TollToken`, name TOLLGATE, symbol TOLL, 18 decimals. - Pool paired with native ETH at the zero address, static LP fee 3000, tick spacing 60, initialPrice `79228162514264337593543950336000`, which is sqrt(1e6) times 2^96, so 1 ETH opens at 1,000,000 TOLL as in test/LaunchRehearsal.t.sol. - Notes disclose the 2% ETH fee, the fixed creator wallet, the 1 ETH lifetime cap, the permissionless payout and burn, the burn sink, immutability, the mechanics, the ledger invariant, and the review points. They give no supply figure and no basis-point figure, and they now state that supply, allocations, chain and policy are not manifest fields. **Checks run.** | Check | Result | | --- | --- | | JSON Schema validation with refinements, from test/scratch | passes, notes at 3954 characters, pure ASCII | | Manifest permissions folded to an address mask | 0x00CC | | Compiled hook ABI constructor | single `address manager`; token has no arguments | | Protected Hook and Token floor suites, fed the manifest's constructor literal, flags and decimals | 9 of 9 pass | | `forge build` and full repository `forge test` | 55 of 55 pass | The commit is cc1d807 on top of the accepted work. Scratch files under test/scratch were left in place, since they are discarded before submission.
Committed as `74a0b6e` on `main`, working tree clean. The deliverable is complete. **What was built** - `src/TollToken.sol`: self-contained ERC-20, zero-argument constructor, mints exactly 1e27 to `msg.sender`, 18 decimals, `burn`/`burnFrom`, no owner, mint, pause or proxy, no imports. - `src/TollgateHook.sol`: flags `0x00CC` only, PoolManager address as the sole constructor argument, constants exactly as specified. Fee is always ETH: exact-in buy and exact-out sell take it in `beforeSwap` as a positive specified delta, the other two directions in `afterSwap` as a positive unspecified delta. Collection is `poolManager.mint(hook, 0, fee)` inside the swap, so the first buy into an ETH-less pool works. `PartialFill` guards the raw delta. Non-ETH pools trade fee-free. Lazy ledger, `CapReached` once, permissionless `payCreator()` and `burnEth()` each in their own unlock, reentrancy lock on transient slot 1. - `src/HookFlags.sol` and `test/mocks/MockERC20.sol` at the paths the protected suite imports. - `lib/`: v4-core 1.0.2 (from the npm tarball, `src/test` excluded), forge-std v1.9.7, solmate `Owned`, all plain files, no submodules. - Docs: `README.md`, `docs/DISCLOSURE.md`, `docs/deployment.md`, `docs/dependencies.md`, and `launch.json` whose notes disclose CREATOR, the 1 ETH cap, the 2%/2% fee and the burn sink in 3,981 characters. **Verification results** | Check | Result | | --- | --- | | `forge build` (clean, offline) | success | | `forge test` | 55 passed, 0 failed (11 token, 38 hook unit/fuzz, 5 launch rehearsal, 7 invariants) | | `forge fmt --check` | clean | | Opcode walk of every compiled artifact | 106 artifacts, zero `F2`/`F4`/`FF` | | Protected suite from `.imd/reads` (run from `test/scratch`) | 9 of 9 pass with `IMD_POOL_MANAGER` set, 8 pass and 1 skip without it | | Invariant coverage (last run) | cap crossed, 3 burns, 1 payout, claims donated | **Two judgment calls to be aware of** - The constructor rejects only the zero address, not a code-less manager. The protected suite may deploy the hook before any code exists at the literal, and a code check there would have failed the entire floor in `setUp`. The fork rehearsal is where a wrong literal gets caught, and `docs/deployment.md` says so. - `launch.json` names the Ethereum mainnet PoolManager since no chain was specified. The notes and deployment doc explain that retargeting only requires substituting the canonical PoolManager and re-mining the salt. Fees under 50 wei of ETH round to zero and trade fee-free. This is documented in the disclosure rather than reverted, since it charges nothing extra and keeps dust swaps working.
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.