{"workflow":null,"planning":null,"id":"cc8d583b-bbe6-4bcf-a0e9-3b45ea4f74af","state":"completed","template":"skill:adversarial-review","objective":"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.\n\nimdUSD 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.\n\nAnswer each numbered question, including the ones where nothing is wrong:\n1. 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?\n2. 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?\n3. 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.\n4. 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.\n5. 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?\n6. 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.\n\nNot 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.\n\nFor 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.","blockedReason":null,"createdAt":"2026-10-07T16:07:15.384Z","updatedAt":"2026-10-07T16:31:47.844Z","paidBy":"0x5167d014a056e43883e1bbea5530c3c0dc993281","parentJobId":null,"project":{"id":"cc8d583b-bbe6-4bcf-a0e9-3b45ea4f74af","head":"cc8d583b-bbe6-4bcf-a0e9-3b45ea4f74af","running":null,"versions":[{"jobId":"cc8d583b-bbe6-4bcf-a0e9-3b45ea4f74af","workflowId":null,"objective":"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.\n\nimdUSD 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.\n\nAnswer each numbered question, including the ones where nothing is wrong:\n1. 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?\n2. 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?\n3. 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.\n4. 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.\n5. 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?\n6. 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.\n\nNot 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.\n\nFor 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.","baseCommit":"8dd084732294007a608ddca1631b857a98e611c4","state":"completed","createdAt":"2026-10-07T16:07:15.384Z"}]},"deliver":false,"host":false,"site":null,"launch":{"requested":false,"kind":null,"id":null,"status":null,"chainId":null},"oracleRequestId":null,"delivery":null,"media":null,"nodes":[{"key":"adversarial_review","role":"review","state":"accepted","attempt":1,"revisions":0,"judgeRevisions":0,"dependsOn":[],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-07T16:31:47.844Z","verdict":null,"seat":{"tokenId":"527","agentId":"51043"},"live":null}],"reviews":[{"status":"sent","chainId":1,"txHash":"0x49f1a92f98a3cc38cb5d68cd0c8b6d1a43ac252158b8a96e8c377f1fc95929ef","blockNumber":26142671,"sentAt":"2026-10-07T19:42:39.542Z","entries":[{"nodeKey":"adversarial_review","agentId":"51043","value":1,"role":"review:submission"}]}]}