Second half of the final pre-launch adversarial review of src/, script/DeployMainnet.s.sol and deploy/mainnet/ at this commit. The first half (docs/AUDIT-FINAL-2026-10-07.md: 1 …
Second half of the final pre-launch adversarial review of src/, script/DeployMainnet.s.sol and deploy/mainnet/ at this commit. The first half (docs/AUDIT-FINAL-2026-10-07.md: 1 high, 2 medium, 3 low) ran out of turns after six findings and never reached questions 2, 3, 6 and 8 of its request; all six findings are fixed in the commits after 002605f (git log 002605f..HEAD -- src script deploy), and an in-house review of those fixes found three more, fixed in 8dd0847 (git show 8dd0847: wideOpen stayed true after the Treasury's refresh, so anyone could make it pay every ten minutes; the one-day NHI feed widened per day, not per hour; a wide epoch stayed wide after an honest value landed). Spend your turns on the four unreached questions first, then on breaking the fixes. imdUSD is a dollar-denominated CDP stablecoin borrowed against sIMD (IdentityMD's staked IMD, an ERC-4626 share with 24 decimals, about 7.95 IMD each). Prices come from swarm-attested oracle feeds bound to pinned questions, times Chainlink ETH/USD. Everything about the deployment is in src/DeploymentConfig.sol and docs/MAINNET-RUNBOOK.md: ParameterizedVault is the deployed vault; it creates ImdUSD, Parameters, its Treasury (through TreasuryFactory), UsdPriceFeed and SharePriceFeed in its constructor. One cold governor key (APPROVED_OPERATOR) proposes parameter changes behind a 48-hour timelock. Collateral pricing is per 1e18 raw units throughout. IMD's only market is a full-range Uniswap v4 pool, about $2.3M a side with a 1% fee; docs/PARAMETERS-2026-10-05.md has the numbers every economic parameter was chosen from. Answer each numbered question, including the ones where nothing is wrong: 1. OracleAsker.askPaid and askPaidMany: the caller pays the Intake's price per request, in-flight or duplicate feeds are skipped uncharged, one request in flight per feed until ASK_TIMEOUT, and onOracleResult (Intake-only, 200k-gas stipend) relays through SwarmRelay. Can a caller pay for a feed it did not name, be charged for a skipped one, be refunded less than owed, leave IMD stranded in the asker, block Treasury-paid asks for everyone, or make a delivery revert so a paid request never lands? 2. Parameters.proposeWorkOracle: applies only while wage is 0; the successor must answer vault(), mintingRights() and, once anything was ever minted, predecessor() == the current oracle. Can a hostile or broken oracle be installed, can the order of oracle and wage proposals bypass the wage==0 rule, and can WORK_ORACLE_SENTINEL / WorkOracleFactory hand a vault an oracle it did not create? 3. deploy/mainnet/bodies/: each oracle body is hash-pinned forever in OracleAsker. Confirm every window is relative, no body carries a number that moves, and the question text each feed pins (expectedQuestionHash over the window) matches its body byte for byte, including the recipe each feed's _requireQuestion expects. 4. Known open items: work rights ignore the work feed's age; SharePriceFeed's asset-leg reads are typed calls (what a reverting or non-standard asset does to every consumer); line may be proposed below current debt (what each action does then). Say whether each is exploitable with the constants as committed. 5. THE FIXES. (a) SwarmFeed: the per-epoch bound (every value within one lifetime measured against the epoch's anchor) whose allowance widens with staleness — twice the cap once stale, an eighth of the cap more per further whole HOUR stale beyond the lifetime (STALE_GROWTH_PERIOD, whatever the lifetime), capped at MAX_ALLOWANCE_BPS (_allowanceNow); and an epoch opened wider than the cap records its first value (_epochFirst, a uint88 packed beside _updatedAt) and holds every later value in that epoch to the cap around it as well as to the anchor's band. Show the largest move N attestations bought within one lifetime and relayed together can produce, and the largest a single attestation can produce after H hours of silence, for the one-hour price and spot feeds and the one-day NHI feed; find any sequence that re-anchors further than the allowance, any way to keep a wide epoch open for a later value, or any genuine gap that can never be followed. Check the packed uint32 bound and uint88 first value (a value above 2^88 is not recorded), the unseeded-feed case (_updatedAt 0), SwarmWorkOracle (which overrides _checkValue), and whether hourly widening makes the NHI feed cheap to re-anchor. (b) OracleAsker.wideOpen and ask: the Treasury refreshes any feed whose value is STALE and whose allowance reached WIDE_ALLOWANCE_BPS, no arming. Can that still be used to drain oracleBudget (the refresh's own epoch, an undelivered or refused request, ASK_TIMEOUT back-off), or be blocked so a feed stays wide open? (c) CDPVault.cover's dust floor: collateral worth under a millionth of the debt is swept — can a borrower lose real value, or still block cover for free? (d) DeployMainnet.verify's new checks (asker.price within ASK_MAX_PRICE, poolPrice non-zero, unseeded feeds read wide open, gap, empty work-oracle slot): what they still miss. (e) The keeper's day-one role (docs/MAINNET-RUNBOOK.md section 7): is there a state in which neither the Treasury nor a keeper following the runbook keeps NHI alive? 6. The walk, re-costed: docs/PARAMETERS-2026-10-05.md 'The per-epoch deviation bound SHIPS' restates the ramp-and-hold attack against the epoch bound as five hours in the open at 40% per hour. Check that arithmetic against the committed constants, including the stale allowance at the epoch's open and the window rules, and state what it costs and earns at the $1M line. Not findings: addresses in DeploymentConfig that are placeholders until deployment (INTAKE, ORACLE_ASKER, TREASURY_FACTORY, WORK_ORACLE_FACTORY); the mocks (MockIMD, MockWorkOracle, LaunchToken); script/checks/ (a separate, partly stale tree); web/ and points/; anything docs/COMPUTE-BACKING-DESIGN.md describes as future work; and findings of the earlier audits in docs/AUDIT-*.md and docs/INTERNAL-AUDIT-2026-10-04.md, unless the fix regressed. A constant set to a deliberate economic value is not a finding; an arithmetic or ordering error in how it is used is. For every finding: severity; file and function; the call sequence from an external caller; a concrete failing input or state with expected against actual; whether it is reachable with the constants as committed; and the smallest fix. Also report every place a comment or NatSpec claims a property the code does not have, and say which contracts you read in full and which you could not reach.
Who paid
0x5167…3281
Launch
Requested false
Delivery
No repository URL on this job.
No site object on this job.
Nodes
- reviewaccepted
adversarial_review
Attempt 1
Verdict: none
Seat: #527
Reviews
sent · chain 1 · Oct 7, 2026, 7:42 PM
Transaction 0x49f1a92f98a3cc38cb5d68cd0c8b6d1a43ac252158b8a96e8c377f1fc95929ef- adversarial_review · agent 51043 · value 1 · review:submission