{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"e4386fc8-fbea-430e-8ffa-e396b6affba4","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"a190c1018c64bd74e149554e5d466c7116eba7456b3fd379d76c000f2f3ac89d","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"75e85339a60f3615712bf51d6348af45fd5a217ad3f0c45279fefd6f977ce377","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"16e09ba764a19d29e16faad2ff0713ab2b00fc71a99101d6fd1d015f59e0311c","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"36a33d022b6469ade92054a0825d75350b5ceab722a3e0d661588ef577586832","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"3aebffb5d5a55d1acc235f20e1b720636d3bf633add453a37107e0e9b5fc72fb","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"79efecd98b9dbe5585666eb0deadd0204e9194f6e87cd03104882bb24af01406","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"74350399ec93c2e1d45ef71b4e383b9a1946232d69121f6c7fa5ac669be97e3d","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"19831760a86b2bbc115d1de386054a857f6c263d077286eef361ddb70408409f","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"# BLOOM V2.4 — MAINNET CONTRACTS, JOB 1/3\n\nBuild NEW, independent Solidity farming infrastructure for Ethereum Mainnet (chain 1). No old BLOOM code, deployments or Codex. Build complete source for Factory/registry, Treasury, reward accounting and three independent farms: stakedBLOOM (BLOOM), stakedSIMD (official sIMD), stakedETH (native ETH). No BLOOM token creation, liquidity or website in this job. No guessed parameters.\n\nASSETS: sIMD farm accepts official sIMD directly OR IMD via atomic official IMD-to-sIMD staking. Verify on-chain addresses, ABI, decimals, conversions, approvals, transferability, exchange-rate semantics and redemption restrictions. Measure actual net sIMD received, not 1:1 assumed; no DEX substitute. Default withdrawal delivers sIMD; offer IMD redemption only if atomic official redemption is supported, with minOut and revert on failure. If protocol is asynchronous, illiquid, locked or incompatible, disable that path and report dependency. Distinguish yield reflected in sIMD price from changes in sIMD token quantity; never invent rebasing behavior.\n\nSHARES: Each farm has isolated, internal, nontransferable fractional 18-decimal shares, one pool-wide exchange rate, and separately accounted underlying assets. Principal plus retained withdrawal fees back shares; reward funding and unpaid claims never back shares, especially in the BLOOM farm where asset and reward token match. Use precise mulDiv, explicit rounding, minSharesOut/minAssetsOut, zero-share rejection, virtual shares/assets against inflation, donation isolation, dust/residual accounting and safe zero-supply reset. No arbitrary admin rescue of user-backed assets. Support whitelisted future farms; no duplicates.\n\nFEES: Deposit fee 0%. Immediate partial/full withdrawals; no BLOOM-imposed lock, cooldown, daily boundary or fee-eligibility delay. On gross redeemed share-backed assets burn redeemed shares and pay 85% user, 1% Treasury, retain 14% in SAME farm to increase remaining share value. If zero shares remain, send full 15% to Treasury. Partial-withdrawal self-benefit and fee sniping are accepted; no address exclusion. Preserve exact accounting despite rounding and prevent fee-on-fee or double collection. Reward claims carry no withdrawal fee.\n\nREWARDS: Each farm has its own separately funded BLOOM reward budget, claimable when accrued without share redemption. Explicitly track free/unallocated funds, scheduled unvested funds, earned unpaid liabilities and paid rewards; never double count or pledge the same tokens twice. Use reward-per-share/debt with persistent user credits, settling BEFORE deposit, share burn, claim, allocation edits and epoch changes. Full exits retain accrued claims. Funding alone NEVER starts emission. Owner sets amounts, duration in days, boosts rates, Continues current epoch with adjusted remaining duration, or Restarts a new epoch. Preserve accrued claims; reschedule only genuinely available future budget, with solvency checks. During zero-staker intervals do not distribute retrospectively; return skipped emissions to unallocated reserve. Define epoch completion, top-ups, dust and excess funding recovery without touching obligations.\n\nETH: Accept native ETH; use verified canonical WETH only as necessary. Send native ETH to beneficiary on exit; if it fails, wrap and send WETH to SAME beneficiary without extra fee. If both fail, revert atomically. Handle forced ETH separately, use safe calls and nonreentrancy.\n\nADMIN: Owner/admin must be the verified requester wallet, never Swarm or a temporary deployer. Confirm address before broadcasting, initialize atomically or restrict initializers, transfer any temporary roles, and verify no worker retains privileges. Owner can whitelist assets, register farms, configure reward allocations/epochs, fund rewards, pause NEW deposits and selectively renounce roles; never auto-renounce. Pausing deposits must not block withdrawals or earned claims. Treasury can spend only fees it actually receives; no admin drain of principal/reward liabilities. Emit events for deposits, withdrawals, fees, claims, epochs, pauses and roles.\n\nTOKEN LATER: BLOOM token is created in Job 2. Produce complete source, ABIs and deployment scripts for all farms NOW. Deploy Factory/Treasury with confirmed inputs, but defer any BLOOM-dependent farm whose constructor needs a real token address. If using one-time owner-only binding instead, prevent initializer front-running and freeze token addresses after activation. Never use a dummy mainnet BLOOM. Keep public deposits/emissions disabled. Document activation: verify BLOOM -> deploy/bind -> fund -> configure -> enable deposits -> explicitly start emissions. No pre-start accrual.\n\nEXECUTION: Compile and run essential deterministic checks for share/fee conservation, partial/final exit, donation/rounding, reward solvency, full-exit claims, epoch changes, IMD integration, ETH fallback and ownership. No repeated audits. Obtain explicit user approval BEFORE EACH mainnet transaction; never request private keys or seed phrases. Deliver source, ABI, reproducible scripts, hashes, constructor inputs, verified links, deployed/pending components, tx receipts, gas, final roles and exact Job 2 dependencies. Never claim deployment without on-chain receipts.","parentJobId":null,"planHash":"4ddcc0e89125ca34cd8468e4f1f92f3ded1148fd57224419acb6534a25c14061","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"e4386fc8-fbea-430e-8ffa-e396b6affba4","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2389-bloom-v2-4"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51515","feedbackHash":"846915f043afaed36710b411b7b064d6e7884a41aadc30cb864bc9862d9248d8","nodeKey":"audit_economics","submissionHash":"a190c1018c64bd74e149554e5d466c7116eba7456b3fd379d76c000f2f3ac89d","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52481","feedbackHash":"721069cbab8acdee3e97b301c64ce8389ad9ae1a6bb431d076c97f124a35665d","nodeKey":"audit_flow","submissionHash":"75e85339a60f3615712bf51d6348af45fd5a217ad3f0c45279fefd6f977ce377","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51338","feedbackHash":"0243b2e6a12f66f8f41aed5d05355ec38cb29bc687ce1f04271a4d702db56506","nodeKey":"audit_judge","submissionHash":"16e09ba764a19d29e16faad2ff0713ab2b00fc71a99101d6fd1d015f59e0311c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51193","feedbackHash":"9e276cac2abfd9f6b1560480388375e396c879b47f24094749ae20daf4b843fa","nodeKey":"audit_judge","submissionHash":"d31f8ee3e46a3f573f003c1b98e838e04ed289d9a4b79f57ab7ebb9c5c1647f9","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52232","feedbackHash":"e74166e96b7a94aa014a3043506ed4b9e3917308c601ef3ddf907d0f18cc7f7f","nodeKey":"audit_math","submissionHash":"36a33d022b6469ade92054a0825d75350b5ceab722a3e0d661588ef577586832","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52240","feedbackHash":"405348caf2493f53f3bb756fcfb9103fec3a6162bfde7e0bb948a2b4ef2de8c7","nodeKey":"audit_permissions","submissionHash":"3aebffb5d5a55d1acc235f20e1b720636d3bf633add453a37107e0e9b5fc72fb","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52157","feedbackHash":"9fd76f1da7f5628f177271f519cac63729ddb56c92a53786d3097e4e4cfec38a","nodeKey":"build_contract_project","submissionHash":"79efecd98b9dbe5585666eb0deadd0204e9194f6e87cd03104882bb24af01406","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52143","feedbackHash":"a4a0afeb35cc4fb9780fbd656c0c5b983471d280d75d50f808aac6f4e7cfd7b4","nodeKey":"build_contract_project","submissionHash":"63f127784cac9a837e6f1f9188469124e2ac39015e7eebadb8d1d95f6f478a56","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52257","feedbackHash":"5a9ed11bf5a1512a932f62276b1eab982da2ee6f4c17d4eb6f85b41cc413d813","nodeKey":"manifest","submissionHash":"74350399ec93c2e1d45ef71b4e383b9a1946232d69121f6c7fa5ac669be97e3d","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51313","feedbackHash":"8c5bc9dbeee838515ba680b6510fc0b4731e8c3f7a7b402c33b57584c9862140","nodeKey":"manifest","submissionHash":"701d04979833b6cebd03a242130a3acf047879e272c6ec90e9011cb5a0e07a3e","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"50981","feedbackHash":"e8e18578d32519a7ed0f4ed9e682946998133045f17018a9397257986785e437","nodeKey":"write_foundry_tests","submissionHash":"19831760a86b2bbc115d1de386054a857f6c263d077286eef361ddb70408409f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52153","feedbackHash":"ad37c636c39cb90b6e7a79bb3f735055de0f94f4bdf89e7b605d086b1a55f640","nodeKey":"write_foundry_tests","submissionHash":"c2340795e0a6f006c57a759785edacd174491cf47e28d8861f03e5b94063c75f","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"e4b4f5831cc6e6b29d4f35b5becc0da5b9d8e8373864d3ae573bc18dc7d2f1cf","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"789312fc56d3f446","findings":[],"hash":"16e09ba764a19d29e16faad2ff0713ab2b00fc71a99101d6fd1d015f59e0311c","nodeId":"56f70d74-4ed4-4c4b-a5ba-ef6bc57ae6d7","outcome":"completed","summary":"The review is complete. Every finding from the previous round is fixed, and I found no new reproducible defect. The findings file at the repository root holds an empty findings list and a coverage row for all 89 entry points.\n\n**Settled findings**\n\n- **High, share inflation through the retained fee.** Fixed. The virtual position is now never below one million share quanta for every decimal count, with the initial one-token-equals-one-share rate preserved. All three attached proofs now pass. The one remaining failing test in the fd7288 proof fails at its own precondition, which asserted the victim mints exactly one share. The victim now mints 928,572 shares. My recheck confirmed the victim's backing stays within one quantum of their deposit, the victim's payout is at least 84.99 of 100, and the attacker ends below their starting balance in both the 100-token and 0.13-token scenarios, plus the no-attacker one-wei-holder variant.\n- **Medium, registration checked less than activation.** Fixed. The registry now calls the farm's new dependency check at registration, so a farm with wrong decimals or chain reverts before it can take an asset slot, and a CREATE2 deployment rolls back with the salt reusable. Both attached proofs pass.\n- **Low, WETH or Treasury as beneficiary.** Fixed. The base recipient filter rejects the Treasury, registry, underlying and reward token; the ETH farm also rejects WETH and the sIMD farm rejects IMD, on deposits, withdrawals, claims and recovery.\n- **Low, taxed deposits accepted but never withdrawable.** Fixed. The ERC20 deposit path and the IMD leg now revert on any inexact receipt, so taxed principal is refused up front.\n- **Low, whitelist as a second pause switch.** Fixed. The whitelist governs admission at registration only, so a renounced PAUSE power is final and epoch starts cannot be blocked through the registry.\n\n**Fresh pass on the revised code**\n\nI re-read the changed lines as new code and checked the static-analysis leads. The sanctioned residual, a later depositor's rounding loss of at most one quantum against a one-share holder, is bounded and unprofitable to set up because the inflater still pays the one percent and fifteen percent fees. I also confirmed that a non-final redemption can never exceed accounted assets for 6, 18 and 24 decimal offsets. The full project suite passes with 116 tests. Deployed sizes are all under the limit, and the manifest is schema-valid with one argument per constructor parameter and the Treasury referenced backward. The slither and aderyn lines are owner-gated paths, deliberate exactness checks, or guarded by the reentrancy lock, and none reproduced as a defect. I dropped the specialist's dust-level observation that a one-share redemption at rate one pays zero, since it is caller-selected, bounded by minAssetsOut, and worth one wei.\n\n**Trust assumptions, not findings:** owner-triggered renounceOwnership on any contract, and post-registration ownership divergence between farms and the registry.","treeHash":null,"usage":{"cachedInputTokens":1127001,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":22434,"runtime":"claude","turns":29,"wallClockMs":406462}},{"artifacts":[],"attempt":1,"bundleHash":"e6b8b4164da13c225768c7dc0e460a7a2448212e512c9106f0831cd0e408eafa","device":"5739ce0d803a43cd","findings":[],"hash":"19831760a86b2bbc115d1de386054a857f6c263d077286eef361ddb70408409f","nodeId":"8541dc90-6a52-48e1-a275-553546bd220f","outcome":"completed","summary":"The suite passes again: 117 of 117 tests, using the verifier's fuzz seed. Three of my earlier tests had broken because the implementation changed on purpose since my last round. I updated them to the new behaviour, added tests for the new checks, and changed only files under `test/`.\n\n**Updated tests**\n- **Taxed deposits** (`test/TokenFailures.t.sol`): a deposit where the farm receives nothing now reverts with `InexactTransfer` instead of `InvalidAmount`. I added a test for a 1% transfer tax: the deposit is refused, no tokens move and existing backing stays the same.\n- **Pause, not delisting** (`test/IntegrationFailures.t.sol`): removing an asset from the whitelist no longer stops deposits into an active farm, so the old \"disabled farm\" test now pauses the farm instead. A new test shows that delisting the sIMD asset still lets someone deposit.\n- **Dependency checks at registration**: the WETH check now expects registration itself to fail, both when WETH has no code and when its decimals are unset, and the asset slot stays free. A new test confirms `activate()` still re-checks if WETH's decimals change after registration. Another shows that both registration and activation refuse to run on the wrong chain.\n- **Payouts that would get stuck**: a new test confirms the farms refuse to pay or credit an address that would trap the funds. That covers WETH on the ETH farm, IMD and sIMD on the sIMD farm, and the Treasury, across deposit, withdrawal, claim and recovery of excess funds.\n\n**Invariant test** (`test/NetworkInvariants.t.sol`): the random-sequence handler skipped all deposits while an asset was delisted, which matched the old behaviour and left out cases that are now valid. Now only a paused farm blocks deposits, and in that case the handler checks that the deposit reverts with `DepositsPaused` and moves no assets. The invariant still passes over 256 runs with no unexpected reverts.\n\n`test/TESTING.md` is updated to match. I found no new defects in the revised implementation, so I wrote no `.imd-findings.json`. As before, the IMD, sIMD and WETH checks run against recorded copies of their mainnet bytecode on a local test chain, not a mainnet fork. Checks against live mainnet state are still to be done.","treeHash":"56a7f0ced8c070d41ebe62ae50f6c1be33f0c59e","usage":{"cachedInputTokens":1081306,"inputTokens":38,"model":"claude-opus-5-5","outputTokens":10659,"runtime":"claude","turns":20,"wallClockMs":336473}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"82692ab5f7f7e54e","findings":[{"citation":"resolved","description":"For 18- and 24-decimal assets (stakedBLOOM, stakedETH, stakedSIMD) the inflation guard is a single virtual share and a single virtual asset unit (Farm.sol:66-67). Donations are isolated, but the 14% retained withdrawal fee is not: a holder who deposits D and withdraws all but one share leaves 0.14*D of backing on that single share (Farm.sol:124,127,163). previewDeposit (Farm.sol:111) then prices new deposits at (0.14D+2)/2 per share, so any deposit below 0.07D reverts with ZeroShares and any deposit in [0.07D, 0.14D) is rounded down to exactly one share and loses up to half its value at entry to the existing holders and the virtual share. In OpenZeppelin-style vaults the attacker permanently loses the virtual share's slice, which is what makes the attack unprofitable; here previewRedeem gives the last holder the whole accountedAssets (Farm.sol:121-123), so the attacker recovers the virtual slice by exiting last and the round trip is net positive despite the 15% exit fee. Seam: precision (floor in previewDeposit) x boundary (1 share remaining) x invariant (a fresh deposit should be backed by its own amount). Cost to the attacker is only the 1% treasury fee on the first withdrawal. minSharesOut defends a careful user, but the project fixtures themselves use minSharesOut=1 and the brief asked for virtual shares/assets against inflation; a 6-decimal future farm would get a 1e12 share offset while the three launch farms get 1. Fix: use a real decimal offset for virtualShares on every asset (e.g. 1e6..1e9 shares per asset unit) and/or keep the virtual share's slice out of the last holder's gross, or at least enforce a minimum first-deposit / minimum-remaining-shares rule.","line":66,"path":"src/core/Farm.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {BloomFactory} from \"src/BloomFactory.sol\";\nimport {BloomTreasury} from \"src/BloomTreasury.sol\";\nimport {StakedBLOOM} from \"src/StakedBLOOM.sol\";\n\ncontract PlainToken is ERC20 {\n    constructor() ERC20(\"BLOOM\", \"BLOOM\") {}\n\n    function mint(address to, uint256 v) external {\n        _mint(to, v);\n    }\n}\n\n/// @notice A 1-share holder inflates the exchange rate with the retained 14% fee and later depositors\n/// lose most of their principal to rounding at entry; the virtual offset of one wei does not stop it\n/// and the last holder recovers the virtual share's value, so the attacker ends up in profit.\ncontract InflationProof is Test {\n    address owner = address(0xA11CE);\n    address attacker = address(0xBAD);\n    address victim = address(0xB1C);\n    BloomFactory registry;\n    BloomTreasury treasury;\n    PlainToken bloom;\n    StakedBLOOM farm;\n\n    function setUp() public {\n        vm.chainId(1);\n        vm.warp(1_800_000_000);\n        bloom = new PlainToken();\n        treasury = new BloomTreasury(owner);\n        registry = new BloomFactory(owner, address(treasury));\n        vm.startPrank(owner);\n        treasury.bindRegistry(address(registry));\n        registry.bindBloom(address(bloom));\n        registry.whitelistAsset(address(bloom), true);\n        vm.stopPrank();\n        farm = new StakedBLOOM(owner, address(registry), address(treasury), address(bloom), 18);\n        vm.startPrank(owner);\n        registry.registerFarm(address(farm));\n        farm.activate();\n        farm.setDepositsPaused(false);\n        vm.stopPrank();\n        bloom.mint(attacker, 1e18);\n        bloom.mint(victim, 0.13e18);\n        vm.prank(attacker);\n        bloom.approve(address(farm), type(uint256).max);\n        vm.prank(victim);\n        bloom.approve(address(farm), type(uint256).max);\n    }\n\n    function testLaterDepositorLosesPrincipalToRateInflation() public {\n        // 1. attacker deposits 1e18 and immediately withdraws all but one share.\n        vm.prank(attacker);\n        uint256 s = farm.deposit(1e18, attacker, 0);\n        vm.prank(attacker);\n        farm.withdraw(s - 1, payable(attacker), 0);\n        assertEq(farm.totalShares(), 1);\n        // 0.14e18 retained now backs a single share: rate ~0.07e18 per share for new deposits.\n        assertGe(farm.accountedAssets(), 0.14e18);\n\n        // 2. victim deposits 0.13e18 (no slippage bound, as the project's own fixtures do with minSharesOut=1).\n        vm.prank(victim);\n        uint256 vs = farm.deposit(0.13e18, victim, 1);\n        assertEq(vs, 1);\n        (uint256 gross,,,) = farm.previewRedeem(vs);\n        // Expected: a fresh deposit is backed by (almost) its full amount before any withdrawal fee.\n        // Actual: the victim's only share is backed by a third of the pool, 0.09e18 of the 0.13e18 paid.\n        assertGe(gross, 0.13e18 * 99 / 100, \"entry rounding loss exceeds 1%\");\n    }\n\n    function testAttackerProfitsWhenVictimExitsFirst() public {\n        vm.prank(attacker);\n        uint256 s = farm.deposit(1e18, attacker, 0);\n        vm.prank(attacker);\n        farm.withdraw(s - 1, payable(attacker), 0);\n        vm.prank(victim);\n        uint256 vs = farm.deposit(0.13e18, victim, 1);\n        vm.prank(victim);\n        farm.withdraw(vs, payable(victim), 0);\n        vm.prank(attacker);\n        farm.withdraw(1, payable(attacker), 0);\n        // Expected: a round trip through a 15% exit fee can never return more than was put in.\n        // Actual: attacker receives ~1.0137e18 for 1e18 staked; the surplus came from the victim.\n        assertLe(bloom.balanceOf(attacker), 1e18, \"attacker round trip is net positive\");\n    }\n}","reproduction":"StakedBLOOM, 18-decimal asset, fresh farm. 1) attacker deposit(1e18) -> 1e18 shares. 2) attacker withdraw(1e18-1 shares): gross 1e18-1, user 0.85e18-1, treasury 0.01e18-1, retained 0.14e18+1; totalShares=1, accountedAssets=0.14e18+2. 3) victim deposit(0.13e18, minSharesOut=1): previewDeposit = 0.13e18*2/(0.14e18+3) = 1 share. previewRedeem(1).gross = (0.27e18+3)/3 = 0.09e18+1. Expected: the victim share is backed by ~0.13e18 before any fee. Actual: backed by 0.09e18, 31% of principal lost at entry. 4) victim withdraw(1) receives 0.0765e18; attacker withdraw(1) as last holder receives 0.16371e18, total attacker balance 1.01371e18 > 1e18 staked. Expected: no round trip through the 15% exit fee is net positive. Proof file: test/scratch/Inflation.t.sol (both tests fail on current code).","severity":"medium","snippet":"        virtualAssets = assetDecimals_ > 18 ? 10 ** (assetDecimals_ - 18) : 1;\n        virtualShares = assetDecimals_ < 18 ? 10 ** (18 - assetDecimals_) : 1;","title":"Share-rate inflation via retained withdrawal fee: one-wei virtual offset plus last-holder-takes-all lets a 1-share holder skim later depositors"},{"citation":"resolved","description":"Deposits reject a zero-share result (Farm.sol:137 ZeroShares) but withdrawals have no symmetric guard: when gross*8500/10000 (Farm.sol:125) truncates to 0 the shares are still burned (Farm.sol:161-162) and the whole gross is booked as retained fee (Farm.sol:127,163). With the default minAssetsOut=0 the caller loses the shares and receives nothing. Boundary x precision seam: at exchange rate 1 (fresh 18-decimal farm) any 1-share redemption, and at rate r any redemption of fewer than ceil(1/(0.85 r)) shares, pays zero. Dust-scale value, user-triggered, so low. Fix: revert (e.g. ZeroAssets) when userAssets == 0 in withdraw, mirroring ZeroShares on deposit.","line":160,"path":"src/core/Farm.sol","reproduction":"StakedBLOOM fresh. a deposit(10) -> 10 shares; b deposit(10) -> 10 shares. a withdraw(1 share, a, minAssetsOut=0): previewRedeem(1) gross = 1*(20+1)/(20+1) = 1, userAssets = 0, treasury = 0, retained = 1. Actual: returns 0, a's shares 10 -> 9, accountedAssets stays 20, no transfer. Expected: the call reverts because it pays nothing, as deposit does for zero shares. Observed in test/scratch/Edges.t.sol testOneShareExitAtRateOne (log 'got for 1 share: 0').","severity":"low","snippet":"        if (userAmount < minAssetsOut) revert Slippage();","title":"withdraw lets a redemption whose user payout rounds to zero burn shares for nothing"}],"hash":"36a33d022b6469ade92054a0825d75350b5ceab722a3e0d661588ef577586832","nodeId":"653849bf-5a6c-465c-bf8d-827253e861e0","outcome":"completed","summary":"Both snippets match the tree, all 89 entry points have coverage rows, and the proof test fails on the current code for the stated reason.\n\n**Outcome:** two findings recorded in `.imd-findings.json`, with a coverage row for every listed entry point.\n\n**Finding 1, medium, share-rate inflation through the retained fee.** For the three launch farms the inflation guard is one virtual share and one virtual asset unit. A holder deposits D, withdraws all but one share, and the 14% retained fee leaves 0.14·D backing that single share. New deposits are then priced at roughly 0.07·D per share, so anything below 0.07·D reverts and anything up to 0.14·D rounds down to one share and loses up to half its value on entry. Because the last holder sweeps the whole accounted balance, the attacker also reclaims the virtual share's slice, which is the piece that normally makes this attack unprofitable. The proof test shows a victim's 0.13e18 deposit backed by only 0.09e18, and the attacker ending a round trip at 1.0137e18 for 1e18 staked despite the 15% exit fee. Proof is in `test/scratch/Inflation.t.sol`.\n\n**Finding 2, low, zero-payout share burn.** Withdrawals have no mirror of the deposit-side zero-share rejection: a one-share exit at rate one pays zero, burns the share, and books the whole gross as retained fee when minAssetsOut is left at zero.\n\n**What held under the Math Precision, Boundary and Numerical Gap guides:** fee split conserves gross exactly with the remainder going to retained, exchange rate never falls below its initial value for 6, 18 and 24 decimal assets, emission schedule is monotone and exact at segment end, reward fractions carry to 1e-36 and dust is released only at zero supply, rewardPerShare headroom is bounded, continueEpoch at the exact end reverts, zero-staker intervals go back to reserve, the sIMD hold blocks redemption only and not transfers, and forced ETH is isolated. Slither's leads on strict equalities, the modulo \"PRNG\", and timestamp comparisons were all traced and are benign.\n\n**Not reached:** no fork check of the pinned mainnet code hashes for IMD, sIMD and WETH, and the ownership and deployment-script rows are marked holds only insofar as nothing in my area touches them.","treeHash":null,"usage":{"cachedInputTokens":1966951,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":43841,"runtime":"claude","turns":35,"wallClockMs":629456}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"b0001bc8a5c908cd","findings":[{"citation":"resolved","description":"BloomFactory._register (reached from registerFarm and deployFarm) checks only owner/registry/treasury/rewardToken/active/depositsPaused. Farm.activate also checks block.chainid, IERC20Metadata(asset).decimals() == assetDecimals, and _verifyAsset (WETH/IMD/sIMD code hashes and decimals). A farm that passes _register but fails activate still gets isFarm[farm]=true and farmForAsset[asset]=farm. The factory has no unregister or replace path, so DuplicateFarm blocks every later farm for that asset. BloomTreasury.bindRegistry is also one-time, so the only fix is to redeploy both Factory and Treasury, and fees already received stay in the old Treasury. This breaks the brief's 'Support whitelisted future farms; no duplicates' for that asset. The repo's own testWrongChainAndDecimalsCannotActivate registers exactly such a farm. The same thing happens if the owner renounces CONFIG on a registered farm before calling activate. The guard gap: activate's decimals check is missing from _register. DeployBLOOMFarm.s.sol checks decimals, but deployFarm(bytes,bytes32) does not.","line":83,"path":"src/BloomFactory.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {BloomFactory} from \"src/BloomFactory.sol\";\nimport {BloomTreasury} from \"src/BloomTreasury.sol\";\nimport {StakedBLOOM} from \"src/StakedBLOOM.sol\";\n\ncontract Tok is ERC20 {\n    constructor() ERC20(\"B\", \"B\") {}\n}\n\n/// A farm that can never activate must not permanently occupy the asset's registry slot.\ncontract UnactivatableFarmSlotTest is Test {\n    address owner = address(0xA11CE);\n    Tok bloom;\n    BloomTreasury treasury;\n    BloomFactory registry;\n\n    function setUp() public {\n        vm.chainId(1);\n        bloom = new Tok(); // 18 decimals\n        treasury = new BloomTreasury(owner);\n        registry = new BloomFactory(owner, address(treasury));\n        vm.startPrank(owner);\n        treasury.bindRegistry(address(registry));\n        registry.bindBloom(address(bloom));\n        registry.whitelistAsset(address(bloom), true);\n        vm.stopPrank();\n    }\n\n    function _initCode(uint8 d) internal view returns (bytes memory) {\n        return abi.encodePacked(\n            type(StakedBLOOM).creationCode,\n            abi.encode(owner, address(registry), address(treasury), address(bloom), d)\n        );\n    }\n\n    function testCorrectFarmCanBeRegisteredAfterMisconfiguredOne() public {\n        vm.startPrank(owner);\n        // Wrong decimals: activate() can never succeed for this farm.\n        try registry.deployFarm(_initCode(6), bytes32(0)) {} catch {}\n        // Fails today with DuplicateFarm: the bad farm holds farmForAsset[BLOOM] forever.\n        address good = registry.deployFarm(_initCode(18), bytes32(uint256(1)));\n        vm.stopPrank();\n        assertEq(registry.farmForAsset(address(bloom)), good);\n    }\n}","reproduction":"State: Treasury and Factory are deployed and bound. bindBloom(BLOOM) is done, BLOOM has 18 decimals, and whitelistAsset(BLOOM,true) is done. 1) As owner, call deployFarm with StakedBLOOM initcode and constructor args (owner, registry, treasury, BLOOM, 6), salt 0. It succeeds and registers. 2) Call farm.activate() on chain 1. It reverts InvalidDependency, and every retry reverts the same way. 3) Call deployFarm with the correct StakedBLOOM initcode (decimals 18), salt 1. It reverts DuplicateFarm. Expected: either _register rejects the farm that cannot activate (for example by checking IERC20Metadata(asset).decimals()==assetDecimals and the same _verifyAsset preconditions), or the owner can replace a registered farm that was never activated and holds no deposits. Actual: the BLOOM farm slot is locked forever. The attached proof fails today with DuplicateFarm(). It passes once _register rejects a farm that cannot activate.","severity":"medium","snippet":"        if (isFarm[farm] || farmForAsset[underlying] != address(0)) revert DuplicateFarm();","title":"Registration checks less than activation: a farm that can never activate permanently occupies its asset slot, with no unregister"},{"citation":"resolved","description":"The brief lets the owner 'selectively renounce roles'. A farm's PAUSE power is meant to be the only way to stop new deposits. But _requireDepositAllowed also reads the factory whitelist, which BloomFactory.whitelistAsset controls under the factory's separate CONFIG power. So after farm.renouncePowers(PAUSE) while deposits are open, the owner (or a later factory owner after transferOwnership) can still stop all new deposits. Because _requireCanStart reuses the same check, they can also block startEpoch and restartEpoch, by calling whitelistAsset(asset,false). They can reopen both later by re-whitelisting. Users who rely on the renunciation get a weaker guarantee than the renounced bitmask advertises. The check is also asymmetric: continueEpoch skips _requireCanStart, so a running epoch can be rescheduled or boosted while deposits are closed, but a new one cannot be started. Withdrawals and claims are unaffected.","line":106,"path":"src/core/Farm.sol","reproduction":"1) Deploy a StakedBLOOM farm, register it, call activate() and setDepositsPaused(false). 2) As owner, call farm.renouncePowers(PAUSE). setDepositsPaused now reverts PowerRenounced(4). 3) As owner, call registry.whitelistAsset(BLOOM,false). 4) Alice calls farm.deposit(1e18, alice, 1) and it reverts DepositsPaused. startEpoch and restartEpoch also revert DepositsPaused. Expected: after PAUSE is renounced, no path can halt new deposits on that farm, or the renunciation docs state that the factory whitelist is a second pause switch. Actual: deposits are halted. This was verified in a local Foundry scratch test: after renouncePowers(4) and whitelistAsset(bloom,false), deposit reverted DepositsPaused().","severity":"low","snippet":"        if (depositsPaused || !IBloomRegistry(registry).isAssetWhitelisted(asset)) revert DepositsPaused();","title":"Renouncing PAUSE does not remove the ability to pause: factory whitelistAsset(asset,false) still stops deposits and epoch starts"}],"hash":"3aebffb5d5a55d1acc235f20e1b720636d3bf633add453a37107e0e9b5fc72fb","nodeId":"4f37b023-bfdc-4ec9-94d7-01d273e33e30","outcome":"completed","summary":"I found two permission defects in the farm code and none that let anyone take user funds. Both findings and a coverage row for every listed entry point (91 rows) are in `.imd-findings.json`. No repository files were changed; the scratch test directory has been removed.\n\n**Findings**\n\n1. **Medium: a farm that can never activate blocks its asset forever** (`src/BloomFactory.sol:83`).\n   - **Cause:** `_register` checks fewer things than `activate()`: it skips the chain id, `decimals() == assetDecimals` and the asset code-hash checks. A farm that fails those still gets registered.\n   - **No way back:** the factory has no way to unregister or replace a farm, and `bindRegistry` on the Treasury is one-time. The only fix is redeploying both Factory and Treasury, and fees already received stay in the old Treasury.\n   - **Reproduction:** call `deployFarm` with StakedBLOOM initcode using decimals 6 when BLOOM has 18. Registration succeeds, `activate()` always reverts `InvalidDependency`, and deploying the correct farm reverts `DuplicateFarm`.\n   - **Proof:** the attached Foundry test fails on the current code with `DuplicateFarm()` and passes once `_register` rejects such a farm.\n   - **Also:** the existing test `testWrongChainAndDecimalsCannotActivate` registers exactly such a farm.\n\n2. **Low: renouncing the pause power doesn't stop deposits from being paused** (`src/core/Farm.sol:106`).\n   - **Cause:** deposits also check the factory whitelist. After the owner calls `renouncePowers(PAUSE)` on a farm, `whitelistAsset(asset, false)` on the factory still halts new deposits. It also blocks `startEpoch` and `restartEpoch`.\n   - **Asymmetry:** `continueEpoch` skips that check, so a running epoch can still be changed while deposits are closed.\n   - **Unaffected:** withdrawals and claims keep working. I confirmed this one in a local scratch test.\n\n**Checked and holding**\n- **Owner-only actions:** every one is gated by owner plus an irreversible renounced-power bitmask. Ownership transfer takes two steps, and the one-time bindings can't be front-run.\n- **Admin recovery:** `recoverExcess`, `recoverUnallocatedRewards` and `spendFees` are each capped so they can't touch user principal or reward obligations. The Treasury can't spend donations.\n- **User paths:** neither withdraw nor claim depends on the pause, the whitelist or the activation flag.\n- **ETH payouts:** a payout capped at 50,000 gas runs under the reentrancy lock and falls back to WETH.\n\n**Static-analysis leads:** the arbitrary-send-eth, reentrancy-balance, weak-prng and strict-equality leads were traced. In each case the recipient is the caller's own chosen address or the call sits behind the owner check or the reentrancy lock, so none became a finding.\n\n**Not covered in depth:** detailed share and reward rounding math, which other reviewers own. User-input mistakes, such as naming the WETH or Treasury address as the payout address, are left out as user error.","treeHash":null,"usage":{"cachedInputTokens":1252281,"inputTokens":30,"model":"claude-opus-5-5","outputTokens":27041,"runtime":"claude","turns":16,"wallClockMs":317182}},{"artifacts":[],"attempt":1,"bundleHash":"e074be0b70eab37eaf2e09d79786380260b64ba3039f9d4e5ad9f7ed0beb99f8","device":"f138d40b9355e7bf","findings":[],"hash":"63f127784cac9a837e6f1f9188469124e2ac39015e7eebadb8d1d95f6f478a56","nodeId":"78bfde33-3c25-4c74-bdf6-ce9a78e3b2f2","outcome":"completed","summary":"Implemented the contracts, tests, ABIs, scripts, hashes, and [deployment handoff](/root/.identitymd/work/e4386fc8-fbea-430e-8ffa-e396b6affba4/78bfde33-3c25-4c74-bdf6-ce9a78e3b2f2/README.md).\n\n- `forge build`, `forge test` (**62 passed**), formatting, and artifact checks pass.\n- No mainnet transactions sent. Farms await the real Job 2 BLOOM token.\n- Immediate sIMD exits work; IMD redemption is disabled because of the [official one-block hold](https://pool4.imd.fun/docs).\n- Historical RPC replay required archive access; current-block verification succeeded.","treeHash":"d554b6f209cc90251b5b09308ea186be4f14b1ef","usage":{"cachedInputTokens":5599488,"inputTokens":177435,"model":"gpt-6-astra","outputTokens":78722,"runtime":"codex","turns":10,"wallClockMs":2371014}},{"artifacts":[],"attempt":1,"bundleHash":"e76bd9a443b786535456b51baa414df0d83424145259e35ee7eb9c9169ab78a5","device":"c4e8f98d7a2a37dc","findings":[],"hash":"701d04979833b6cebd03a242130a3acf047879e272c6ec90e9011cb5a0e07a3e","nodeId":"b936b166-c6c6-4641-a34c-c2132e51fe12","outcome":"completed","summary":"Created [launch.json](/home/imd/.identitymd/work/e4386fc8-fbea-430e-8ffa-e396b6affba4/b936b166-c6c6-4641-a34c-c2132e51fe12/launch.json) for `BloomTreasury`, then `BloomFactory`, with `$owner` and matching constructor arguments. Notes document deferred farms and Job 2 dependencies.\n\nChecks passed: manifest structure, compiled ABI matching, `forge build`, and all 62 tests using the required fuzz seed.\n\nOnly `launch.json` changed. No transactions broadcast.","treeHash":"672f29699cdf7f1e73b299b77852462aaed17046","usage":{"cachedInputTokens":189312,"inputTokens":38934,"model":"gpt-6-astra","outputTokens":2821,"runtime":"codex","turns":3,"wallClockMs":90086}},{"artifacts":[],"attempt":1,"bundleHash":"d740928db19d5062f3ad37a1e4e298d5893b74e2f695b5fb76ea96815eca7eda","device":"22c9b760d0a15149","findings":[],"hash":"74350399ec93c2e1d45ef71b4e383b9a1946232d69121f6c7fa5ac669be97e3d","nodeId":"b936b166-c6c6-4641-a34c-c2132e51fe12","outcome":"completed","summary":"The existing launch.json is correct and needs no change. This revision round listed no findings, and every check confirms the manifest as it stands.\n\n**What I verified**\n\n- **Schema**: launch.json has exactly kind, contracts and notes. Kind is evm_contracts. Notes are a single string of 1,791 characters, under the 4,000 limit.\n- **Contracts match the accepted source**: BloomTreasury takes one argument, the owner, written as $owner. BloomFactory takes the owner then the treasury address, written as $owner and $contract:BloomTreasury. Both names are unique, short identifiers, and the reference points backward.\n- **Ownership**: the Managed base assigns ownership from the explicit constructor argument, never from msg.sender or tx.origin, so the factory and the IMD launch wallet hold no role.\n- **Deferred farms are correctly omitted**: StakedBLOOM, StakedSIMD and StakedETH each require the real BLOOM address in their constructors. BLOOM is created in Job 2, and the brief forbids a placeholder token. The notes document the activation path through the one-time bindBloom and bindRegistry functions.\n- **Build and tests**: `forge build` succeeds and the full suite passes with the pinned fuzz seed. All 67 tests passed with 0 failures.\n- **Deployment rehearsal**: a scratch test deployed both contracts via create2 from a factory address in manifest order on chain id 1. Both report the requester wallet as owner, the factory stores the treasury address, and both runtimes are under the EIP-170 size limit. That scratch test lives in test/scratch and is not part of the submission.\n\n**Working tree**: clean. No file other than launch.json is part of the deliverable, and launch.json itself is unchanged from the accepted version.","treeHash":"38c43f7053308c31a6d533c41190bd07cadc4679","usage":{"cachedInputTokens":297881,"inputTokens":226,"model":"claude-fable-5-1","outputTokens":3950,"runtime":"claude","turns":8,"wallClockMs":66420}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a4e285247c6f8aed","findings":[{"citation":"resolved","description":"The share conversion uses a 1-wei virtual share/asset offset for 18-decimal assets (Farm.sol:66-67). That offset only defends against share-price inflation when the value captured by the virtual share is unredeemable, so the inflater loses at least what any victim loses. Two design choices break that assumption together. (1) The 14% retained withdrawal fee is a sanctioned way to raise accountedAssets without minting shares: deposit D, withdraw D-1 shares, and the single remaining share is backed by ~0.14*D. (2) previewRedeem's `last` branch pays the final holder the entire accountedAssets, so the value the virtual share took from every earlier (non-last) exit is handed to whoever exits last. An attacker who front-runs a pending deposit of V chooses D so the single remaining share is backed by just over V. The victim's V then mints exactly 1 share (floor(2V/(A+1)) = 1). When the victim exits before the attacker, the non-last formula gives them 1/(1+1+1) of the pool, i.e. one third is assigned to the virtual share; the attacker then exits last and receives all of it. Net: attacker profit > 0 after paying the 1% treasury fee twice, and the victim loses 43% of principal instead of the documented 15%. Reward accrual is also distorted in the poisoned state (1 share vs 1 share for unequal capital). The victim's minSharesOut would protect only if set from a pre-attack preview; a victim depositing into an already-poisoned farm previews 1 share, sets minSharesOut=1, and loses the same way. Assumption violated (First Principles): 'virtual offset residue is never a windfall' (docs/ACCOUNTING.md says the last redemption avoids residue 'becoming a windfall for the next depositor', but it becomes a windfall for the last exiter instead).","line":121,"path":"src/core/Farm.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {BloomFactory} from \"src/BloomFactory.sol\";\nimport {BloomTreasury} from \"src/BloomTreasury.sol\";\nimport {StakedBLOOM} from \"src/StakedBLOOM.sol\";\n\ncontract ProofToken is ERC20 {\n    constructor() ERC20(\"BLOOM\", \"BLOOM\") {}\n\n    function mint(address to, uint256 value) external {\n        _mint(to, value);\n    }\n}\n\n/// @notice Retained-fee inflation setup + last-holder-takes-all residual: a front-running attacker\n/// profits and the victim loses far more than the 15% withdrawal fee. The 1-wei virtual offset does\n/// not protect because the virtual share's dilution is paid back to whoever exits last.\ncontract InflationProofTest is Test {\n    address owner = address(0xA11CE);\n    address attacker = address(0xBAD);\n    address victim = address(0xB0B);\n    BloomFactory registry;\n    BloomTreasury treasury;\n    ProofToken bloom;\n    StakedBLOOM farm;\n\n    function setUp() public {\n        vm.chainId(1);\n        vm.warp(1_800_000_000);\n        bloom = new ProofToken();\n        treasury = new BloomTreasury(owner);\n        registry = new BloomFactory(owner, address(treasury));\n        vm.startPrank(owner);\n        treasury.bindRegistry(address(registry));\n        registry.bindBloom(address(bloom));\n        registry.whitelistAsset(address(bloom), true);\n        vm.stopPrank();\n        farm = new StakedBLOOM(owner, address(registry), address(treasury), address(bloom), 18);\n        vm.startPrank(owner);\n        registry.registerFarm(address(farm));\n        farm.activate();\n        farm.setDepositsPaused(false);\n        vm.stopPrank();\n        bloom.mint(attacker, 1e24);\n        bloom.mint(victim, 1e24);\n        vm.prank(attacker);\n        bloom.approve(address(farm), type(uint256).max);\n        vm.prank(victim);\n        bloom.approve(address(farm), type(uint256).max);\n    }\n\n    function testFrontRunInflationIsUnprofitableAndVictimOnlyPaysTheFee() public {\n        uint256 victimDeposit = 100 ether;\n        // Attacker sees the victim's 100 BLOOM deposit in the mempool and front-runs it:\n        // deposit D, withdraw all but one share. 14% of the gross stays as backing of the single\n        // remaining share, so accountedAssets lands just above the victim's deposit.\n        uint256 targetBacking = victimDeposit + 1;\n        uint256 attackerDeposit = (targetBacking - 1) * 100 / 14 + 2;\n        uint256 attackerBefore = bloom.balanceOf(attacker);\n        vm.startPrank(attacker);\n        uint256 attackerShares = farm.deposit(attackerDeposit, attacker, 0);\n        farm.withdraw(attackerShares - 1, payable(attacker), 0);\n        vm.stopPrank();\n\n        // Victim's deposit lands: 100 BLOOM mints a single share.\n        vm.prank(victim);\n        uint256 victimShares = farm.deposit(victimDeposit, victim, 0);\n\n        // Victim exits first (non-last path): the virtual share takes a third of the pool.\n        uint256 victimBefore = bloom.balanceOf(victim);\n        vm.prank(victim);\n        farm.withdraw(victimShares, payable(victim), 0);\n        uint256 victimOut = bloom.balanceOf(victim) - victimBefore;\n\n        // Attacker exits last and receives every residual unit, including the virtual-share dilution.\n        vm.prank(attacker);\n        farm.withdraw(1, payable(attacker), 0);\n        uint256 attackerAfter = bloom.balanceOf(attacker);\n\n        // Expected: the inflation setup must not be profitable, and the victim must lose no more than\n        // the documented 15% withdrawal fee (plus negligible rounding).\n        assertLe(attackerAfter, attackerBefore, \"attacker profits from retained-fee inflation setup\");\n        assertGe(\n            victimOut + victimDeposit / 1000,\n            victimDeposit * 85 / 100,\n            \"victim loses far more than the 15% withdrawal fee\"\n        );\n    }\n}","reproduction":"StakedBLOOM, 18-decimal BLOOM, empty farm. Victim will deposit V=100e18. Attacker front-runs: deposit(D=714_285_714_285_714_285_716, attacker, 0) -> D shares; withdraw(D-1, attacker, 0) -> accountedAssets = 100e18+2, totalShares = 1. Victim: deposit(100e18, victim, 0) -> previewDeposit = floor(100e18*2/(100e18+3)) = 1 share. Victim: withdraw(1, victim, 0): gross = 1*(200e18+3)/(2+1) = 66.67e18, user payout 56.67e18 (expected >= 85e18, i.e. only the 15% fee). Attacker: withdraw(1, attacker, 0) takes the `last` branch, gross = all remaining accountedAssets = 142.67e18, user 121.3e18. Attacker balance: 1,000,000e18 before -> 1,000,014.12e18 after (profit 14.12 BLOOM). Expected: inflation setup unprofitable and victim loses at most the 15% fee. Proof test test/scratch/InflationProof.t.sol fails on this tree with 'attacker profits from retained-fee inflation setup: 1000014123809523809523810 > 1000000000000000000000000'. A larger virtual share offset (e.g. 10^6 share quanta, as the official sIMD vault uses) makes the setup unprofitable and the victim's rounding loss negligible even with the last-holder rule; alternatively do not pay the virtual-share residue to the last holder. Verified fix direction: the same proof passes against a scratch copy of Farm.sol whose virtualShares is multiplied by 1e6 (attacker ends below their starting balance; victim keeps >= 84.9 of 100).","severity":"high","snippet":"        bool last = shares == totalShares;\n        gross = last\n            ? accountedAssets\n            : Math.mulDiv(shares, accountedAssets + virtualAssets, totalShares + virtualShares);","title":"Retained-fee inflation setup is profitable: last-holder residual windfall returns the virtual-share dilution to the attacker, victim loses ~28% beyond the fee"},{"citation":"resolved","description":"Farm.withdraw pays the fee through Farm._payFee (which reverts on `received != amount`, Farm.sol:222) and the user through _sendExact, which requires both the farm debit and the recipient credit to equal `amount` exactly. The brief allows the owner to whitelist future ERC20 farms. If a whitelisted asset later enables an outbound transfer tax, a transfer-size cap or a blacklist (upgradeable or owner-configurable tokens are common), every withdraw reverts for every holder, including the final-exit path. recoverExcess cannot help because excessBalance subtracts accountedAssets. There is no tax-tolerant or partial-exit path, so principal is unrecoverable for as long as the token behaves that way. The deposit side already measures net receipt and tolerates inbound taxes, so the asymmetry is between deposit (tolerant) and withdraw (strict). This is documented as 'unsupported outbound tax' in the tests, so it is reported as a design limitation with a concrete locking input rather than a bypass.","line":287,"path":"src/core/RewardLedger.sol","reproduction":"ERC20Farm with a MockToken-style asset. alice deposit(100e18, alice, 1) succeeds (net receipt measured). Token owner sets a 1% outbound fee (bloom.setFee(100) in test/helpers/Fixtures.sol MockToken). alice withdraw(100e18, alice, 0) reverts (treasury receiveTokenFee sees received != amount; _sendExact would also revert). Expected: a holder can always exit at least net of the token's own tax; actual: no holder can exit while the tax is on, and owner has no path to release accountedAssets. The existing test testMeasuredNetDepositAndUnsupportedOutboundTaxRevert demonstrates the revert; it does not test that funds remain reachable if the tax is never turned off.","severity":"low","snippet":"        if (\n            beforeSelf - IERC20(token).balanceOf(address(this)) != amount\n                || IERC20(token).balanceOf(recipient) - beforeRecipient != amount\n        ) revert InexactTransfer();","title":"An asset that starts taxing or blocking outbound transfers permanently locks all principal: every exit path reverts and no recovery of accounted assets exists"}],"hash":"75e85339a60f3615712bf51d6348af45fd5a217ad3f0c45279fefd6f977ce377","nodeId":"d70b0a4e-ae81-4c28-8041-fac8d198b830","outcome":"completed","summary":"The review is complete and the findings are written to `.imd-findings.json`.\n\n**What I found**\n\n- **High: retained-fee inflation attack is profitable** (`src/core/Farm.sol:121`). The farm uses a 1-wei virtual share offset. That defense only works if the value absorbed by the virtual share is never paid out. Here it is: the \"last holder takes all residual\" branch of `previewRedeem` hands that value to whoever exits last. An attacker front-runs a 100 BLOOM deposit by depositing ~714 BLOOM and withdrawing all but one share, so the 14% retained fee leaves a single share backed by just over 100 BLOOM. The victim's deposit mints exactly 1 share. If the victim exits before the attacker, they receive 56.67 BLOOM instead of 85, and the attacker exits last with a net profit of about 14 BLOOM. The proof test in `test/scratch/InflationProof.t.sol` fails on the current tree and passes against a scratch copy with a 10^6 virtual-share offset, so the fix direction is confirmed.\n- **Low: a whitelisted asset that later taxes or blocks outbound transfers locks all principal.** Deposits tolerate inbound taxes, but both the fee path and the user payout require exact transfers, and no recovery path can reach accounted assets. This matches the authors' own \"unsupported\" test, so it is reported as a documented design limitation with a concrete locking input.\n\n**What held**\n\nEverything else in the Execution Trace, Periphery and First Principles checklists traced clean: reward settlement ordering, zero-staker skipping, epoch state transitions, dust release at zero supply, the ETH native-then-WETH fallback, the atomic IMD-to-sIMD path with measured receipt and approval reset, treasury fee gating, two-step ownership and selective power renunciation. All slither and aderyn leads were examined and none survived as findings. The existing 61 unit tests pass, and my probe of zero-staker epoch completion followed by re-entry conserved every reward unit.\n\n**Coverage**\n\nAll 90 listed entry points have a row. The deposit and withdraw entry points on every farm reference finding 1 since they share the affected conversion code. The rest are marked as holding, plus three rows for invariants and the static-analysis leads. No source file was changed. Only `.imd-findings.json` and the scratch tests under `test/scratch/` were written.","treeHash":null,"usage":{"cachedInputTokens":2077112,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":51909,"runtime":"claude","turns":41,"wallClockMs":759723}},{"artifacts":[],"attempt":1,"bundleHash":"d6ff0bf3579108d0f92863d62866b7f4a3b0346953fc5d8ad08d82a0e9942a1b","device":"37eed9f56188ea8b","findings":[],"hash":"79efecd98b9dbe5585666eb0deadd0204e9194f6e87cd03104882bb24af01406","nodeId":"78bfde33-3c25-4c74-bdf6-ce9a78e3b2f2","outcome":"completed","summary":"Both mandatory findings reproduced and are fixed; the three advisory findings also reproduced and are fixed. All checks pass.\n\n**What changed**\n\n- **Share inflation (high).** `Farm` now keeps the virtual position at no less than one million share quanta for every asset. The pivot moved from 18 to 12 decimals, so BLOOM and ETH use a 1e6/1e6 offset and sIMD uses 1e12/1e6, while the initial rate stays one whole token per whole share. A later depositor's rounding loss is now bounded by one quantum, at most a millionth of the backing, and the inflater still pays the Treasury 1% plus 15% of its retained backing on exit. The last-holder residual rule is unchanged and the bound is documented in `docs/ACCOUNTING.md`.\n- **Registry slot (medium).** `Farm.verifyDependencies()` now holds every activation precondition except registry membership, and `BloomFactory._register` calls it for both `registerFarm` and `deployFarm`. A farm with wrong decimals or on the wrong chain is refused at registration, the CREATE2 creation is rolled back, and the correct farm can take the slot.\n- **Stranding beneficiaries (low).** Recipients that would strand a payout are rejected before any state change: Treasury, registry, underlying and reward tokens, plus WETH for the ETH farm and IMD for the sIMD farm.\n- **Taxed deposits (low).** ERC20 deposits and the IMD leg of `depositIMD` revert unless the exact amount arrives, so a taxed token can never hold principal it could not pay back.\n- **Whitelist as second pause (low).** Active farms no longer read the whitelist for deposits or epoch starts. The whitelist admits assets at registration only, so renouncing the pause power is final.\n\n**Verification**\n\n| Check | Result |\n|---|---|\n| `forge build` | pass |\n| `forge test` with the verifier seed | 67 delivered tests pass, plus both reviewer proofs from `test/scratch/` |\n| `forge fmt --check` | pass |\n| `scripts/export_artifacts.py --check` | ABIs and hashes regenerated and matching |\n\nTests I rewrote or added cover the proof scenario, the no-attacker one-wei-holder variant, offset values per decimal count, registration refusal via both factory paths, rejected recipients on all three farms, taxed deposit refusal, and whitelist-after-renounce semantics. README, ACCOUNTING, DEPLOYMENT and VALIDATION are updated, and `.imd-responses.json` answers all five findings as fixed.","treeHash":"0d1ca8cf071028d77582f2dcba5a32b4276822b5","usage":{"cachedInputTokens":2118785,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":53267,"runtime":"claude","turns":69,"wallClockMs":765824}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ea89e16822824c6f","findings":[{"citation":"resolved","description":"_validRecipient (src/core/RewardLedger.sol:294) only rejects address(0) and the farm itself. Two reachable beneficiaries make the native-then-WETH delivery path end with the user's 85% held by a party that cannot or will not return it. (1) beneficiary == WETH: the 50k-gas native call succeeds because WETH9's fallback is deposit(), so the user's ETH is converted into WETH credited to the FARM, not the user; it shows up as excessBalance(WETH) and only the owner's recoverExcess can move it. (2) beneficiary == treasury: BloomTreasury has no receive(), so the native call fails, the farm wraps and transfers WETH to the Treasury, where availableFees(WETH) stays 0 forever and spendFees cannot release it. In both cases the withdrawal reports success, shares are burned and the 15% fee is collected, while the principal is unrecoverable by the user. This is user-selected input, so impact is limited to the caller, but the contract advertises a guaranteed delivery to the beneficiary and a one-line check prevents both traps.","line":53,"path":"src/StakedETH.sol","reproduction":"Setup as test/ETH.t.sol (etch WETH9, activate StakedETH, unpause). alice: deposit{value:10 ether}(alice,1) -> 10e18 shares. alice: withdraw(10e18, payable(WETH), 0). Expected: alice (or the named beneficiary) controls 8.5 ether. Actual: IERC20(WETH).balanceOf(farm) == 8.5e18 and farm.excessBalance(WETH) == 8.5e18; alice receives nothing. Variant: withdraw(10e18, payable(address(treasury)), 0) -> IERC20(WETH).balanceOf(treasury) == 8.5e18, treasury.availableFees(WETH) == 0, treasury.balance == 1.5e18 (the fee). Reproduced in test/scratch/Probe2.t.sol testBeneficiaryWETH/testBeneficiaryTreasury (logs: farm WETH 8500000000000000000, excess WETH 8500000000000000000; treasury WETH 8500000000000000000, available 0). Fix: in StakedETH, reject beneficiary == WETH and beneficiary == treasury (or override _validRecipient).","severity":"low","snippet":"        uint256 beforeWETH = IERC20(WETH).balanceOf(address(this));\n        IWETH(WETH).deposit{value: amount}();\n        if (IERC20(WETH).balanceOf(address(this)) - beforeWETH != amount) revert InexactTransfer();\n        _sendExact(WETH, beneficiary, amount);","title":"StakedETH.withdraw strands the user payout when beneficiary is the WETH contract or the Treasury"},{"citation":"resolved","description":"The pinned sIMD runtime (docs/evidence/simd-verification.json, code hash re-verified against mainnet 0xe8333e...80e5 during this review) exposes an owner setPaused that makes maxDeposit return 0 and reverts deposit/redeem, and an owner rescue function for arbitrary tokens. While paused, depositIMD reverts (correct: the direct sIMD path and sIMD withdrawals keep working, so no farm funds are stuck). The rescue power can change the IMD value behind the farm's sIMD units without changing accountedAssets; the farm correctly accounts units, not value. No code change is required; this is recorded so the judge has the trust assumption explicit. Not a defect in this code.","line":41,"path":"src/StakedSIMD.sol","reproduction":"vm.etch official runtime; owner of vault calls setPaused(true); alice.depositIMD(100 ether, alice, 1, 1) reverts (vault DepositMoreThanMax/EnforcedPause); alice.deposit(sIMD) and withdraw still succeed. Expected and actual match; informational only.","severity":"info","snippet":"        IStakedIMD(asset).deposit(receivedIMD, address(this));","title":"Official sIMD vault owner powers (pause, rescue) are an external dependency on StakedSIMD value, documented but not enforceable by the farm"},{"citation":"resolved","description":"FarmInvariantTest and testFuzzWithdrawConservation run only against StakedBLOOM with an 18-decimal mock, so the virtualAssets=1e6 branch used by the real sIMD farm and the native-ETH payout branch are covered by fixed-value unit tests only. During this review a scratch fuzz over decimals 0..36 with three users, two partial exits and a full drain (test/scratch/Probe.t.sol, 600 runs) and a reward-ledger claimability fuzz (test/scratch/Probe2.t.sol, 1000 runs) found no violation: deposits == payouts + treasury, farm balance 0 at zero supply, all reward units paid or returned to free reserve. Reported as a coverage note, not a defect.","line":108,"path":"test/Invariants.t.sol","reproduction":"Run forge test --match-path test/scratch/Probe.t.sol --fuzz-runs 600: passes. The delivered suite has no equivalent for assetDecimals != 18 or for StakedETH.","severity":"info","snippet":"        handler = new FarmHandler(farm, treasury, bloom, owner, [alice, bob, carol]);","title":"Delivered invariant/fuzz suite only exercises an 18-decimal mock; 24-decimal (sIMD) and native ETH farms lack conservation fuzzing"}],"hash":"a190c1018c64bd74e149554e5d466c7116eba7456b3fd379d76c000f2f3ac89d","nodeId":"a1cd00d1-788c-448d-8427-917bf2403626","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds the findings and a full coverage record (89 rows, all entry points answered). No repository file was changed; the only writes are the findings file and expendable scratch tests.\n\n**Outcome of the economics audit (Economic Security, Invariant, Flow Gap)**\n\nNo critical, high or medium defect survived verification. The share and reward ledgers behave as specified under every sequence I could construct.\n\n- **Share and fee conservation holds.** A scratch fuzz across all asset decimals 0 to 36, with three users, partial exits and a full drain, confirmed deposits always equal payouts plus Treasury fees, and the farm balance is zero when supply is zero. The 85/1/14 split, the last-exit full 15 percent to Treasury, and virtual-offset rounding all reconcile exactly.\n- **Reward ledger is solvent and non-double-pledging.** A second fuzz over staggered deposits, partial burns and full exits showed every funded unit is either paid or returned to the free reserve, with earned liabilities and credits reaching zero at zero supply. A single-quantum staker across 20 epochs stays claimable with the index far from its cap.\n- **External dependencies verified.** The pinned IMD, sIMD and WETH code hashes in the source match mainnet (checked by RPC during the review). The IMD-to-sIMD deposit path measures actual sIMD received, clears approval and reverts cleanly if the vault is paused, while direct sIMD exits are unaffected.\n\n**Findings written**\n\n1. **Low.** `StakedETH.withdraw` strands the payout when the beneficiary is the WETH contract or the Treasury. WETH's fallback accepts the native call and credits the farm, or the Treasury has no receive function and ends up holding WETH it can never spend. Reproduced with concrete balances in scratch tests. The fix is a one-line beneficiary check.\n2. **Info.** The official sIMD vault's owner pause and rescue powers are an external trust assumption on value, not units. The farm handles them correctly, recorded so the judge has it explicit.\n3. **Info.** The delivered invariant and fuzz suite covers only the 18-decimal mock; the 24-decimal and native ETH branches rely on fixed-value unit tests. My scratch fuzzing covered those branches and found nothing.\n\nCoverage: 88 entry points marked holds, one (StakedETH.withdraw) marked finding. Admin-only functions outside my area were traced for guards and marked holds with that reason. Nothing was left unreached.","treeHash":null,"usage":{"cachedInputTokens":1983650,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":47819,"runtime":"claude","turns":45,"wallClockMs":748674}},{"artifacts":[],"attempt":1,"bundleHash":"122ea54526020ffd45f587daf39081b3211c7ba64b33565c99c5728ee3acefd3","device":"943650541094145e","findings":[],"hash":"c2340795e0a6f006c57a759785edacd174491cf47e28d8861f03e5b94063c75f","nodeId":"8541dc90-6a52-48e1-a275-553546bd220f","outcome":"completed","summary":"Added 45 tests under `test/`, covering failure paths, rounding, permissions, integrations, and invariants across all three farms and Treasury.\n\nValidation passed:\n- `forge build`\n- `forge test`: **107 passed**, using the required seed\n- New invariants: **24,576 randomized calls**, zero unexpected reverts\n\nNo production defect was reproduced. Integration tests run offline; live-state validation remains pending.","treeHash":"d5fc8acfe73594186a9a00049759d41acb3e311e","usage":{"cachedInputTokens":3692544,"inputTokens":153439,"model":"gpt-6-astra","outputTokens":35365,"runtime":"codex","turns":8,"wallClockMs":1035786}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fedfd42dfee2f4e6","findings":[{"citation":"resolved","description":"For the three launch farms (18-decimal BLOOM and ETH, 24-decimal sIMD) the offset is a single virtual share (Farm.sol:66-67). Donations are isolated, but the 14% retained withdrawal fee is a sanctioned way to raise accountedAssets without minting shares. If a holder exits all but one share, or a 1-wei holder stays in after a large exit, a single share is left backed by about 14% of the exited gross. previewDeposit (Farm.sol:111) rounds the next deposit down to whole shares at that coarse price. A deposit V below about half the backing reverts ZeroShares. A deposit at or just above the backing mints exactly 1 share, and up to half of its value is lost at entry to the existing holder and the virtual share. In an OpenZeppelin-style vault the inflater permanently loses the virtual share's slice, which makes the attack unprofitable. Here previewRedeem's `last` branch (Farm.sol:121-123, `? accountedAssets`) pays the whole remaining accountedAssets to the final exiter, so the inflater gets the virtual slice back by exiting last. minSharesOut does not help a victim who quotes from the poisoned state, where the preview is honestly 1 share. The state also occurs without any attacker. This breaks the brief's requirements for virtual shares/assets against inflation and for precise accounting. The 15% fee becomes a loss of about 30-43% for the victim. Fix: use a real decimal offset for virtualShares on every asset (for example 1e6 or more share quanta per asset unit), and/or keep the virtual share's slice out of the last holder's gross. The fe1685 author reports the attached proof passes with virtualShares multiplied by 1e6.","line":67,"path":"src/core/Farm.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {BloomFactory} from \"src/BloomFactory.sol\";\nimport {BloomTreasury} from \"src/BloomTreasury.sol\";\nimport {StakedBLOOM} from \"src/StakedBLOOM.sol\";\n\ncontract ProofToken is ERC20 {\n    constructor() ERC20(\"BLOOM\", \"BLOOM\") {}\n\n    function mint(address to, uint256 value) external {\n        _mint(to, value);\n    }\n}\n\n/// @notice Retained-fee inflation setup + last-holder-takes-all residual: a front-running attacker\n/// profits and the victim loses far more than the 15% withdrawal fee. The 1-wei virtual offset does\n/// not protect because the virtual share's dilution is paid back to whoever exits last.\ncontract InflationProofTest is Test {\n    address owner = address(0xA11CE);\n    address attacker = address(0xBAD);\n    address victim = address(0xB0B);\n    BloomFactory registry;\n    BloomTreasury treasury;\n    ProofToken bloom;\n    StakedBLOOM farm;\n\n    function setUp() public {\n        vm.chainId(1);\n        vm.warp(1_800_000_000);\n        bloom = new ProofToken();\n        treasury = new BloomTreasury(owner);\n        registry = new BloomFactory(owner, address(treasury));\n        vm.startPrank(owner);\n        treasury.bindRegistry(address(registry));\n        registry.bindBloom(address(bloom));\n        registry.whitelistAsset(address(bloom), true);\n        vm.stopPrank();\n        farm = new StakedBLOOM(owner, address(registry), address(treasury), address(bloom), 18);\n        vm.startPrank(owner);\n        registry.registerFarm(address(farm));\n        farm.activate();\n        farm.setDepositsPaused(false);\n        vm.stopPrank();\n        bloom.mint(attacker, 1e24);\n        bloom.mint(victim, 1e24);\n        vm.prank(attacker);\n        bloom.approve(address(farm), type(uint256).max);\n        vm.prank(victim);\n        bloom.approve(address(farm), type(uint256).max);\n    }\n\n    function testFrontRunInflationIsUnprofitableAndVictimOnlyPaysTheFee() public {\n        uint256 victimDeposit = 100 ether;\n        // Attacker sees the victim's 100 BLOOM deposit in the mempool and front-runs it:\n        // deposit D, withdraw all but one share. 14% of the gross stays as backing of the single\n        // remaining share, so accountedAssets lands just above the victim's deposit.\n        uint256 targetBacking = victimDeposit + 1;\n        uint256 attackerDeposit = (targetBacking - 1) * 100 / 14 + 2;\n        uint256 attackerBefore = bloom.balanceOf(attacker);\n        vm.startPrank(attacker);\n        uint256 attackerShares = farm.deposit(attackerDeposit, attacker, 0);\n        farm.withdraw(attackerShares - 1, payable(attacker), 0);\n        vm.stopPrank();\n\n        // Victim's deposit lands: 100 BLOOM mints a single share.\n        vm.prank(victim);\n        uint256 victimShares = farm.deposit(victimDeposit, victim, 0);\n\n        // Victim exits first (non-last path): the virtual share takes a third of the pool.\n        uint256 victimBefore = bloom.balanceOf(victim);\n        vm.prank(victim);\n        farm.withdraw(victimShares, payable(victim), 0);\n        uint256 victimOut = bloom.balanceOf(victim) - victimBefore;\n\n        // Attacker exits last and receives every residual unit, including the virtual-share dilution.\n        vm.prank(attacker);\n        farm.withdraw(1, payable(attacker), 0);\n        uint256 attackerAfter = bloom.balanceOf(attacker);\n\n        // Expected: the inflation setup must not be profitable, and the victim must lose no more than\n        // the documented 15% withdrawal fee (plus negligible rounding).\n        assertLe(attackerAfter, attackerBefore, \"attacker profits from retained-fee inflation setup\");\n        assertGe(\n            victimOut + victimDeposit / 1000,\n            victimDeposit * 85 / 100,\n            \"victim loses far more than the 15% withdrawal fee\"\n        );\n    }\n}","reproduction":"StakedBLOOM, 18-decimal BLOOM, empty active farm (proof below; run with forge test --match-path, it fails on this tree). Victim will deposit V=100e18. Attacker front-runs with deposit(714285714285714285716, attacker, 0) and then withdraw(D-1 shares), leaving totalShares=1 and accountedAssets=100e18+2. Victim deposit(100e18, victim, 0) mints floor(100e18*2/(100e18+3)) = 1 share. Victim withdraw(1) is non-last: gross=(200e18+3)/3=66.67e18, victim receives 56.67e18 (expected >= 85e18). Attacker withdraw(1) takes the last branch: gross=142.67e18. Attacker balance goes 1,000,000e18 -> 1,000,014.12e18; observed failure: 'attacker profits from retained-fee inflation setup: 1000014123809523809523810 > 1000000000000000000000000'. The fd7288 proof also fails on this tree: attacker round trip 1.01371e18 > 1e18 staked, and the victim's 0.13e18 deposit is backed by 0.09e18. No-attacker variant (my scratch test, passes on this tree, showing the state): bob deposit(1 wei), alice deposit(100e18), then alice withdraw(100e18 shares) leaves bob 1 share with accountedAssets=14e18+1. carol deposit(10e18, minSharesOut=1) gets 1 share, and previewRedeem(1).gross = 8e18, so 2e18 (20%) is lost at entry before any fee.","severity":"high","snippet":"        virtualShares = assetDecimals_ < 18 ? 10 ** (18 - assetDecimals_) : 1;","title":"Share inflation through the retained 14% fee: a 1-unit virtual share offset combined with last-holder-takes-all lets a 1-share holder skim later depositors (merges audit_flow fe1685 and audit_math fd7"},{"citation":"resolved","description":"_register (reached from registerFarm and deployFarm) checks owner/registry/treasury/rewardToken/active/depositsPaused. Farm.activate (Farm.sol:71-88) also requires IERC20Metadata(asset).decimals()==assetDecimals, block.chainid==1 and _verifyAsset (code hashes, WETH/IMD decimals). StakedBLOOM takes bloomDecimals_ as a free constructor argument that nothing checks before registration. A farm that registers but cannot activate still sets isFarm and farmForAsset[asset] forever. Every later farm for that asset reverts DuplicateFarm. BloomTreasury.bindRegistry is one-time, so recovery requires redeploying both Factory and Treasury, and fees already received stay in the old Treasury. This breaks 'Support whitelisted future farms; no duplicates' for that asset (BLOOM, sIMD or ETH). Fix: check IERC20Metadata(asset).decimals()==assetDecimals (and the farm's _verifyAsset preconditions) in _register, or allow the owner to replace a registered farm that is not active and has totalShares==0.","line":83,"path":"src/BloomFactory.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {BloomFactory} from \"src/BloomFactory.sol\";\nimport {BloomTreasury} from \"src/BloomTreasury.sol\";\nimport {StakedBLOOM} from \"src/StakedBLOOM.sol\";\n\ncontract Tok is ERC20 {\n    constructor() ERC20(\"B\", \"B\") {}\n}\n\n/// A farm that can never activate must not permanently occupy the asset's registry slot.\ncontract UnactivatableFarmSlotTest is Test {\n    address owner = address(0xA11CE);\n    Tok bloom;\n    BloomTreasury treasury;\n    BloomFactory registry;\n\n    function setUp() public {\n        vm.chainId(1);\n        bloom = new Tok(); // 18 decimals\n        treasury = new BloomTreasury(owner);\n        registry = new BloomFactory(owner, address(treasury));\n        vm.startPrank(owner);\n        treasury.bindRegistry(address(registry));\n        registry.bindBloom(address(bloom));\n        registry.whitelistAsset(address(bloom), true);\n        vm.stopPrank();\n    }\n\n    function _initCode(uint8 d) internal view returns (bytes memory) {\n        return abi.encodePacked(\n            type(StakedBLOOM).creationCode,\n            abi.encode(owner, address(registry), address(treasury), address(bloom), d)\n        );\n    }\n\n    function testCorrectFarmCanBeRegisteredAfterMisconfiguredOne() public {\n        vm.startPrank(owner);\n        // Wrong decimals: activate() can never succeed for this farm.\n        try registry.deployFarm(_initCode(6), bytes32(0)) {} catch {}\n        // Fails today with DuplicateFarm: the bad farm holds farmForAsset[BLOOM] forever.\n        address good = registry.deployFarm(_initCode(18), bytes32(uint256(1)));\n        vm.stopPrank();\n        assertEq(registry.farmForAsset(address(bloom)), good);\n    }\n}","reproduction":"Treasury and Factory are deployed and bound, bindBloom(BLOOM 18 decimals) is done and whitelistAsset(BLOOM,true) is done. As owner: deployFarm(StakedBLOOM initcode with args (owner, registry, treasury, BLOOM, 6), salt 0) succeeds and registers. farm.activate() then reverts InvalidDependency every time. deployFarm(StakedBLOOM initcode with decimals 18, salt 1) reverts DuplicateFarm(). Expected: the correct farm registers. Attached proof fails on this tree with DuplicateFarm().","severity":"medium","snippet":"        if (isFarm[farm] || farmForAsset[underlying] != address(0)) revert DuplicateFarm();","title":"Factory registration checks less than activate(): a farm that can never activate permanently occupies its asset's farmForAsset slot, with no unregister/replace path"},{"citation":"resolved","description":"_validRecipient only rejects address(0) and the farm itself. With beneficiary == WETH, the native call succeeds because WETH9's fallback is deposit(). The ETH becomes WETH credited to the farm, not the user, and only the owner's recoverExcess can move it. With beneficiary == treasury, BloomTreasury has no receive(), so the native call fails and the farm wraps and sends WETH to the Treasury. That WETH never enters receivedFees, so spendFees can never release it. In both cases the shares are burned and the fee is taken while the user's payout is out of their control. The input is user-selected, so the impact is limited to the caller. Fix: reject beneficiary == WETH and beneficiary == treasury in StakedETH.withdraw.","line":47,"path":"src/StakedETH.sol","reproduction":"Setup as test/ETH.t.sol. alice: deposit{value:10 ether}(alice,1), then withdraw(10e18, payable(WETH), 0). Result: IERC20(WETH).balanceOf(farm) == 8.5e18 and excessBalance(WETH) == 8.5e18, and alice receives nothing. Variant: withdraw(10e18, payable(address(treasury)), 0). Result: IERC20(WETH).balanceOf(treasury) == 8.5e18 and treasury.availableFees(WETH) == 0. Both reproduced in my scratch test (testBeneficiaryWETH, testBeneficiaryTreasury pass with these assertions).","severity":"low","snippet":"            ok := call(NATIVE_SEND_GAS, beneficiary, amount, 0, 0, 0, 0)","title":"StakedETH.withdraw strands the user's 85% when beneficiary is the WETH contract or the Treasury"},{"citation":"resolved","description":"ERC20Farm.deposit mints shares for the measured net receipt and so accepts fee-on-transfer assets. But Farm._payFee (Farm.sol:222) and _sendExact require the exact amount to arrive and to leave, so the same token can never be withdrawn: every partial and final exit reverts, and recoverExcess excludes accountedAssets. The docs call outbound tax unsupported, yet the deposit path does not fail closed. Users of a whitelisted taxed asset (for example a future farm, or a BLOOM with a transfer tax from Job 2) can deposit but not exit while the tax is on. Admission is a trusted owner decision, hence low. Fix: in deposit, revert when received != assets so an unsupported token is rejected before it takes principal.","line":34,"path":"src/core/ERC20Farm.sol","reproduction":"FarmFixture StakedBLOOM with MockToken. bloom.setFee(100), then alice deposit(100e18, alice, 1) succeeds with 99e18 shares. alice withdraw(99e18, alice, 0) reverts, withdraw(49.5e18, alice, 0) reverts too, and excessBalance(bloom)==0. Expected: the deposit is rejected up front, or the exit succeeds net of the token's tax. Actual: the principal is unrecoverable while the tax stays on. Reproduced in my scratch test testTaxFromStartLocksPrincipal (passes with these expectRevert assertions).","severity":"low","snippet":"        uint256 received = IERC20(asset).balanceOf(address(this)) - beforeBalance;","title":"ERC20 deposits accept transfer-taxed tokens (net receipt measured) but every withdrawal of such a token reverts, so principal deposited while a tax is active is locked"},{"citation":"resolved","description":"The brief lets the owner selectively renounce roles. After farm.renouncePowers(PAUSE), setDepositsPaused reverts. But _requireDepositAllowed also reads the Factory whitelist, which is controlled by the Factory's separate CONFIG power. So the Factory owner, or a later owner after transferOwnership, can still halt every deposit to the farm by de-whitelisting its asset. Through _requireCanStart they can also block startEpoch and restartEpoch, while continueEpoch keeps working. Withdrawals and claims are unaffected, hence low. Fix: document the whitelist as a second deposit switch in the renunciation semantics, or have deposits ignore the whitelist once the farm is active.","line":106,"path":"src/core/Farm.sol","reproduction":"Activate StakedBLOOM and unpause it. Owner calls farm.renouncePowers(4); setDepositsPaused now reverts PowerRenounced(4). Owner calls registry.whitelistAsset(BLOOM,false). alice deposit(1e18, alice, 1) reverts DepositsPaused(). Reproduced in my scratch test testRenouncePauseStillPausable (expectRevert(Farm.DepositsPaused.selector) passes).","severity":"low","snippet":"        if (depositsPaused || !IBloomRegistry(registry).isAssetWhitelisted(asset)) revert DepositsPaused();","title":"Renouncing a farm's PAUSE power does not remove the ability to halt deposits and epoch starts: Factory whitelistAsset(asset,false) is a second pause switch"}],"hash":"d31f8ee3e46a3f573f003c1b98e838e04ed289d9a4b79f57ab7ebb9c5c1647f9","nodeId":"56f70d74-4ed4-4c4b-a5ba-ef6bc57ae6d7","outcome":"completed","summary":"The review is finished. `.imd-findings.json` in the repo root holds 5 findings and 91 coverage rows: all 89 entry points plus 2 invariants. No source files were changed, and the scratch tests and build output have been deleted.\n\n## Findings\n\n1. **High: share inflation through the retained 14% fee** (`src/core/Farm.sol:67`). This merges two specialist findings with the same root cause (audit_flow fe1685 and audit_math fd7288).\n   - **Cause:** the guard against share inflation is a single virtual share, and the last holder to exit gets everything left in the pool.\n   - **Attack:** an attacker withdraws all but one share, so the 14% retained fee leaves that share backed by a large amount. A victim's 100 BLOOM deposit then mints exactly 1 share.\n   - **Result:** if the victim exits first they get back 56.67 BLOOM, where 85 is expected after the fee. The attacker exits last and ends 14.12 BLOOM up.\n   - **Without an attacker:** the same state arises naturally. Someone deposits 1 wei, a large holder exits fully, and the next 10 BLOOM deposit gets 1 share worth 8 BLOOM.\n   - Both specialist proofs fail on the current code for the stated reason. I attached fe1685's.\n2. **Medium: a farm that can never activate permanently blocks its asset** (`src/BloomFactory.sol:83`). Registration doesn't check the decimals that `activate()` later requires, so a farm built with the wrong decimals registers anyway. Its slot can't be cleared, and every later farm for that asset reverts with `DuplicateFarm`. Fixing it means redeploying both Factory and Treasury. The attached proof fails on the current code.\n3. **Low: StakedETH payout stranded for some beneficiaries** (`src/StakedETH.sol:47`). Withdrawing with the WETH contract as beneficiary leaves the 85% payout as WETH in the farm, which only the owner can recover. Withdrawing to the Treasury leaves it as WETH there, where it can never be spent.\n4. **Low: deposits of a transfer-taxed token can't be withdrawn** (`src/core/ERC20Farm.sol:34`). Deposits accept such a token by measuring what actually arrived. Every withdrawal of it then reverts, so that principal is locked while the tax is on.\n5. **Low: renouncing a farm's pause power doesn't remove the ability to stop deposits** (`src/core/Farm.sol:106`). After the farm's PAUSE power is renounced, taking the asset off the Factory whitelist still blocks deposits and starting new epochs. Withdrawals and claims are unaffected.\n\n## Specialist findings dropped\n- **Zero-payout withdrawal burns shares:** `docs/ACCOUNTING.md` says this is intended, so that dust can't block a zero-supply reset, and `minAssetsOut` protects the caller. The suggested fix would break that.\n- **sIMD vault owner powers:** the docs record the vault owner as renounced, and this isn't a defect in this code.\n- **Fuzz coverage note:** the specialist's own scratch fuzzing found no violation, so there's no defect to report.\n\n## My own pass\nI reread the code and found nothing the specialists missed. This covered the reward ledger accounting, the epoch transitions, the ETH fallback path, the IMD deposit path (the sIMD one-block hold doesn't affect the farm, which never redeems) and Treasury spending. The `launch.json` manifest is deployable: 2 contracts, constructor arguments in the right order, no external calls in constructors, and small runtime sizes.\n\nI reproduced every finding I kept by running tests. Findings 3–5 come from my own scratch tests and carry no proof file, since proofs are only required for high and critical.","treeHash":null,"usage":{"cachedInputTokens":1472543,"inputTokens":32,"model":"claude-opus-5-5","outputTokens":30389,"runtime":"claude","turns":18,"wallClockMs":339518}}],"verification":[{"checks":[{"durationMs":6757,"exitCode":0,"name":"build","output":"Compiling 70 files with Solc 0.8.26\nSolc 0.8.26 finished in 6.64s\nCompiler run successful!\n","passed":true},{"durationMs":18481,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/ETH.t.sol:ETHTest\n[PASS] testBothDeliveryPathsFailAtomically() (gas: 645070)\n[PASS] testDirectSendRejectedDepositSlippageAndZeroDeposit() (gas: 159250)\n[PASS] testForcedETHNeverBacksSharesOrRewards() (gas: 409749)\n[PASS] testGasGriefCannotPreventWETHFallback() (gas: 483274)\n[PASS] testLargeRevertDataCannotPreventWETHFallback() (gas: 489195)\n[PASS] testNativeCallbackCannotReenterWithdrawal() (gas: 577317)\n[PASS] testNativePartialAndFullExit() (gas: 637860)\n[PASS] testNativePrincipalAndBloomRewardsRemainSeparate() (gas: 1062924)\n[PASS] testRejectingBeneficiaryReceivesCanonicalWETHWithNoExtraFee() (gas: 482960)\n[PASS] testWETHAndTreasuryBeneficiariesAreRejectedBeforeAnyPayout() (gas: 281561)\n[PASS] testWrappingFailureAlsoRollsBack() (gas: 558135)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 3.34ms (2.41ms CPU time)\n\nRan 3 tests for test/IntegrationFailures.t.sol:ActivationFailuresTest\n[PASS] testCanonicalWETHIdentityAndDecimalsAreRequiredBeforeRegistration() (gas: 474696)\n[PASS] testOfficialSIMDMetadataAndCodeHashesMustAllMatch() (gas: 509583)\n[PASS] testWrongChainRefusesRegistrationAndActivation() (gas: 302300)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 3.54ms (1.67ms CPU time)\n\nRan 13 tests for test/Administration.t.sol:AdministrationTest\n[PASS] testBindingsAreOneTimeAndDependenciesCannotFrontRun() (gas: 983586)\n[PASS] testCancelledFutureBudgetIsFreeButAccruedClaimIsProtected() (gas: 1274713)\n[PASS] testCreate2FactoryDeploysFarmWithOwnerAndInitiallyDisabled() (gas: 4684821)\n[PASS] testExplicitOwnerNeverWorkerOrFactory() (gas: 81613)\n[PASS] testFarmThatCouldNeverActivateCannotTakeTheAssetSlot() (gas: 4703577)\n[PASS] testFutureFarmRequiresWhitelistCorrectOwnerAndNoDuplicates() (gas: 2155894)\n[PASS] testOnlyOwnerCanBindActivatePauseAllocateAndRecover() (gas: 219575)\n[PASS] testStrandingRecipientsAreRejected() (gas: 1263657)\n[PASS] testTreasuryFailedTransferRollsBackSpending() (gas: 510642)\n[PASS] testTreasuryOnlySpendsReceivedFeesNotDonationsOrFarmFunds() (gas: 747352)\n[PASS] testTwoStepOwnershipAndSelectivePermanentRenunciation() (gas: 725171)\n[PASS] testUnboundAndUnregisteredContractsRejectActivation() (gas: 482714)\n[PASS] testWhitelistGovernsAdmissionOnlyAndRenouncedPauseIsFinal() (gas: 2130499)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 77.13ms (6.52ms CPU time)\n\nRan 10 tests for test/TokenFailures.t.sol:TokenFailuresTest\n[PASS] testFalseAndNonBooleanReturnsRollBackDepositsIncludingTokenSideEffects() (gas: 352472)\n[PASS] testFalseApproveOrTransferCannotBurnSharesOrRecordUnreceivedFees() (gas: 657606)\n[PASS] testFundingCreditsOnlyNetReceiptAndDoesNotUseExistingPrincipal() (gas: 1152530)\n[PASS] testOptionalReturnTokenWorksThroughDepositFeePayoutAndTreasurySpend() (gas: 612161)\n[PASS] testPartiallyTaxedDepositIsRefusedSoExitsCannotTakeOthersPrincipal() (gas: 361083)\n[PASS] testTaxedExcessRecoveryCannotTouchBackingOrRewardReserve() (gas: 504725)\n[PASS] testTaxedRewardClaimCannotConsumeCreditAndCanBeRetried() (gas: 1236327)\n[PASS] testTaxedTreasurySpendRestoresFeeAllowanceAndRecipientBalance() (gas: 570924)\n[PASS] testTokenCallbackCannotCheckpointDuringInboundOrOutboundAccounting() (gas: 508128)\n[PASS] testZeroNetFundingAndZeroNetDepositRevertAtomically() (gas: 280044)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 252.35ms (3.31ms CPU time)\n\nRan 5 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] testAllApplicationConstructorsSucceedWithDependenciesAbsent() (gas: 240456)\n[PASS] testCoreScriptAssignsEveryPrivilegeToConfirmedRequesterAndDoesNotInitialize() (gas: 10354342)\n[PASS] testFarmScriptsTakeRealInputsAndNeverEnableDepositsOrEmissions() (gas: 58818632)\n[PASS] testScriptRejectsMissingBloomAndWrongChain() (gas: 8510378)\n[PASS] testScriptRejectsWrongRequesterAndUnboundToken() (gas: 8989950)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 265.21ms (78.02ms CPU time)\n\nRan 12 tests for test/AuthorityFailures.t.sol:AuthorityFailuresTest\n[PASS] testAllRewardOperationsHonorRenunciationWithoutTouchingUserObligations() (gas: 1204553)\n[PASS] testConfigPauseAndSpendPowersCanBeRenouncedIndependently() (gas: 1056606)\n[PASS] testDepositWithdrawalFeeAndClaimEventsMatchActualAmounts() (gas: 995550)\n[PASS] testEpochPauseRoleAndTreasurySpendEvents() (gas: 984723)\n[PASS] testEveryPrivilegedFarmEntryRejectsUnprivilegedCaller() (gas: 976049)\n[PASS] testFactoryAndTreasuryCannotBeReconfiguredByDepositor() (gas: 253399)\n[PASS] testInvalidRenunciationMasksHaveNoEffect() (gas: 452918)\n[PASS] testMalformedInitCodeAndOversizedInputCannotPolluteRegistry() (gas: 447909)\n[PASS] testRecoveryRenunciationSurvivesOwnershipTransferButClaimsAndExitsWork() (gas: 1265790)\n[PASS] testTreasuryBindingRejectsWrongOwnerWrongTreasuryAndNoCode() (gas: 122255)\n[PASS] testUnregisteredCallersCannotPretendDonationsAreTreasuryFees() (gas: 164229)\n[PASS] test_RevertedCreate2RegistrationRollsBackCreationAndSaltRemainsUsable() (gas: 7743238)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 265.30ms (6.08ms CPU time)\n\nRan 13 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDecimals24ZeroShareAndDecimals6FractionalShares() (gas: 2995224)\n[PASS] testDonationIsolationAndZeroSupplyReset() (gas: 875875)\n[PASS] testFuzzWithdrawConservation(uint128,uint128,uint64) (runs: 256, μ: 911903, ~: 924115)\nLogs:\n  Bound result 8846627376820857003659010005\n  Bound result 16395032295248894590\n  Bound result 61\n\n[PASS] testPartialAndFinalExitConserveEveryUnit() (gas: 1010537)\n[PASS] testRetainedFeeInflationSetupIsUnprofitableAndLossBoundedByOneQuantum() (gas: 1523023)\n[PASS] testRewardFundingNeverBacksBloomShares() (gas: 661312)\n[PASS] testSameBlockFullExitNoCooldown() (gas: 378030)\n[PASS] testSharesHaveNoTransferOrApprovalInterface() (gas: 216773)\n[PASS] testSlippageAndZeroInputsRevertAtomically() (gas: 465334)\n[PASS] testTaxedTransfersAreRejectedBeforeTakingPrincipalAndAtExit() (gas: 868586)\n[PASS] testTokenFailureAndCallbackCannotStealShares() (gas: 663104)\n[PASS] testVirtualOffsetHeadroomPreservesExitAtUintLimit() (gas: 2177904)\n[PASS] testVirtualOffsetsKeepInitialRateAndAtLeastOneMillionQuanta() (gas: 1833636)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 269.23ms (259.31ms CPU time)\n\nRan 14 tests for test/Rewards.t.sol:RewardsTest\n[PASS] testCannotPledgeEarnedRewardsTwiceOrRecoverObligations() (gas: 1004298)\n[PASS] testContinueBoostAndRestartPreserveEarnedAndEpochIdentity() (gas: 1229154)\n[PASS] testEpochBoundaryAndInvalidConfiguration() (gas: 978553)\n[PASS] testFrequentClaimSettlementsPreserveSubWeiFractions() (gas: 1636807)\n[PASS] testFullExitRetainsClaimAndClaimHasNoFee() (gas: 1246779)\n[PASS] testFundingAndConfigurationNeverStartAccrual() (gas: 786567)\n[PASS] testFuzzRewardsSolventAcrossTimeAndShareEdits(uint96,uint96,uint96,uint32) (runs: 256, μ: 1656201, ~: 1686538)\nLogs:\n  Bound result 31215\n  Bound result 432001\n  Bound result 1026354288\n  Bound result 4\n\n[PASS] testLateDepositorReceivesNoPastRewards() (gas: 1296670)\n[PASS] testOversizedEpochCannotBrickOneShareAccrual() (gas: 1201879)\n[PASS] testPausedDepositsDoNotBlockClaimsWithdrawalOrAccrual() (gas: 1123568)\n[PASS] testRewardTransferFailureRollsBackClaimAndCanRetry() (gas: 1101188)\n[PASS] testRoundingFractionsSurviveSettlementsAndDustReleasesOnlyAtZeroSupply() (gas: 1750145)\n[PASS] testTopUpsStayFreeAndOnlyFreeFundsRecoverable() (gas: 1002992)\n[PASS] testZeroStakerIntervalsReturnToReserveAndNeverRetroactive() (gas: 1451825)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 269.14ms (246.58ms CPU time)\n\nRan 10 tests for test/IMD.t.sol:IMDIntegrationTest\n[PASS] testAtomicIMDDepositMeasuresNonOneToOneAndClearsApproval() (gas: 497225)\n[PASS] testFarmRewardsIndependentOfOfficialVaultYield() (gas: 1060381)\n[PASS] testIMDConversionSlippageAndShareSlippageRollbackAllTransfers() (gas: 532218)\n[PASS] testIMDRedemptionExplicitlyDisabledEvenAfterHoldExpires() (gas: 301474)\n[PASS] testOfficialDecimalsApprovalsAndDirectDeposit() (gas: 375218)\n[PASS] testOfficialHoldBlocksRedemptionButImmediateInKindExitWorks() (gas: 699509)\n[PASS] testOfficialThirdPartyMintCanRestampHoldButCannotBlockSIMDExit() (gas: 662805)\n[PASS] testProtocolDepositFailureRollsBackAndNoDexFallback() (gas: 174706)\n[PASS] testTokenAndVaultContractsAreRejectedAsBeneficiaries() (gas: 379496)\n[PASS] testValueYieldDoesNotMintFarmAssetsOrShares() (gas: 398357)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 269.25ms (3.15ms CPU time)\n\nRan 11 tests for test/IntegrationFailures.t.sol:IntegrationFailuresTest\n[PASS] testDelistingAnActiveFarmsAssetDoesNotPauseItsDeposits() (gas: 242288)\n[PASS] testFallbackFailureRestoresNativeFeeAndAccruedRewardStateThenRetries() (gas: 1464713)\n[PASS] testFarmSpecificStrandingRecipientsAreRejectedOnDepositWithdrawAndClaim() (gas: 648706)\n[PASS] testIMDDustAfterVaultYieldCannotProduceZeroFarmSharesOrTrapIMD() (gas: 390871)\n[PASS] testNativeReceiverCannotCheckpointDuringWithdrawalButNativeDeliverySucceeds() (gas: 512730)\n[PASS] testPausedExternalVaultRollsBackIMDPathButStillAllowsDirectSIMDAndExit() (gas: 779569)\n[PASS] testPausedFarmRejectsBothSIMDInputsWithoutMovingAnyTokens() (gas: 184662)\n[PASS] testPreexistingIMDDonationIsNotConsumedByAtomicStaking() (gas: 499532)\n[PASS] testRecoveringForcedNativeToRejectingRecipientIsAtomic() (gas: 206890)\n[PASS] testRejectingNativeTreasurySpendRollsBackAndDoesNotWrap() (gas: 476527)\n[PASS] testRewardBudgetCannotBeBorrowedAcrossFarms() (gas: 356196)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 269.11ms (3.27ms CPU time)\n\nRan 11 tests for test/EdgeProperties.t.sol:EdgePropertiesTest\n[PASS] testBeneficiaryGiftSettlesExistingSharesBeforeMintAndCallerCannotStealThem() (gas: 1006683)\n[PASS] testDurationOverflowAtTimestampBoundaryRevertsBeforeReservingFunds() (gas: 203527)\n[PASS] testFuzz_ClaimFrequencyDoesNotEraseFractionalCredits(uint96,uint8) (runs: 1000, μ: 2833211, ~: 2446082)\nLogs:\n  Bound result 145799106242230603\n  Bound result 3\n\n[PASS] testFuzz_DonationsAndRewardFundingCannotInflateAnySupportedDecimalPool(uint8,uint96,uint96) (runs: 1000, μ: 2645845, ~: 2662896)\nLogs:\n  Bound result 0\n  Bound result 928\n  Bound result 655105\n\n[PASS] testFuzz_RepeatedRoundTripsCannotExtractAnotherStakersBacking(uint8,uint96,uint8) (runs: 1000, μ: 3956831, ~: 3619495)\nLogs:\n  Bound result 13\n  Bound result 84\n  Bound result 3\n\n[PASS] testOldExitCreditSurvivesNewPoolAndEpochWithoutSubsidizingShares() (gas: 2096419)\n[PASS] testOneWeiFinalExitTransfersAllDustToTreasuryAndCanReenter() (gas: 725026)\n[PASS] testOneWeiPartialBurnCannotCollectFeeTwice() (gas: 674965)\n[PASS] testPrestartScheduleCanBeReplacedCancelledAndRecoveredWithoutAccrual() (gas: 836285)\n[PASS] test_RevertedContinueAtExactEndDoesNotLoseLastEmission() (gas: 990914)\n[PASS] test_RevertedWithdrawalRestoresLazyEpochStateSharesAndCredits() (gas: 855364)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 269.29ms (749.25ms CPU time)\n\nRan 1 test for test/Invariants.t.sol:FarmInvariantTest\n[PASS]\nFarmInvariantTest invariants:\n[PASS] invariantPrincipalAndFeeConservation\n[PASS] invariantRewardSolvencyAndCredits\n FarmInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+-----------+-------+---------+----------╮\n| Contract    | Selector  | Calls | Reverts | Discards |\n+======================================================+\n| FarmHandler | cancel    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | claim     | 828   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | deposit   | 808   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | donate    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | editEpoch | 827   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | elapse    | 797   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | fund      | 837   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | pause     | 842   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | recover   | 836   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | withdraw  | 817   | 0       | 0        |\n╰-------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 683\n  Bound result 1905\n  Bound result 1871\n  Bound result 4344\n  Bound result 6959\n  Bound result 459\n  Bound result 148\n  Bound result 2166413321\n  Bound result 2115\n  Bound result 4345\n  Bound result 440\n  Bound result 4900178740\n  Bound result 5159\n  Bound result 14\n  Bound result 8807\n  Bound result 108256\n  Bound result 7448\n  Bound result 7570\n  Bound result 8753\n  Bound result 5447\n  Bound result 1612\n  Bound result 10834\n  Bound result 9575\n  Bound result 7757\n  Bound result 2\n  Bound result 905453640\n  Bound result 6386506982564926813467\n  Bound result 9063\n  Bound result 3475513386\n  Bound result 2517\n  Bound result 15\n  Bound result 387\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.78s (1.78s CPU time)\n\nRan 2 tests for test/NetworkInvariants.t.sol:NetworkInvariantTest\n[PASS] invariant_CustodySharesFeesAndRewardsRemainConserved() (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------+-----------------+-------+---------+----------╮\n| Contract       | Selector        | Calls | Reverts | Discards |\n+===============================================================+\n| NetworkHandler | cancel          | 1481  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | claim           | 1566  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | controls        | 1547  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | deposit         | 1566  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | depositIMD      | 1436  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | donate          | 1595  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | editEpoch       | 1554  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | elapse          | 1581  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | fund            | 1556  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | recoverDonation | 1471  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | recoverFree     | 1584  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | roundTrip       | 1552  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | spend           | 1525  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | startConfigured | 1567  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | vaultYield      | 1459  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | withdraw        | 1536  | 0       | 0        |\n╰----------------+-----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 100000000000000000000000000\n  Bound result 100000000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 1000\n  Bound result 335028\n  Bound result 100000000000000000000000\n  Bound result 14923\n  Bound result 345600\n  Bound result 8\n  Bound result 612236111111111112110\n  Bound result 28\n  Bound result 10\n  Bound result 0\n  Bound result 19192\n  Bound result 19871768074316742043\n  Bound result 114000000000000000000\n  Bound result 9999999999000000015456\n  Bound result 9999999999000000015456\n  Bound result 9999999999000000015456\n  Bound result 95\n  Bound result 900000000000000000000\n  Bound result 9999000000000000000234\n  Bound result 200000000000000000000\n  Bound result 9999000000000000005657\n  Bound result 21169\n  Bound result 3901\n  Bound result 6850\n  Bound result 18888\n  Bound result 81603205753206176947\n  Bound result 79335778228205436736\n  Bound result 7899580406736382131563922\n  Bound result 32\n  Bound result 17914\n  Bound result 22476\n  Bound result 10\n  Bound result 2708\n  Bound result 1000000\n  Bound result 1000\n  Bound result 15000000000000000000\n  Bound result 2429\n  Bound result 77157\n  Bound result 21188\n  Bound result 3717\n  Bound result 1\n  Bound result 356380181028824153986\n  Bound result 14247718106057014526062\n  Bound result 44184\n  Bound result 7899580406736382131563920\n  Bound result 289699475756271539322\n  Bound result 99999999999999999999997\n  Bound result 14321\n  Bound result 1500000000000000000\n  Bound result 8194183699909843346820\n  Bound result 8194183699909843346820\n  Bound result 1024272962578358782431\n  Bound result 87755312158786570097286\n  Bound result 28\n  Bound result 30000000000000000000\n  Bound result 99000000000000000000\n  Bound result 2000000000000000000000\n  Bound result 1401\n  Bound result 9999999999000000900001\n  Bound result 9999999999000000900001\n  Bound result 9999999999000000900001\n  Bound result 4420\n  Bound result 69173340114600131077610\n  Bound result 4628624049806664970269\n  Bound result 4628624049806664970269\n  Bound result 295589519743107385379\n  Bound result 255855930082286918177\n  Bound result 136271999986827637033\n  Bound result 1498697318490522287054\n  Bound result 1818684681037034355891387269\n  Bound result 102999999999999999997009\n  Bound result 494713711770088084161\n\n[PASS] test_HandlerExercisesFallbackClaimsAndAllAssetRecoveryBeforeClosing() (gas: 6661272)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 100000000000000000000000000\n  Bound result 100000000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 86400\n  Bound result 10000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100\n  Bound result 200\n  Bound result 300\n  Bound result 100\n  Bound result 200\n  Bound result 100\n  Bound result 1\n  Bound result 100\n  Bound result 200\n  Bound result 300\n  Bound result 100\n  Bound result 200\n  Bound result 100\n  Bound result 1\n  Bound result 100\n  Bound result 200\n  Bound result 300\n  Bound result 100\n  Bound result 200\n  Bound result 100\n  Bound result 1\n  Bound result 900000000000000000000\n  Bound result 18100000000000000000\n  Bound result 900000000000000000000\n  Bound result 6185454545454559223140496\n  Bound result 900000000000000000000\n  Bound result 18100000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 18.35s (18.35s CPU time)\n\nRan 13 test suites in 18.36s (22.34s CPU time): 116 tests passed, 0 failed, 0 skipped (116 total tests)\n","passed":true},{"durationMs":94,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BloomFactory.acceptOwnership()\",\"BloomFactory.bindBloom(address)\",\"BloomFactory.deployFarm(bytes,bytes32)\",\"BloomFactory.registerFarm(address)\",\"BloomFactory.renounceOwnership()\",\"BloomFactory.renouncePowers(uint256)\",\"BloomFactory.transferOwnership(address)\",\"BloomFactory.whitelistAsset(address,bool)\",\"BloomTreasury.acceptOwnership()\",\"BloomTreasury.bindRegistry(address)\",\"BloomTreasury.receiveNativeFee()\",\"BloomTreasury.receiveTokenFee(address,uint256)\",\"BloomTreasury.renounceOwnership()\",\"BloomTreasury.renouncePowers(uint256)\",\"BloomTreasury.spendFees(address,address,uint256)\",\"BloomTreasury.transferOwnership(address)\",\"ERC20Farm.acceptOwnership()\",\"ERC20Farm.activate()\",\"ERC20Farm.cancelFutureRewards()\",\"ERC20Farm.checkpoint()\",\"ERC20Farm.claimRewards(address)\",\"ERC20Farm.configureEpoch(uint256,uint256)\",\"ERC20Farm.continueEpoch(uint256,uint256)\",\"ERC20Farm.deposit(uint256,address,uint256)\",\"ERC20Farm.fundRewards(uint256)\",\"ERC20Farm.recoverExcess(address,address,uint256)\",\"ERC20Farm.recoverUnallocatedRewards(address,uint256)\",\"ERC20Farm.renounceOwnership()\",\"ERC20Farm.renouncePowers(uint256)\",\"ERC20Farm.restartEpoch(uint256,uint256)\",\"ERC20Farm.setDepositsPaused(bool)\",\"ERC20Farm.startEpoch()\",\"ERC20Farm.transferOwnership(address)\",\"ERC20Farm.withdraw(uint256,address,uint256)\",\"StakedBLOOM.acceptOwnership()\",\"StakedBLOOM.activate()\",\"StakedBLOOM.cancelFutureRewards()\",\"StakedBLOOM.checkpoint()\",\"StakedBLOOM.claimRewards(address)\",\"StakedBLOOM.configureEpoch(uint256,uint256)\",\"StakedBLOOM.continueEpoch(uint256,uint256)\",\"StakedBLOOM.deposit(uint256,address,uint256)\",\"StakedBLOOM.fundRewards(uint256)\",\"StakedBLOOM.recoverExcess(address,address,uint256)\",\"StakedBLOOM.recoverUnallocatedRewards(address,uint256)\",\"StakedBLOOM.renounceOwnership()\",\"StakedBLOOM.renouncePowers(uint256)\",\"StakedBLOOM.restartEpoch(uint256,uint256)\",\"StakedBLOOM.setDepositsPaused(bool)\",\"StakedBLOOM.startEpoch()\",\"StakedBLOOM.transferOwnership(address)\",\"StakedBLOOM.withdraw(uint256,address,uint256)\",\"StakedETH.acceptOwnership()\",\"StakedETH.activate()\",\"StakedETH.cancelFutureRewards()\",\"StakedETH.checkpoint()\",\"StakedETH.claimRewards(address)\",\"StakedETH.configureEpoch(uint256,uint256)\",\"StakedETH.continueEpoch(uint256,uint256)\",\"StakedETH.deposit(address,uint256)\",\"StakedETH.fundRewards(uint256)\",\"StakedETH.recoverExcess(address,address,uint256)\",\"StakedETH.recoverUnallocatedRewards(address,uint256)\",\"StakedETH.renounceOwnership()\",\"StakedETH.renouncePowers(uint256)\",\"StakedETH.restartEpoch(uint256,uint256)\",\"StakedETH.setDepositsPaused(bool)\",\"StakedETH.startEpoch()\",\"StakedETH.transferOwnership(address)\",\"StakedETH.withdraw(uint256,address,uint256)\",\"StakedSIMD.acceptOwnership()\",\"StakedSIMD.activate()\",\"StakedSIMD.cancelFutureRewards()\",\"StakedSIMD.checkpoint()\",\"StakedSIMD.claimRewards(address)\",\"StakedSIMD.configureEpoch(uint256,uint256)\",\"StakedSIMD.continueEpoch(uint256,uint256)\",\"StakedSIMD.deposit(uint256,address,uint256)\",\"StakedSIMD.depositIMD(uint256,address,uint256,uint256)\",\"StakedSIMD.fundRewards(uint256)\",\"StakedSIMD.recoverExcess(address,address,uint256)\",\"StakedSIMD.recoverUnallocatedRewards(address,uint256)\",\"StakedSIMD.renounceOwnership()\",\"StakedSIMD.renouncePowers(uint256)\",\"StakedSIMD.restartEpoch(uint256,uint256)\",\"StakedSIMD.setDepositsPaused(bool)\",\"StakedSIMD.startEpoch()\",\"StakedSIMD.transferOwnership(address)\",\"StakedSIMD.withdraw(uint256,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":99,\"abi/BloomFactory.json\":581,\"abi/BloomTreasury.json\":498,\"abi/ERC20Farm.json\":1726,\"abi/StakedBLOOM.json\":1734,\"abi/StakedETH.json\":1788,\"abi/StakedSIMD.json\":1848,\"deployment/BloomTreasury.unsigned.json\":23,\"docs/ACCOUNTING.md\":89,\"docs/DEPENDENCIES.md\":16,\"docs/DEPLOYMENT.md\":85,\"docs/INTEGRATION.md\":77,\"docs/VALIDATION.md\":56,\"docs/artifact-hashes.json\":1250,\"docs/deployment-status.json\":24,\"docs/evidence/dependency-revalidation.json\":31,\"docs/evidence/imd-verification.json\":1860,\"docs/evidence/mainnet-reads.json\":104,\"docs/evidence/simd-verification.json\":1120,\"docs/evidence/weth-verification.json\":318,\"docs/validation/core-simulation.txt\":7,\"docs/validation/forge-test.txt\":703,\"foundry.toml\":23,\"remappings.txt\":2,\"script/DeployBLOOMFarm.s.sol\":17,\"script/DeployCore.s.sol\":16,\"script/DeployETHFarm.s.sol\":12,\"script/DeploySIMDFarm.s.sol\":12,\"script/DeploymentInputs.sol\":26,\"scripts/export_artifacts.py\":80,\"scripts/prepare_deployment.py\":93,\"scripts/verify_mainnet.py\":53,\"src/BloomFactory.sol\":100,\"src/BloomTreasury.sol\":100,\"src/MainnetAssets.sol\":15,\"src/StakedBLOOM.sol\":13,\"src/StakedETH.sol\":65,\"src/StakedSIMD.sol\":69,\"src/core/ERC20Farm.sol\":47,\"src/core/Farm.sol\":256,\"src/core/Managed.sol\":34,\"src/core/RewardLedger.sol\":300,\"src/interfaces/IBloom.sol\":43,\"test/Accounting.t.sol\":263,\"test/Administration.t.sol\":297,\"test/AuthorityFailures.t.sol\":285,\"test/Deployment.t.sol\":131,\"test/ETH.t.sol\":234,\"test/EdgeProperties.t.sol\":273,\"test/IMD.t.sol\":186,\"test/IntegrationFailures.t.sol\":326,\"test/Invariants.t.sol\":147,\"test/NetworkInvariants.t.sol\":502,\"test/Rewards.t.sol\":314,\"test/TESTING.md\":62,\"test/TokenFailures.t.sol\":247,\"test/fixtures/OfficialIMD.sol\":10,\"test/fixtures/OfficialSIMD.sol\":9,\"test/fixtures/OfficialWETH.sol\":10,\"test/helpers/Fixtures.sol\":145,\"test/helpers/NetworkFixture.sol\":57},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"19831760a86b2bbc115d1de386054a857f6c263d077286eef361ddb70408409f","verifiedTreeHash":"56a7f0ced8c070d41ebe62ae50f6c1be33f0c59e","verifierVersion":"0.1.0+560ab6a2"},{"checks":[{"durationMs":3404,"exitCode":0,"name":"build","output":"Compiling 64 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.32s\nCompiler run successful!\n","passed":true},{"durationMs":1574,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 12 tests for test/Administration.t.sol:AdministrationTest\n[PASS] testBindingsAreOneTimeAndDependenciesCannotFrontRun() (gas: 983586)\n[PASS] testCancelledFutureBudgetIsFreeButAccruedClaimIsProtected() (gas: 1284391)\n[PASS] testCreate2FactoryDeploysFarmWithOwnerAndInitiallyDisabled() (gas: 4632776)\n[PASS] testExplicitOwnerNeverWorkerOrFactory() (gas: 81591)\n[PASS] testFutureFarmRequiresWhitelistCorrectOwnerAndNoDuplicates() (gas: 2148488)\n[PASS] testOnlyOwnerCanBindActivatePauseAllocateAndRecover() (gas: 219663)\n[PASS] testTreasuryFailedTransferRollsBackSpending() (gas: 515482)\n[PASS] testTreasuryOnlySpendsReceivedFeesNotDonationsOrFarmFunds() (gas: 752192)\n[PASS] testTwoStepOwnershipAndSelectivePermanentRenunciation() (gas: 729767)\n[PASS] testUnboundAndUnregisteredContractsRejectActivation() (gas: 478048)\n[PASS] testWhitelistRemovalOnlyStopsDeposits() (gas: 457008)\n[PASS] testWrongChainAndDecimalsCannotActivate() (gas: 1179593)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 2.37ms (6.15ms CPU time)\n\nRan 9 tests for test/IMD.t.sol:IMDIntegrationTest\n[PASS] testAtomicIMDDepositMeasuresNonOneToOneAndClearsApproval() (gas: 502301)\n[PASS] testFarmRewardsIndependentOfOfficialVaultYield() (gas: 1070651)\n[PASS] testIMDConversionSlippageAndShareSlippageRollbackAllTransfers() (gas: 542468)\n[PASS] testIMDRedemptionExplicitlyDisabledEvenAfterHoldExpires() (gas: 306513)\n[PASS] testOfficialDecimalsApprovalsAndDirectDeposit() (gas: 380326)\n[PASS] testOfficialHoldBlocksRedemptionButImmediateInKindExitWorks() (gas: 704259)\n[PASS] testOfficialThirdPartyMintCanRestampHoldButCannotBlockSIMDExit() (gas: 667377)\n[PASS] testProtocolDepositFailureRollsBackAndNoDexFallback() (gas: 179919)\n[PASS] testValueYieldDoesNotMintFarmAssetsOrShares() (gas: 403544)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 4.21ms (3.49ms CPU time)\n\nRan 10 tests for test/ETH.t.sol:ETHTest\n[PASS] testBothDeliveryPathsFailAtomically() (gas: 649818)\n[PASS] testDirectSendRejectedDepositSlippageAndZeroDeposit() (gas: 169545)\n[PASS] testForcedETHNeverBacksSharesOrRewards() (gas: 413706)\n[PASS] testGasGriefCannotPreventWETHFallback() (gas: 487978)\n[PASS] testLargeRevertDataCannotPreventWETHFallback() (gas: 493899)\n[PASS] testNativeCallbackCannotReenterWithdrawal() (gas: 582044)\n[PASS] testNativePartialAndFullExit() (gas: 647378)\n[PASS] testNativePrincipalAndBloomRewardsRemainSeparate() (gas: 1072904)\n[PASS] testRejectingBeneficiaryReceivesCanonicalWETHWithNoExtraFee() (gas: 487664)\n[PASS] testWrappingFailureAlsoRollsBack() (gas: 562861)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 35.22ms (2.80ms CPU time)\n\nRan 14 tests for test/Rewards.t.sol:RewardsTest\n[PASS] testCannotPledgeEarnedRewardsTwiceOrRecoverObligations() (gas: 1020036)\n[PASS] testContinueBoostAndRestartPreserveEarnedAndEpochIdentity() (gas: 1245313)\n[PASS] testEpochBoundaryAndInvalidConfiguration() (gas: 995374)\n[PASS] testFrequentClaimSettlementsPreserveSubWeiFractions() (gas: 1651872)\n[PASS] testFullExitRetainsClaimAndClaimHasNoFee() (gas: 1257201)\n[PASS] testFundingAndConfigurationNeverStartAccrual() (gas: 797436)\n[PASS] testFuzzRewardsSolventAcrossTimeAndShareEdits(uint96,uint96,uint96,uint32) (runs: 256, μ: 1665764, ~: 1701602)\nLogs:\n  Bound result 2655\n  Bound result 16248\n  Bound result 7361\n  Bound result 2\n\n[PASS] testLateDepositorReceivesNoPastRewards() (gas: 1312300)\n[PASS] testOversizedEpochCannotBrickOneShareAccrual() (gas: 1212257)\n[PASS] testPausedDepositsDoNotBlockClaimsWithdrawalOrAccrual() (gas: 1134058)\n[PASS] testRewardTransferFailureRollsBackClaimAndCanRetry() (gas: 1111460)\n[PASS] testRoundingFractionsSurviveSettlementsAndDustReleasesOnlyAtZeroSupply() (gas: 1764777)\n[PASS] testTopUpsStayFreeAndOnlyFreeFundsRecoverable() (gas: 1013604)\n[PASS] testZeroStakerIntervalsReturnToReserveAndNeverRetroactive() (gas: 1467500)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 42.00ms (50.82ms CPU time)\n\nRan 11 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDecimals24ZeroShareAndDecimals6FractionalShares() (gas: 2996232)\n[PASS] testDonationIsolationAndZeroSupplyReset() (gas: 885686)\n[PASS] testFuzzWithdrawConservation(uint128,uint128,uint64) (runs: 256, μ: 920832, ~: 933822)\nLogs:\n  Bound result 12587435\n  Bound result 900000000000000000000\n  Bound result 14321\n\n[PASS] testMeasuredNetDepositAndUnsupportedOutboundTaxRevert() (gas: 687597)\n[PASS] testPartialAndFinalExitConserveEveryUnit() (gas: 1020217)\n[PASS] testRewardFundingNeverBacksBloomShares() (gas: 666539)\n[PASS] testSameBlockFullExitNoCooldown() (gas: 383056)\n[PASS] testSharesHaveNoTransferOrApprovalInterface() (gas: 222055)\n[PASS] testSlippageAndZeroInputsRevertAtomically() (gas: 485514)\n[PASS] testTokenFailureAndCallbackCannotStealShares() (gas: 673434)\n[PASS] testVirtualOffsetHeadroomPreservesExitAtUintLimit() (gas: 2176092)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 42.07ms (40.74ms CPU time)\n\nRan 5 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] testAllApplicationConstructorsSucceedWithDependenciesAbsent() (gas: 240789)\n[PASS] testCoreScriptAssignsEveryPrivilegeToConfirmedRequesterAndDoesNotInitialize() (gas: 10258771)\n[PASS] testFarmScriptsTakeRealInputsAndNeverEnableDepositsOrEmissions() (gas: 58176347)\n[PASS] testScriptRejectsMissingBloomAndWrongChain() (gas: 8419148)\n[PASS] testScriptRejectsWrongRequesterAndUnboundToken() (gas: 8914250)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 47.60ms (66.20ms CPU time)\n\nRan 1 test for test/Invariants.t.sol:FarmInvariantTest\n[PASS]\nFarmInvariantTest invariants:\n[PASS] invariantPrincipalAndFeeConservation\n[PASS] invariantRewardSolvencyAndCredits\n FarmInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+-----------+-------+---------+----------╮\n| Contract    | Selector  | Calls | Reverts | Discards |\n+======================================================+\n| FarmHandler | cancel    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | claim     | 828   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | deposit   | 808   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | donate    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | editEpoch | 827   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | elapse    | 797   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | fund      | 837   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | pause     | 842   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | recover   | 836   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | withdraw  | 817   | 0       | 0        |\n╰-------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 684\n  Bound result 1904\n  Bound result 2731061622\n  Bound result 1352\n  Bound result 6958\n  Bound result 3340342381\n  Bound result 474\n  Bound result 202\n  Bound result 2166413321\n  Bound result 2197\n  Bound result 8\n  Bound result 4343\n  Bound result 4900178740\n  Bound result 5531\n  Bound result 4\n  Bound result 8790\n  Bound result 2817\n  Bound result 7447\n  Bound result 8025\n  Bound result 8607\n  Bound result 5710\n  Bound result 1610\n  Bound result 10926\n  Bound result 9698\n  Bound result 8108\n  Bound result 19\n  Bound result 905456384\n  Bound result 6386506982564926813467\n  Bound result 9339\n  Bound result 2428830012\n  Bound result 2486\n  Bound result 15\n  Bound result 425\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.49s (1.49s CPU time)\n\nRan 7 test suites in 1.49s (1.66s CPU time): 62 tests passed, 0 failed, 0 skipped (62 total tests)\n","passed":true},{"durationMs":52,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BloomFactory.acceptOwnership()\",\"BloomFactory.bindBloom(address)\",\"BloomFactory.deployFarm(bytes,bytes32)\",\"BloomFactory.registerFarm(address)\",\"BloomFactory.renounceOwnership()\",\"BloomFactory.renouncePowers(uint256)\",\"BloomFactory.transferOwnership(address)\",\"BloomFactory.whitelistAsset(address,bool)\",\"BloomTreasury.acceptOwnership()\",\"BloomTreasury.bindRegistry(address)\",\"BloomTreasury.receiveNativeFee()\",\"BloomTreasury.receiveTokenFee(address,uint256)\",\"BloomTreasury.renounceOwnership()\",\"BloomTreasury.renouncePowers(uint256)\",\"BloomTreasury.spendFees(address,address,uint256)\",\"BloomTreasury.transferOwnership(address)\",\"ERC20Farm.acceptOwnership()\",\"ERC20Farm.activate()\",\"ERC20Farm.cancelFutureRewards()\",\"ERC20Farm.checkpoint()\",\"ERC20Farm.claimRewards(address)\",\"ERC20Farm.configureEpoch(uint256,uint256)\",\"ERC20Farm.continueEpoch(uint256,uint256)\",\"ERC20Farm.deposit(uint256,address,uint256)\",\"ERC20Farm.fundRewards(uint256)\",\"ERC20Farm.recoverExcess(address,address,uint256)\",\"ERC20Farm.recoverUnallocatedRewards(address,uint256)\",\"ERC20Farm.renounceOwnership()\",\"ERC20Farm.renouncePowers(uint256)\",\"ERC20Farm.restartEpoch(uint256,uint256)\",\"ERC20Farm.setDepositsPaused(bool)\",\"ERC20Farm.startEpoch()\",\"ERC20Farm.transferOwnership(address)\",\"ERC20Farm.withdraw(uint256,address,uint256)\",\"StakedBLOOM.acceptOwnership()\",\"StakedBLOOM.activate()\",\"StakedBLOOM.cancelFutureRewards()\",\"StakedBLOOM.checkpoint()\",\"StakedBLOOM.claimRewards(address)\",\"StakedBLOOM.configureEpoch(uint256,uint256)\",\"StakedBLOOM.continueEpoch(uint256,uint256)\",\"StakedBLOOM.deposit(uint256,address,uint256)\",\"StakedBLOOM.fundRewards(uint256)\",\"StakedBLOOM.recoverExcess(address,address,uint256)\",\"StakedBLOOM.recoverUnallocatedRewards(address,uint256)\",\"StakedBLOOM.renounceOwnership()\",\"StakedBLOOM.renouncePowers(uint256)\",\"StakedBLOOM.restartEpoch(uint256,uint256)\",\"StakedBLOOM.setDepositsPaused(bool)\",\"StakedBLOOM.startEpoch()\",\"StakedBLOOM.transferOwnership(address)\",\"StakedBLOOM.withdraw(uint256,address,uint256)\",\"StakedETH.acceptOwnership()\",\"StakedETH.activate()\",\"StakedETH.cancelFutureRewards()\",\"StakedETH.checkpoint()\",\"StakedETH.claimRewards(address)\",\"StakedETH.configureEpoch(uint256,uint256)\",\"StakedETH.continueEpoch(uint256,uint256)\",\"StakedETH.deposit(address,uint256)\",\"StakedETH.fundRewards(uint256)\",\"StakedETH.recoverExcess(address,address,uint256)\",\"StakedETH.recoverUnallocatedRewards(address,uint256)\",\"StakedETH.renounceOwnership()\",\"StakedETH.renouncePowers(uint256)\",\"StakedETH.restartEpoch(uint256,uint256)\",\"StakedETH.setDepositsPaused(bool)\",\"StakedETH.startEpoch()\",\"StakedETH.transferOwnership(address)\",\"StakedETH.withdraw(uint256,address,uint256)\",\"StakedSIMD.acceptOwnership()\",\"StakedSIMD.activate()\",\"StakedSIMD.cancelFutureRewards()\",\"StakedSIMD.checkpoint()\",\"StakedSIMD.claimRewards(address)\",\"StakedSIMD.configureEpoch(uint256,uint256)\",\"StakedSIMD.continueEpoch(uint256,uint256)\",\"StakedSIMD.deposit(uint256,address,uint256)\",\"StakedSIMD.depositIMD(uint256,address,uint256,uint256)\",\"StakedSIMD.fundRewards(uint256)\",\"StakedSIMD.recoverExcess(address,address,uint256)\",\"StakedSIMD.recoverUnallocatedRewards(address,uint256)\",\"StakedSIMD.renounceOwnership()\",\"StakedSIMD.renouncePowers(uint256)\",\"StakedSIMD.restartEpoch(uint256,uint256)\",\"StakedSIMD.setDepositsPaused(bool)\",\"StakedSIMD.startEpoch()\",\"StakedSIMD.transferOwnership(address)\",\"StakedSIMD.withdraw(uint256,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":98,\"abi/BloomFactory.json\":581,\"abi/BloomTreasury.json\":498,\"abi/ERC20Farm.json\":1693,\"abi/StakedBLOOM.json\":1701,\"abi/StakedETH.json\":1755,\"abi/StakedSIMD.json\":1815,\"deployment/BloomTreasury.unsigned.json\":23,\"docs/ACCOUNTING.md\":87,\"docs/DEPENDENCIES.md\":16,\"docs/DEPLOYMENT.md\":85,\"docs/INTEGRATION.md\":77,\"docs/VALIDATION.md\":52,\"docs/artifact-hashes.json\":1218,\"docs/deployment-status.json\":24,\"docs/evidence/dependency-revalidation.json\":31,\"docs/evidence/imd-verification.json\":1860,\"docs/evidence/mainnet-reads.json\":104,\"docs/evidence/simd-verification.json\":1120,\"docs/evidence/weth-verification.json\":318,\"docs/validation/core-simulation.txt\":7,\"docs/validation/forge-test.txt\":680,\"foundry.toml\":23,\"remappings.txt\":2,\"script/DeployBLOOMFarm.s.sol\":17,\"script/DeployCore.s.sol\":16,\"script/DeployETHFarm.s.sol\":12,\"script/DeploySIMDFarm.s.sol\":12,\"script/DeploymentInputs.sol\":26,\"scripts/export_artifacts.py\":80,\"scripts/prepare_deployment.py\":93,\"scripts/verify_mainnet.py\":53,\"src/BloomFactory.sol\":97,\"src/BloomTreasury.sol\":100,\"src/MainnetAssets.sol\":15,\"src/StakedBLOOM.sol\":13,\"src/StakedETH.sol\":59,\"src/StakedSIMD.sol\":64,\"src/core/ERC20Farm.sol\":45,\"src/core/Farm.sol\":234,\"src/core/Managed.sol\":34,\"src/core/RewardLedger.sol\":300,\"src/interfaces/IBloom.sol\":42,\"test/Accounting.t.sol\":199,\"test/Administration.t.sol\":241,\"test/Deployment.t.sol\":131,\"test/ETH.t.sol\":218,\"test/IMD.t.sol\":172,\"test/Invariants.t.sol\":147,\"test/Rewards.t.sol\":314,\"test/fixtures/OfficialIMD.sol\":10,\"test/fixtures/OfficialSIMD.sol\":9,\"test/fixtures/OfficialWETH.sol\":10,\"test/helpers/Fixtures.sol\":145},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":3842,"exitCode":0,"name":"slither","output":"[high/medium] arbitrary-send-eth at src/core/Farm.sol:213: Farm._payFee(uint256) (src/core/Farm.sol#213-226) sends eth to arbitrary user\n[high/medium] arbitrary-send-eth at src/core/Farm.sol:187: Farm.recoverExcess(address,address,uint256) (src/core/Farm.sol#187-202) sends eth to arbitrary user\n[high/medium] arbitrary-send-eth at src/BloomTreasury.sol:74: BloomTreasury.spendFees(address,address,uint256) (src/BloomTreasury.sol#74-95) sends eth to arbitrary user\n[high/medium] weak-prng at src/core/RewardLedger.sol:215: RewardLedger._rewardDelta(address,uint256) (src/core/RewardLedger.sol#215-225) uses a weak PRNG: \"fraction %= REWARD_PRECISION (src/core/RewardLedger.sol#224)\"\n[high/medium] reentrancy-balance at src/StakedSIMD.sol:25: Reentrancy in StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48):\n[high/medium] reentrancy-balance at src/StakedETH.sol:42: Reentrancy in StakedETH._payUnderlying(address,uint256) (src/StakedETH.sol#42-58):\n[high/medium] reentrancy-balance at src/StakedSIMD.sol:25: Reentrancy in StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48):\n[high/medium] reentrancy-balance at src/core/Farm.sol:213: Reentrancy in Farm._payFee(uint256) (src/core/Farm.sol#213-226):\n[medium/high] incorrect-equality at src/core/Farm.sol:213: Farm._payFee(uint256) (src/core/Farm.sol#213-226) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/Farm.sol:130: Farm._mintShares(address,uint256,uint256) (src/core/Farm.sol#130-149) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/StakedSIMD.sol:25: StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/Farm.sol:130: Farm._mintShares(address,uint256,uint256) (src/core/Farm.sol#130-149) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/Farm.sol:115: Farm.previewRedeem(uint256) (src/core/Farm.sol#115-128) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/RewardLedger.sol:237: RewardLedger._afterShareBurn(address) (src/core/RewardLedger.sol#237-250) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/RewardLedger.sol:282: RewardLedger._sendExact(address,address,uint256) (src/core/RewardLedger.sol#282-291) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/RewardLedger.sol:237: RewardLedger._afterShareBurn(address) (src/core/RewardLedger.sol#237-250) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/RewardLedger.sol:252: RewardLedger.claimRewards(address) (src/core/RewardLedger.sol#252-264) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/RewardLedger.sol:77: RewardLedger.fundRewards(uint256) (src/core/RewardLedger.sol#77-89) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/StakedSIMD.sol:25: Reentrancy in StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48):\n[medium/medium] unused-return at src/StakedSIMD.sol:25: StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48) ignores return value by IStakedIMD(asset).deposit(receivedIMD,address(this)) (src/StakedSIMD.sol#41)\n[low/medium] missing-zero-check at src/core/Farm.sol:187: Farm.recoverExcess(address,address,uint256).recipient (src/core/Farm.sol#187) lacks a zero-check on :\n[low/medium] reentrancy-benign at src/StakedSIMD.sol:25: Reentrancy in StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48):\n[low/medium] timestamp at src/core/RewardLedger.sol:237: RewardLedger._afterShareBurn(address) (src/core/RewardLedger.sol#237-250) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:282: RewardLedger._sendExact(address,address,uint256) (src/core/RewardLedger.sol#282-291) uses timestamp for comparisons\n[low/medium] timestamp at src/core/Farm.sol:204: Farm._assertSolvent() (src/core/Farm.sol#204-211) uses timestamp for comparisons\n[low/medium] timestamp at src/core/Farm.sol:180: Farm.excessBalance(address) (src/core/Farm.sol#180-184) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:267: RewardLedger.recoverUnallocatedRewards(address,uint256) (src/core/RewardLedger.sol#267-280) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:252: RewardLedger.claimRewards(address) (src/core/RewardLedger.sol#252-264) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:143: RewardLedger._reschedule(uint256,uint256) (src/core/RewardLedger.sol#143-160) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:187: RewardLedger._updateRewards() (src/core/RewardLedger.sol#187-206) uses timestamp for comparisons\n[low/medium] timestamp at src/core/Farm.sol:187: Farm.recoverExcess(address,address,uint256) (src/core/Farm.sol#187-202) uses timestamp for comparisons","passed":true},{"durationMs":578,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/BloomFactory.sol:39: Reentrancy: State change after external call (11 places)\n[low] centralization-risk at src/core/Managed.sol:8: Centralization Risk (2 places)\n[low] large-numeric-literal at src/StakedETH.sol:13: Large Numeric Literal (2 places)\n[low] literal-instead-of-constant at src/StakedETH.sol:18: Literal Instead of Constant (10 places)\n[low] non-reentrant-not-first at src/BloomTreasury.sol:52: `nonReentrant` is Not the First Modifier (12 places)\n[low] unchecked-return at src/StakedSIMD.sol:41: Unchecked Return","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"63f127784cac9a837e6f1f9188469124e2ac39015e7eebadb8d1d95f6f478a56","verifiedTreeHash":"d554b6f209cc90251b5b09308ea186be4f14b1ef","verifierVersion":"0.1.0+560ab6a2"},{"checks":[{"durationMs":3421,"exitCode":0,"name":"build","output":"Compiling 64 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.33s\nCompiler run successful!\n","passed":true},{"durationMs":1659,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 9 tests for test/IMD.t.sol:IMDIntegrationTest\n[PASS] testAtomicIMDDepositMeasuresNonOneToOneAndClearsApproval() (gas: 502301)\n[PASS] testFarmRewardsIndependentOfOfficialVaultYield() (gas: 1070651)\n[PASS] testIMDConversionSlippageAndShareSlippageRollbackAllTransfers() (gas: 542468)\n[PASS] testIMDRedemptionExplicitlyDisabledEvenAfterHoldExpires() (gas: 306513)\n[PASS] testOfficialDecimalsApprovalsAndDirectDeposit() (gas: 380326)\n[PASS] testOfficialHoldBlocksRedemptionButImmediateInKindExitWorks() (gas: 704259)\n[PASS] testOfficialThirdPartyMintCanRestampHoldButCannotBlockSIMDExit() (gas: 667377)\n[PASS] testProtocolDepositFailureRollsBackAndNoDexFallback() (gas: 179919)\n[PASS] testValueYieldDoesNotMintFarmAssetsOrShares() (gas: 403544)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 4.15ms (4.62ms CPU time)\n\nRan 11 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDecimals24ZeroShareAndDecimals6FractionalShares() (gas: 2996232)\n[PASS] testDonationIsolationAndZeroSupplyReset() (gas: 885686)\n[PASS] testFuzzWithdrawConservation(uint128,uint128,uint64) (runs: 256, μ: 920832, ~: 933822)\nLogs:\n  Bound result 12587435\n  Bound result 900000000000000000000\n  Bound result 14321\n\n[PASS] testMeasuredNetDepositAndUnsupportedOutboundTaxRevert() (gas: 687597)\n[PASS] testPartialAndFinalExitConserveEveryUnit() (gas: 1020217)\n[PASS] testRewardFundingNeverBacksBloomShares() (gas: 666539)\n[PASS] testSameBlockFullExitNoCooldown() (gas: 383056)\n[PASS] testSharesHaveNoTransferOrApprovalInterface() (gas: 222055)\n[PASS] testSlippageAndZeroInputsRevertAtomically() (gas: 485514)\n[PASS] testTokenFailureAndCallbackCannotStealShares() (gas: 673434)\n[PASS] testVirtualOffsetHeadroomPreservesExitAtUintLimit() (gas: 2176092)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 37.23ms (42.83ms CPU time)\n\nRan 10 tests for test/ETH.t.sol:ETHTest\n[PASS] testBothDeliveryPathsFailAtomically() (gas: 649818)\n[PASS] testDirectSendRejectedDepositSlippageAndZeroDeposit() (gas: 169545)\n[PASS] testForcedETHNeverBacksSharesOrRewards() (gas: 413706)\n[PASS] testGasGriefCannotPreventWETHFallback() (gas: 487978)\n[PASS] testLargeRevertDataCannotPreventWETHFallback() (gas: 493899)\n[PASS] testNativeCallbackCannotReenterWithdrawal() (gas: 582044)\n[PASS] testNativePartialAndFullExit() (gas: 647378)\n[PASS] testNativePrincipalAndBloomRewardsRemainSeparate() (gas: 1072904)\n[PASS] testRejectingBeneficiaryReceivesCanonicalWETHWithNoExtraFee() (gas: 487664)\n[PASS] testWrappingFailureAlsoRollsBack() (gas: 562861)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 37.13ms (2.27ms CPU time)\n\nRan 12 tests for test/Administration.t.sol:AdministrationTest\n[PASS] testBindingsAreOneTimeAndDependenciesCannotFrontRun() (gas: 983586)\n[PASS] testCancelledFutureBudgetIsFreeButAccruedClaimIsProtected() (gas: 1284391)\n[PASS] testCreate2FactoryDeploysFarmWithOwnerAndInitiallyDisabled() (gas: 4632776)\n[PASS] testExplicitOwnerNeverWorkerOrFactory() (gas: 81591)\n[PASS] testFutureFarmRequiresWhitelistCorrectOwnerAndNoDuplicates() (gas: 2148488)\n[PASS] testOnlyOwnerCanBindActivatePauseAllocateAndRecover() (gas: 219663)\n[PASS] testTreasuryFailedTransferRollsBackSpending() (gas: 515482)\n[PASS] testTreasuryOnlySpendsReceivedFeesNotDonationsOrFarmFunds() (gas: 752192)\n[PASS] testTwoStepOwnershipAndSelectivePermanentRenunciation() (gas: 729767)\n[PASS] testUnboundAndUnregisteredContractsRejectActivation() (gas: 478048)\n[PASS] testWhitelistRemovalOnlyStopsDeposits() (gas: 457008)\n[PASS] testWrongChainAndDecimalsCannotActivate() (gas: 1179593)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 42.30ms (9.89ms CPU time)\n\nRan 14 tests for test/Rewards.t.sol:RewardsTest\n[PASS] testCannotPledgeEarnedRewardsTwiceOrRecoverObligations() (gas: 1020036)\n[PASS] testContinueBoostAndRestartPreserveEarnedAndEpochIdentity() (gas: 1245313)\n[PASS] testEpochBoundaryAndInvalidConfiguration() (gas: 995374)\n[PASS] testFrequentClaimSettlementsPreserveSubWeiFractions() (gas: 1651872)\n[PASS] testFullExitRetainsClaimAndClaimHasNoFee() (gas: 1257201)\n[PASS] testFundingAndConfigurationNeverStartAccrual() (gas: 797436)\n[PASS] testFuzzRewardsSolventAcrossTimeAndShareEdits(uint96,uint96,uint96,uint32) (runs: 256, μ: 1665764, ~: 1701602)\nLogs:\n  Bound result 19043\n  Bound result 589\n  Bound result 17596\n  Bound result 254\n\n[PASS] testLateDepositorReceivesNoPastRewards() (gas: 1312300)\n[PASS] testOversizedEpochCannotBrickOneShareAccrual() (gas: 1212257)\n[PASS] testPausedDepositsDoNotBlockClaimsWithdrawalOrAccrual() (gas: 1134058)\n[PASS] testRewardTransferFailureRollsBackClaimAndCanRetry() (gas: 1111460)\n[PASS] testRoundingFractionsSurviveSettlementsAndDustReleasesOnlyAtZeroSupply() (gas: 1764777)\n[PASS] testTopUpsStayFreeAndOnlyFreeFundsRecoverable() (gas: 1013604)\n[PASS] testZeroStakerIntervalsReturnToReserveAndNeverRetroactive() (gas: 1467500)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 43.92ms (51.39ms CPU time)\n\nRan 5 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] testAllApplicationConstructorsSucceedWithDependenciesAbsent() (gas: 240789)\n[PASS] testCoreScriptAssignsEveryPrivilegeToConfirmedRequesterAndDoesNotInitialize() (gas: 10258771)\n[PASS] testFarmScriptsTakeRealInputsAndNeverEnableDepositsOrEmissions() (gas: 58176347)\n[PASS] testScriptRejectsMissingBloomAndWrongChain() (gas: 8419148)\n[PASS] testScriptRejectsWrongRequesterAndUnboundToken() (gas: 8914250)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 64.16ms (90.13ms CPU time)\n\nRan 1 test for test/Invariants.t.sol:FarmInvariantTest\n[PASS]\nFarmInvariantTest invariants:\n[PASS] invariantPrincipalAndFeeConservation\n[PASS] invariantRewardSolvencyAndCredits\n FarmInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+-----------+-------+---------+----------╮\n| Contract    | Selector  | Calls | Reverts | Discards |\n+======================================================+\n| FarmHandler | cancel    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | claim     | 828   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | deposit   | 808   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | donate    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | editEpoch | 827   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | elapse    | 797   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | fund      | 837   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | pause     | 842   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | recover   | 836   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | withdraw  | 817   | 0       | 0        |\n╰-------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 684\n  Bound result 1904\n  Bound result 2731061622\n  Bound result 1352\n  Bound result 6958\n  Bound result 3340342381\n  Bound result 474\n  Bound result 202\n  Bound result 2166413321\n  Bound result 2197\n  Bound result 8\n  Bound result 4343\n  Bound result 4900178740\n  Bound result 5531\n  Bound result 4\n  Bound result 8790\n  Bound result 2817\n  Bound result 7447\n  Bound result 8025\n  Bound result 8607\n  Bound result 5710\n  Bound result 1610\n  Bound result 10926\n  Bound result 9698\n  Bound result 8108\n  Bound result 19\n  Bound result 905456384\n  Bound result 6386506982564926813467\n  Bound result 9339\n  Bound result 2428830012\n  Bound result 2486\n  Bound result 15\n  Bound result 425\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.55s (1.55s CPU time)\n\nRan 7 test suites in 1.56s (1.78s CPU time): 62 tests passed, 0 failed, 0 skipped (62 total tests)\n","passed":true},{"durationMs":57,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BloomFactory.acceptOwnership()\",\"BloomFactory.bindBloom(address)\",\"BloomFactory.deployFarm(bytes,bytes32)\",\"BloomFactory.registerFarm(address)\",\"BloomFactory.renounceOwnership()\",\"BloomFactory.renouncePowers(uint256)\",\"BloomFactory.transferOwnership(address)\",\"BloomFactory.whitelistAsset(address,bool)\",\"BloomTreasury.acceptOwnership()\",\"BloomTreasury.bindRegistry(address)\",\"BloomTreasury.receiveNativeFee()\",\"BloomTreasury.receiveTokenFee(address,uint256)\",\"BloomTreasury.renounceOwnership()\",\"BloomTreasury.renouncePowers(uint256)\",\"BloomTreasury.spendFees(address,address,uint256)\",\"BloomTreasury.transferOwnership(address)\",\"ERC20Farm.acceptOwnership()\",\"ERC20Farm.activate()\",\"ERC20Farm.cancelFutureRewards()\",\"ERC20Farm.checkpoint()\",\"ERC20Farm.claimRewards(address)\",\"ERC20Farm.configureEpoch(uint256,uint256)\",\"ERC20Farm.continueEpoch(uint256,uint256)\",\"ERC20Farm.deposit(uint256,address,uint256)\",\"ERC20Farm.fundRewards(uint256)\",\"ERC20Farm.recoverExcess(address,address,uint256)\",\"ERC20Farm.recoverUnallocatedRewards(address,uint256)\",\"ERC20Farm.renounceOwnership()\",\"ERC20Farm.renouncePowers(uint256)\",\"ERC20Farm.restartEpoch(uint256,uint256)\",\"ERC20Farm.setDepositsPaused(bool)\",\"ERC20Farm.startEpoch()\",\"ERC20Farm.transferOwnership(address)\",\"ERC20Farm.withdraw(uint256,address,uint256)\",\"StakedBLOOM.acceptOwnership()\",\"StakedBLOOM.activate()\",\"StakedBLOOM.cancelFutureRewards()\",\"StakedBLOOM.checkpoint()\",\"StakedBLOOM.claimRewards(address)\",\"StakedBLOOM.configureEpoch(uint256,uint256)\",\"StakedBLOOM.continueEpoch(uint256,uint256)\",\"StakedBLOOM.deposit(uint256,address,uint256)\",\"StakedBLOOM.fundRewards(uint256)\",\"StakedBLOOM.recoverExcess(address,address,uint256)\",\"StakedBLOOM.recoverUnallocatedRewards(address,uint256)\",\"StakedBLOOM.renounceOwnership()\",\"StakedBLOOM.renouncePowers(uint256)\",\"StakedBLOOM.restartEpoch(uint256,uint256)\",\"StakedBLOOM.setDepositsPaused(bool)\",\"StakedBLOOM.startEpoch()\",\"StakedBLOOM.transferOwnership(address)\",\"StakedBLOOM.withdraw(uint256,address,uint256)\",\"StakedETH.acceptOwnership()\",\"StakedETH.activate()\",\"StakedETH.cancelFutureRewards()\",\"StakedETH.checkpoint()\",\"StakedETH.claimRewards(address)\",\"StakedETH.configureEpoch(uint256,uint256)\",\"StakedETH.continueEpoch(uint256,uint256)\",\"StakedETH.deposit(address,uint256)\",\"StakedETH.fundRewards(uint256)\",\"StakedETH.recoverExcess(address,address,uint256)\",\"StakedETH.recoverUnallocatedRewards(address,uint256)\",\"StakedETH.renounceOwnership()\",\"StakedETH.renouncePowers(uint256)\",\"StakedETH.restartEpoch(uint256,uint256)\",\"StakedETH.setDepositsPaused(bool)\",\"StakedETH.startEpoch()\",\"StakedETH.transferOwnership(address)\",\"StakedETH.withdraw(uint256,address,uint256)\",\"StakedSIMD.acceptOwnership()\",\"StakedSIMD.activate()\",\"StakedSIMD.cancelFutureRewards()\",\"StakedSIMD.checkpoint()\",\"StakedSIMD.claimRewards(address)\",\"StakedSIMD.configureEpoch(uint256,uint256)\",\"StakedSIMD.continueEpoch(uint256,uint256)\",\"StakedSIMD.deposit(uint256,address,uint256)\",\"StakedSIMD.depositIMD(uint256,address,uint256,uint256)\",\"StakedSIMD.fundRewards(uint256)\",\"StakedSIMD.recoverExcess(address,address,uint256)\",\"StakedSIMD.recoverUnallocatedRewards(address,uint256)\",\"StakedSIMD.renounceOwnership()\",\"StakedSIMD.renouncePowers(uint256)\",\"StakedSIMD.restartEpoch(uint256,uint256)\",\"StakedSIMD.setDepositsPaused(bool)\",\"StakedSIMD.startEpoch()\",\"StakedSIMD.transferOwnership(address)\",\"StakedSIMD.withdraw(uint256,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":98,\"abi/BloomFactory.json\":581,\"abi/BloomTreasury.json\":498,\"abi/ERC20Farm.json\":1693,\"abi/StakedBLOOM.json\":1701,\"abi/StakedETH.json\":1755,\"abi/StakedSIMD.json\":1815,\"deployment/BloomTreasury.unsigned.json\":23,\"docs/ACCOUNTING.md\":87,\"docs/DEPENDENCIES.md\":16,\"docs/DEPLOYMENT.md\":85,\"docs/INTEGRATION.md\":77,\"docs/VALIDATION.md\":52,\"docs/artifact-hashes.json\":1218,\"docs/deployment-status.json\":24,\"docs/evidence/dependency-revalidation.json\":31,\"docs/evidence/imd-verification.json\":1860,\"docs/evidence/mainnet-reads.json\":104,\"docs/evidence/simd-verification.json\":1120,\"docs/evidence/weth-verification.json\":318,\"docs/validation/core-simulation.txt\":7,\"docs/validation/forge-test.txt\":680,\"foundry.toml\":23,\"launch.json\":19,\"remappings.txt\":2,\"script/DeployBLOOMFarm.s.sol\":17,\"script/DeployCore.s.sol\":16,\"script/DeployETHFarm.s.sol\":12,\"script/DeploySIMDFarm.s.sol\":12,\"script/DeploymentInputs.sol\":26,\"scripts/export_artifacts.py\":80,\"scripts/prepare_deployment.py\":93,\"scripts/verify_mainnet.py\":53,\"src/BloomFactory.sol\":97,\"src/BloomTreasury.sol\":100,\"src/MainnetAssets.sol\":15,\"src/StakedBLOOM.sol\":13,\"src/StakedETH.sol\":59,\"src/StakedSIMD.sol\":64,\"src/core/ERC20Farm.sol\":45,\"src/core/Farm.sol\":234,\"src/core/Managed.sol\":34,\"src/core/RewardLedger.sol\":300,\"src/interfaces/IBloom.sol\":42,\"test/Accounting.t.sol\":199,\"test/Administration.t.sol\":241,\"test/Deployment.t.sol\":131,\"test/ETH.t.sol\":218,\"test/IMD.t.sol\":172,\"test/Invariants.t.sol\":147,\"test/Rewards.t.sol\":314,\"test/fixtures/OfficialIMD.sol\":10,\"test/fixtures/OfficialSIMD.sol\":9,\"test/fixtures/OfficialWETH.sol\":10,\"test/helpers/Fixtures.sol\":145},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"701d04979833b6cebd03a242130a3acf047879e272c6ec90e9011cb5a0e07a3e","verifiedTreeHash":"672f29699cdf7f1e73b299b77852462aaed17046","verifierVersion":"0.1.0+560ab6a2"},{"checks":[{"durationMs":3724,"exitCode":0,"name":"build","output":"Compiling 64 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.63s\nCompiler run successful!\n","passed":true},{"durationMs":1785,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/ETH.t.sol:ETHTest\n[PASS] testBothDeliveryPathsFailAtomically() (gas: 645070)\n[PASS] testDirectSendRejectedDepositSlippageAndZeroDeposit() (gas: 159250)\n[PASS] testForcedETHNeverBacksSharesOrRewards() (gas: 409749)\n[PASS] testGasGriefCannotPreventWETHFallback() (gas: 483274)\n[PASS] testLargeRevertDataCannotPreventWETHFallback() (gas: 489195)\n[PASS] testNativeCallbackCannotReenterWithdrawal() (gas: 577317)\n[PASS] testNativePartialAndFullExit() (gas: 637860)\n[PASS] testNativePrincipalAndBloomRewardsRemainSeparate() (gas: 1062924)\n[PASS] testRejectingBeneficiaryReceivesCanonicalWETHWithNoExtraFee() (gas: 482960)\n[PASS] testWETHAndTreasuryBeneficiariesAreRejectedBeforeAnyPayout() (gas: 281561)\n[PASS] testWrappingFailureAlsoRollsBack() (gas: 558135)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 3.65ms (3.55ms CPU time)\n\nRan 10 tests for test/IMD.t.sol:IMDIntegrationTest\n[PASS] testAtomicIMDDepositMeasuresNonOneToOneAndClearsApproval() (gas: 497225)\n[PASS] testFarmRewardsIndependentOfOfficialVaultYield() (gas: 1060381)\n[PASS] testIMDConversionSlippageAndShareSlippageRollbackAllTransfers() (gas: 532218)\n[PASS] testIMDRedemptionExplicitlyDisabledEvenAfterHoldExpires() (gas: 301474)\n[PASS] testOfficialDecimalsApprovalsAndDirectDeposit() (gas: 375218)\n[PASS] testOfficialHoldBlocksRedemptionButImmediateInKindExitWorks() (gas: 699509)\n[PASS] testOfficialThirdPartyMintCanRestampHoldButCannotBlockSIMDExit() (gas: 662805)\n[PASS] testProtocolDepositFailureRollsBackAndNoDexFallback() (gas: 174706)\n[PASS] testTokenAndVaultContractsAreRejectedAsBeneficiaries() (gas: 379496)\n[PASS] testValueYieldDoesNotMintFarmAssetsOrShares() (gas: 398357)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 3.64ms (3.64ms CPU time)\n\nRan 13 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDecimals24ZeroShareAndDecimals6FractionalShares() (gas: 2995224)\n[PASS] testDonationIsolationAndZeroSupplyReset() (gas: 875875)\n[PASS] testFuzzWithdrawConservation(uint128,uint128,uint64) (runs: 256, μ: 910753, ~: 924103)\nLogs:\n  Bound result 3000000000000000000\n  Bound result 800000000000000000000\n  Bound result 2668722545\n\n[PASS] testPartialAndFinalExitConserveEveryUnit() (gas: 1010537)\n[PASS] testRetainedFeeInflationSetupIsUnprofitableAndLossBoundedByOneQuantum() (gas: 1523023)\n[PASS] testRewardFundingNeverBacksBloomShares() (gas: 661312)\n[PASS] testSameBlockFullExitNoCooldown() (gas: 378030)\n[PASS] testSharesHaveNoTransferOrApprovalInterface() (gas: 216773)\n[PASS] testSlippageAndZeroInputsRevertAtomically() (gas: 465334)\n[PASS] testTaxedTransfersAreRejectedBeforeTakingPrincipalAndAtExit() (gas: 868586)\n[PASS] testTokenFailureAndCallbackCannotStealShares() (gas: 663104)\n[PASS] testVirtualOffsetHeadroomPreservesExitAtUintLimit() (gas: 2177904)\n[PASS] testVirtualOffsetsKeepInitialRateAndAtLeastOneMillionQuanta() (gas: 1833636)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 49.63ms (55.20ms CPU time)\n\nRan 13 tests for test/Administration.t.sol:AdministrationTest\n[PASS] testBindingsAreOneTimeAndDependenciesCannotFrontRun() (gas: 983586)\n[PASS] testCancelledFutureBudgetIsFreeButAccruedClaimIsProtected() (gas: 1274713)\n[PASS] testCreate2FactoryDeploysFarmWithOwnerAndInitiallyDisabled() (gas: 4684821)\n[PASS] testExplicitOwnerNeverWorkerOrFactory() (gas: 81613)\n[PASS] testFarmThatCouldNeverActivateCannotTakeTheAssetSlot() (gas: 4703577)\n[PASS] testFutureFarmRequiresWhitelistCorrectOwnerAndNoDuplicates() (gas: 2155894)\n[PASS] testOnlyOwnerCanBindActivatePauseAllocateAndRecover() (gas: 219575)\n[PASS] testStrandingRecipientsAreRejected() (gas: 1263657)\n[PASS] testTreasuryFailedTransferRollsBackSpending() (gas: 510642)\n[PASS] testTreasuryOnlySpendsReceivedFeesNotDonationsOrFarmFunds() (gas: 747352)\n[PASS] testTwoStepOwnershipAndSelectivePermanentRenunciation() (gas: 725171)\n[PASS] testUnboundAndUnregisteredContractsRejectActivation() (gas: 482714)\n[PASS] testWhitelistGovernsAdmissionOnlyAndRenouncedPauseIsFinal() (gas: 2130499)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 49.74ms (9.71ms CPU time)\n\nRan 14 tests for test/Rewards.t.sol:RewardsTest\n[PASS] testCannotPledgeEarnedRewardsTwiceOrRecoverObligations() (gas: 1004298)\n[PASS] testContinueBoostAndRestartPreserveEarnedAndEpochIdentity() (gas: 1229154)\n[PASS] testEpochBoundaryAndInvalidConfiguration() (gas: 978553)\n[PASS] testFrequentClaimSettlementsPreserveSubWeiFractions() (gas: 1636807)\n[PASS] testFullExitRetainsClaimAndClaimHasNoFee() (gas: 1246779)\n[PASS] testFundingAndConfigurationNeverStartAccrual() (gas: 786567)\n[PASS] testFuzzRewardsSolventAcrossTimeAndShareEdits(uint96,uint96,uint96,uint32) (runs: 256, μ: 1655931, ~: 1686538)\nLogs:\n  Bound result 32920472225624112\n  Bound result 11892089935238\n  Bound result 422016505797269\n  Bound result 642706\n\n[PASS] testLateDepositorReceivesNoPastRewards() (gas: 1296670)\n[PASS] testOversizedEpochCannotBrickOneShareAccrual() (gas: 1201879)\n[PASS] testPausedDepositsDoNotBlockClaimsWithdrawalOrAccrual() (gas: 1123568)\n[PASS] testRewardTransferFailureRollsBackClaimAndCanRetry() (gas: 1101188)\n[PASS] testRoundingFractionsSurviveSettlementsAndDustReleasesOnlyAtZeroSupply() (gas: 1750145)\n[PASS] testTopUpsStayFreeAndOnlyFreeFundsRecoverable() (gas: 1002992)\n[PASS] testZeroStakerIntervalsReturnToReserveAndNeverRetroactive() (gas: 1451825)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 49.66ms (57.61ms CPU time)\n\nRan 5 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] testAllApplicationConstructorsSucceedWithDependenciesAbsent() (gas: 240456)\n[PASS] testCoreScriptAssignsEveryPrivilegeToConfirmedRequesterAndDoesNotInitialize() (gas: 10354342)\n[PASS] testFarmScriptsTakeRealInputsAndNeverEnableDepositsOrEmissions() (gas: 58818632)\n[PASS] testScriptRejectsMissingBloomAndWrongChain() (gas: 8510378)\n[PASS] testScriptRejectsWrongRequesterAndUnboundToken() (gas: 8989950)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 53.44ms (65.16ms CPU time)\n\nRan 1 test for test/Invariants.t.sol:FarmInvariantTest\n[PASS]\nFarmInvariantTest invariants:\n[PASS] invariantPrincipalAndFeeConservation\n[PASS] invariantRewardSolvencyAndCredits\n FarmInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+-----------+-------+---------+----------╮\n| Contract    | Selector  | Calls | Reverts | Discards |\n+======================================================+\n| FarmHandler | cancel    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | claim     | 828   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | deposit   | 808   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | donate    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | editEpoch | 827   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | elapse    | 797   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | fund      | 837   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | pause     | 842   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | recover   | 836   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | withdraw  | 817   | 0       | 0        |\n╰-------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 683\n  Bound result 1905\n  Bound result 1871\n  Bound result 4344\n  Bound result 6959\n  Bound result 459\n  Bound result 148\n  Bound result 2166413321\n  Bound result 2115\n  Bound result 525\n  Bound result 1806\n  Bound result 10\n  Bound result 4900178740\n  Bound result 5174\n  Bound result 17\n  Bound result 1313373041\n  Bound result 141516\n  Bound result 7438\n  Bound result 7757\n  Bound result 8694\n  Bound result 5647\n  Bound result 8861\n  Bound result 193\n  Bound result 9720\n  Bound result 7938\n  Bound result 25\n  Bound result 4138968485\n  Bound result 6386506982564926813467\n  Bound result 9159\n  Bound result 7470\n  Bound result 2527\n  Bound result 15\n  Bound result 5508\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.68s (1.67s CPU time)\n\nRan 7 test suites in 1.68s (1.89s CPU time): 67 tests passed, 0 failed, 0 skipped (67 total tests)\n","passed":true},{"durationMs":72,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BloomFactory.acceptOwnership()\",\"BloomFactory.bindBloom(address)\",\"BloomFactory.deployFarm(bytes,bytes32)\",\"BloomFactory.registerFarm(address)\",\"BloomFactory.renounceOwnership()\",\"BloomFactory.renouncePowers(uint256)\",\"BloomFactory.transferOwnership(address)\",\"BloomFactory.whitelistAsset(address,bool)\",\"BloomTreasury.acceptOwnership()\",\"BloomTreasury.bindRegistry(address)\",\"BloomTreasury.receiveNativeFee()\",\"BloomTreasury.receiveTokenFee(address,uint256)\",\"BloomTreasury.renounceOwnership()\",\"BloomTreasury.renouncePowers(uint256)\",\"BloomTreasury.spendFees(address,address,uint256)\",\"BloomTreasury.transferOwnership(address)\",\"ERC20Farm.acceptOwnership()\",\"ERC20Farm.activate()\",\"ERC20Farm.cancelFutureRewards()\",\"ERC20Farm.checkpoint()\",\"ERC20Farm.claimRewards(address)\",\"ERC20Farm.configureEpoch(uint256,uint256)\",\"ERC20Farm.continueEpoch(uint256,uint256)\",\"ERC20Farm.deposit(uint256,address,uint256)\",\"ERC20Farm.fundRewards(uint256)\",\"ERC20Farm.recoverExcess(address,address,uint256)\",\"ERC20Farm.recoverUnallocatedRewards(address,uint256)\",\"ERC20Farm.renounceOwnership()\",\"ERC20Farm.renouncePowers(uint256)\",\"ERC20Farm.restartEpoch(uint256,uint256)\",\"ERC20Farm.setDepositsPaused(bool)\",\"ERC20Farm.startEpoch()\",\"ERC20Farm.transferOwnership(address)\",\"ERC20Farm.withdraw(uint256,address,uint256)\",\"StakedBLOOM.acceptOwnership()\",\"StakedBLOOM.activate()\",\"StakedBLOOM.cancelFutureRewards()\",\"StakedBLOOM.checkpoint()\",\"StakedBLOOM.claimRewards(address)\",\"StakedBLOOM.configureEpoch(uint256,uint256)\",\"StakedBLOOM.continueEpoch(uint256,uint256)\",\"StakedBLOOM.deposit(uint256,address,uint256)\",\"StakedBLOOM.fundRewards(uint256)\",\"StakedBLOOM.recoverExcess(address,address,uint256)\",\"StakedBLOOM.recoverUnallocatedRewards(address,uint256)\",\"StakedBLOOM.renounceOwnership()\",\"StakedBLOOM.renouncePowers(uint256)\",\"StakedBLOOM.restartEpoch(uint256,uint256)\",\"StakedBLOOM.setDepositsPaused(bool)\",\"StakedBLOOM.startEpoch()\",\"StakedBLOOM.transferOwnership(address)\",\"StakedBLOOM.withdraw(uint256,address,uint256)\",\"StakedETH.acceptOwnership()\",\"StakedETH.activate()\",\"StakedETH.cancelFutureRewards()\",\"StakedETH.checkpoint()\",\"StakedETH.claimRewards(address)\",\"StakedETH.configureEpoch(uint256,uint256)\",\"StakedETH.continueEpoch(uint256,uint256)\",\"StakedETH.deposit(address,uint256)\",\"StakedETH.fundRewards(uint256)\",\"StakedETH.recoverExcess(address,address,uint256)\",\"StakedETH.recoverUnallocatedRewards(address,uint256)\",\"StakedETH.renounceOwnership()\",\"StakedETH.renouncePowers(uint256)\",\"StakedETH.restartEpoch(uint256,uint256)\",\"StakedETH.setDepositsPaused(bool)\",\"StakedETH.startEpoch()\",\"StakedETH.transferOwnership(address)\",\"StakedETH.withdraw(uint256,address,uint256)\",\"StakedSIMD.acceptOwnership()\",\"StakedSIMD.activate()\",\"StakedSIMD.cancelFutureRewards()\",\"StakedSIMD.checkpoint()\",\"StakedSIMD.claimRewards(address)\",\"StakedSIMD.configureEpoch(uint256,uint256)\",\"StakedSIMD.continueEpoch(uint256,uint256)\",\"StakedSIMD.deposit(uint256,address,uint256)\",\"StakedSIMD.depositIMD(uint256,address,uint256,uint256)\",\"StakedSIMD.fundRewards(uint256)\",\"StakedSIMD.recoverExcess(address,address,uint256)\",\"StakedSIMD.recoverUnallocatedRewards(address,uint256)\",\"StakedSIMD.renounceOwnership()\",\"StakedSIMD.renouncePowers(uint256)\",\"StakedSIMD.restartEpoch(uint256,uint256)\",\"StakedSIMD.setDepositsPaused(bool)\",\"StakedSIMD.startEpoch()\",\"StakedSIMD.transferOwnership(address)\",\"StakedSIMD.withdraw(uint256,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":99,\"abi/BloomFactory.json\":581,\"abi/BloomTreasury.json\":498,\"abi/ERC20Farm.json\":1726,\"abi/StakedBLOOM.json\":1734,\"abi/StakedETH.json\":1788,\"abi/StakedSIMD.json\":1848,\"deployment/BloomTreasury.unsigned.json\":23,\"docs/ACCOUNTING.md\":89,\"docs/DEPENDENCIES.md\":16,\"docs/DEPLOYMENT.md\":85,\"docs/INTEGRATION.md\":77,\"docs/VALIDATION.md\":56,\"docs/artifact-hashes.json\":1250,\"docs/deployment-status.json\":24,\"docs/evidence/dependency-revalidation.json\":31,\"docs/evidence/imd-verification.json\":1860,\"docs/evidence/mainnet-reads.json\":104,\"docs/evidence/simd-verification.json\":1120,\"docs/evidence/weth-verification.json\":318,\"docs/validation/core-simulation.txt\":7,\"docs/validation/forge-test.txt\":703,\"foundry.toml\":23,\"launch.json\":19,\"remappings.txt\":2,\"script/DeployBLOOMFarm.s.sol\":17,\"script/DeployCore.s.sol\":16,\"script/DeployETHFarm.s.sol\":12,\"script/DeploySIMDFarm.s.sol\":12,\"script/DeploymentInputs.sol\":26,\"scripts/export_artifacts.py\":80,\"scripts/prepare_deployment.py\":93,\"scripts/verify_mainnet.py\":53,\"src/BloomFactory.sol\":100,\"src/BloomTreasury.sol\":100,\"src/MainnetAssets.sol\":15,\"src/StakedBLOOM.sol\":13,\"src/StakedETH.sol\":65,\"src/StakedSIMD.sol\":69,\"src/core/ERC20Farm.sol\":47,\"src/core/Farm.sol\":256,\"src/core/Managed.sol\":34,\"src/core/RewardLedger.sol\":300,\"src/interfaces/IBloom.sol\":43,\"test/Accounting.t.sol\":263,\"test/Administration.t.sol\":297,\"test/Deployment.t.sol\":131,\"test/ETH.t.sol\":234,\"test/IMD.t.sol\":186,\"test/Invariants.t.sol\":147,\"test/Rewards.t.sol\":314,\"test/fixtures/OfficialIMD.sol\":10,\"test/fixtures/OfficialSIMD.sol\":9,\"test/fixtures/OfficialWETH.sol\":10,\"test/helpers/Fixtures.sol\":145},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"74350399ec93c2e1d45ef71b4e383b9a1946232d69121f6c7fa5ac669be97e3d","verifiedTreeHash":"38c43f7053308c31a6d533c41190bd07cadc4679","verifierVersion":"0.1.0+560ab6a2"},{"checks":[{"durationMs":3352,"exitCode":0,"name":"build","output":"Compiling 64 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.26s\nCompiler run successful!\n","passed":true},{"durationMs":1576,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 10 tests for test/IMD.t.sol:IMDIntegrationTest\n[PASS] testAtomicIMDDepositMeasuresNonOneToOneAndClearsApproval() (gas: 497225)\n[PASS] testFarmRewardsIndependentOfOfficialVaultYield() (gas: 1060381)\n[PASS] testIMDConversionSlippageAndShareSlippageRollbackAllTransfers() (gas: 532218)\n[PASS] testIMDRedemptionExplicitlyDisabledEvenAfterHoldExpires() (gas: 301474)\n[PASS] testOfficialDecimalsApprovalsAndDirectDeposit() (gas: 375218)\n[PASS] testOfficialHoldBlocksRedemptionButImmediateInKindExitWorks() (gas: 699509)\n[PASS] testOfficialThirdPartyMintCanRestampHoldButCannotBlockSIMDExit() (gas: 662805)\n[PASS] testProtocolDepositFailureRollsBackAndNoDexFallback() (gas: 174706)\n[PASS] testTokenAndVaultContractsAreRejectedAsBeneficiaries() (gas: 379496)\n[PASS] testValueYieldDoesNotMintFarmAssetsOrShares() (gas: 398357)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 2.73ms (3.19ms CPU time)\n\nRan 5 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] testAllApplicationConstructorsSucceedWithDependenciesAbsent() (gas: 240456)\n[PASS] testCoreScriptAssignsEveryPrivilegeToConfirmedRequesterAndDoesNotInitialize() (gas: 10354342)\n[PASS] testFarmScriptsTakeRealInputsAndNeverEnableDepositsOrEmissions() (gas: 58818632)\n[PASS] testScriptRejectsMissingBloomAndWrongChain() (gas: 8510378)\n[PASS] testScriptRejectsWrongRequesterAndUnboundToken() (gas: 8989950)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 50.68ms (65.82ms CPU time)\n\nRan 13 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDecimals24ZeroShareAndDecimals6FractionalShares() (gas: 2995224)\n[PASS] testDonationIsolationAndZeroSupplyReset() (gas: 875875)\n[PASS] testFuzzWithdrawConservation(uint128,uint128,uint64) (runs: 256, μ: 910753, ~: 924103)\nLogs:\n  Bound result 3000000000000000000\n  Bound result 800000000000000000000\n  Bound result 2668722545\n\n[PASS] testPartialAndFinalExitConserveEveryUnit() (gas: 1010537)\n[PASS] testRetainedFeeInflationSetupIsUnprofitableAndLossBoundedByOneQuantum() (gas: 1523023)\n[PASS] testRewardFundingNeverBacksBloomShares() (gas: 661312)\n[PASS] testSameBlockFullExitNoCooldown() (gas: 378030)\n[PASS] testSharesHaveNoTransferOrApprovalInterface() (gas: 216773)\n[PASS] testSlippageAndZeroInputsRevertAtomically() (gas: 465334)\n[PASS] testTaxedTransfersAreRejectedBeforeTakingPrincipalAndAtExit() (gas: 868586)\n[PASS] testTokenFailureAndCallbackCannotStealShares() (gas: 663104)\n[PASS] testVirtualOffsetHeadroomPreservesExitAtUintLimit() (gas: 2177904)\n[PASS] testVirtualOffsetsKeepInitialRateAndAtLeastOneMillionQuanta() (gas: 1833636)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 53.77ms (48.41ms CPU time)\n\nRan 11 tests for test/ETH.t.sol:ETHTest\n[PASS] testBothDeliveryPathsFailAtomically() (gas: 645070)\n[PASS] testDirectSendRejectedDepositSlippageAndZeroDeposit() (gas: 159250)\n[PASS] testForcedETHNeverBacksSharesOrRewards() (gas: 409749)\n[PASS] testGasGriefCannotPreventWETHFallback() (gas: 483274)\n[PASS] testLargeRevertDataCannotPreventWETHFallback() (gas: 489195)\n[PASS] testNativeCallbackCannotReenterWithdrawal() (gas: 577317)\n[PASS] testNativePartialAndFullExit() (gas: 637860)\n[PASS] testNativePrincipalAndBloomRewardsRemainSeparate() (gas: 1062924)\n[PASS] testRejectingBeneficiaryReceivesCanonicalWETHWithNoExtraFee() (gas: 482960)\n[PASS] testWETHAndTreasuryBeneficiariesAreRejectedBeforeAnyPayout() (gas: 281561)\n[PASS] testWrappingFailureAlsoRollsBack() (gas: 558135)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 53.77ms (2.59ms CPU time)\n\nRan 14 tests for test/Rewards.t.sol:RewardsTest\n[PASS] testCannotPledgeEarnedRewardsTwiceOrRecoverObligations() (gas: 1004298)\n[PASS] testContinueBoostAndRestartPreserveEarnedAndEpochIdentity() (gas: 1229154)\n[PASS] testEpochBoundaryAndInvalidConfiguration() (gas: 978553)\n[PASS] testFrequentClaimSettlementsPreserveSubWeiFractions() (gas: 1636807)\n[PASS] testFullExitRetainsClaimAndClaimHasNoFee() (gas: 1246779)\n[PASS] testFundingAndConfigurationNeverStartAccrual() (gas: 786567)\n[PASS] testFuzzRewardsSolventAcrossTimeAndShareEdits(uint96,uint96,uint96,uint32) (runs: 256, μ: 1655931, ~: 1686538)\nLogs:\n  Bound result 1937698047564\n  Bound result 506567277471\n  Bound result 11453844641265470364\n  Bound result 465828\n\n[PASS] testLateDepositorReceivesNoPastRewards() (gas: 1296670)\n[PASS] testOversizedEpochCannotBrickOneShareAccrual() (gas: 1201879)\n[PASS] testPausedDepositsDoNotBlockClaimsWithdrawalOrAccrual() (gas: 1123568)\n[PASS] testRewardTransferFailureRollsBackClaimAndCanRetry() (gas: 1101188)\n[PASS] testRoundingFractionsSurviveSettlementsAndDustReleasesOnlyAtZeroSupply() (gas: 1750145)\n[PASS] testTopUpsStayFreeAndOnlyFreeFundsRecoverable() (gas: 1002992)\n[PASS] testZeroStakerIntervalsReturnToReserveAndNeverRetroactive() (gas: 1451825)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 53.68ms (60.87ms CPU time)\n\nRan 13 tests for test/Administration.t.sol:AdministrationTest\n[PASS] testBindingsAreOneTimeAndDependenciesCannotFrontRun() (gas: 983586)\n[PASS] testCancelledFutureBudgetIsFreeButAccruedClaimIsProtected() (gas: 1274713)\n[PASS] testCreate2FactoryDeploysFarmWithOwnerAndInitiallyDisabled() (gas: 4684821)\n[PASS] testExplicitOwnerNeverWorkerOrFactory() (gas: 81613)\n[PASS] testFarmThatCouldNeverActivateCannotTakeTheAssetSlot() (gas: 4703577)\n[PASS] testFutureFarmRequiresWhitelistCorrectOwnerAndNoDuplicates() (gas: 2155894)\n[PASS] testOnlyOwnerCanBindActivatePauseAllocateAndRecover() (gas: 219575)\n[PASS] testStrandingRecipientsAreRejected() (gas: 1263657)\n[PASS] testTreasuryFailedTransferRollsBackSpending() (gas: 510642)\n[PASS] testTreasuryOnlySpendsReceivedFeesNotDonationsOrFarmFunds() (gas: 747352)\n[PASS] testTwoStepOwnershipAndSelectivePermanentRenunciation() (gas: 725171)\n[PASS] testUnboundAndUnregisteredContractsRejectActivation() (gas: 482714)\n[PASS] testWhitelistGovernsAdmissionOnlyAndRenouncedPauseIsFinal() (gas: 2130499)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 53.85ms (8.39ms CPU time)\n\nRan 1 test for test/Invariants.t.sol:FarmInvariantTest\n[PASS]\nFarmInvariantTest invariants:\n[PASS] invariantPrincipalAndFeeConservation\n[PASS] invariantRewardSolvencyAndCredits\n FarmInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+-----------+-------+---------+----------╮\n| Contract    | Selector  | Calls | Reverts | Discards |\n+======================================================+\n| FarmHandler | cancel    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | claim     | 828   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | deposit   | 808   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | donate    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | editEpoch | 827   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | elapse    | 797   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | fund      | 837   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | pause     | 842   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | recover   | 836   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | withdraw  | 817   | 0       | 0        |\n╰-------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 683\n  Bound result 1905\n  Bound result 1871\n  Bound result 4344\n  Bound result 6959\n  Bound result 459\n  Bound result 148\n  Bound result 2166413321\n  Bound result 2115\n  Bound result 525\n  Bound result 1806\n  Bound result 10\n  Bound result 4900178740\n  Bound result 5174\n  Bound result 17\n  Bound result 1313373041\n  Bound result 141516\n  Bound result 7438\n  Bound result 7757\n  Bound result 8694\n  Bound result 5647\n  Bound result 8861\n  Bound result 193\n  Bound result 9720\n  Bound result 7938\n  Bound result 25\n  Bound result 4138968485\n  Bound result 6386506982564926813467\n  Bound result 9159\n  Bound result 7470\n  Bound result 2527\n  Bound result 15\n  Bound result 5508\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.48s (1.48s CPU time)\n\nRan 7 test suites in 1.48s (1.75s CPU time): 67 tests passed, 0 failed, 0 skipped (67 total tests)\n","passed":true},{"durationMs":63,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BloomFactory.acceptOwnership()\",\"BloomFactory.bindBloom(address)\",\"BloomFactory.deployFarm(bytes,bytes32)\",\"BloomFactory.registerFarm(address)\",\"BloomFactory.renounceOwnership()\",\"BloomFactory.renouncePowers(uint256)\",\"BloomFactory.transferOwnership(address)\",\"BloomFactory.whitelistAsset(address,bool)\",\"BloomTreasury.acceptOwnership()\",\"BloomTreasury.bindRegistry(address)\",\"BloomTreasury.receiveNativeFee()\",\"BloomTreasury.receiveTokenFee(address,uint256)\",\"BloomTreasury.renounceOwnership()\",\"BloomTreasury.renouncePowers(uint256)\",\"BloomTreasury.spendFees(address,address,uint256)\",\"BloomTreasury.transferOwnership(address)\",\"ERC20Farm.acceptOwnership()\",\"ERC20Farm.activate()\",\"ERC20Farm.cancelFutureRewards()\",\"ERC20Farm.checkpoint()\",\"ERC20Farm.claimRewards(address)\",\"ERC20Farm.configureEpoch(uint256,uint256)\",\"ERC20Farm.continueEpoch(uint256,uint256)\",\"ERC20Farm.deposit(uint256,address,uint256)\",\"ERC20Farm.fundRewards(uint256)\",\"ERC20Farm.recoverExcess(address,address,uint256)\",\"ERC20Farm.recoverUnallocatedRewards(address,uint256)\",\"ERC20Farm.renounceOwnership()\",\"ERC20Farm.renouncePowers(uint256)\",\"ERC20Farm.restartEpoch(uint256,uint256)\",\"ERC20Farm.setDepositsPaused(bool)\",\"ERC20Farm.startEpoch()\",\"ERC20Farm.transferOwnership(address)\",\"ERC20Farm.withdraw(uint256,address,uint256)\",\"StakedBLOOM.acceptOwnership()\",\"StakedBLOOM.activate()\",\"StakedBLOOM.cancelFutureRewards()\",\"StakedBLOOM.checkpoint()\",\"StakedBLOOM.claimRewards(address)\",\"StakedBLOOM.configureEpoch(uint256,uint256)\",\"StakedBLOOM.continueEpoch(uint256,uint256)\",\"StakedBLOOM.deposit(uint256,address,uint256)\",\"StakedBLOOM.fundRewards(uint256)\",\"StakedBLOOM.recoverExcess(address,address,uint256)\",\"StakedBLOOM.recoverUnallocatedRewards(address,uint256)\",\"StakedBLOOM.renounceOwnership()\",\"StakedBLOOM.renouncePowers(uint256)\",\"StakedBLOOM.restartEpoch(uint256,uint256)\",\"StakedBLOOM.setDepositsPaused(bool)\",\"StakedBLOOM.startEpoch()\",\"StakedBLOOM.transferOwnership(address)\",\"StakedBLOOM.withdraw(uint256,address,uint256)\",\"StakedETH.acceptOwnership()\",\"StakedETH.activate()\",\"StakedETH.cancelFutureRewards()\",\"StakedETH.checkpoint()\",\"StakedETH.claimRewards(address)\",\"StakedETH.configureEpoch(uint256,uint256)\",\"StakedETH.continueEpoch(uint256,uint256)\",\"StakedETH.deposit(address,uint256)\",\"StakedETH.fundRewards(uint256)\",\"StakedETH.recoverExcess(address,address,uint256)\",\"StakedETH.recoverUnallocatedRewards(address,uint256)\",\"StakedETH.renounceOwnership()\",\"StakedETH.renouncePowers(uint256)\",\"StakedETH.restartEpoch(uint256,uint256)\",\"StakedETH.setDepositsPaused(bool)\",\"StakedETH.startEpoch()\",\"StakedETH.transferOwnership(address)\",\"StakedETH.withdraw(uint256,address,uint256)\",\"StakedSIMD.acceptOwnership()\",\"StakedSIMD.activate()\",\"StakedSIMD.cancelFutureRewards()\",\"StakedSIMD.checkpoint()\",\"StakedSIMD.claimRewards(address)\",\"StakedSIMD.configureEpoch(uint256,uint256)\",\"StakedSIMD.continueEpoch(uint256,uint256)\",\"StakedSIMD.deposit(uint256,address,uint256)\",\"StakedSIMD.depositIMD(uint256,address,uint256,uint256)\",\"StakedSIMD.fundRewards(uint256)\",\"StakedSIMD.recoverExcess(address,address,uint256)\",\"StakedSIMD.recoverUnallocatedRewards(address,uint256)\",\"StakedSIMD.renounceOwnership()\",\"StakedSIMD.renouncePowers(uint256)\",\"StakedSIMD.restartEpoch(uint256,uint256)\",\"StakedSIMD.setDepositsPaused(bool)\",\"StakedSIMD.startEpoch()\",\"StakedSIMD.transferOwnership(address)\",\"StakedSIMD.withdraw(uint256,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":99,\"abi/BloomFactory.json\":581,\"abi/BloomTreasury.json\":498,\"abi/ERC20Farm.json\":1726,\"abi/StakedBLOOM.json\":1734,\"abi/StakedETH.json\":1788,\"abi/StakedSIMD.json\":1848,\"deployment/BloomTreasury.unsigned.json\":23,\"docs/ACCOUNTING.md\":89,\"docs/DEPENDENCIES.md\":16,\"docs/DEPLOYMENT.md\":85,\"docs/INTEGRATION.md\":77,\"docs/VALIDATION.md\":56,\"docs/artifact-hashes.json\":1250,\"docs/deployment-status.json\":24,\"docs/evidence/dependency-revalidation.json\":31,\"docs/evidence/imd-verification.json\":1860,\"docs/evidence/mainnet-reads.json\":104,\"docs/evidence/simd-verification.json\":1120,\"docs/evidence/weth-verification.json\":318,\"docs/validation/core-simulation.txt\":7,\"docs/validation/forge-test.txt\":703,\"foundry.toml\":23,\"remappings.txt\":2,\"script/DeployBLOOMFarm.s.sol\":17,\"script/DeployCore.s.sol\":16,\"script/DeployETHFarm.s.sol\":12,\"script/DeploySIMDFarm.s.sol\":12,\"script/DeploymentInputs.sol\":26,\"scripts/export_artifacts.py\":80,\"scripts/prepare_deployment.py\":93,\"scripts/verify_mainnet.py\":53,\"src/BloomFactory.sol\":100,\"src/BloomTreasury.sol\":100,\"src/MainnetAssets.sol\":15,\"src/StakedBLOOM.sol\":13,\"src/StakedETH.sol\":65,\"src/StakedSIMD.sol\":69,\"src/core/ERC20Farm.sol\":47,\"src/core/Farm.sol\":256,\"src/core/Managed.sol\":34,\"src/core/RewardLedger.sol\":300,\"src/interfaces/IBloom.sol\":43,\"test/Accounting.t.sol\":263,\"test/Administration.t.sol\":297,\"test/Deployment.t.sol\":131,\"test/ETH.t.sol\":234,\"test/IMD.t.sol\":186,\"test/Invariants.t.sol\":147,\"test/Rewards.t.sol\":314,\"test/fixtures/OfficialIMD.sol\":10,\"test/fixtures/OfficialSIMD.sol\":9,\"test/fixtures/OfficialWETH.sol\":10,\"test/helpers/Fixtures.sol\":145},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":3970,"exitCode":0,"name":"slither","output":"[high/medium] arbitrary-send-eth at src/core/Farm.sol:209: Farm.recoverExcess(address,address,uint256) (src/core/Farm.sol#209-224) sends eth to arbitrary user\n[high/medium] arbitrary-send-eth at src/core/Farm.sol:235: Farm._payFee(uint256) (src/core/Farm.sol#235-248) sends eth to arbitrary user\n[high/medium] arbitrary-send-eth at src/BloomTreasury.sol:74: BloomTreasury.spendFees(address,address,uint256) (src/BloomTreasury.sol#74-95) sends eth to arbitrary user\n[high/medium] weak-prng at src/core/RewardLedger.sol:215: RewardLedger._rewardDelta(address,uint256) (src/core/RewardLedger.sol#215-225) uses a weak PRNG: \"fraction %= REWARD_PRECISION (src/core/RewardLedger.sol#224)\"\n[high/medium] reentrancy-balance at src/StakedSIMD.sol:25: Reentrancy in StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48):\n[high/medium] reentrancy-balance at src/StakedETH.sol:48: Reentrancy in StakedETH._payUnderlying(address,uint256) (src/StakedETH.sol#48-64):\n[high/medium] reentrancy-balance at src/StakedSIMD.sol:25: Reentrancy in StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48):\n[high/medium] reentrancy-balance at src/core/Farm.sol:235: Reentrancy in Farm._payFee(uint256) (src/core/Farm.sol#235-248):\n[medium/high] incorrect-equality at src/core/Farm.sol:152: Farm._mintShares(address,uint256,uint256) (src/core/Farm.sol#152-171) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/Farm.sol:152: Farm._mintShares(address,uint256,uint256) (src/core/Farm.sol#152-171) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/RewardLedger.sol:237: RewardLedger._afterShareBurn(address) (src/core/RewardLedger.sol#237-250) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/RewardLedger.sol:282: RewardLedger._sendExact(address,address,uint256) (src/core/RewardLedger.sol#282-291) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/RewardLedger.sol:237: RewardLedger._afterShareBurn(address) (src/core/RewardLedger.sol#237-250) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/RewardLedger.sol:252: RewardLedger.claimRewards(address) (src/core/RewardLedger.sol#252-264) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/Farm.sol:235: Farm._payFee(uint256) (src/core/Farm.sol#235-248) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/Farm.sol:137: Farm.previewRedeem(uint256) (src/core/Farm.sol#137-150) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/core/RewardLedger.sol:77: RewardLedger.fundRewards(uint256) (src/core/RewardLedger.sol#77-89) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/StakedSIMD.sol:25: Reentrancy in StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48):\n[medium/medium] unused-return at src/StakedSIMD.sol:25: StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48) ignores return value by IStakedIMD(asset).deposit(receivedIMD,address(this)) (src/StakedSIMD.sol#41)\n[low/medium] missing-zero-check at src/core/Farm.sol:209: Farm.recoverExcess(address,address,uint256).recipient (src/core/Farm.sol#209) lacks a zero-check on :\n[low/medium] reentrancy-benign at src/StakedSIMD.sol:25: Reentrancy in StakedSIMD.depositIMD(uint256,address,uint256,uint256) (src/StakedSIMD.sol#25-48):\n[low/medium] timestamp at src/core/Farm.sol:202: Farm.excessBalance(address) (src/core/Farm.sol#202-206) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:237: RewardLedger._afterShareBurn(address) (src/core/RewardLedger.sol#237-250) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:282: RewardLedger._sendExact(address,address,uint256) (src/core/RewardLedger.sol#282-291) uses timestamp for comparisons\n[low/medium] timestamp at src/core/Farm.sol:209: Farm.recoverExcess(address,address,uint256) (src/core/Farm.sol#209-224) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:267: RewardLedger.recoverUnallocatedRewards(address,uint256) (src/core/RewardLedger.sol#267-280) uses timestamp for comparisons\n[low/medium] timestamp at src/core/Farm.sol:226: Farm._assertSolvent() (src/core/Farm.sol#226-233) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:252: RewardLedger.claimRewards(address) (src/core/RewardLedger.sol#252-264) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:143: RewardLedger._reschedule(uint256,uint256) (src/core/RewardLedger.sol#143-160) uses timestamp for comparisons\n[low/medium] timestamp at src/core/RewardLedger.sol:187: RewardLedger._updateRewards() (src/core/RewardLedger.sol#187-206) uses timestamp for comparisons","passed":true},{"durationMs":510,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/BloomFactory.sol:39: Reentrancy: State change after external call (9 places)\n[low] centralization-risk at src/core/Managed.sol:8: Centralization Risk (2 places)\n[low] large-numeric-literal at src/StakedETH.sol:13: Large Numeric Literal (2 places)\n[low] literal-instead-of-constant at src/StakedETH.sol:18: Literal Instead of Constant (6 places)\n[low] non-reentrant-not-first at src/BloomTreasury.sol:52: `nonReentrant` is Not the First Modifier (12 places)\n[low] unchecked-return at src/StakedSIMD.sol:41: Unchecked Return","passed":true},{"durationMs":1966,"exitCode":0,"name":"proof 82730568c33e","output":"Compiling 53 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.38s\nCompiler run successful!\n\nRan 1 test for test/imd-proof-e64a7933/Proof_82730568c33e.t.sol:InflationProofTest\n[PASS] testFrontRunInflationIsUnprofitableAndVictimOnlyPaysTheFee() (gas: 822058)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.28ms (501.70µs CPU time)\n\nRan 1 test suite in 3.27ms (1.28ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true},{"durationMs":1404,"exitCode":0,"name":"proof 0cdb46606750","output":"2026-10-21T15:58:01.414678Z ERROR foundry_compilers_artifacts_solc::sources: error=\"/tmp/imd-verify-FW8DYY/repo/test/imd-proof-e64a7933/Proof_82730568c33e.t.sol\": No such file or directory (os error 2)\nCompiling 1 files with Solc 0.8.26\nSolc 0.8.26 finished in 888.08ms\nCompiler run successful!\n\nRan 1 test for test/imd-proof-accc2868/Proof_0cdb46606750.t.sol:UnactivatableFarmSlotTest\n[PASS] testCorrectFarmCanBeRegisteredAfterMisconfiguredOne() (gas: 6861577)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 904.39µs (435.81µs CPU time)\n\nRan 1 test suite in 3.52ms (904.39µs CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"79efecd98b9dbe5585666eb0deadd0204e9194f6e87cd03104882bb24af01406","verifiedTreeHash":"0d1ca8cf071028d77582f2dcba5a32b4276822b5","verifierVersion":"0.1.0+560ab6a2"},{"checks":[{"durationMs":5703,"exitCode":0,"name":"build","output":"Compiling 70 files with Solc 0.8.26\nSolc 0.8.26 finished in 5.59s\nCompiler run successful!\n","passed":true},{"durationMs":17564,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/IntegrationFailures.t.sol:ActivationFailuresTest\n[PASS] testCanonicalWETHIdentityAndDecimalsAreRequiredBeforeActivation() (gas: 398493)\n[PASS] testOfficialSIMDMetadataAndCodeHashesMustAllMatch() (gas: 500243)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.02ms (1.01ms CPU time)\n\nRan 9 tests for test/IntegrationFailures.t.sol:IntegrationFailuresTest\n[PASS] testDisabledFarmRejectsBothSIMDInputsWithoutMovingAnyTokens() (gas: 178761)\n[PASS] testFallbackFailureRestoresNativeFeeAndAccruedRewardStateThenRetries() (gas: 1474363)\n[PASS] testIMDDustAfterVaultYieldCannotProduceZeroFarmSharesOrTrapIMD() (gas: 396159)\n[PASS] testNativeReceiverCannotCheckpointDuringWithdrawalButNativeDeliverySucceeds() (gas: 517358)\n[PASS] testPausedExternalVaultRollsBackIMDPathButStillAllowsDirectSIMDAndExit() (gas: 789691)\n[PASS] testPreexistingIMDDonationIsNotConsumedByAtomicStaking() (gas: 504344)\n[PASS] testRecoveringForcedNativeToRejectingRecipientIsAtomic() (gas: 211692)\n[PASS] testRejectingNativeTreasurySpendRollsBackAndDoesNotWrap() (gas: 481286)\n[PASS] testRewardBudgetCannotBeBorrowedAcrossFarms() (gas: 355569)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 6.92ms (2.72ms CPU time)\n\nRan 10 tests for test/ETH.t.sol:ETHTest\n[PASS] testBothDeliveryPathsFailAtomically() (gas: 649818)\n[PASS] testDirectSendRejectedDepositSlippageAndZeroDeposit() (gas: 169545)\n[PASS] testForcedETHNeverBacksSharesOrRewards() (gas: 413706)\n[PASS] testGasGriefCannotPreventWETHFallback() (gas: 487978)\n[PASS] testLargeRevertDataCannotPreventWETHFallback() (gas: 493899)\n[PASS] testNativeCallbackCannotReenterWithdrawal() (gas: 582044)\n[PASS] testNativePartialAndFullExit() (gas: 647378)\n[PASS] testNativePrincipalAndBloomRewardsRemainSeparate() (gas: 1072904)\n[PASS] testRejectingBeneficiaryReceivesCanonicalWETHWithNoExtraFee() (gas: 487664)\n[PASS] testWrappingFailureAlsoRollsBack() (gas: 562861)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 216.28ms (2.35ms CPU time)\n\nRan 9 tests for test/IMD.t.sol:IMDIntegrationTest\n[PASS] testAtomicIMDDepositMeasuresNonOneToOneAndClearsApproval() (gas: 502301)\n[PASS] testFarmRewardsIndependentOfOfficialVaultYield() (gas: 1070651)\n[PASS] testIMDConversionSlippageAndShareSlippageRollbackAllTransfers() (gas: 542468)\n[PASS] testIMDRedemptionExplicitlyDisabledEvenAfterHoldExpires() (gas: 306513)\n[PASS] testOfficialDecimalsApprovalsAndDirectDeposit() (gas: 380326)\n[PASS] testOfficialHoldBlocksRedemptionButImmediateInKindExitWorks() (gas: 704259)\n[PASS] testOfficialThirdPartyMintCanRestampHoldButCannotBlockSIMDExit() (gas: 667377)\n[PASS] testProtocolDepositFailureRollsBackAndNoDexFallback() (gas: 179919)\n[PASS] testValueYieldDoesNotMintFarmAssetsOrShares() (gas: 403544)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 232.78ms (3.09ms CPU time)\n\nRan 12 tests for test/AuthorityFailures.t.sol:AuthorityFailuresTest\n[PASS] testAllRewardOperationsHonorRenunciationWithoutTouchingUserObligations() (gas: 1214707)\n[PASS] testConfigPauseAndSpendPowersCanBeRenouncedIndependently() (gas: 1068975)\n[PASS] testDepositWithdrawalFeeAndClaimEventsMatchActualAmounts() (gas: 1005771)\n[PASS] testEpochPauseRoleAndTreasurySpendEvents() (gas: 995090)\n[PASS] testEveryPrivilegedFarmEntryRejectsUnprivilegedCaller() (gas: 986649)\n[PASS] testFactoryAndTreasuryCannotBeReconfiguredByDepositor() (gas: 253399)\n[PASS] testInvalidRenunciationMasksHaveNoEffect() (gas: 457611)\n[PASS] testMalformedInitCodeAndOversizedInputCannotPolluteRegistry() (gas: 447909)\n[PASS] testRecoveryRenunciationSurvivesOwnershipTransferButClaimsAndExitsWork() (gas: 1275833)\n[PASS] testTreasuryBindingRejectsWrongOwnerWrongTreasuryAndNoCode() (gas: 122255)\n[PASS] testUnregisteredCallersCannotPretendDonationsAreTreasuryFees() (gas: 164229)\n[PASS] test_RevertedCreate2RegistrationRollsBackCreationAndSaltRemainsUsable() (gas: 7652422)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 240.55ms (5.61ms CPU time)\n\nRan 9 tests for test/TokenFailures.t.sol:TokenFailuresTest\n[PASS] testFalseAndNonBooleanReturnsRollBackDepositsIncludingTokenSideEffects() (gas: 363172)\n[PASS] testFalseApproveOrTransferCannotBurnSharesOrRecordUnreceivedFees() (gas: 662077)\n[PASS] testFundingCreditsOnlyNetReceiptAndDoesNotUseExistingPrincipal() (gas: 1162751)\n[PASS] testOptionalReturnTokenWorksThroughDepositFeePayoutAndTreasurySpend() (gas: 617010)\n[PASS] testTaxedExcessRecoveryCannotTouchBackingOrRewardReserve() (gas: 509728)\n[PASS] testTaxedRewardClaimCannotConsumeCreditAndCanBeRetried() (gas: 1246401)\n[PASS] testTaxedTreasurySpendRestoresFeeAllowanceAndRecipientBalance() (gas: 575862)\n[PASS] testTokenCallbackCannotCheckpointDuringInboundOrOutboundAccounting() (gas: 512955)\n[PASS] testZeroNetFundingAndZeroNetDepositRevertAtomically() (gas: 285297)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 271.72ms (4.45ms CPU time)\n\nRan 11 tests for test/Accounting.t.sol:AccountingTest\n[PASS] testDecimals24ZeroShareAndDecimals6FractionalShares() (gas: 2996232)\n[PASS] testDonationIsolationAndZeroSupplyReset() (gas: 885686)\n[PASS] testFuzzWithdrawConservation(uint128,uint128,uint64) (runs: 256, μ: 918629, ~: 933768)\nLogs:\n  Bound result 8846627376820857003659010005\n  Bound result 16395032295248894590\n  Bound result 61\n\n[PASS] testMeasuredNetDepositAndUnsupportedOutboundTaxRevert() (gas: 687597)\n[PASS] testPartialAndFinalExitConserveEveryUnit() (gas: 1020217)\n[PASS] testRewardFundingNeverBacksBloomShares() (gas: 666539)\n[PASS] testSameBlockFullExitNoCooldown() (gas: 383056)\n[PASS] testSharesHaveNoTransferOrApprovalInterface() (gas: 222055)\n[PASS] testSlippageAndZeroInputsRevertAtomically() (gas: 485514)\n[PASS] testTokenFailureAndCallbackCannotStealShares() (gas: 673434)\n[PASS] testVirtualOffsetHeadroomPreservesExitAtUintLimit() (gas: 2176092)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 271.92ms (274.74ms CPU time)\n\nRan 5 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] testAllApplicationConstructorsSucceedWithDependenciesAbsent() (gas: 240789)\n[PASS] testCoreScriptAssignsEveryPrivilegeToConfirmedRequesterAndDoesNotInitialize() (gas: 10258771)\n[PASS] testFarmScriptsTakeRealInputsAndNeverEnableDepositsOrEmissions() (gas: 58176347)\n[PASS] testScriptRejectsMissingBloomAndWrongChain() (gas: 8419148)\n[PASS] testScriptRejectsWrongRequesterAndUnboundToken() (gas: 8914250)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 272.85ms (115.79ms CPU time)\n\nRan 12 tests for test/Administration.t.sol:AdministrationTest\n[PASS] testBindingsAreOneTimeAndDependenciesCannotFrontRun() (gas: 983586)\n[PASS] testCancelledFutureBudgetIsFreeButAccruedClaimIsProtected() (gas: 1284391)\n[PASS] testCreate2FactoryDeploysFarmWithOwnerAndInitiallyDisabled() (gas: 4632776)\n[PASS] testExplicitOwnerNeverWorkerOrFactory() (gas: 81591)\n[PASS] testFutureFarmRequiresWhitelistCorrectOwnerAndNoDuplicates() (gas: 2148488)\n[PASS] testOnlyOwnerCanBindActivatePauseAllocateAndRecover() (gas: 219663)\n[PASS] testTreasuryFailedTransferRollsBackSpending() (gas: 515482)\n[PASS] testTreasuryOnlySpendsReceivedFeesNotDonationsOrFarmFunds() (gas: 752192)\n[PASS] testTwoStepOwnershipAndSelectivePermanentRenunciation() (gas: 729767)\n[PASS] testUnboundAndUnregisteredContractsRejectActivation() (gas: 478048)\n[PASS] testWhitelistRemovalOnlyStopsDeposits() (gas: 457008)\n[PASS] testWrongChainAndDecimalsCannotActivate() (gas: 1179593)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 273.19ms (6.36ms CPU time)\n\nRan 14 tests for test/Rewards.t.sol:RewardsTest\n[PASS] testCannotPledgeEarnedRewardsTwiceOrRecoverObligations() (gas: 1020036)\n[PASS] testContinueBoostAndRestartPreserveEarnedAndEpochIdentity() (gas: 1245313)\n[PASS] testEpochBoundaryAndInvalidConfiguration() (gas: 995374)\n[PASS] testFrequentClaimSettlementsPreserveSubWeiFractions() (gas: 1651872)\n[PASS] testFullExitRetainsClaimAndClaimHasNoFee() (gas: 1257201)\n[PASS] testFundingAndConfigurationNeverStartAccrual() (gas: 797436)\n[PASS] testFuzzRewardsSolventAcrossTimeAndShareEdits(uint96,uint96,uint96,uint32) (runs: 256, μ: 1667041, ~: 1701602)\nLogs:\n  Bound result 32920472225624112\n  Bound result 11892089935238\n  Bound result 422016505797269\n  Bound result 642706\n\n[PASS] testLateDepositorReceivesNoPastRewards() (gas: 1312300)\n[PASS] testOversizedEpochCannotBrickOneShareAccrual() (gas: 1212257)\n[PASS] testPausedDepositsDoNotBlockClaimsWithdrawalOrAccrual() (gas: 1134058)\n[PASS] testRewardTransferFailureRollsBackClaimAndCanRetry() (gas: 1111460)\n[PASS] testRoundingFractionsSurviveSettlementsAndDustReleasesOnlyAtZeroSupply() (gas: 1764777)\n[PASS] testTopUpsStayFreeAndOnlyFreeFundsRecoverable() (gas: 1013604)\n[PASS] testZeroStakerIntervalsReturnToReserveAndNeverRetroactive() (gas: 1467500)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 273.28ms (196.76ms CPU time)\n\nRan 11 tests for test/EdgeProperties.t.sol:EdgePropertiesTest\n[PASS] testBeneficiaryGiftSettlesExistingSharesBeforeMintAndCallerCannotStealThem() (gas: 1022075)\n[PASS] testDurationOverflowAtTimestampBoundaryRevertsBeforeReservingFunds() (gas: 203505)\n[PASS] testFuzz_ClaimFrequencyDoesNotEraseFractionalCredits(uint96,uint8) (runs: 1000, μ: 2837304, ~: 2459779)\nLogs:\n  Bound result 3357\n  Bound result 3\n\n[PASS] testFuzz_DonationsAndRewardFundingCannotInflateAnySupportedDecimalPool(uint8,uint96,uint96) (runs: 1000, μ: 2648239, ~: 2664688)\nLogs:\n  Bound result 2\n  Bound result 419\n  Bound result 471545\n\n[PASS] testFuzz_RepeatedRoundTripsCannotExtractAnotherStakersBacking(uint8,uint96,uint8) (runs: 1000, μ: 3965318, ~: 3646299)\nLogs:\n  Bound result 2\n  Bound result 545\n  Bound result 3\n\n[PASS] testOldExitCreditSurvivesNewPoolAndEpochWithoutSubsidizingShares() (gas: 2121564)\n[PASS] testOneWeiFinalExitTransfersAllDustToTreasuryAndCanReenter() (gas: 735044)\n[PASS] testOneWeiPartialBurnCannotCollectFeeTwice() (gas: 684862)\n[PASS] testPrestartScheduleCanBeReplacedCancelledAndRecoveredWithoutAccrual() (gas: 846439)\n[PASS] test_RevertedContinueAtExactEndDoesNotLoseLastEmission() (gas: 1001421)\n[PASS] test_RevertedWithdrawalRestoresLazyEpochStateSharesAndCredits() (gas: 865753)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 273.31ms (747.90ms CPU time)\n\nRan 1 test for test/Invariants.t.sol:FarmInvariantTest\n[PASS]\nFarmInvariantTest invariants:\n[PASS] invariantPrincipalAndFeeConservation\n[PASS] invariantRewardSolvencyAndCredits\n FarmInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+-----------+-------+---------+----------╮\n| Contract    | Selector  | Calls | Reverts | Discards |\n+======================================================+\n| FarmHandler | cancel    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | claim     | 828   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | deposit   | 808   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | donate    | 800   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | editEpoch | 827   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | elapse    | 797   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | fund      | 837   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | pause     | 842   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | recover   | 836   | 0       | 0        |\n|-------------+-----------+-------+---------+----------|\n| FarmHandler | withdraw  | 817   | 0       | 0        |\n╰-------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 684\n  Bound result 1904\n  Bound result 2731061622\n  Bound result 1352\n  Bound result 6958\n  Bound result 3340342381\n  Bound result 474\n  Bound result 202\n  Bound result 2166413321\n  Bound result 2197\n  Bound result 8\n  Bound result 4343\n  Bound result 4900178740\n  Bound result 5531\n  Bound result 4\n  Bound result 8790\n  Bound result 85\n  Bound result 7447\n  Bound result 7978\n  Bound result 8605\n  Bound result 5709\n  Bound result 1610\n  Bound result 10795\n  Bound result 9749\n  Bound result 8086\n  Bound result 20\n  Bound result 905456055\n  Bound result 6386506982564926813467\n  Bound result 9271\n  Bound result 7488\n  Bound result 2456\n  Bound result 15\n  Bound result 423\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.70s (1.70s CPU time)\n\nRan 2 tests for test/NetworkInvariants.t.sol:NetworkInvariantTest\n[PASS] invariant_CustodySharesFeesAndRewardsRemainConserved() (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------+-----------------+-------+---------+----------╮\n| Contract       | Selector        | Calls | Reverts | Discards |\n+===============================================================+\n| NetworkHandler | cancel          | 1481  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | claim           | 1566  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | controls        | 1547  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | deposit         | 1566  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | depositIMD      | 1436  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | donate          | 1595  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | editEpoch       | 1554  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | elapse          | 1581  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | fund            | 1556  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | recoverDonation | 1471  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | recoverFree     | 1584  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | roundTrip       | 1552  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | spend           | 1525  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | startConfigured | 1567  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | vaultYield      | 1459  | 0       | 0        |\n|----------------+-----------------+-------+---------+----------|\n| NetworkHandler | withdraw        | 1536  | 0       | 0        |\n╰----------------+-----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 100000000000000000000000000\n  Bound result 100000000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 37000000000000000000\n  Bound result 335028\n  Bound result 100000000000000000000000\n  Bound result 14721\n  Bound result 15\n  Bound result 8\n  Bound result 1000000000000000014719\n  Bound result 28\n  Bound result 49152\n  Bound result 0\n  Bound result 18877\n  Bound result 7607\n  Bound result 9999999999000000015180\n  Bound result 9999999999000000015180\n  Bound result 9999999999000000015180\n  Bound result 244\n  Bound result 30000000000000000000\n  Bound result 9999000000000000019966\n  Bound result 700000000000000000000\n  Bound result 9999000000000000009324\n  Bound result 20522\n  Bound result 2806\n  Bound result 5572\n  Bound result 18325\n  Bound result 874824874276615265950\n  Bound result 79335979762088435335\n  Bound result 21788\n  Bound result 36304746914621315765074\n  Bound result 16984\n  Bound result 21963\n  Bound result 10\n  Bound result 3\n  Bound result 354\n  Bound result 8500\n  Bound result 40\n  Bound result 1000\n  Bound result 1000000000000000000000\n  Bound result 77157\n  Bound result 20113\n  Bound result 2494\n  Bound result 16\n  Bound result 14583\n  Bound result 14247718106057014526062\n  Bound result 44184\n  Bound result 26910548756143780730\n  Bound result 99999999999999999999997\n  Bound result 12674\n  Bound result 31\n  Bound result 8194183699909843346820\n  Bound result 8194183699909843346820\n  Bound result 1024272962578354521517\n  Bound result 71484135511504353777939\n  Bound result 28\n  Bound result 49153\n  Bound result 1000000\n  Bound result 2000000000000000000000\n  Bound result 1375\n  Bound result 24\n  Bound result 69173340114600131077610\n  Bound result 9999999999002495578191\n  Bound result 9999999999002495578191\n  Bound result 638612072471012469986\n  Bound result 39304746914621315763055\n  Bound result 18100000000000000506\n  Bound result 128264576967240856718\n  Bound result 3027533684943775504443352843\n  Bound result 100649236111111111111112\n  Bound result 308284557436305832760\n\n[PASS] test_HandlerExercisesFallbackClaimsAndAllAssetRecoveryBeforeClosing() (gas: 6688407)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 100000000000000000000000000\n  Bound result 100000000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 1000000000000000000000\n  Bound result 10\n  Bound result 86400\n  Bound result 10000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100\n  Bound result 200\n  Bound result 300\n  Bound result 100\n  Bound result 200\n  Bound result 100\n  Bound result 1\n  Bound result 100\n  Bound result 200\n  Bound result 300\n  Bound result 100\n  Bound result 200\n  Bound result 100\n  Bound result 1\n  Bound result 100\n  Bound result 200\n  Bound result 300\n  Bound result 100\n  Bound result 200\n  Bound result 100\n  Bound result 1\n  Bound result 900000000000000000000\n  Bound result 18100000000000000000\n  Bound result 900000000000000000000\n  Bound result 6185454545454545454559223\n  Bound result 900000000000000000000\n  Bound result 18100000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 17.46s (17.46s CPU time)\n\nRan 13 test suites in 17.47s (21.50s CPU time): 107 tests passed, 0 failed, 0 skipped (107 total tests)\n","passed":true},{"durationMs":98,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BloomFactory.acceptOwnership()\",\"BloomFactory.bindBloom(address)\",\"BloomFactory.deployFarm(bytes,bytes32)\",\"BloomFactory.registerFarm(address)\",\"BloomFactory.renounceOwnership()\",\"BloomFactory.renouncePowers(uint256)\",\"BloomFactory.transferOwnership(address)\",\"BloomFactory.whitelistAsset(address,bool)\",\"BloomTreasury.acceptOwnership()\",\"BloomTreasury.bindRegistry(address)\",\"BloomTreasury.receiveNativeFee()\",\"BloomTreasury.receiveTokenFee(address,uint256)\",\"BloomTreasury.renounceOwnership()\",\"BloomTreasury.renouncePowers(uint256)\",\"BloomTreasury.spendFees(address,address,uint256)\",\"BloomTreasury.transferOwnership(address)\",\"ERC20Farm.acceptOwnership()\",\"ERC20Farm.activate()\",\"ERC20Farm.cancelFutureRewards()\",\"ERC20Farm.checkpoint()\",\"ERC20Farm.claimRewards(address)\",\"ERC20Farm.configureEpoch(uint256,uint256)\",\"ERC20Farm.continueEpoch(uint256,uint256)\",\"ERC20Farm.deposit(uint256,address,uint256)\",\"ERC20Farm.fundRewards(uint256)\",\"ERC20Farm.recoverExcess(address,address,uint256)\",\"ERC20Farm.recoverUnallocatedRewards(address,uint256)\",\"ERC20Farm.renounceOwnership()\",\"ERC20Farm.renouncePowers(uint256)\",\"ERC20Farm.restartEpoch(uint256,uint256)\",\"ERC20Farm.setDepositsPaused(bool)\",\"ERC20Farm.startEpoch()\",\"ERC20Farm.transferOwnership(address)\",\"ERC20Farm.withdraw(uint256,address,uint256)\",\"StakedBLOOM.acceptOwnership()\",\"StakedBLOOM.activate()\",\"StakedBLOOM.cancelFutureRewards()\",\"StakedBLOOM.checkpoint()\",\"StakedBLOOM.claimRewards(address)\",\"StakedBLOOM.configureEpoch(uint256,uint256)\",\"StakedBLOOM.continueEpoch(uint256,uint256)\",\"StakedBLOOM.deposit(uint256,address,uint256)\",\"StakedBLOOM.fundRewards(uint256)\",\"StakedBLOOM.recoverExcess(address,address,uint256)\",\"StakedBLOOM.recoverUnallocatedRewards(address,uint256)\",\"StakedBLOOM.renounceOwnership()\",\"StakedBLOOM.renouncePowers(uint256)\",\"StakedBLOOM.restartEpoch(uint256,uint256)\",\"StakedBLOOM.setDepositsPaused(bool)\",\"StakedBLOOM.startEpoch()\",\"StakedBLOOM.transferOwnership(address)\",\"StakedBLOOM.withdraw(uint256,address,uint256)\",\"StakedETH.acceptOwnership()\",\"StakedETH.activate()\",\"StakedETH.cancelFutureRewards()\",\"StakedETH.checkpoint()\",\"StakedETH.claimRewards(address)\",\"StakedETH.configureEpoch(uint256,uint256)\",\"StakedETH.continueEpoch(uint256,uint256)\",\"StakedETH.deposit(address,uint256)\",\"StakedETH.fundRewards(uint256)\",\"StakedETH.recoverExcess(address,address,uint256)\",\"StakedETH.recoverUnallocatedRewards(address,uint256)\",\"StakedETH.renounceOwnership()\",\"StakedETH.renouncePowers(uint256)\",\"StakedETH.restartEpoch(uint256,uint256)\",\"StakedETH.setDepositsPaused(bool)\",\"StakedETH.startEpoch()\",\"StakedETH.transferOwnership(address)\",\"StakedETH.withdraw(uint256,address,uint256)\",\"StakedSIMD.acceptOwnership()\",\"StakedSIMD.activate()\",\"StakedSIMD.cancelFutureRewards()\",\"StakedSIMD.checkpoint()\",\"StakedSIMD.claimRewards(address)\",\"StakedSIMD.configureEpoch(uint256,uint256)\",\"StakedSIMD.continueEpoch(uint256,uint256)\",\"StakedSIMD.deposit(uint256,address,uint256)\",\"StakedSIMD.depositIMD(uint256,address,uint256,uint256)\",\"StakedSIMD.fundRewards(uint256)\",\"StakedSIMD.recoverExcess(address,address,uint256)\",\"StakedSIMD.recoverUnallocatedRewards(address,uint256)\",\"StakedSIMD.renounceOwnership()\",\"StakedSIMD.renouncePowers(uint256)\",\"StakedSIMD.restartEpoch(uint256,uint256)\",\"StakedSIMD.setDepositsPaused(bool)\",\"StakedSIMD.startEpoch()\",\"StakedSIMD.transferOwnership(address)\",\"StakedSIMD.withdraw(uint256,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":98,\"abi/BloomFactory.json\":581,\"abi/BloomTreasury.json\":498,\"abi/ERC20Farm.json\":1693,\"abi/StakedBLOOM.json\":1701,\"abi/StakedETH.json\":1755,\"abi/StakedSIMD.json\":1815,\"deployment/BloomTreasury.unsigned.json\":23,\"docs/ACCOUNTING.md\":87,\"docs/DEPENDENCIES.md\":16,\"docs/DEPLOYMENT.md\":85,\"docs/INTEGRATION.md\":77,\"docs/VALIDATION.md\":52,\"docs/artifact-hashes.json\":1218,\"docs/deployment-status.json\":24,\"docs/evidence/dependency-revalidation.json\":31,\"docs/evidence/imd-verification.json\":1860,\"docs/evidence/mainnet-reads.json\":104,\"docs/evidence/simd-verification.json\":1120,\"docs/evidence/weth-verification.json\":318,\"docs/validation/core-simulation.txt\":7,\"docs/validation/forge-test.txt\":680,\"foundry.toml\":23,\"remappings.txt\":2,\"script/DeployBLOOMFarm.s.sol\":17,\"script/DeployCore.s.sol\":16,\"script/DeployETHFarm.s.sol\":12,\"script/DeploySIMDFarm.s.sol\":12,\"script/DeploymentInputs.sol\":26,\"scripts/export_artifacts.py\":80,\"scripts/prepare_deployment.py\":93,\"scripts/verify_mainnet.py\":53,\"src/BloomFactory.sol\":97,\"src/BloomTreasury.sol\":100,\"src/MainnetAssets.sol\":15,\"src/StakedBLOOM.sol\":13,\"src/StakedETH.sol\":59,\"src/StakedSIMD.sol\":64,\"src/core/ERC20Farm.sol\":45,\"src/core/Farm.sol\":234,\"src/core/Managed.sol\":34,\"src/core/RewardLedger.sol\":300,\"src/interfaces/IBloom.sol\":42,\"test/Accounting.t.sol\":199,\"test/Administration.t.sol\":241,\"test/AuthorityFailures.t.sol\":285,\"test/Deployment.t.sol\":131,\"test/ETH.t.sol\":218,\"test/EdgeProperties.t.sol\":273,\"test/IMD.t.sol\":172,\"test/IntegrationFailures.t.sol\":267,\"test/Invariants.t.sol\":147,\"test/NetworkInvariants.t.sol\":493,\"test/Rewards.t.sol\":314,\"test/TESTING.md\":62,\"test/TokenFailures.t.sol\":234,\"test/fixtures/OfficialIMD.sol\":10,\"test/fixtures/OfficialSIMD.sol\":9,\"test/fixtures/OfficialWETH.sol\":10,\"test/helpers/Fixtures.sol\":145,\"test/helpers/NetworkFixture.sol\":57},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"c2340795e0a6f006c57a759785edacd174491cf47e28d8861f03e5b94063c75f","verifiedTreeHash":"d5fc8acfe73594186a9a00049759d41acb3e311e","verifierVersion":"0.1.0+560ab6a2"}]}