{"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":"a6715145-76db-498f-9ca9-a11ed38d82a8","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":null,"dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"2d7d84a1a9972f1497e5bc68a704cbf42294d08c62d2868f102ffe3b909b9b51","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"2d7d84a1a9972f1497e5bc68a704cbf42294d08c62d2868f102ffe3b909b9b51","skillId":"adapt-contract-project","state":"failed"},{"acceptedSubmissionHash":null,"dependsOn":["adapt_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":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["adapt_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":"waiting"},{"acceptedSubmissionHash":"b4f19237aab0aa8d5e38d63b14dbed7a4b7b0ba01b1b1f50217961d0c3ccb744","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":null,"dependsOn":["adapt_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":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["adapt_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":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["adapt_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":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["adapt_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":"waiting"}],"objective":"Launch the pinned Mugi V1 contracts-only source on Ethereum mainnet. Import this exact Foundry repository and inspect README.md, foundry.toml, inventory.json, launch.json, src/imd, and test/imd. The IMD launch transaction must create and record exactly these four contracts in this order: MugiIMDCrewFactory, MugiV1IMDDeploymentFactory, MugiIMDAccountingFactory, MugiIMDEngineFactory. Their static constructor arguments are exactly those in launch.json and the manifest repeated below. There are no constructor-created children, value payments, or post-deployment calls in this IMD transaction. This is evm_contracts; do not add a standard launch token, distributor, pool, swarm token allocation, or token launch economics. Preserve the tested contract source and compiler settings (Solidity 0.8.26, Cancun, optimizer 200, viaIR, bytecode_hash none); packaging/manifest adaptation is allowed. If a source change is necessary, report the blocking reason rather than automatically deploying changed code. The protocol owner is 0x20714d50f4675c366de30b603728a90ddddb240f. The deployment factory's committed hook initcode hash is 0xbc3c1605ac7a5e7781e7923e764c5e673c9480991b0d532f1799b78af4ac4359; it must not be changed or replaced. FULL FOLLOW-ON LIFECYCLE DISCLOSURE: after this IMD factory deployment, the owner calls these factories to deploy the hash-pinned hook at its permission-bit CREATE2 address, ten full crew ERC20 contracts, the airdrop, Chainlink VRF adapter, IMD plan verifier, swap router, and separate hook-bound ledger, buyback, price-oracle and V4 liquidity-engine modules. These ordinary contracts use CALL with explicit authorization, not proxies or delegatecall. The owner binds modules and configures the season, funds ten V4 pools separately, then a public relayer can activate after 100 registrations or seven days, provided every pool is seeded. Crew tokens intentionally implement hook-controlled mint/burn and transfer restrictions tied to elimination and settlement; the owner can pause trading while claims and lifecycle settlement retain their defined paths. Disclose these intentional rules to source admission; do not silently remove pause or replace the tokens with unrestricted ERC20 semantics. Liquidity is controlled by the hook-bound engine, with a prelaunch abort recovery and final migration to a manually selected V2 target. Confirm this disclosed factory/follow-on architecture is accepted by evm_contracts source admission; do not conceal descendants or claim each will be an independent Explorer launch entry. Return the IMD launch record, four recorded addresses, submitted transaction references, and final source commit. Do not submit source verification to Etherscan, Blockscout, Sourcify, or any explorer. If the platform requires source verification, stop with needs_input before deployment and explain the requirement. Manifest: {\"contracts\":[{\"constructorArgs\":[],\"contract\":\"MugiIMDCrewFactory\"},{\"constructorArgs\":[\"0x20714d50f4675c366de30b603728a90ddddb240f\",\"$contract:MugiIMDCrewFactory\",\"0xbc3c1605ac7a5e7781e7923e764c5e673c9480991b0d532f1799b78af4ac4359\"],\"contract\":\"MugiV1IMDDeploymentFactory\"},{\"constructorArgs\":[],\"contract\":\"MugiIMDAccountingFactory\"},{\"constructorArgs\":[],\"contract\":\"MugiIMDEngineFactory\"}],\"kind\":\"evm_contracts\",\"notes\":\"Four recorded factories. The owner later deploys the hash-pinned hook, ten crew tokens, and modules through these factories. Accounting and liquidity-engine modules use ordinary CALL and require owner binding before configuration and pool funding. Source admission remains pending. Descendant contracts are not assumed to be individual IMD Explorer artifacts. No explorer source verification requested.\"}","parentJobId":null,"planHash":"c46b7cd0ac786eb97fd854df48059b6218b89d46add8a7c26ab177f9047f8f76","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"a6715145-76db-498f-9ca9-a11ed38d82a8","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2416-mugiimdcrewfactory-mugiv1imddeploymentfa"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52617","feedbackHash":"648857120c8d2cde562d900043e19831aa227b82cee2ccab8ec59a7fc90498ae","nodeKey":"audit_imported_code","submissionHash":"b4f19237aab0aa8d5e38d63b14dbed7a4b7b0ba01b1b1f50217961d0c3ccb744","tag1":"review:submission","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"816bab6a92b04dff4d531c12cfff4b630aad6d424436e032f803a5261c1fd766","state":"blocked","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a9158e223bd79f25","findings":[],"hash":"9e75652f272a16f5964a6725eafe980b8a08184f17ccd04e3bc7187748f39f4e","nodeId":"c804932f-bbab-4ce3-8722-37a17edeb4cb","outcome":"failed","summary":"needs input: A requester-approved resolution of reproduced high-severity audit finding 78745007b5e5eac37ffc4193b44fe9d7a5f13f5dcb8aa6498d0d0d768ba9e55c is required. The supplied Proof_78745007b5e5.t.sol fails because an accepted but unfulfilled randomness request leaves the season in AwaitingRandomness. An independent scratch test using the actual MugiVRFAdapter confirms that after 30 simulated days, re-request, retryDelivery, settlement, finalization, prelaunch abort and token claims/transfers cannot recover the season; all ten LP positions remain locked. Recovery requires Solidity changes, which this packaging-only assignment prohibits, and the resulting hook initcode would require a newly reviewed and approved commitment instead of silently replacing 0xbc3c1605ac7a5e7781e7923e764c5e673c9480991b0d532f1799b78af4ac4359. The existing four-factory manifest already matches the requested order and static arguments. forge build passed; the unchanged project test suite passed with the requested fuzz seed","treeHash":null,"usage":{"cachedInputTokens":1617664,"inputTokens":109194,"model":"gpt-6-astra","outputTokens":10665,"runtime":"codex","turns":8,"wallClockMs":500275}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"76df9026b98e4277","findings":[{"citation":"resolved","description":"requestElimination() moves the hook to AwaitingRandomness and the only exit is receiveRandomness() from randomnessProvider for exactly pendingRequest. There is no deadline, re-request, owner recovery or abort after launch (abortPrelaunch requires Setup). MugiVRFAdapter also refuses a second request while activeRequestId != 0 and only retries delivery of a word it already received. If the Chainlink VRF v2.5 request is never fulfilled (subscription underfunded until the pending request expires, adapter removed as consumer, subscription cancelled by its owner, coordinator/keyHash deprecated), the hook is stuck forever: every pool's LP ETH stays in the engine, treasure/ownBurnBudget ETH stays in the hook, beforeTokenTransfer reverts TransferFrozen for all crew tokens (phase != Live), swaps revert in beforeSwap, claimTokens reverts, settleRound/finalize revert. Player funds and the owner's seeded liquidity are locked permanently.","line":223,"path":"src/imd/MugiIMDGameHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {MugiIMDGameHook} from \"src/imd/MugiIMDGameHook.sol\";\nimport {MugiIMDCrewFactory} from \"src/imd/MugiIMDCrewFactory.sol\";\nimport {MugiIMDAccountingFactory} from \"src/imd/MugiIMDAccountingFactory.sol\";\nimport {MugiIMDEngineFactory} from \"src/imd/MugiIMDEngineFactory.sol\";\nimport {MugiAirdrop} from \"src/game/MugiAirdrop.sol\";\n\n/// @dev Stands in for a Chainlink VRF request that is accepted but never fulfilled\n/// (subscription underfunded past the request expiry, consumer removed, or the\n/// subscription cancelled). It records requests and never calls back.\ncontract SilentRandomness {\n    uint256 public requests;\n    function requestRandomness() external returns (uint256) { return ++requests; }\n}\n\ncontract VrfStallTest is Test {\n    uint256 internal constant SUPPLY = 1_000_000 ether;\n    address internal constant TEAM = address(0x7EA0);\n    address internal constant COMMUNITY = address(0xC000);\n    MugiIMDGameHook internal game;\n    SilentRandomness internal randomness;\n\n    receive() external payable {}\n\n    function setUp() public {\n        vm.deal(address(this), 1_000 ether);\n        IPoolManager manager = new PoolManager(address(this));\n        address hookAddress = address(uint160(0x1234000000) | uint160(0x2aec));\n        deployCodeTo(\n            \"MugiIMDGameHook.sol:MugiIMDGameHook\",\n            abi.encode(address(this), manager, TEAM, COMMUNITY, address(0), SUPPLY),\n            hookAddress\n        );\n        game = MugiIMDGameHook(payable(hookAddress));\n        MugiIMDAccountingFactory.Modules memory m = new MugiIMDAccountingFactory().deployForHook(hookAddress);\n        game.bindAccounting(m.ledger, m.budgets, m.prices, new MugiIMDEngineFactory().deployForHook(hookAddress, manager));\n        address[10] memory crew = new MugiIMDCrewFactory().deployCrewSet(hookAddress, 1);\n        MugiAirdrop airdrop = new MugiAirdrop(hookAddress, address(0xA77E57), SUPPLY, crew);\n        randomness = new SilentRandomness();\n        game.configure(crew, airdrop, address(randomness), address(0));\n        for (uint8 i; i < 10; ++i) game.seedPool{value: 1 ether}(i);\n        vm.warp(block.timestamp + 7 days);\n        game.launch();\n    }\n\n    function testUnfulfilledRandomnessCanBeRequestedAgain() public {\n        vm.warp(game.nextCutoff());\n        game.requestElimination();\n        assertEq(uint8(game.phase()), uint8(MugiIMDGameHook.Phase.AwaitingRandomness));\n\n        // The VRF request is never fulfilled. Thirty days later the season must still\n        // have a way forward; today every path is closed and ~10 ETH of LP is locked.\n        vm.warp(block.timestamp + 30 days);\n        (bool retried,) = address(game).call(abi.encodeCall(MugiIMDGameHook.requestElimination, ()));\n        assertTrue(retried, \"stalled VRF request leaves the season permanently in AwaitingRandomness\");\n        assertEq(randomness.requests(), 2);\n    }\n}","reproduction":"State: season launched with 10 seeded pools (1 ETH each) and a randomness provider whose request is accepted but never fulfilled. Call requestElimination() at nextCutoff -> phase AwaitingRandomness. Warp 30 days, call requestElimination() again. Expected: a stalled request can be re-issued (or the season otherwise recovered). Actual: reverts InvalidState; no function in the hook, adapter or modules changes phase, so all LP ETH and crew-token transfers are frozen forever. The attached proof (test/scratch/VrfStall.t.sol) fails with 'stalled VRF request leaves the season permanently in AwaitingRandomness'.","severity":"high","snippet":"        phase = Phase.AwaitingRandomness;","title":"Unfulfilled VRF request permanently freezes the season: no timeout or re-request path out of AwaitingRandomness"},{"citation":"resolved","description":"The hook constructor takes v2MigrationTarget_ and checks it has code (line 105), and this value is part of the hash-pinned hook initcode (hookInitCodeHash), suggesting the V2 destination is committed at deployment. It is never stored. migrateToV2(target) accepts any address with code, can be called repeatedly, and pays it address(this).balance - teamEth - reservedEth (the final pool's removed LP ETH principal, LiquidityDeferred ETH, settlement-division dust, unspent round buyback budgets, treasure[survivor] and ownBurnBudget[survivor]) plus the hook's whole survivor-token balance (including unclaimed player escrow erased at finalize). The owner can therefore route all residual protocol ETH to an arbitrary contract of its own (e.g. one whose receiveV1Finale forwards msg.value to the owner EOA). The brief discloses a manually selected V2 target, but the committed constructor argument gives holders a guarantee the code does not enforce.","line":406,"path":"src/imd/MugiIMDGameHook.sol","reproduction":"Deploy the hook with v2MigrationTarget_ = X (a contract). Run the season to Finalized. Owner deploys Y whose receiveV1Finale(uint8,address,uint256) payable forwards msg.value to the owner EOA and calls migrateToV2(Y). Expected: revert because Y != X (committed target). Actual: succeeds; Y receives the final pool's ETH principal plus all non-reserved hook ETH and the survivor token inventory. A second migrateToV2 call later also succeeds and sends any ETH that arrived since.","severity":"medium","snippet":"    function migrateToV2(address target) external onlyOwner guarded {","title":"v2MigrationTarget_ constructor argument is validated and then discarded; migrateToV2 sends all residual ETH and survivor inventory to any owner-chosen contract"},{"citation":"resolved","description":"Each elimination converts a holder's defeated-crew balance into virtual survivor claims backed by tokens the hook mints into escrow. Those claims can only be materialised by claimTokens/claimToken, which _requireClaims restricts to phase Live and block.timestamp < nextCutoff. finalize() is permissionless from exactly nextCutoff after the 9th settlement; finalizeMigration zeroes walletScaled/virtualScaled/escrowBacking for the survivor and _preview returns zero virtual balances for every account once finalized. The escrowed tokens stay in the hook and migrateToV2 transfers them to the owner-selected target. Any player who held eliminated-crew tokens and did not claim in the final <24h window (or during any earlier Live window) loses those survivor tokens in V1 with no claim path, even though the claim was earned in an earlier round. claimEth still works, so only the token side is forfeited.","line":165,"path":"src/imd/modules/MugiIMDLedger.sol","reproduction":"Alice holds crew 0 tokens; crew 0 is eliminated in round 1, so previewAccount(Alice) shows claimable survivor tokens. Alice does not call claimTokens before the 9th round's nextCutoff. Anyone calls finalize() at nextCutoff. Expected: Alice can still claim her escrowed survivor tokens (or they are earmarked for her). Actual: previewAccount(Alice).claimableTokens are all 0, claimTokens reverts InvalidState (phase Finalized), and migrateToV2 moves the backing tokens to the owner-chosen target.","severity":"medium","snippet":"        self.virtualScaled[finalToken] = 0;","title":"Players' unclaimed survivor-token escrow (earned from earlier eliminations) is erased at permissionless finalize and handed to the V2 target"},{"citation":"resolved","description":"The owner can toggle paused at any time; _requireLive then reverts every beforeSwap (all buys/sells through the V4 pools) and every executeBuyback/executeOwnBuyback. There is no maximum duration or timelock. Elimination, settlement and claims still proceed (as disclosed), so holders can be forced to ride eliminations without being able to sell. The launch rules forbid pausing/freezing holder balances; the brief discloses this pause intentionally and asks it not be silently removed. It must be explicitly accepted by evm_contracts source admission or the launch is incompatible.","line":218,"path":"src/imd/MugiIMDGameHook.sol","reproduction":"Live season, Alice holds crew 3 tokens. Owner calls setPaused(true). Alice sells through MugiIMDSwapRouter.sell(3, amount, 0, deadline): reverts (beforeSwap -> _requireLive -> InvalidState). Anyone calls requestElimination/settleRound at the cutoff; if crew 3 is drawn, Alice's position is converted at 3/4 while she was unable to exit. Expected under evm_contracts rules: no owner trading pause. Actual: unbounded owner pause.","severity":"medium","snippet":"    function setPaused(bool value) external onlyOwner { paused = value; emit PauseChanged(value); }","title":"Admission: owner can pause all trading at any time with no bound (setPaused)"},{"citation":"resolved","description":"beforeTokenTransfer reverts TransferFrozen for any non-protocol transfer unless phase == Live, before nextCutoff, and the crew is alive. Consequences: (a) all transfers freeze in Setup, AwaitingRandomness, OutcomeReady, Settling; (b) eliminated-crew balances can never move again; (c) after finalize() (phase Finalized) even the surviving crew token is non-transferable forever in V1; (d) after abortPrelaunch (phase Aborted) every token, including airdrop or LP-returned balances, is frozen forever. This is the disclosed elimination rule, but it is a freeze of holder balances that the evm_contracts recipe forbids; admission must accept it explicitly. Item (c) is not stated in the brief and should be disclosed (survivor holders keep only a non-transferable V1 receipt).","line":438,"path":"src/imd/MugiIMDGameHook.sol","reproduction":"Run a season to Finalized. Bob holds 100 survivor tokens and calls token.transfer(carol, 1). Expected (standard ERC20 / evm_contracts): succeeds. Actual: reverts TransferFrozen because phase == Finalized. Likewise after owner abortPrelaunch(): any transfer reverts TransferFrozen permanently.","severity":"medium","snippet":"            if (phase != Phase.Live || block.timestamp >= nextCutoff || (aliveMask & (uint16(1) << crew)) == 0","title":"Admission: crew-token transfers are frozen outside the live window, permanently for eliminated crews, and permanently for every crew after finalize or abort"},{"citation":"resolved","description":"After launch the hook mints new survivor-crew supply in every settlement: _addMatchedLiquidity mints the tokens matched to re-added ETH (line 295) and _beginSettlement mints migration escrow (line 278, minted[i] from ledger.recordElimination). mint/burn are restricted to the hook (MugiCrewToken.onlyHook), as disclosed, but post-launch minting is listed as forbidden by the evm_contracts launch rules; admission must accept it explicitly. Supply is not capped at initialSupply.","line":295,"path":"src/imd/MugiIMDGameHook.sol","reproduction":"Launch a season with SUPPLY = 1,000,000e18 per crew. After round 1 settleRound(10), totalSupply() of each surviving crew token exceeds 1,000,000e18 by the minted escrow plus matched-liquidity tokens (each seeded at initialSupply, then mint(address(this), needed)). Expected under evm_contracts rules: no mint after launch. Actual: supply increases every round.","severity":"medium","snippet":"        token.mint(address(this), needed);","title":"Admission: crew tokens are minted after launch by the hook during settlement"},{"citation":"resolved","description":"The IMD transaction records only MugiIMDCrewFactory, MugiV1IMDDeploymentFactory, MugiIMDAccountingFactory and MugiIMDEngineFactory. The application itself is created later: deployHook (hook initcode supplied as calldata, bound only by hookInitCodeHash), deployModules (10 MugiIMDCrewToken, MugiIMDSwapRouter, MugiVRFAdapter, MugiIMDVerifier, MugiAirdrop), MugiIMDAccountingFactory.deployForHook (ledger, buybacks, oracle) and MugiIMDEngineFactory.deployForHook (V4 engine) = 19 descendants. They then need post-deployment configuration: hook.bindAccounting, hook.configure (which calls ledger.initialize and setExcluded), owner seedPool funding, MugiIMDVerifier.pinRequest/setPolicy (Ownable, mutable signer). MugiCrewToken inherits OZ Initializable with an external initialize (disabled in the IMD constructor path). The recipe forbids configuration after deployment/initializers; the protected floor only rehearses the four factories (they pass: runtimes 7,748/18,646/16,219/12,215 bytes, no reachable DELEGATECALL/CALLCODE/SELFDESTRUCT under the protected scan, constructors make no external calls). The hook's creation bytecode is never part of the signed ReleaseAttestation creation-bytes set, only its hash is committed in a constructor argument. Admission must accept this staged architecture explicitly; descendants are not IMD Explorer artifacts.","line":94,"path":"src/imd/MugiV1IMDDeploymentFactory.sol","reproduction":"Execute the IMD launch of the four factories: no hook, token, module or pool exists afterwards (MugiV1IMDDeploymentFactory.hook() == address(0), tokens(0) == address(0)). Only after owner calls deployHook(salt, initCode), deployModules(config), deployForHook x2, bindAccounting, configure and 10x seedPool does a playable application exist. Expected under evm_contracts: application fully configured in constructors. Actual: 19 descendants and multiple owner configuration calls after deployment.","severity":"medium","snippet":"    function deployHook(bytes32 salt, bytes calldata initCode) external onlyOwner returns (MugiGameHook deployedHook) {","title":"Admission: the four recorded factories exist to create 19 descendants that are configured after deployment; only the factories' bytecode is in the IMD artifact set"},{"citation":"resolved","description":"deployModules passes c.imdVerifierOwner unchecked. That owner can setPolicy to its own signer (panel/quorum minimum 2 is self-reported in the signed struct) and pinRequest any plan hash, so any plan whose per-crew allocations lie within the 75%-125% band enforced by MugiIMDBuybacks.approve can be approved by one key. Impact is bounded to redistributing a round's buyback budget between crews, but it is an additional privileged party not named in the brief (protocol owner is 0x20714d50...).","line":90,"path":"src/game/MugiIMDVerifier.sol","reproduction":"deployModules with imdVerifierOwner = V. V calls setPolicy(V_signer,2,2,1 days), pinRequest(id, q, h, t) for a plan giving crew A 125% and crew B 75% of the equal share, signs an attestation with panelSize=quorum=agreed=2. approvePlan(plan, proof) succeeds and executeBuyback spends the skewed allocation.","severity":"low","snippet":"    function setPolicy(address signer_, uint16 panelSize_, uint16 quorum_, uint64 maxAge_) external onlyOwner {","title":"MugiIMDVerifier owner (arbitrary imdVerifierOwner) can rotate the oracle signer and pin any buyback plan"},{"citation":"resolved","description":"hookInitCodeHash covers MugiIMDGameHook creation code plus abi.encode(owner, manager, team, community, v2MigrationTarget, initialSupply). The brief gives owner 0x20714d50f4675c366de30b603728a90ddddb240f but not team, community, v2 target or supply, and no test or inventory entry pins 0xbc3c1605...4359, so the reviewer could not reproduce it. The hash is immutable; deployHook also requires the hook's owner_ to equal the factory owner. If the hash was produced from any other compiler setting, source byte, or argument, deployHook reverts InvalidHookInitCode forever and a new factory launch is needed.","line":96,"path":"src/imd/MugiV1IMDDeploymentFactory.sol","reproduction":"Compute keccak256(abi.encodePacked(type(MugiIMDGameHook).creationCode, abi.encode(0x20714d50f4675c366de30b603728a90ddddb240f, 0x000000000004444c5dc75cB358380D2e3dE08A90, TEAM, COMMUNITY, V2, SUPPLY))) from this tree with the pinned foundry.toml and compare with 0xbc3c1605ac7a5e7781e7923e764c5e673c9480991b0d532f1799b78af4ac4359 before launch. If not equal, deployHook(salt, initCode) reverts InvalidHookInitCode for every initCode except a preimage of the hash.","severity":"info","snippet":"        if (keccak256(initCode) != hookInitCodeHash || initCode.length > 49_152) revert InvalidHookInitCode();","title":"Committed hookInitCodeHash 0xbc3c...4359 cannot be verified from the repository; a mismatch makes the deployment factory permanently unusable"}],"hash":"b4f19237aab0aa8d5e38d63b14dbed7a4b7b0ba01b1b1f50217961d0c3ccb744","nodeId":"f062672b-4928-499e-aa58-66cd0ac4f0cc","outcome":"completed","summary":"I've written the review to `.imd-findings.json` (9 findings) and changed no repository files. The one test I wrote under `test/scratch/` has been run and then deleted, and the working tree is clean. Nothing was deployed or submitted. So there is no launch record, no addresses, no transaction references and no new commit; the source is still commit `56673ae`.\n\n**What I read:** all 16 source files (the four factories, the hook, the crew token and its IMD wrapper, the ledger, buyback, price-oracle and V4-engine modules, the fee library, the swap router, the airdrop, the VRF adapter and the plan verifier), plus `launch.json`, `foundry.toml`, `README.md` and the test suites. The existing tests pass (92 passed, 2 skipped because they need a mainnet RPC). I didn't reach: the live Chainlink VRF coordinator, the Uniswap V4 PoolManager on mainnet, IMD's real ProjectFactory, `floor/OwnerChecks.sol` (not supplied), the future V2 receiver contract, and the inputs behind the committed hook hash.\n\n**Findings, most severe first:**\n1. **High – the season can freeze permanently if randomness never arrives** (`MugiIMDGameHook.sol:223`). Once an elimination is requested, the only way forward is the VRF callback. There is no timeout, no way to request again, and no recovery after launch. If the Chainlink request is never fulfilled (for example the subscription is underfunded until the request expires, or it is cancelled), all pool ETH is locked and every crew token is frozen. A Foundry proof is attached; it fails on the current code for exactly this reason.\n2. **Medium – the committed V2 target is not enforced** (`:406`). The hook's constructor checks the V2 target argument and then discards it. `migrateToV2` lets the owner send all leftover ETH and the hook's remaining survivor tokens to any contract they choose, and can be called more than once.\n3. **Medium – players lose unclaimed survivor tokens at finalize** (`MugiIMDLedger.sol:165`). Players earn survivor tokens from eliminated crews but can only claim them while the season is live and before the cutoff. Anyone can call `finalize()` at that cutoff, which wipes these claims, and the tokens backing them go to the V2 target.\n4. **Medium – things the `evm_contracts` rules forbid, which admission must explicitly accept:**\n   - the owner can pause all trading with no time limit (`:218`);\n   - token transfers are frozen outside the live window, forever for eliminated crews, and forever for *every* crew after finalize or an abort (`:438`). The brief doesn't mention the freeze of the surviving crew after finalize;\n   - the hook mints new crew tokens after launch (`:295`, `:278`);\n   - the four recorded factories create 19 descendants that need configuring after deployment, and only the factories' bytecode is in the signed artifact set (`MugiV1IMDDeploymentFactory.sol:94`).\n5. **Low** – whoever owns the plan verifier can be any address. That owner can change the oracle signer and get a skewed buyback plan approved, within the ±25% band per crew.\n6. **Info** – the committed hook hash `0xbc3c…4359` can't be checked from this repository. The team, community, V2 target and supply values behind it aren't stated anywhere I could find. If it doesn't match the compiled hook, `deployHook` can never succeed and a new factory launch would be needed.\n\n**Admission-floor check:** the four factories should pass. Their runtimes are 7,748, 18,646, 16,219 and 12,215 bytes, all under the 24,576-byte limit. A copy of the protected check's opcode scan finds no reachable DELEGATECALL, CALLCODE or SELFDESTRUCT. None of their constructors call another contract. `launch.json` matches the brief's manifest exactly.\n\nThe disclosed architecture is incompatible with standard `evm_contracts` rules on four points: the pause, the transfer freezes, minting after launch, and setup after deployment. It can only launch if source admission explicitly accepts these disclosed rules. The descendants are not separate IMD Explorer entries.","treeHash":null,"usage":{"cachedInputTokens":2200627,"inputTokens":54,"model":"claude-opus-5-5","outputTokens":27078,"runtime":"claude","turns":29,"wallClockMs":432265}}],"verification":[]}