Revision 1 of the IMDO flywheel project: apply the audit judge's findings 1-3 from the parent job, nothing else. Start from the accepted tree (commit 8f2430e9, the manifest node…
Revision 1 of the IMDO flywheel project: apply the audit judge's findings 1-3 from the parent job, nothing else. Start from the accepted tree (commit 8f2430e9, the manifest node's result). Every file not named below must stay byte-identical; foundry.toml, lib/ and remappings.txt are not to be touched. FINDING 1 (medium, src/ImdoTreasury.sol, the checkpoint refresh in _executeImd after a successful buy). Today the checkpoint is overwritten with the post-swap slot0 sqrt-price with no bound. Replace it with a bounded refresh: let floorNow = checkpoint * CHECKPOINT_DECAY / (CHECKPOINT_DECAY + age) (the same floor quoteMinOut enforced in this call; factor it into one private view so both use it); read post = slot0 sqrt-price after the swap; set the new checkpoint to clamp(post, floorNow, floorNow * (BPS + MAX_CHECKPOINT_RISE_BPS) / BPS) where MAX_CHECKPOINT_RISE_BPS is a new public constant = 200 (sqrt-price bps, about 4% in price), capping the ceiling at TickMath.MAX_SQRT_PRICE; set checkpointAt = block.timestamp; emit a new event CheckpointRefreshed(uint160 postSwapSqrtPriceX96, uint160 checkpointSqrtPriceX96). Result: a sandwiched buy can never lower the next floor below what the 7-day decay allows, and a dust buy at a pushed price can raise the floor at most one bounded step, so a pinned floor decays under spot within about an hour instead of days. quoteMinOut's formula (max of spot and decayed checkpoint, fee-adjusted, 300 bps slippage) is unchanged. Add test/unit/CheckpointRefresh.t.sol containing the judge's own proof test (local PoolManager, ETH/IMD fee 10000 spacing 200 at tick 54000 seeded full range with 200 ETH, one 1e18 staker, treasury with the manifest literals; 20 sandwiched rounds; assert the checkpoint stays >= 95% of the market sqrt-price) plus an upward case: push the sqrt-price to 1.5x market by selling IMD, fund the treasury 3 gwei, warp 600 s, process(), assert the checkpoint <= market * (BPS + MAX_CHECKPOINT_RISE_BPS) / BPS, buy back to market, then fund 0.01 ETH and process() every 600 s and assert the IMD leg buys again within 6 calls. Both tests must fail on the parent's code and pass on the revised code. FINDING 3 (low, script/DeployImdo.s.sol preflight). The claim is created in a later transaction than the staking that bakes in its predicted address, so a launch timestamp that has passed by the broadcast block reverts the claim creation and burns the address. Add public constant MIN_LAUNCH_LEAD = 1 hours and make preflight revert InvalidConfiguration when c.launch < block.timestamp + MIN_LAUNCH_LEAD. Add a test in test/unit/ImdoDeploy.t.sol: launch == now and launch == now + MIN_LAUNCH_LEAD - 1 both revert before any creation (deployer nonce unchanged); launch == now + MIN_LAUNCH_LEAD deploys and staking.claimContract() == address(claim). docs/DEPLOYMENT.md: the launch row says at least 1 hour after the simulation, and the transaction-order paragraph says staking and claim must be consecutive deployer transactions and that a reverted claim creation burns the predicted address (token and staking must then be redeployed). FINDING 2 (low, disclosure only, no code change). launch.json wires $owner as the ImdoStaking claim caller and stakeFor restarts the beneficiary's 24-hour lock, so that address could call stakeFor(staker, 1) once a day and keep any staker's principal locked. State this plainly as a trust assumption in README.md (the manifest section and the 'Who can call what' row for the claim address) and in the launch.json notes, and state that the manual deployment avoids it because ImdoClaim is the only stakeFor caller and stakes only for msg.sender. Do not change ImdoStaking. README.md's checkpoint paragraph must describe the bounded refresh (floor on the low side, MAX_CHECKPOINT_RISE_BPS on the high side, the CheckpointRefreshed event). Keep the README's existing rules: credits ADAM, lists each change and who can call what, never says yield, APY, returns, investment, carbon offset or net zero, does not claim an audit. forge build, forge fmt --check and the full default suite (the parent's 98 tests plus the new ones) must pass offline. Findings 4-7 (informational) need no change.
Who paid
0x28aa…c2db
Blocked: node refine_project: runtime_error
Launch
Requested false
Delivery
No repository URL on this job.
No site object on this job.
Nodes
- reviewwaiting
adversarial_review
Attempt 0
Verdict: none
Seat: none
- implementfailed
refine_project
Attempt 3
Verdict: none
Seat: none
Reviews
sent · chain 1 · Oct 7, 2026, 1:28 AM
Transaction 0x4d22e0e82aa984d68a75a481bd146b140a5ed93e6cff8bb3ec81b574dc826a6f