{"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":"9cd98310-b905-4697-b7c3-a653ac25836c","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"e229981aa30bfa372196c1a66e936dbf4f107c17150803cf361fa9b572ab8969","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":"accepted"},{"acceptedSubmissionHash":"f139a3cfb7890ce290b315b0feb5d6c4c5eadc6eae1530113e0004be188c77c8","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":"accepted"},{"acceptedSubmissionHash":"5c3b0130c4cb7bb46a3bc5a78080018027e207fd19fdae148570768054f7e646","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":"accepted"},{"acceptedSubmissionHash":"524f08d73dc9d64a701f8fc7aeac9c3eb295c1434dda9590fd83ace712861378","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":"beb84f5bd734a8b10deb6bc84da242a71fb6226ee2765b09af026e5e5d4d4afa","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":"accepted"},{"acceptedSubmissionHash":"37014cc9a068778423545a3f57243d2590972a5830a0e56e732d0faa433057fe","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":"accepted"},{"acceptedSubmissionHash":null,"dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"failed"},{"acceptedSubmissionHash":"9b92bcc9d27e4a456a3903fd9bf7c7cbabae7d13ff9a88c436be6fe20533e3a2","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Deploy LARP (Linked Avatar Registry Protocol) on Ethereum exactly as in the repository, four contracts in this order. (1) LARPBurner(0x000000000004444c5dc75cB358380D2e3dE08A90 PoolManager; 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7 $IMD; 10000; 60; 0xc6C965Bd164c483e87d0B550671798e9A3602840 POOL4 hook; 10000; 200; 0x0000198C940D8cD70Cb9ACeC5E3af8216ac57d2F IMD6900; 0; 60; 0x667f4621030aCfAfb1bD0B64d33610A8567f2A44 pair hook). (2) LARP(0x0000eC93127BAA929E58E97dd0095A2BFb38ec1D identity.md). (3) IMDNames(identity.md; $contract:LARP; $contract:LARPBurner; 0x35dA9C0303507ddf708E87F2568EdDf12c47a059 artist; 0xa43e6F75ee006411F79Ac1C84120606C2330DE82 IMD's oracle Intake; 0x5598Aa9146215Bc13eb26f2c692Ad1461Fd32982 IMD's oracle signer). (4) LARPLinks(identity.md; 0xfF03410d0Fe5fa8f7F59F743de35E333D9857120 IMD's launcher; $contract:LARP; $contract:IMDNames; $contract:LARPBurner). Keep: no owner or upgrade; prices change only by the swarm's verdict within the guardrails; out-of-gas swaps revert. Do not change interfaces or constructor arguments. Constructors call nothing (test_DeploysOnAFreshChain); no CALLCODE/DELEGATECALL/SELFDESTRUCT (test_PassesTheAdmissionScan); one transaction (test_FitsOneTransaction). Offline, 142 tests. AUDIT.md's fixes are tested: check, don't re-raise. Coverage: each audit must answer all 138 entry points: the 4 constructors; LARPBurner: receive, POOL_MANAGER, IMD, POOL4_FEE, POOL4_SPACING, POOL4_HOOK, BACKUP_FEE, BACKUP_SPACING, IMD6900, PAIR_FEE, PAIR_SPACING, PAIR_HOOK, DEAD, MAX_BURN, POOL_SHARE_BPS, burn, burnImd, quoteImd, unlockCallback; LARP: IDENTITY, SLOTS, DOMAIN_SEPARATOR, nonces, setAgent, setAgentBySig, resignAgent, agentOf, identityOfAgent, canAct, setFace, clearFace, equip, unequip, faceOf, itemOf, wearerOf, faceURI, avatarOf, itemURI, supportsInterface; IMDNames: IDENTITY, LARP, BURNER, TLD, ROYALTY_BPS, ACTION, INTAKE, ORACLE_SIGNER, MIN_PRICE, MAX_PRICE, COOLDOWN, EXECUTE_WINDOW, MIN_PANEL, MIN_QUORUM, prices, epoch, lastChange, proposalCount, proposal, propose, onVerdict, onNoVerdict, execute, artist, renderer, rendererLocked, priceOf, crewPrice, tollOf, register, registerWithImd, link, linkWithImd, unlink, setPrimary, setText, nameOfToken, nameOf, identityOf, resolve, resolveName, primaryOf, text, tokenURI, royaltyInfo, setRenderer, setArtist, lockRenderer, name, symbol, balanceOf, ownerOf, approve, getApproved, setApprovalForAll, isApprovedForAll, transferFrom, both safeTransferFrom, supportsInterface; LARPLinks: IDENTITY, LAUNCHER, LARP, NAMES, BURNER, isFren, asked, frenCount, fren, unfren, crewCount, crewByName, invited, foundCrew, foundCrewWithImd, invite, setOpen, join, leave, kick, passCaptain, disband, crewOf, crew, allocOf, proveAlloc, launchCount, launchJeet, jeetOf, jeetOfRange, rankOf, tierOf, titleOf, cardOf. A coverage ratio below 1 is not a whole number: the launch blocks.","parentJobId":null,"planHash":"67d0f68375221f0a5d45e65b000d360a092c237bb344ec3abc4c67c6f7d2c5f8","previousHash":"71ca9308f60fa5cfd1fa527f6a35981e488fb1bb01e15527467a6232b5ac16d2","projectId":"9cd98310-b905-4697-b7c3-a653ac25836c","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1381-larpburner-larp-imdnames-larplinks"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51508","feedbackHash":"25e49ea0b87c320cbb42c501c36fb00af34f562ddc4294b8879b34c5f53db40c","nodeKey":"audit_economics","submissionHash":"f139a3cfb7890ce290b315b0feb5d6c4c5eadc6eae1530113e0004be188c77c8","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52127","feedbackHash":"f2c47beba2d17b6bf3bb62c779a33e25a08431329dd71f3b99d7920ff47f2f60","nodeKey":"audit_flow","submissionHash":"5c3b0130c4cb7bb46a3bc5a78080018027e207fd19fdae148570768054f7e646","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52164","feedbackHash":"2806ac359f472bcbbfd226cca371e04f28b95a766ca0d161da4157bbfb589009","nodeKey":"audit_math","submissionHash":"beb84f5bd734a8b10deb6bc84da242a71fb6226ee2765b09af026e5e5d4d4afa","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52129","feedbackHash":"906c1cbc1147ba84707909b705be82d0366d05ef0db8a92866ab41c2a1732abd","nodeKey":"audit_permissions","submissionHash":"37014cc9a068778423545a3f57243d2590972a5830a0e56e732d0faa433057fe","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52152","feedbackHash":"6070fda328cf9ef09b7903f98ae6247f0d457482039d36a6d3f67898427534d3","nodeKey":"write_foundry_tests","submissionHash":"9b92bcc9d27e4a456a3903fd9bf7c7cbabae7d13ff9a88c436be6fe20533e3a2","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"3467917727bc03945dfe484c44c4c963f1ccdc212fd7b8729b8cbde2aaa10270","state":"blocked","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"63c29c49a249ab7e","findings":[{"citation":"resolved","description":"Trust gap (access x asymmetry). `_tryUnlock` cannot tell a caller who starved the call from a callee that burned the gas it was given: any failed route that leaves no more than a quarter of the gas reverts the whole call. AUDIT.md's trust table promises the opposite for the parties that can cause exactly that failure: for the POOL4 hook (owned by IMD's treasury) 'if it fails or turns hostile: the burner falls to route 2'; for IMD6900 ('upgradeable', owned by the IMD6900 timelock) 'if its burn refuses, the share goes to 0x…dEaD as $IMD'; for the pair hook the same. Those fallbacks only hold for a callee that reverts cheaply. A callee that spends the gas (an upgraded IMD6900 `burn` that loops, or a hook whose beforeSwap/afterSwap runs out of gas) leaves ~3-4/64 of the gas after the nested frames unwind, below the quarter, so `burn` and `burnImd` revert at every gas limit. Because `IMDNames.register`, `link` (with a toll), `registerWithImd`, `linkWithImd`, `LARPLinks.foundCrew` and `foundCrewWithImd` all call the burner synchronously, every paid action of the protocol reverts for as long as that party keeps its code that way, ETH already parked in the burner cannot be burned, and there is no owner to re-route (by design). The IMD6900 path is the strongest: `IBurnable(IMD6900).burn(out)` runs inside the unlock callback at every `burn` and `burnImd`, and the token is documented as upgradeable, so its timelock alone can freeze all of LARP's fee paths. A cheaply reverting callee still falls through as documented; this is only the gas-burning shape, which the existing tests `test_ASwapOutOfGasReverts` / `test_ANestedSwapOutOfGasReverts` currently encode as the intended outcome. Fix that keeps 'a caller cannot skip a route by sending too little gas': give each try a fixed budget and require the caller to bring it, then treat every failure inside the budget as the callee's: `if (gasleft() < ROUTE_GAS + ROUTE_GAS / 63 + 30_000) revert TooLittleGas(); try POOL_MANAGER.unlock{gas: ROUTE_GAS}(...) {...} catch { return (false, \"\"); }` with ROUTE_GAS generous for a hooked v4 swap (the proof passes with 1_500_000). The two existing out-of-gas tests then need to assert 'parked / fell through' instead of 'reverted', and the brief's 'out-of-gas swaps revert' is kept in the sense that a starved call reverts before the try. This is a design decision for the author: it trades 'a legitimate route that needs more than ROUTE_GAS is skipped' for 'no third party can halt the fee path'.","line":245,"path":"src/LARPBurner.sol","reproduction":"State: a real v4 PoolManager; the hookless ETH/$IMD pool (1%, spacing 200) has liquidity; the pair pool has liquidity with an IMD6900 whose `burn(uint256)` loops forever (what its timelock can upgrade it into). Call `burner.burn{value: 0.01 ether, gas: 5_000_000}(0)`. Expected (AUDIT.md): route 1 buys $IMD, the IMD6900 share falls through and all the $IMD goes to 0x…dEaD. Actual: the call reverts with TooLittleGas (0x5dd42bb6); `IMDNames.register{value: priceOf('alice')}('alice', to, 0)` reverts the same way at any gas limit. Second shape: POOL4 carries a hook at an address with BEFORE_SWAP_FLAG whose beforeSwap loops; the hookless pool has liquidity; `burn{value: 0.01 ether, gas: 5_000_000}(0)` reverts TooLittleGas instead of buying on the hookless pool. Both are in test/scratch/HostileCalleeHaltsFees.t.sol (2 failing tests on this code; both pass with the fixed-budget try above).","severity":"medium","snippet":"            if (gasleft() <= gasBefore / OOG_DIVISOR) revert TooLittleGas();","title":"A gas-burning callee (IMD6900's upgradeable burn, or a POOL4/pair hook) turns the burner's documented fallbacks into TooLittleGas, halting every paid LARP action"},{"citation":"resolved","description":"Access asymmetry: `_agents[imdId]` is written only by the identity's owner (setAgent / setAgentBySig), but `_agentIdentity[agent]` is keyed by the agent address and written by whoever last named that address, with no consent of the address or of the identity it already serves. `identityOfAgent(K)` then reports a stranger's identity as the one K speaks for, and reports it `live`, while `canAct(1, K)` still holds for the original identity. Any consumer that resolves a key to its identity (an IMD agent presenting itself as 'identity #1', a front end, a contract using identityOfAgent as the reverse of canAct) is redirected to the attacker's identity, for the cost of owning any identity.md. The interface documents it as 'the identity `agent` was last made the agent of', so the on-chain permissions are intact; the defect is that the reverse lookup is not the agent's or the first identity's to keep. Fix without changing interfaces: in `_setAgent`, keep an existing live binding (`(uint256 cur, bool live) = identityOfAgent(agent); if (live && cur != imdId) revert AgentTaken();`), or only write `_agentIdentity` when the existing one is not live.","line":136,"path":"src/LARP.sol","reproduction":"alice owns identity 1, mallory owns identity 2, K is any address. 1) alice: `larp.setAgent(1, K)`; `identityOfAgent(K)` = (1, true). 2) mallory: `larp.setAgent(2, K)`. Expected: K's reverse record stays with identity 1 (or the call refuses). Actual: `identityOfAgent(K)` = (2, true) while `canAct(1, K)` is still (true, alice). test/scratch/AgentReverseRecord.t.sol shows it ('2 != 1').","severity":"low","snippet":"            _agentIdentity[agent] = imdId + 1;","title":"Any identity owner can overwrite the reverse record identityOfAgent(K) of another user's live agent key"},{"citation":"resolved","description":"Asymmetry between the two burn paths under one caller-chosen condition. The PoolManager allows one unlock at a time: a nested `POOL_MANAGER.unlock` reverts `AlreadyUnlocked()` cheaply, which `_tryUnlock` treats as an ordinary route failure. A contract that first calls `pm.unlock` itself and, inside its `unlockCallback`, pays a LARP fee in $IMD (`registerWithImd`, `linkWithImd`, `foundCrewWithImd`, or a direct `burnImd`) therefore gets the IMD6900 leg skipped: the whole fee goes to 0x…dEaD as $IMD and no IMD6900 is bought or burned, contradicting 'Every fee ... 6.9% buys IMD6900' and AUDIT.md's 'no call that goes through skips the IMD6900 buy'. The ETH path from inside an unlock parks instead (every route fails), and is burned properly by the next outside `burn`, so only the $IMD path has this hole. No funds are lost and the $IMD is still burned; the harm is to the IMD6900 buying pressure of fees paid that way (6.9% of each). Fix: refuse to run while the PoolManager is unlocked, e.g. in `burn`/`burnImd` read the PoolManager's unlock flag via `exttload(Lock.IS_UNLOCKED_SLOT)` and revert, or treat a route failure with `AlreadyUnlocked()` as a revert of the call.","line":225,"path":"src/LARPBurner.sol","reproduction":"State: POOL4, the hookless pool and the pair pool all have liquidity (test/Base.sol). A contract U holds 100 $IMD, approved to IMDNames. U calls `pm.unlock(\"\")`, and in its `unlockCallback` calls `names.registerWithImd('alice', U, type(uint256).max)`. Expected: 6.9% of the quoted $IMD buys IMD6900 on the pair pool and burns it (IMD6900 totalSupply drops). Actual: the name is registered, the $IMD goes to 0x…dEaD, and IMD6900 totalSupply is unchanged. test/scratch/InsideUnlock.t.sol (passes: the skip happens).","severity":"low","snippet":"            (bool ok, bytes memory result) = _tryUnlock(TO_PAIR, share);\n            if (ok) burned6900 = abi.decode(result, (uint256));\n            else share = 0;","title":"A payer who calls from inside their own PoolManager unlock makes the burner skip the IMD6900 buy for that fee"}],"hash":"37014cc9a068778423545a3f57243d2590972a5830a0e56e732d0faa433057fe","nodeId":"f4f73dc7-6d12-497a-b500-72af7d1c84ac","outcome":"completed","summary":"The review is complete and written to `.imd-findings.json`. No tracked file was changed; only the findings file and three scratch tests exist outside the tree.\n\n**Findings (3), from the Access Control, Trust Gap and Asymmetry guides**\n\n- **Medium, trust gap in the burner's out-of-gas rule.** `_tryUnlock` at `src/LARPBurner.sol:245` cannot tell a starved caller from a callee that burned the gas it was given, so any such failure reverts the whole call. AUDIT.md's trust table promises the opposite for exactly the parties who can cause it: a hostile POOL4 hook \"falls to route 2\", a refusing IMD6900 `burn` \"goes to dEaD as $IMD\". Those hold only for a cheap revert. An upgraded IMD6900 `burn` that loops, or a hook whose beforeSwap loops, makes `burn` and `burnImd` revert at every gas limit, and with them every `register`, `link` with a toll, and `foundCrew` in ETH or $IMD. There is no owner to re-route. The proof file has two tests that fail on this code and pass with a fixed route budget (require the caller brings it, forward it with `{gas:}`, treat any failure inside as the callee's). I flagged that this is a design decision since two existing tests encode the current behaviour as intended.\n- **Low, access asymmetry in LARP agents.** Any identity owner can call `setAgent` with someone else's live agent key and rewrite `identityOfAgent(K)` to their own identity, reported live, while `canAct` still holds for the original identity. Reproduced in a scratch test.\n- **Low, asymmetry between the two fee paths.** A payer who calls `registerWithImd` from inside their own PoolManager unlock makes the burner's nested unlock fail cheaply, so the 6.9% IMD6900 leg is skipped and the whole fee goes to dEaD as $IMD. The ETH path parks instead and burns properly later. Reproduced with the real PoolManager.\n\n**Coverage.** All 138 entry points have a row. Every verifier-listed name is answered exactly. Marked `finding`: the burner's burn/burnImd, the six paid IMDNames and LARPLinks entry points, setAgent, setAgentBySig and identityOfAgent. Everything else is `holds` with a one-line reason; nothing is `unreached`.\n\n**Checked and not raised.** The onVerdict path (Intake-only, own pending id, signer in this contract's domain, panel rules), execute's epoch and cooldown gates, the PoolManager-only callback, the name toll rule across every change of hands, crew and fren symmetry, proveAlloc's root binding, the artist's art-only powers, and the quote's PoolManager storage slots against v4-core. Slither's and aderyn's lines were all leads I traced; none became a finding on its own. The identity.md probe over RPC failed, so whether a burned captain identity can freeze a crew was not verified and is not reported.","treeHash":null,"usage":{"cachedInputTokens":1826438,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":54674,"runtime":"claude","turns":35,"wallClockMs":1070893}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3a40eaafbd83a6bc","findings":[{"citation":"resolved","description":"AUDIT.md L-01 says a route that fails with no more than 1/63 of its gas left reverts the call, so a caller cannot skip POOL4 (or the IMD6900 buy) by starving the swap. The check only holds when the frame that runs out of gas is the one the try calls (test_ASwapOutOfGasReverts uses a PoolManager whose unlock itself loops). In the real path the out-of-gas happens in PoolManager.swap or in the pool's hook, three or four frames below the burner's try: every intermediate frame keeps 1/64 of its own gas and hands it back when it reverts, so after a failure d frames deep roughly d/64 of gasBefore is left, which is above gasBefore/63 for any d >= 2. The route is then treated as a normal failure: the ETH falls to the next route or parks, and in _burnImd the 6.9% IMD6900 buy is skipped and sent to DEAD as $IMD. Exploitability today depends on how much gas the POOL4 hook and the pair hook consume (the remainder after a deep failure is about 6% of the gas given), so the impact is a weakened guarantee rather than a loss. Fix: treat a failure as out-of-gas when gasleft() is below a larger fraction (for example gasBefore / 8, well above any real revert's leftover), or give the unlock an explicit gas stipend and require that stipend to be available before trying the route.","line":234,"path":"src/LARPBurner.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {LARPBurner, PoolKey, SwapParams} from \"src/LARPBurner.sol\";\n\n/// @dev A PoolManager that calls the burner back (as the real one does) and whose swap burns all the gas it is given,\n/// as a heavy hook would: the out-of-gas happens two calls below the burner's try, not one.\ncontract NestedHogPoolManager {\n    uint256 public swaps;\n\n    function unlock(bytes calldata data) external returns (bytes memory) {\n        return LARPBurner(payable(msg.sender)).unlockCallback(data);\n    }\n\n    function swap(PoolKey memory, SwapParams memory, bytes calldata) external returns (int256) {\n        while (true) {}\n        return 0;\n    }\n}\n\ncontract NestedGasTest is Test {\n    event Parked(uint256 eth);\n\n    function test_ANestedOutOfGasIsNotCaught() public {\n        NestedHogPoolManager pm = new NestedHogPoolManager();\n        LARPBurner burner = new LARPBurner(\n            address(pm), address(0x1111), 10_000, 60, address(0), 10_000, 200, address(0x6900), 0, 60, address(0)\n        );\n        vm.deal(address(this), 1 ether);\n        // The same probe as test_ASwapOutOfGasReverts, one level deeper: the fix expects TooLittleGas.\n        (bool ok, bytes memory err) =\n            address(burner).call{value: 0.05 ether, gas: 3_000_000}(abi.encodeCall(burner.burn, (0)));\n        emit log_named_bytes(\"error\", err);\n        emit log_named_uint(\"burner balance (parked)\", address(burner).balance);\n        assertFalse(ok, \"a swap that ran out of gas should revert the burn (TooLittleGas), not park the ETH\");\n        assertEq(bytes4(err), LARPBurner.TooLittleGas.selector);\n    }\n}","reproduction":"State: a PoolManager that calls msg.sender.unlockCallback(data) in unlock (as the real one does) and whose swap burns all the gas it is given. Call: burner.burn{value: 0.05 ether, gas: 3_000_000}(0). Expected (per L-01 and test_ASwapOutOfGasReverts): revert TooLittleGas. Actual: the call succeeds, both routes are reported failed, Parked(0.05 ether) is emitted and burn returns 0. Trace: route 0 consumed 2,860,440 gas and left about 140k (> 3,000,000/63 = 47.6k), route 1 consumed 131k and left about 6k (> 131k/63 = 2k). The attached test fails on this code and passes once a failure that ate the gas is reverted.","severity":"low","snippet":"            if (gasleft() <= gasBefore / 63) revert TooLittleGas();","title":"L-01 fix is depth-1 only: an out-of-gas two or more frames below the try is not detected, so a swap that runs out of gas still skips its route"},{"citation":"resolved","description":"propose accepts next == prices (_checkStep allows to == from, test_TheOracleMustBePaid relies on it) and the swarm will approve it, since the current prices meet the guidelines by construction. execute of that no-op bumps epoch and sets lastChange, so every other approved proposal in the old epoch reverts Stale and nothing can execute for COOLDOWN (7 days). An attacker who wants the ETH prices to stay where they are (for example while ETH/USD moves so that names drift outside the $1-5 guideline) repeats this weekly: propose the current prices (0.5 IMD), get the verdict, and win the execute race at the cooldown's expiry with a higher priority fee. Honest proposers pay the same 0.5 IMD per attempt and never land. Fix: refuse next == prices in propose, do not bump epoch or lastChange when prices did not change, or let execute accept a proposal whose next still passes _checkStep against the current prices instead of requiring epoch equality.","line":201,"path":"src/SwarmPrices.sol","reproduction":"1. Alice: propose({0.005,0.0012,0.0005,0.0005}, 0.5e18) -> id A; intake delivers an approving verdict -> Approved. 2. Mallory: propose({0.0069,0.00169,0.00069,0.00069} (the current prices), 0.5e18) -> id B; verdict approving -> Approved. 3. Mallory: execute(B): succeeds, epoch 0 -> 1, lastChange = now, prices unchanged. 4. Anyone: execute(A) -> reverts Stale (expected: A, a swarm-approved change, applies). Re-proposing A and getting it approved gives an id C that reverts Cooling until lastChange + 7 days; Mallory repeats steps 2-3 at that instant. Expected: a proposal that changes nothing cannot void an approved change; actual: it does, at 0.5 IMD per week.","severity":"low","snippet":"        if (p.epoch != epoch) revert Stale();","title":"Any approved proposal, including one that changes nothing, resets the cooldown and stales every other approved proposal: price governance can be frozen for 0.5 IMD a week"},{"citation":"resolved","description":"The oracle-consumer reference requires the intake, action id, asset/price and signer to be constructor inputs and settable, never constants, so that a new action version (oracle-2), a moved Intake or a rotated signer does not need a redeploy. SwarmPrices hardcodes ACTION and makes INTAKE and ORACLE_SIGNER immutable, and the protocol has no owner by design. The fee being a call argument covers only a price move. AUDIT.md accepts 'if IMD stops answering, prices stay' but the consequence is stronger: once the Intake stops selling oracle-1 (ActionNotSold) every propose reverts for everyone, and once the signer key rotates every verdict reverts BadVerdictSignature, leaving proposals Pending forever with their 0.5 IMD spent. Names and crews then stay priced in ETH at the last values while ETH/USD moves, so the $1-5 guideline the swarm enforces can no longer be met. Without adding an owner, the swarm's own verdict mechanism could ratify a new (intake, action, signer) triple the same way it ratifies prices; or the adapter should state the freeze as an accepted outcome in the launch notes.","line":81,"path":"src/SwarmPrices.sol","reproduction":"State: IMD's Intake at 0xa43e... no longer sells bytes32('oracle.request@oracle-1') (or the signer is no longer 0x5598...). Call: propose(validNext, 0.5e18) -> reverts inside Intake.requestWithFailure (ActionNotSold); or, with a rotated key, the Intake's callback onVerdict(id, a, sig) reverts BadVerdictSignature and the Intake records the delivery as failed, not retried. Expected (per the oracle reference): a settable intake/action/signer; actual: no function on IMDNames can change any of them, prices stay fixed forever.","severity":"low","snippet":"    bytes32 public constant ACTION = bytes32(\"oracle.request@oracle-1\");","title":"Price governance has no path for a new Intake, action id or oracle signer: when IMD retires oracle-1, Intake v2 or rotates the signer key, prices are frozen forever"},{"citation":"resolved","description":"royaltyInfo names LARPBurner as the royalty receiver for every sale. Marketplaces pay the royalty in the sale currency; accepted offers (OpenSea, Blur bids) settle in WETH, so a 6.9% WETH royalty lands in the burner. The burner handles only native ETH (burn) and $IMD (burnImd/_imdHeld); it has no function that reads, swaps or unwraps any other token, so that value is stranded rather than burned, contradicting 'every fee burns'. Fix: a permissionless path that unwraps a WETH balance to ETH (WETH is immutable and well known on Ethereum) before burn runs, or document that only ETH-settled sales burn their royalty.","line":294,"path":"src/IMDNames.sol","reproduction":"State: name X owned by Alice; a WETH bid of 1 WETH accepted on a royalty-honouring market. The market transfers 0.069 WETH to BURNER. Then: burner.burn(0) spends only address(this).balance (ETH) and burnImd reads only IMD.balanceOf(burner). Expected: the 0.069 ETH-equivalent is burned; actual: WETH.balanceOf(BURNER) == 0.069e18 forever, no function can move it. Any ERC-20 sent to the burner behaves the same.","severity":"low","snippet":"        return (BURNER, salePrice * ROYALTY_BPS / 10_000);","title":"Royalties paid in an ERC-20 (WETH offers on marketplaces) are sent to the burner and can never be burned or moved"},{"citation":"resolved","description":"bytes4(keccak256('onVerdict(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)')) is 0x8bf09c1b; 0x510379c7 is the selector of the reference example's onOracleResult with the same parameters. Because propose passes this.onVerdict.selector in the Callback struct, the Intake calls the right function; only the document is wrong. The struct shape is correct: the protocol vector's signature verifies (I deployed IMDNames at 0x2748 on chain 11155111 with the vector signer and delivered the vector attestation with VECTOR_SIGNATURE: accepted, status Rejected because its answer type is a list; a bool true signed by the vector key: Approved). The repository has no such conformance test; its tests sign with their own key only, which the oracle reference warns proves nothing about the protocol's digest. Adding the vector test is recommended.","line":120,"path":"AUDIT.md","reproduction":"forge: assertEq(IMDNames.onVerdict.selector, bytes4(0x510379c7)) fails with 0x8bf09c1b != 0x510379c7; cast sig 'onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)' = 0x510379c7.","severity":"info","snippet":"    selector `0x510379c7` matches IMD's docs.","title":"AUDIT.md cites the wrong callback selector: 0x510379c7 is the reference's onOracleResult, onVerdict's is 0x8bf09c1b (harmless: the selector is passed at request time)"},{"citation":"resolved","description":"Contracts read in full: src/LARPBurner.sol, src/LARP.sol (+ILARP.sol), src/IMDNames.sol (+IIMDNames.sol) with src/SwarmPrices.sol, src/LARPLinks.sol, src/Labels.sol, src/SafeReads.sol; AUDIT.md, README.md, test/Base.sol, test/Mocks.sol, test/SwarmPrices.t.sol, test/LARPBurner.t.sol, test/Launch.t.sol; vendored solady ERC721/Base64 and v4-core FullMath only as used. Baseline: forge test --offline: 140 passed, 11 fork tests skipped (no network). Not reachable (offline): the live PoolManager 0x0000...4444, $IMD 0xD34a..., POOL4 hook 0xc6C9..., IMD6900 0x0000198C... and its pair hook 0x667f..., IMD's launcher 0xfF03... and its distributors, the Intake 0xa43e... and identity.md 0x0000eC93...; their ABIs (distributorOf(uint64)=0x6c637492, roundOf(uint256)=0xc7c38091, claimed(uint256,address)=0x120aa877, token()=0xfc0c546a, burn(uint256), requestWithFailure) were checked as selectors only; the fork tests that exercise them did not run here. Launch constraints re-checked locally: constructors store only (test_DeploysOnAFreshChain), opcode scan clean (test_PassesTheAdmissionScan), one transaction (test_FitsOneTransaction). Constructor arguments in the brief match README/Launch.t.sol: Intake is version 2 (requestWithFailure), signer and action id match the oracle reference. Oracle conformance: I ran the reference's protocol vector (chain 11155111, consumer 0x2748, VECTOR_DIGEST/VECTOR_SIGNATURE) against IMDNames.onVerdict: the protocol's signature verifies and a fresh bool-true signed by the vector key approves (no finding; the repo lacks this test, see info).\n\nEntry points, all 138 answered (verdict in brackets):\nConstructors: LARPBurner [stores immutables, zero checks, no calls], LARP [stores IDENTITY], IMDNames [stores, SwarmPrices bounds check pure, artist may be 0 by design], LARPLinks [stores, zero checks].\nLARPBurner: receive [accepts ETH, ok]; POOL_MANAGER, IMD, POOL4_FEE, POOL4_SPACING, POOL4_HOOK, BACKUP_FEE, BACKUP_SPACING, IMD6900, PAIR_FEE, PAIR_SPACING, PAIR_HOOK, DEAD, MAX_BURN, POOL_SHARE_BPS [immutable/constant getters, ok]; burn [tload lock, MAX_BURN cap, route fallthrough, minImd; finding: nested OOG evades TooLittleGas (low)]; burnImd [locked, ok]; quoteImd [slot math matches v4 StateLibrary (pools slot 6, liquidity +3), max of two spots, reverts without both; spot manipulation acknowledged L-07, cost check holds at stated depth]; unlockCallback [only PoolManager, exact-fill checks on both legs, sync/settle/take order correct, IMD6900 burn atomic with the swap].\nLARP: IDENTITY, SLOTS, DOMAIN_SEPARATOR, nonces [ok]; setAgent [owner only, bumps nonce]; setAgentBySig [deadline, live holder, nonce, low-s, 1271 fallback; replay impossible]; resignAgent [agent only]; agentOf, identityOfAgent, canAct [liveness bound to holder]; setFace, equip [canAct, NotAMask, ownership/copies checks, two-way _placed kept]; clearFace, unequip [placer or controller]; faceOf, itemOf, wearerOf, faceURI, avatarOf, itemURI [staticcall reads, gas forwarded as documented I-07]; supportsInterface [ok].\nIMDNames: IDENTITY, LARP, BURNER, TLD, ROYALTY_BPS, ACTION, INTAKE, ORACLE_SIGNER, MIN_PRICE, MAX_PRICE, COOLDOWN, EXECUTE_WINDOW, MIN_PANEL, MIN_QUORUM, prices, epoch, lastChange, proposalCount, proposal [getters, ok]; propose [bounds+step, pulls fee from caller, approves intake, body valid JSON within limits; finding: identical-price proposals allowed, see low]; onVerdict [intake only, own pending id only, protocol digest verified against the reference vector, panel/quorum/expiry checks; fits 200k gas]; onNoVerdict [intake only, closes]; execute [approved, window, epoch, cooldown; finding: cooldown/epoch reset griefing (low)]; artist, renderer, rendererLocked [ok]; priceOf [BadName on invalid], crewPrice, tollOf [ok]; register [price exact, _mint before burn, no receiver hook]; registerWithImd [quote then transferFrom to burner then burnImd]; link [toll exact, state before burn]; linkWithImd [same]; unlink [controller or owner]; setPrimary [owner ","line":3,"path":"AUDIT.md","reproduction":"Not a defect. Commands run: forge test --offline (140 passed, 11 skipped fork tests); forge test --match-path test/scratch/Conformance.t.sol (protocol vector accepted); forge test --match-path test/scratch/NestedGas.t.sol (fails on this code: see the low finding on LARPBurner.sol:234).","severity":"info","snippet":"Scope: `src/` at this commit: `LARPBurner`, `LARP` / `ILARP`, `IMDNames` / `IIMDNames` with `SwarmPrices`,","title":"Scope, reachability and entry-point coverage of this review"}],"hash":"524f08d73dc9d64a701f8fc7aeac9c3eb295c1434dda9590fd83ace712861378","nodeId":"514e118c-ffb4-46f3-98e1-ffe0c8f933af","outcome":"completed","summary":"Review complete. No tracked file was changed; the output is `.imd-findings.json` (6 entries) plus the two scratch tests under `test/scratch/`.\n\n**Result: no critical, high or medium defects.** The baseline suite passes offline (140 tests, 11 fork tests skipped), the launch constraints hold, and the constructor arguments in the brief match the repository. The oracle integration is sound: I ran the protocol's own attestation vector from the oracle reference against `IMDNames.onVerdict` and the protocol's signature verifies, so struct, type string and domain match what the oracle signs. The repository itself lacks that test; its tests only self-sign.\n\n**Findings recorded**\n\n- **Low, with proof.** The L-01 gas fix in `LARPBurner._tryUnlock` only catches an out-of-gas in the frame the try calls. The real failure sits three or four frames deep, and each intermediate frame returns its reserved 1/64, leaving far more than 1/63. A PoolManager whose swap burns all gas makes `burn` succeed and park the ETH where `TooLittleGas` is expected. The scratch test fails on the current code.\n- **Low.** A proposal with unchanged prices passes the guardrails and the swarm approves it. Executing it bumps the epoch and resets the 7 day cooldown, staling every other approved proposal. Governance can be frozen for 0.5 IMD a week.\n- **Low.** The action id is a constant and the Intake and signer are immutable with no owner. The oracle reference requires these to be changeable. If IMD retires oracle-1, Intake v2 or rotates the signer, prices freeze forever.\n- **Low.** Royalties paid in WETH or any ERC-20 land in the burner, which can only burn ETH and $IMD. That value is stranded.\n- **Info.** AUDIT.md cites callback selector 0x510379c7, which is the reference example's `onOracleResult`. `onVerdict` is 0x8bf09c1b. Harmless, since the selector is passed at request time.\n- **Info.** Scope and coverage: all 138 entry points answered, per contract, with the list of contracts read and the live mainnet contracts that could not be reached offline (PoolManager, $IMD, both hooks, IMD6900, launcher and distributors, Intake, identity.md), whose ABIs were checked as selectors only.\n\nAcknowledged items in AUDIT.md were re-checked and hold at the stated pool depths, including the spot-price quote for $IMD payments and the two-way name link bookkeeping across sales.","treeHash":null,"usage":{"cachedInputTokens":2077102,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":56789,"runtime":"claude","turns":32,"wallClockMs":1154086}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fd5402086dce252e","findings":[{"citation":"resolved","description":"IMDNames inherits solady's ERC721, whose approve, transferFrom and both safeTransferFrom are declared payable (lib/solady/src/tokens/ERC721.sol lines 202, 252, 313, 330). IMDNames neither overrides them nor rejects msg.value on them, and it has no receive, withdraw or sweep: every other ETH entry point of the contract (register, link) checks msg.value against the exact amount due and forwards it to the burner. ETH that rides along with a name transfer or approval is therefore accepted silently and stranded in IMDNames forever; it never reaches the burner, so it is neither burned nor refundable. AUDIT.md I-10 only covers ETH force-sent via selfdestruct/coinbase; this is an ordinary call path a wallet or integration can hit by mistake. Fix (keeps the ERC-721 ABI): override approve, transferFrom and both safeTransferFrom in IMDNames as payable overrides that revert WrongPrice() when msg.value != 0 before calling super, or forward any msg.value to BURNER so it burns like every other fee.","line":21,"path":"src/IMDNames.sol","reproduction":"Deploy as in the repository. Alice registers 'kekw' (names.register{value: priceOf('kekw')}('kekw', alice, 0)). Then vm.prank(alice); names.transferFrom{value: 1 ether}(alice, bob, id): the call succeeds, bob owns the name, and address(names).balance == 1 ether. bob then calls names.approve{value: 0.5 ether}(alice, id): succeeds, address(names).balance == 1.5 ether. No function of IMDNames can move that ETH (no receive/fallback, no withdraw, nothing sends ETH except register/link which forward exactly msg.value). Expected: a transfer or approval carrying ETH reverts (as register/link do for a wrong amount) or the ETH goes to the burner. Verified with test/scratch/PayableLock.t.sol (passes on this code, i.e. the ETH is kept).","severity":"low","snippet":"contract IMDNames is ERC721, IIMDNames, SwarmPrices {","title":"IMDNames keeps any ETH sent with approve/transferFrom/safeTransferFrom (solady's payable ERC-721 surface) and has no way to release it"}],"hash":"5c3b0130c4cb7bb46a3bc5a78080018027e207fd19fdae148570768054f7e646","nodeId":"955c27cc-3fe4-42de-a69e-eb6cf2178940","outcome":"completed","summary":"Audit complete. The findings file is written with one substantiated finding and a coverage row for all 42 listed entry points plus the constructors, views and the invariants I checked.\n\n**Outcome: one low finding, nothing critical, high or medium in my area.**\n\n**Finding (low):** IMDNames inherits solady's ERC721, whose `approve`, `transferFrom` and both `safeTransferFrom` are payable. IMDNames neither rejects nor forwards that ETH, and has no receive, withdraw or sweep. ETH sent along with a transfer or approval is stranded in the contract and never burned. I confirmed it with a scratch test: a transfer carrying 1 ETH succeeds and the contract balance stays at 1 ETH. The fix is to override those four functions and revert on nonzero value, or forward it to the burner.\n\n**What held, traced from entry to final state:**\n- Burner: lock, WETH unwrap, exact-fill route attempts, the quarter-gas out-of-gas rule, delta decoding, sync/settle/take order, and that only the burner's own unlock can reach the callback.\n- Quote path: the storage offsets `_spot` reads match v4's StateLibrary, and the max-of-two-pools quote cannot be lowered by moving one pool.\n- Names: the two-way link bookkeeping including the cross-relink case, the toll logic matching `tollOf`, and the exact-value checks on every ETH path.\n- Swarm prices: proposals keyed by the Intake's request id so a stranger's own paid question hits `NotPending`, guardrails enforced at proposal time and tied to the epoch at execution, and the callback fits the 200k gas stipend.\n- LARP and Links: agent signatures, placement bookkeeping, crew and fren state transitions, and the Merkle proof path. Every hardcoded selector matches `cast sig`.\n\n**Not reached:** nothing in the assigned area. I could not verify live-chain behaviour of POOL4's hook, the pair hook, IMD6900's upgradeable `burn`, or the real distributor's `roundOf` layout offline. The repository's fork tests cover those.\n\n**Environment note:** the worker's 1.5 GB memory cap kills solc when the whole tree compiles at once. Running suites per file works, and all 149 offline tests pass that way.","treeHash":null,"usage":{"cachedInputTokens":2186126,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":59508,"runtime":"claude","turns":29,"wallClockMs":1363804}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"759c614fdc84ff66","findings":[],"hash":"9223163c87d8f9c633f581f2e27999573877791db38481230a94236839e737a9","nodeId":"697c166b-2f5e-429f-9f39-21e4ac61f31d","outcome":"failed","summary":"needs input: The accepted LARPBurner constructor takes three int24 tick-spacing arguments (pool4Spacing, backupSpacing, pairSpacing at positions 3, 6 and 9). The evm_contracts manifest refuses signed-integer constructor types ('unsupported constructor type int24 at 3'), so no launch.json can deploy the contract as it stands. Fixing it needs a source change to LARPBurner, which this manifest-only task may not make. — May a builder change LARPBurner's constructor so the three tick spacings are passed as uint24 (or as other unsigned types) and cast to int24 inside the constructor, keeping the same values (60, 200, 60), argument order and public int24 getters? Or would you rather hard-code the spacings as constants and drop those three arguments?","treeHash":null,"usage":{"cachedInputTokens":320869,"inputTokens":22,"model":"claude-opus-5-5","outputTokens":5878,"runtime":"claude","turns":12,"wallClockMs":457676}},{"artifacts":[],"attempt":1,"bundleHash":"eff30b3e3899ae4c01f61a5f9ac17e2db026025bea8fa42ee0b7625bd7554303","device":"7c748c02cd2ee98f","findings":[{"description":"`fren` and `invite` refuse an identity whose `ownerOf` answers nobody (`NoSuchIdentity`), but `passCaptain(crewId, imdId)` only checks that `imdId` is a member. A member identity that has stopped existing (burned, or any identity whose `ownerOf` reverts) is still on the roll, so the captain can hand the crew to it. From then on `_captain` fails for everyone, because `LARP.canAct` is false when the holder is address(0): the crew can't be opened, closed, invited to, kicked, passed on or disbanded, and `crewByName` keeps the name taken forever (crew ids are never reused, so the name is lost to every future crew). Members can still `leave`. Whether identity.md tokens can be burned decides how reachable this is; the same stuck state also arises if the captain's own identity is burned, which no check at pass time can prevent, but the explicit hand-over to nobody is avoidable with the same `NoSuchIdentity` check `invite` already makes. Suggested fix: in `passCaptain`, `if (IDENTITY.ownerOf(imdId, gasleft()) == address(0)) revert NoSuchIdentity();`.","line":285,"path":"src/LARPLinks.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {LARP} from \"src/LARP.sol\";\nimport {ILARP} from \"src/ILARP.sol\";\nimport {IMDNames} from \"src/IMDNames.sol\";\nimport {IIMDNames} from \"src/IIMDNames.sol\";\nimport {LARPLinks} from \"src/LARPLinks.sol\";\nimport {LARPBurner} from \"src/LARPBurner.sol\";\n\n/// @dev An ERC-721 with ownerOf, mint, transfer and burn (a token that no longer exists reverts).\ncontract Identity {\n    mapping(uint256 => address) internal _owners;\n\n    function mint(address to, uint256 id) external {\n        _owners[id] = to;\n    }\n\n    function burn(uint256 id) external {\n        delete _owners[id];\n    }\n\n    function ownerOf(uint256 id) external view returns (address) {\n        require(_owners[id] != address(0), \"nonexistent\");\n        return _owners[id];\n    }\n}\n\n/// @title A crew can be handed to an identity nobody holds, and is then stuck for good\n/// @notice `invite` and `fren` refuse an identity that does not exist (`NoSuchIdentity`), but `passCaptain` only\n/// checks that the identity is a member. A member identity that stops existing (burned) can be made captain: from\n/// then on nobody passes `_captain` (canAct is false when ownerOf is zero), so the crew can't be run, opened,\n/// disbanded, left by... anyone can still leave, but the crew's name is locked forever and its captaincy can't move.\ncontract PassCaptainToNobodyTest is Test {\n    Identity identity;\n    LARP larp;\n    IMDNames names;\n    LARPLinks links;\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        identity = new Identity();\n        larp = new LARP(address(identity));\n        LARPBurner burner =\n            new LARPBurner(address(1), address(2), 10_000, 60, address(0), 10_000, 200, address(3), 0, 60, address(0));\n        names = new IMDNames(address(identity), larp, address(burner), address(4), address(5), address(6));\n        links = new LARPLinks(address(identity), address(7), larp, names, address(burner));\n        identity.mint(alice, 1);\n        identity.mint(bob, 2);\n        // a crew paid in IMD needs pools; here the burner is a stub, so write the crew in through foundCrew's\n        // storage effects: use a burner that takes ETH\n        vm.etch(address(burner), address(new EthSink()).code);\n        vm.deal(alice, 1 ether);\n        uint256 price = names.crewPrice();\n        vm.prank(alice);\n        links.foundCrew{value: price}(1, bytes32(\"frens\"), true, 0);\n        vm.prank(bob);\n        links.join(2, 1);\n    }\n\n    function test_ACaptaincyCannotGoToAnIdentityNobodyHolds() public {\n        identity.burn(2); // identity 2 no longer exists, but is still on the crew's roll\n        vm.prank(alice);\n        vm.expectRevert(LARPLinks.NoSuchIdentity.selector); // expected: refused like `invite` and `fren`\n        links.passCaptain(1, 2);\n        // actual: the call succeeds, and the crew is now run by nobody\n        (uint256 captain,,,,) = links.crew(1);\n        assertEq(captain, 1, \"the captaincy must stay with alice\");\n        vm.prank(alice);\n        links.disband(1); // alice can still end her crew\n    }\n}\n\ncontract EthSink {\n    function burn(uint256) external payable returns (uint256) {\n        return 0;\n    }\n\n    receive() external payable {}\n}","reproduction":"Alice holds identity 1 and founds crew 1 (open); Bob holds identity 2 and joins. Identity 2 is burned (ownerOf(2) reverts). Alice calls passCaptain(1, 2). Expected: revert NoSuchIdentity, captain stays 1, Alice can still disband. Actual: the call succeeds, crew(1).captain == 2, and every captain action on crew 1 (setOpen, invite, kick, passCaptain, disband) now reverts NotCaptain for everyone; the name 'frens' can never be founded again.","severity":"low","title":"passCaptain hands a crew to an identity nobody holds, locking the crew and its name for good"},{"description":"`_agentIdentity[agent]` is overwritten by every `setAgent`/`setAgentBySig` naming the same key, and never cleared on removal or resignation. An agent named for identity 4 and then for identity 5 stays the live agent of both (`canAct(4, agent)` is true), but `identityOfAgent(agent)` answers (5, true); after 5 removes it, it answers (5, false) while the agent still runs 4. The function is documented as 'the identity `agent` was last made the agent of', so this is by design and display-only (nothing in LARP, IMDNames or LARPLinks decides on it), but a front end that uses it to find an agent's identity will miss the others. Exercised by `test_SetAgentBySigEdges` and `test_AgentEdges` in test/EntryPoints.t.sol.","line":109,"path":"src/LARP.sol","reproduction":"setAgent(4, X); setAgent(5, X); identityOfAgent(X) == (5, true) and canAct(4, X) == true. Then setAgent(5, address(0)): identityOfAgent(X) == (5, false) although canAct(4, X) is still true.","severity":"info","title":"identityOfAgent reports only the last identity an agent was named for"},{"description":"A burn of a few wei (1 wei in the test) buys nothing after Uniswap v4 rounds the 1% fee up to the whole amount, so both routes fail with `Unfilled` and the ETH is parked (`Parked(1)`); `burn(minImd > 0)` then reverts `TooLittleIMD`. Nothing is lost: the dust joins the next fee's burn (`test_BurnerReceivesPlainEthFromAnyone`). Noted because a front end that sends tiny royalties and expects a non-zero `Bought` will see a park instead.","line":212,"path":"src/LARPBurner.sol","reproduction":"Send 1 wei to the burner, call burn(0): returns 0, balance stays 1 wei. Then burn{value: 0.001 ether}(0): returns > 0 and the balance is 0.","severity":"info","title":"Dust ETH under the pool fee's rounding is parked, not burned, until a larger fee joins it"}],"hash":"9b92bcc9d27e4a456a3903fd9bf7c7cbabae7d13ff9a88c436be6fe20533e3a2","nodeId":"f01a5aa4-9a8c-4a89-a30e-1a2787b306d4","outcome":"completed","summary":"Work complete. Summary:\n\n**What I delivered** (three new files under `test/`, all passing; the full offline suite is now 183 tests, 0 failures, plus the 11 fork tests that skip offline as before):\n\n- `test/EntryPoints.t.sol` (30 tests). Calls every one of the 138 listed entry points across the four contracts with assertions, and adds the adversarial edges the existing suite skipped: zero-address constructors, one-wei-over and one-wei-under prices and quotes, exact 2x and half-step guardrail boundaries, verdicts signed for another chain or with a wrong answer type, the last second of the execute window and cooldown, the full ERC-721 surface including operators and refusing receivers, 32-character labels and a label with a byte after its padding, a single-leaf Merkle tree and the largest provable allocation, a launcher that answers a dirty word, every crew refusal, tier boundaries, and a fuzz test that nothing but `execute` moves a price.\n- `test/LARPBurner.invariant.t.sol`. A handler with three wallets that fund the burner in ETH and $IMD, burn with random minimums, and trade on all three pools between calls. Invariants: ETH is either still in the burner or was sold to the PoolManager; $IMD is at DEAD, in the pair pool, or still waiting; nothing waits after a burn; IMD6900 supply only falls and the burner never holds it; every call kept its per-call rules.\n- `test/SwarmPrices.invariant.t.sol`. A handler that proposes in and out of bounds, delivers sound, weak, expired, negative and forged verdicts, fails proposals, executes, and warps time. Invariants: prices stay within the guardrails and ordered; prices equal the ghost that only a successful `execute` updates; every executed step was approved, in-epoch, within its window, at most 2x, and at least a cooldown apart; the contract keeps no $IMD.\n\n**Findings** written to `.imd-findings.json` (the harness excludes it from git on purpose):\n\n- **Low.** `passCaptain` can hand a crew to a member identity that no longer exists, since it lacks the `NoSuchIdentity` check that `invite` and `fren` make. The crew then has no captain anyone can act for, and its name is locked forever. The proof under `test/scratch/` fails on the current code.\n- **Info.** `identityOfAgent` reports only the last identity an agent was named for, by design.\n- **Info.** ETH dust below the pool fee's rounding is parked, not burned, until a larger fee joins it.\n\nNo critical, high or medium defects found. AUDIT.md's fixes hold under the new edge and invariant tests.","treeHash":"1b9e168e7004cc3d46861fa57f20dc3880bf4e2e","usage":{"cachedInputTokens":3874869,"inputTokens":770,"model":"claude-fable-5-1","outputTokens":84505,"runtime":"claude","turns":51,"wallClockMs":1427758}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"63458a1bd2b2d376","findings":[{"citation":"resolved","description":"burn(minImd) sets eth = min(balance, MAX_BURN) (line 151) and then compares the $IMD bought for that capped amount with minImd (line 163). The natspec and README present minImd as the caller's slippage bound (\"Reverts if the ETH bought less than minImd\"; \"callers can set minImd; the site should pass a quote\"), and IMDNames.register/link and LARPLinks.foundCrew forward the caller's minImd to this check. Two boundary cases break that reading. (1) Fee above MAX_BURN: only 0.1 ETH is swapped, so any minImd derived from quoteImd(fee) (even with a wide slippage allowance) can never be met and the call reverts TooLittleIMD every time; the caller must drop minImd to at most what 0.1 ETH buys, i.e. give up the guard. This is reachable through IMDNames: the swarm guardrails allow `short` up to MAX_PRICE = 1 ETH (0.0069 -> 0.0138 -> ... -> 0.22 ETH after five weekly 2x steps), and register{value: price}(label, to, quoteImd(price)*90/100) then reverts for every short name. (2) Parked ETH: when the burner already holds ETH (royalties, earlier parked fees), the swap is 0.1 ETH regardless of the caller's fee, so a minImd many times larger than the caller's fee could buy passes; the bound no longer says anything about the price the caller's own ETH got. Neither case loses funds (ETH is burned either way and the surplus waits for the next call), but the one slippage parameter the protocol exposes is unusable above the cap and meaningless below it when ETH is parked. Seam: boundary (MAX_BURN cap) x invariant (minImd bounds the caller's execution). Fix options: compare minImd against imd * fee_contribution / eth (pro-rata), or document that minImd must be quoted for min(fee, MAX_BURN) and have register/link/foundCrew quote on that basis.","line":163,"path":"src/LARPBurner.sol","reproduction":"Local PoolManager with POOL4 and the backup pool filled as in test/Base.sol (_fillPool4, _fillBackup). (1) q = burner.quoteImd(0.2 ether); burner.burn{value: 0.2 ether}(q * 90 / 100) -> reverts TooLittleIMD (expected: a 10% slippage allowance on a fair quote succeeds). burner.burn{value: 0.2 ether}(0) returns the $IMD for 0.1 ETH only (about half of q) and leaves 0.1 ETH in the burner. Through IMDNames: with prices.short = 0.2 ether (vm.store(address(names), bytes32(0), packed prices) in the test, or five weekly swarm-approved 2x steps on chain), names.register{value: 0.2 ether}(\"kek\", alice, burner.quoteImd(0.2 ether) * 90 / 100) reverts TooLittleIMD. (2) vm.deal(address(burner), 0.0931 ether); burner.burn{value: 0.0069 ether}(burner.quoteImd(0.0069 ether) * 10) succeeds and returns >= 10x the caller's quote (expected: a bound 10x above what the fee can buy fails). Test: test/scratch/MinImdCap.t.sol (three tests, all pass on the current code by asserting this behaviour).","severity":"low","snippet":"        if (imd < minImd) revert TooLittleIMD();","title":"LARPBurner.burn: minImd is checked against the whole MAX_BURN-capped swap, not the caller's fee, so a quote-based bound always reverts for a fee above 0.1 ETH and is diluted by parked ETH"}],"hash":"beb84f5bd734a8b10deb6bc84da242a71fb6226ee2765b09af026e5e5d4d4afa","nodeId":"a553d31f-2df3-43b5-8e0a-c7a5fd824283","outcome":"completed","summary":"The review is complete and written to `.imd-findings.json`. Git shows no tracked-file changes; the findings file and `test/scratch/` are ignored paths, as intended.\n\n**Result: one low finding, no critical, high or medium, in the math, boundary and numerical-gap area.** All 138 entry points have a coverage row, with 137 `holds` and 1 `finding`.\n\n**The finding (low).** `LARPBurner.burn` checks `minImd` against the $IMD bought for the whole swap, which is capped at 0.1 ETH, rather than for the caller's own fee. Two boundary cases follow, and the scratch test `test/scratch/MinImdCap.t.sol` reproduces both on the current code:\n- A fee above the cap can never satisfy a quote-based bound. Sending 0.2 ETH with `minImd` set to 90% of its quote reverts every time, because only 0.1 ETH is swapped. This reaches `IMDNames.register` once the swarm raises the short-name price past 0.1 ETH, which the guardrails allow after five weekly doublings.\n- Parked ETH dilutes the bound. With 0.0931 ETH already waiting in the burner, a 0.0069 ETH fee passes a `minImd` ten times its own quote, since the swap is 0.1 ETH regardless.\n\nNo funds are lost in either case, so it is low. The fix I suggest is a pro-rata comparison, or documenting that callers quote on the smaller of their fee and the cap.\n\n**What I verified and found holding**, with the main checks:\n- Burner: the v4 pool storage slot and Slot0 packing the spot quote reads, the two FullMath steps and their overflow headroom, the BalanceDelta split and `int128` casts for both token orderings, the exact-fill checks, the 6.9% share rounding, and the quarter-gas out-of-gas rule including the frame-depth arithmetic.\n- SwarmPrices: the 2x step and MIN/MAX bounds in uint256 with no overflow, the ordering constraint, the quorum ratio in uint16, the window and cooldown comparators at their equality edges, and the ETH decimal formatter's trailing-zero loop.\n- IMDNames: every payable path enforces an exact `msg.value`, prices can never be zero, the card's size and length arithmetic, and the royalty computation.\n- LARPLinks: the jeet formula's divisor is never zero, the paging bounds cannot underflow or overflow, the tier division is guarded, and the Merkle leaf and sorted-pair hashing match the fixture format.\n- Labels and SafeReads: suffix stripping, the 32-byte mask, and the return-data bounds checks.\n\n**Not changed:** the acknowledged items in AUDIT.md (spot-price IMD quotes, sandwich bounds, the no-op proposal residual) were checked against the code and remain as documented, so I did not re-raise them. The 11 fork tests could not run offline, so the live hook and distributor behaviours rest on the repository's own fork evidence.","treeHash":null,"usage":{"cachedInputTokens":1856624,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":46522,"runtime":"claude","turns":26,"wallClockMs":918885}},{"artifacts":[],"attempt":1,"bundleHash":"de989e1993eb0d8555fa25ab7697351b171dea16b8b9d47ee78320e51d9bccf8","device":"fc87c05048aca47d","findings":[],"hash":"e229981aa30bfa372196c1a66e936dbf4f107c17150803cf361fa9b572ab8969","nodeId":"a1aff12d-cf62-42f4-afa3-d1b7dd5307d8","outcome":"completed","summary":"Done. The project arrived already launch-ready, so no launch rule forced a change; the work was reproducing and fixing the imported audit.\n\n**What I verified first**\n- Build and the 140 offline tests passed on arrival. Constructors call nothing, the opcode scan is clean, four creations fit one transaction, all sizes are under EIP-170.\n- The brief's launch order and constructor arguments match README and `test/Launch.t.sol`. The artist is the launch owner's static address. Interfaces, constructor arguments and the 138 entry points are untouched.\n\n**Audit findings that reproduced, now fixed and tested**\n- **Nested out-of-gas (L-01 depth-1).** The supplied proof failed on the arriving code. `_tryUnlock` in `src/LARPBurner.sol` now treats a failure that leaves no more than a quarter of the gas as out-of-gas, which covers 16 frames of depth instead of one. Test: `test_ANestedSwapOutOfGasReverts`, plus the proof itself passes.\n- **No-op proposal griefing.** Proposing the current prices, approving and executing did stale a waiting approved change. `propose` now refuses an unchanged price set with `NoChange` before any payment. One existing test that relied on a no-op proposal was moved to a real change. Tests: `test_AProposalMustChangeAPrice`, `test_AnApprovedChangeCantBeStaledByANoOp`.\n- **Stranded WETH royalties.** `burn` now unwraps any WETH9 the burner holds, best effort, with no call at deployment and no new entry point. Three tests cover unwrap, the per-call cap, and a refusing WETH.\n- **Wrong selector in AUDIT.md.** Corrected to 0x8bf09c1b in AUDIT.md and the source comment, and the protocol's oracle conformance vector was added as `test/OracleConformance.t.sol`: IMDNames accepts the protocol's real signature and approves a fresh true from the vector key.\n\n**Not changed, stated in ADAPTATION.md and AUDIT.md**\n- No rotation path for the Intake, action id or signer: the brief keeps no owner and fixed interfaces, so the freeze is recorded as an accepted outcome.\n- A one-wei \"change\" can still reset the cooldown; that is inherent to one change a week with open execution, and only works while current prices still meet the guidelines.\n\n**Final state**\n\n| check | result |\n|---|---|\n| forge build --offline | clean |\n| forge test --offline | 149 passed, 0 failed, 11 fork tests skipped |\n\nChanged files: `src/LARPBurner.sol`, `src/SwarmPrices.sol`, `test/LARPBurner.t.sol`, `test/SwarmPrices.t.sol`, new `test/OracleConformance.t.sol`, `AUDIT.md`, `README.md`, new `ADAPTATION.md`. No launch.json was written, nothing was installed, and the working tree is left uncommitted for the submission step.","treeHash":"da1ed514f07eb5d865614c5d108667d8e465c3be","usage":{"cachedInputTokens":4285893,"inputTokens":1058,"model":"claude-fable-5-1","outputTokens":40960,"runtime":"claude","turns":49,"wallClockMs":1057664}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3516474d8a268bd8","findings":[{"citation":"resolved","description":"The burner's only defence against sandwiching is MAX_BURN (0.1 ETH), which AUDIT.md L-04 states is 'below POOL4's ~0.24 ETH sandwich break-even'. The cap applies per call and `burn` is permissionless with `minImd = 0` allowed, so an attacker calls `burn(0)` as many times as needed inside one transaction, between a front-run buy and a back-run sell on POOL4 (route 0 is always tried first, with no price limit: `MIN_PRICE_LIMIT`). The burner's own ETH (ERC-2981 royalties sent by markets, unwrapped WETH, `Parked` fees, and the remainder of any fee above 0.1 ETH, see finding 2) has no slippage floor at all: `minImd` only protects the caller who set it. The sandwich break-even therefore scales with everything the burner holds, not with 0.1 ETH. Economics measured on a v4 pool shaped like POOL4 (liquidity 1e21 at ~2,000 IMD/ETH, ~22 ETH of virtual depth, 1% fee): with 1 ETH of royalties parked, a 2 ETH front-run + ten `burn(0)` + back-run nets the attacker +0.1177 ETH after both 1% fees, and the $IMD burned falls from 1,897 to 1,607 (-15%). A single 0.1 ETH burn sandwiched the same way loses the attacker 0.0229 ETH, so the stated break-even only holds if 0.1 ETH is the most one transaction can push through the pool. Who loses: the protocol's burn (less $IMD and IMD6900 destroyed per fee); who profits: any searcher watching the burner's balance. Minimal fix that keeps the interface: bound the ETH spent per block, e.g. store `lastBurnBlock` and let `burn` spend ETH only when `block.number > lastBurnBlock` (or track `spentThisBlock` and cap it at MAX_BURN), so a sandwich can wrap at most 0.1 ETH; alternatively refuse `burn` of the burner's own ETH unless `imd >= minImd` with a non-zero floor derived from both pools' spot (`quoteImd`) minus the fee.","line":150,"path":"src/LARPBurner.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {MockERC20} from \"forge-std/mocks/MockERC20.sol\";\nimport {PoolManager} from \"@uniswap/v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"@uniswap/v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"@uniswap/v4-core/src/interfaces/IHooks.sol\";\nimport {PoolKey as V4PoolKey} from \"@uniswap/v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"@uniswap/v4-core/src/types/Currency.sol\";\nimport {ModifyLiquidityParams, SwapParams as V4SwapParams} from \"@uniswap/v4-core/src/types/PoolOperation.sol\";\nimport {BalanceDelta} from \"@uniswap/v4-core/src/types/BalanceDelta.sol\";\nimport {TickMath} from \"@uniswap/v4-core/src/libraries/TickMath.sol\";\n\nimport {LARPBurner} from \"src/LARPBurner.sol\";\n\ncontract ProofIMD is MockERC20 {\n    constructor() {\n        initialize(\"IMD\", \"IMD\", 18);\n    }\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\ncontract ProofIMD6900 is MockERC20 {\n    constructor() {\n        initialize(\"IMD6900\", \"IMD6900\", 18);\n    }\n\n    function burn(uint256 amount) external {\n        _burn(msg.sender, amount);\n    }\n}\n\n/// @dev Full-range liquidity for a native-ETH/ERC-20 pool, paid by the caller.\ncontract ProofAdder {\n    IPoolManager immutable pm;\n\n    constructor(IPoolManager pm_) {\n        pm = pm_;\n    }\n\n    function add(V4PoolKey memory key, int256 liquidity) external payable {\n        pm.unlock(abi.encode(key, liquidity, msg.sender));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (V4PoolKey memory key, int256 liquidity, address payer) = abi.decode(data, (V4PoolKey, int256, address));\n        (BalanceDelta delta,) = pm.modifyLiquidity(\n            key,\n            ModifyLiquidityParams(\n                TickMath.minUsableTick(key.tickSpacing), TickMath.maxUsableTick(key.tickSpacing), liquidity, 0\n            ),\n            \"\"\n        );\n        pm.settle{value: uint256(uint128(-delta.amount0()))}();\n        pm.sync(key.currency1);\n        ProofIMD(Currency.unwrap(key.currency1)).transferFrom(payer, address(pm), uint256(uint128(-delta.amount1())));\n        pm.settle();\n        if (address(this).balance > 0) payable(payer).transfer(address(this).balance);\n        return \"\";\n    }\n\n    receive() external payable {}\n}\n\n/// @dev The sandwicher: buys $IMD with ETH on POOL4, drains the burner's parked ETH through `burn(0)` calls in the\n/// same transaction, and sells the $IMD back. Everything in one `run`.\ncontract Sandwicher {\n    IPoolManager immutable pm;\n    LARPBurner immutable burner;\n    ProofIMD immutable imd;\n    V4PoolKey key;\n\n    constructor(IPoolManager pm_, LARPBurner burner_, ProofIMD imd_, V4PoolKey memory key_) {\n        pm = pm_;\n        burner = burner_;\n        imd = imd_;\n        key = key_;\n    }\n\n    /// @notice One transaction: front-run, N burns of the burner's own ETH, back-run.\n    function run(uint256 frontRun, uint256 burns) external {\n        pm.unlock(abi.encode(true, frontRun));\n        for (uint256 i; i < burns; ++i) {\n            try burner.burn(0) {} catch {}\n        }\n        uint256 held = imd.balanceOf(address(this));\n        pm.unlock(abi.encode(false, held));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        (bool ethIn, uint256 amount) = abi.decode(data, (bool, uint256));\n        BalanceDelta d = pm.swap(\n            key,\n            V4SwapParams(ethIn, -int256(amount), ethIn ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1),\n            \"\"\n        );\n        if (ethIn) {\n            pm.settle{value: amount}();\n            pm.take(key.currency1, address(this), uint256(uint128(d.amount1())));\n        } else {\n            pm.sync(key.currency1);\n            imd.transfer(address(pm), amount);\n            pm.settle();\n            pm.take(key.currency0, address(this), uint256(uint128(d.amount0())));\n        }\n        return \"\";\n    }\n\n    receive() external payable {}\n}\n\n/// @title MAX_BURN is a per-call cap: a sandwicher drains all parked ETH in one transaction at its own price\n/// @dev Fails on the current code: the attacker nets ETH from the burner's parked fees. Passes once `burn` bounds the\n/// ETH spent per block (or protects its own spend with a price floor), so that no single transaction can push more\n/// than MAX_BURN through a manipulated pool.\ncontract BatchedBurnSandwichTest is Test {\n    address constant DEAD = 0x000000000000000000000000000000000000dEaD;\n\n    ProofIMD imd;\n    ProofIMD6900 imd6900;\n    PoolManager pm;\n    ProofAdder adder;\n    V4PoolKey pool4;\n    V4PoolKey backup;\n    V4PoolKey pair;\n    LARPBurner burner;\n\n    function setUp() public {\n        imd = new ProofIMD();\n        imd6900 = new ProofIMD6900();\n        pm = new PoolManager(address(this));\n        adder = new ProofAdder(IPoolManager(address(pm)));\n        pool4 = V4PoolKey(Currency.wrap(address(0)), Currency.wrap(address(imd)), 10_000, 60, IHooks(address(0)));\n        backup = V4PoolKey(Currency.wrap(address(0)), Currency.wrap(address(imd)), 10_000, 200, IHooks(address(0)));\n        pm.initialize(pool4, TickMath.getSqrtPriceAtTick(76_020)); // ~2,000 IMD per ETH\n        pm.initialize(backup, TickMath.getSqrtPriceAtTick(76_000));\n        bool imdIs0 = address(imd) < address(imd6900);\n        pair = imdIs0\n            ? V4PoolKey(Currency.wrap(address(imd)), Currency.wrap(address(imd6900)), 0, 60, IHooks(address(0)))\n            : V4PoolKey(Currency.wrap(address(imd6900)), Currency.wrap(address(imd)), 0, 60, IHooks(address(0)));\n        pm.initialize(pair, TickMath.getSqrtPriceAtTick(imdIs0 ? int24(92_100) : int24(-92_100)));\n        burner = new LARPBurner(\n            address(pm), address(imd), 10_000, 60, address(0), 10_000, 200, address(imd6900), 0, 60, address(0)\n        );\n        imd.mint(address(this), 1e30);\n        imd.approve(address(adder), type(uint256).max);\n        vm.deal(address(this), 10_000 ether);\n        // POOL4 as the audit describes it: ~22 ETH of virtual depth (liquidity 1e21 at ~2,000 IMD per ETH).\n        adder.add{value: 1_000 ether}(pool4, 1e21);\n        // The pair pool stays empty: the 6.9% share goes to DEAD as $IMD, which keeps the accounting simple.\n    }\n\n    function test_OneTransactionDrainsAllParkedEthAtTheSandwichersPrice() public {\n        // 1 ETH of royalties (ERC-2981 pays the burner in ETH) waits in the burner, as `Parked` fees or WETH do too.\n        vm.deal(address(burner), 1 ether);\n\n        // What those royalties burn when nobody interferes: ten honest `burn(0)` calls.\n        uint256 snap = vm.snapshotState();\n        for (uint256 i; i < 10; ++i) {\n            burner.burn(0);\n        }\n        uint256 honestBurn = imd.balanceOf(DEAD);\n        vm.revertToState(snap);\n\n        Sandwicher attacker = new Sandwicher(IPoolManager(address(pm)), burner, imd, pool4);\n        vm.deal(address(attacker), 2 ether);\n        uint256 before = address(attacker).balance;\n\n        // One transaction: buy $IMD with 2 ETH, let the burner spend its whole 1 ETH at the pushed price in ten\n        // MAX_BURN-sized calls, sell the $IMD back.\n        attacker.run(2 ether, 10);\n\n        uint256 after_ = address(attacker).balance;\n        uint256 sandwichedBurn = imd.balanceOf(DEAD);\n        emit log_named_uint(\"ETH the burner spent in one tx (wei)\", 1 ether - address(burner).balance);\n        emit log_named_uint(\"IMD burned, honest (wei)\", honestBurn);\n        emit log_named_uint(\"IMD burned, sandwiched (wei)\", sandwichedBurn);\n        emit log_named_int(\"attacker net ETH (wei)\", int256(after_) - int256(before));\n\n        assertLe(after_, before, \"a sandwicher must not net ETH from the burner's parked fees in one transaction\");\n    }\n\n    receive() external payable {}\n}","reproduction":"State: POOL4 with ~22 ETH virtual depth (liquidity 1e21 at ~2,000 IMD/ETH, 1% fee), pair pool empty, 1 ETH sitting in the burner (royalties). Attacker contract, one transaction: (1) PoolManager.unlock -> swap 2 ETH -> $IMD on POOL4 (exact input, no limit); (2) LARPBurner.burn(0) ten times (each spends MAX_BURN = 0.1 ETH of the burner's balance: `test_AtMostMaxBurnPerCall` already shows consecutive calls drain it); (3) swap all $IMD back -> ETH. Expected (L-04's claim): the attacker cannot profit because at most 0.1 ETH is exposed. Actual: burner balance 0, attacker ETH 2.1177 (from 2.0), $IMD to DEAD 1,606.7 instead of 1,897.4. test/scratch/BatchedBurnSandwich.t.sol fails on this code with `2117732604643095026 > 2000000000000000000`; with the ETH spend bounded per block the same attacker loses 0.0229 ETH and it passes.","severity":"medium","snippet":"        uint256 eth = address(this).balance;\n        if (eth > MAX_BURN) eth = MAX_BURN;","title":"MAX_BURN caps ETH per call, not per transaction: anyone's burn(0) lets a sandwicher spend all parked ETH at a manipulated price in one transaction"},{"citation":"resolved","description":"`register`, `link` (src/IMDNames.sol:123) and `LARPLinks.foundCrew` (src/LARPLinks.sol:208) forward the full price to `burn{value: price}(minImd)`, but `burn` spends at most MAX_BURN = 0.1 ETH per call and parks the rest (`Parked` is only emitted when nothing was bought, so the remainder parks silently). The swarm may set any price up to MAX_PRICE = 1 ether (ten times MAX_BURN): four approved doublings take `short` from 0.0069 to 0.1104 ETH. From then on (a) `minImd` protects only the first 0.1 ETH of the payer's fee, the remainder waits for anyone's `burn(0)` with no floor (the exposure finding 1 exploits), and (b) a payer who sets `minImd = burner.quoteImd(price)`, which is what the burner's own view suggests, always reverts with TooLittleIMD because only 0.1 ETH is swapped. Interface guarantee violated: 'Reverts if the ETH bought less than minImd' reads as a bound on the fee being paid, and `quoteImd(price)` is not satisfiable for price > MAX_BURN. Minimal fix: in `burn`, spend `max(MAX_BURN, msg.value)` (the caller's own fee is always swapped whole and bounded by `minImd`; the cap only limits how much *parked* ETH joins), or document that `minImd` must be quoted on `min(price, MAX_BURN)` and have the site do so.","line":109,"path":"src/IMDNames.sol","reproduction":"State: prices.short = 0.1104 ether (four proposals of 2x each approved by the oracle signer and executed a week apart; SwarmPrices.t.sol's helpers sign such verdicts), POOL4 live. Call `names.register{value: 0.1104 ether}(bytes32(\"abc\"), alice, burner.quoteImd(0.1104 ether))`. Expected: the fee of 0.1104 ETH buys at least the quoted $IMD or reverts for a price reason. Actual: `burn` swaps 0.1 ETH only, `imd` (~199 $IMD at 2,000/ETH) < minImd (~220 $IMD) -> revert TooLittleIMD; with `minImd = 0` the call succeeds, 0.1 ETH is swapped and 0.0104 ETH stays in the burner with no slippage protection until someone's `burn(0)`.","severity":"low","snippet":"        LARPBurner(payable(BURNER)).burn{value: price}(minImd);","title":"Fees above MAX_BURN are forwarded whole but only 0.1 ETH is swapped: minImd covers a tenth of a 1 ETH fee and the rest parks unprotected"},{"citation":"resolved","description":"AUDIT.md L-07 accepts spot quotes because lowering the quote means moving the hookless pool too, '~600 ETH deep'. That depth is third-party liquidity anyone can withdraw (the trust table says so), and `_spot` only requires `liquidity != 0`: one wei of liquidity makes the backup pool's spot price free to set with a dust swap, after which the quote is governed by POOL4 alone (~22-26 ETH deep). Measured on a POOL4-shaped pool (liquidity 1e21 at ~2,000 IMD/ETH) with 1e15 liquidity in the backup pool: `quoteImd(0.0069 ether)` = 13.81 $IMD before; after a 10 ETH buy on POOL4 and a 0.01 ETH buy on the backup pool it is 6.63 $IMD; unwinding the 10 ETH on POOL4 costs 0.169 ETH in fees (99.831 ETH back of 100), the dust leg at most 0.01 ETH. Saving per short name: 7.18 $IMD ~ 0.0036 ETH, so ~50 short names registered through `registerWithImd` in the same transaction (about 9M gas) break even and every further name is bought at half price; at higher swarm prices the count falls proportionally (at `short` = 0.1 ETH, 4 names). The same quote is used by `linkWithImd` and `LARPLinks.foundCrewWithImd`. Who loses: the burn (each name burns half the $IMD it should); who profits: a bulk registrant. Minimal fix: have `_spot` return 0 (so `quoteImd` reverts NoPrice and payment falls back to ETH, which is swapped at the real price) when a pool's liquidity is below a floor that makes a half-price push cost more than MAX_PRICE worth of names, or quote from the deeper pool's price only.","line":175,"path":"src/LARPBurner.sol","reproduction":"State: POOL4 liquidity 1e21 at tick 76,020 (~2,000 IMD/ETH), backup pool liquidity 1e15 (anyone can add it; the audit's 600 ETH is not enforced). Read `burner.quoteImd(0.0069 ether)` -> 13,809,904,580,659,090,831. Attacker tx: unlock+swap 10 ETH -> $IMD on POOL4; unlock+swap 0.01 ETH -> $IMD on the backup pool; `names.registerWithImd(label_i, attacker, 7 ether)` for 50+ distinct 3-letter labels; swap the 13,732 $IMD back on POOL4. Expected: each short name burns the $IMD worth of 0.0069 ETH (~13.8 $IMD). Actual: `quoteImd(0.0069 ether)` = 6,633,122,562,986,724,701 during the transaction, each name is paid with 6.63 $IMD, and the round trip returned 99.831 of the 100 ETH (0.169 ETH cost).","severity":"low","snippet":"    function quoteImd(uint256 eth) external view returns (uint256) {\n        uint256 a = _spot(PoolKey(address(0), IMD, POOL4_FEE, POOL4_SPACING, POOL4_HOOK), eth);\n        uint256 b = _spot(PoolKey(address(0), IMD, BACKUP_FEE, BACKUP_SPACING, address(0)), eth);\n        if (a == 0 || b == 0) revert NoPrice();\n        return a > b ? a : b;","title":"quoteImd's 'higher of two spot prices' is only as safe as the hookless pool's depth, which nobody guarantees: with a thin backup pool a 0.17 ETH round trip halves the $IMD charged"}],"hash":"f139a3cfb7890ce290b315b0feb5d6c4c5eadc6eae1530113e0004be188c77c8","nodeId":"ef2f2522-c4b8-4133-81e4-1a413b0f518b","outcome":"completed","summary":"The review is complete. The findings are in `.imd-findings.json` with the proof test under `test/scratch/`, and no source or configuration file was changed (the git status is clean apart from the findings file and the scratch test).\n\n**Result: one medium and two low findings in the economics area. No critical or high.** The project's own suite passes offline (149 tests), and all 42 listed entry points plus six invariants have coverage rows: 35 hold, 7 point at a finding, none unreached.\n\n**Finding 1, medium.** The burner's 0.1 ETH cap in `burn` is per call, not per transaction, and `burn(0)` is permissionless with no price floor. AUDIT.md L-04 rests on that cap being below POOL4's sandwich break-even, but a searcher simply front-runs, calls `burn(0)` ten times, and back-runs in one transaction. Measured on a POOL4-shaped pool with 1 ETH of royalties parked:\n\n| scenario | attacker net | $IMD burned |\n|---|---|---|\n| honest ten burns | n/a | 1,897 |\n| 2 ETH front-run, ten burns, back-run | +0.118 ETH | 1,607 |\n| same sandwich on a single 0.1 ETH burn | −0.023 ETH | n/a |\n\nThe proof test fails on the current code and passes once ETH spend is bounded per block, which is the minimal fix I proposed.\n\n**Finding 2, low.** `register`, `link` and `foundCrew` forward the whole fee, but the burner swaps at most 0.1 ETH. The swarm can raise a price to 1 ETH, so above 0.1 ETH the payer's `minImd` covers only a tenth of the fee, the rest parks unprotected, and a `minImd` taken from `quoteImd(price)` always reverts.\n\n**Finding 3, low.** The $IMD quote's safety assumes the hookless pool stays about 600 ETH deep, which no code enforces. With dust liquidity there, a 10 ETH push on POOL4 costing 0.17 ETH round-trip halves the quote, so roughly 50 short names in one transaction break even. This sharpens the acknowledged L-07 rather than re-raising it.\n\n**Checked and holding** in my area: swarm price guardrails and epoch staleness, oracle callback gating, the two-way name link and toll accounting, exact v4 settlement in the callback, the transient reentrancy lock, no ETH stranded in IMDNames or LARPLinks, crew and fren counters, and the Merkle proof path. The static-analysis leads (strict equality, unused returns, reentrancy-events) were traced and none is a defect.","treeHash":null,"usage":{"cachedInputTokens":2984712,"inputTokens":802,"model":"claude-fable-5-1","outputTokens":49735,"runtime":"claude","turns":26,"wallClockMs":819148}}],"verification":[{"checks":[{"durationMs":87999,"exitCode":0,"name":"build","output":"Compiling 96 files with Solc 0.8.26\nSolc 0.8.26 finished in 87.84s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARP.sol:111:33\n    │\n111 │         if (at == 0) return (0, false);\n    │                                 ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARP.sol:120:64\n    │\n120 │         if (holder == address(0) || who == address(0)) return (false, holder);\n    │                                                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARP.sol:121:36\n    │\n121 │         if (who == holder) return (true, holder);\n    │                                    ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SafeReads.sol:21:46\n   │\n21 │         return ok && w >> 160 == 0 ? address(uint160(w)) : address(0);\n   │                                              ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SwarmPrices.sol:82:38\n   │\n82 │     bytes32 public constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n   ╭▸ src/SafeReads.sol:47:40\n   │\n47 │         (bool ok, bytes memory data) = target.staticcall{gas: gasCap}(call);\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARP.sol:265:36\n    │\n265 │         if (at == 0) return (0, 0, false);\n    │                                    ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/SwarmPrices.sol:131:33\n    │\n131 │     constructor(address intake, address oracleSigner, Prices memory start) {\n    │                                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/SwarmPrices.sol:131:17\n    │\n131 │     constructor(address intake, address oracleSigner, Prices memory start) {\n    │                 ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARPBurner.sol:243:21\n    │\n243 │             return (true, r);\n    │                     ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARPBurner.sol:246:21\n    │\n246 │             return (false, \"\");\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/LARPBurner.sol:107:9\n    │\n107 │         address pairHook\n    │         ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/LARP.sol:78:13\n   │\n78 │         if (block.timestamp > deadline) revert Expired();\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/LARP.sol:138:9\n    │\n138 │         emit AgentSet(imdId, holder, agent);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/LARPBurner.sol:101:9\n    │\n101 │         address pool4Hook,\n    │         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmPrices.sol:174:9\n    │\n174 │         emit Proposed(requestId, number, msg.sender, next);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/LARPBurner.sol:242:13\n    │\n242 │         try POOL_MANAGER.unlock(abi.encode(route, amount)) returns (bytes memory r) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/LARPBurner.sol:157:21\n    │\n157 │                     emit Bought(eth, imd, route);\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/LARPBurner.sol:161:27\n    │\n161 │             if (imd == 0) emit Parked(eth);\n    │                           ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/LARPBurner.sol:231:9\n    │\n231 │         emit Burned(rest, share, burned6900);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/LARPBurner.sol:245:55\n    │\n245 │             if (gasleft() <= gasBefore / OOG_DIVISOR) revert TooLittleGas();\n    │                                                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARP.sol:159:45\n    │\n159 │         return ok && answer.length >= 32 && bytes4(abi.decode(answer, (bytes32))) == 0x1626ba7e;\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes4' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/LARP.sol:310:15\n    │\n310 │             ++digits;\n    │               ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARP.sol:314:36\n    │\n314 │             out[--digits] = bytes1(uint8(48 + value % 10));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARP.sol:325:22\n    │\n325 │             out[i] = bytes16(\"0123456789abcdef\")[v & 15];\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes16' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:220:33\n    │\n220 │         if (at == 0) return (0, false);\n    │                                 ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:228:42\n    │\n228 │         if (owner == address(0)) return (false, address(0), 0, false);\n    │                                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:228:64\n    │\n228 │         if (owner == address(0)) return (false, address(0), 0, false);\n    │                                                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:240:33\n    │\n240 │         if (label == 0) return (false, address(0), 0, false);\n    │                                 ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:240:55\n    │\n240 │         if (label == 0) return (false, address(0), 0, false);\n    │                                                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:247:37\n    │\n247 │         if (at == 0) return (0, \"\", false);\n    │                                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:193:43\n    │\n193 │                 pair, SwapParams(imdIs0, -int256(amount), imdIs0 ? MIN_PRICE_LIMIT : MAX_PRICE_LIMIT), \"\"\n    │                                           ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:196:27\n    │\n196 │                 imdIs0 ? (int128(delta >> 128), int128(delta)) : (int128(delta), int128(delta >> 128));\n    │                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:196:49\n    │\n196 │                 imdIs0 ? (int128(delta >> 128), int128(delta)) : (int128(delta), int128(delta >> 128));\n    │                                                 ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:196:67\n    │\n196 │                 imdIs0 ? (int128(delta >> 128), int128(delta)) : (int128(delta), int128(delta >> 128));\n    │                                                                   ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:196:82\n    │\n196 │                 imdIs0 ? (int128(delta >> 128), int128(delta)) : (int128(delta), int128(delta >> 128));\n    │                                                                                  ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:197:30\n    │\n197 │             if (imdDelta != -int128(int256(amount)) || outDelta <= 0) revert Unfilled();\n    │                              ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:197:37\n    │\n197 │             if (imdDelta != -int128(int256(amount)) || outDelta <= 0) revert Unfilled();\n    │                                     ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPBurner.sol:200:13\n    │\n200 │             POOL_MANAGER.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:201:27\n    │\n201 │             uint256 out = uint128(outDelta);\n    │                           ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:209:61\n    │\n209 │         int256 d = POOL_MANAGER.swap(key, SwapParams(true, -int256(amount), MIN_PRICE_LIMIT), \"\");\n    │                                                             ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:210:27\n    │\n210 │         int128 ethDelta = int128(d >> 128);\n    │                           ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:211:25\n    │\n211 │         int128 bought = int128(d);\n    │                         ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:212:26\n    │\n212 │         if (ethDelta != -int128(int256(amount)) || bought <= 0) revert Unfilled();\n    │                          ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:212:33\n    │\n212 │         if (ethDelta != -int128(int256(amount)) || bought <= 0) revert Unfilled();\n    │                                 ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPBurner.sol:213:9\n    │\n213 │         POOL_MANAGER.settle{value: amount}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:214:47\n    │\n214 │         POOL_MANAGER.take(IMD, address(this), uint128(bought));\n    │                                               ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:215:27\n    │\n215 │         return abi.encode(uint256(uint128(bought)));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:215:35\n    │\n215 │         return abi.encode(uint256(uint128(bought)));\n    │                                   ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/LARPBurner.sol:231:34\n    │\n231 │         emit Burned(rest, share, burned6900);\n    │                                  ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMDNames.sol:67:63\n   │\n67 │     constructor(address identity, ILARP larp, address burner, address artist_, address intake, address oracleSigner)\n   │                                                               ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMDNames.sol:109:9\n    │\n109 │         LARPBurner(payable(BURNER)).burn{value: price}(minImd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMDNames.sol:123:24\n    │\n123 │         if (toll != 0) LARPBurner(payable(BURNER)).burn{value: toll}(minImd);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMDNames.sol:137:9\n    │\n137 │         emit NameRegistered(tokenId, label, to, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMDNames.sol:153:13\n    │\n153 │             emit NameUnlinked(old, imdId);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMDNames.sol:158:13\n    │\n158 │             emit NameUnlinked(tokenId, was - 1);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMDNames.sol:162:9\n    │\n162 │         emit NameLinked(tokenId, imdId, holder, toll);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMDNames.sol:185:9\n    │\n185 │         emit NameUnlinked(tokenId, imdId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMDNames.sol:181:22\n    │\n181 │         (bool ok,) = LARP.canAct(imdId, msg.sender);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmPrices.sol:187:16\n    │\n187 │             && block.timestamp <= a.expiresAt && a.answer.length == 32 && uint256(bytes32(a.answer)) == 1;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmPrices.sol:190:9\n    │\n190 │         emit Verdict(requestId, approved, a.agreed, a.panelSize);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmPrices.sol:187:83\n    │\n187 │             && block.timestamp <= a.expiresAt && a.answer.length == 32 && uint256(bytes32(a.answer)) == 1;\n    │                                                                                   ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmPrices.sol:189:23\n    │\n189 │         p.decidedAt = uint64(block.timestamp);\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMDNames.sol:306:26\n    │\n306 │     function setRenderer(address renderer_) external {\n    │                          ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMDNames.sol:314:24\n    │\n314 │     function setArtist(address artist_) external {\n    │                        ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPLinks.sol:208:9\n    │\n208 │         LARPBurner(payable(BURNER)).burn{value: msg.value}(minImd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/Labels.sol:23:16\n   │\n23 │         while (n < 32 && label[n] != 0) ++n;\n   │                ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPLinks.sol:327:22\n    │\n327 │         (bool ok,) = LARP.canAct(c.captain, msg.sender);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPLinks.sol:342:39\n    │\n342 │         address distributor = address(uint160(w));\n    │                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPLinks.sol:380:31\n    │\n380 │             j.token = address(uint160(t));\n    │                               ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPLinks.sol:443:9\n    │\n443 │         (, c.faceCollection, c.faceTokenId, c.faceLive) = LARP.faceOf(imdId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPLinks.sol:454:22\n    │\n454 │         (bool ok,) = LARP.canAct(imdId, msg.sender);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmPrices.sol:207:44\n    │\n207 │         if (p.status != Status.Approved || block.timestamp > p.decidedAt + EXECUTE_WINDOW) revert NotApproved();\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmPrices.sol:209:32\n    │\n209 │         if (lastChange != 0 && block.timestamp < lastChange + COOLDOWN) revert Cooling();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmPrices.sol:213:22\n    │\n213 │         lastChange = uint64(block.timestamp);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmPrices.sol:309:36\n    │\n309 │             digits[i - 1] = bytes1(uint8(48 + frac % 10));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/SwarmPrices.sol:325:15\n    │\n325 │             ++digits;\n    │               ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmPrices.sol:329:36\n    │\n329 │             out[--digits] = bytes1(uint8(48 + value % 10));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/EntryPoints.t.sol:923:88\n    │\n923 │         (Attestation memory a, bytes memory sig) = _attest(true, 9, 7, 9, 4663, uint64(block.timestamp + 1 days));\n    │                                                                                        ━━━━━━━━━━━━━━━\n    ‡\n952 │         vm.warp(a.expiresAt);\n    │         ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/EntryPoints.t.sol:827:30\n    │\n827 │             issuedAt: uint64(block.timestamp),\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n952 │         vm.warp(a.expiresAt);\n    │         ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/EntryPoints.t.sol:926:48\n    │\n926 │         assertEq(names.proposal(id).decidedAt, block.timestamp);\n    │                                                ━━━━━━━━━━━━━━━\n    ‡\n952 │         vm.warp(a.expiresAt);\n    │         ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/EntryPoints.t.sol:928:65\n    │\n928 │         (a, sig) = _attest(true, 9, 7, 9, block.chainid, uint64(block.timestamp + 1 days));\n    │                                                                 ━━━━━━━━━━━━━━━\n    ‡\n952 │         vm.warp(a.expiresAt);\n    │         ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/EntryPoints.t.sol:940:65\n    │\n940 │         (a, sig) = _attest(true, 9, 7, 9, block.chainid, uint64(block.timestamp + 1 days));\n    │                                                                 ━━━━━━━━━━━━━━━\n    ‡\n952 │         vm.warp(a.expiresAt);\n    │         ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/EntryPoints.t.sol:946:65\n    │\n946 │         (a, sig) = _attest(true, 9, 7, 9, block.chainid, uint64(block.timestamp + 1 days));\n    │                                                                 ━━━━━━━━━━━━━━━\n    ‡\n952 │         vm.warp(a.expiresAt);\n    │         ──────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/EntryPoints.t.sol:957:65\n    │\n957 │         (a, sig) = _attest(true, 9, 7, 9, block.chainid, uint64(block.timestamp));\n    │                                                                 ━━━━━━━━━━━━━━━\n958 │         vm.warp(block.timestamp + 1);\n    │         ──────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/EntryPoints.t.sol:827:30\n    │\n827 │             issuedAt: uint64(block.timestamp),\n    │                              ━━━━━━━━━━━━━━━\n    ‡\n958 │         vm.warp(block.timestamp + 1);\n    │         ──────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/EntryPoints.t.sol:958:17\n    │\n958 │         vm.warp(block.timestamp + 1);\n    │         ────────━━━━━━━━━━━━━━━───── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/LARPAgents.t.sol:139:28\n    │\n139 │         uint256 deadline = block.timestamp + 1 hours;\n    │                            ━━━━━━━━━━━━━━━\n140 │         bytes memory sig = _sign(ownerKey, 7, agent, owner, 0, deadline);\n141 │         vm.warp(deadline + 1);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":27598,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/MainnetFork.t.sol:MainnetForkTest\n[SKIP] test_ACrewBuysAndBurnsRealIMD() (gas: 0)\n[SKIP] test_ANameBuysRealIMDOnPool4AndBurnsIt() (gas: 0)\n[SKIP] test_ANameChangesHandsAndBurns() (gas: 0)\n[SKIP] test_ANamePaidInRealImd() (gas: 0)\n[SKIP] test_APriceProposalThroughIMDsRealIntake() (gas: 0)\n[SKIP] test_AnAgentRunsTheTreasurysIdentity() (gas: 0)\n[SKIP] test_AnIdentityWearsAWorkerFren() (gas: 0)\n[SKIP] test_RealProofsRefuseTampering() (gas: 0)\n[SKIP] test_TheHooklessPoolTakesWhatPool4Cant() (gas: 0)\n[SKIP] test_TheRealJeetBoard() (gas: 0)\n[SKIP] test_TheTreasurysCard() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 11 skipped; finished in 519.60µs (689.41µs CPU time)\n\nRan 14 tests for test/LARPAgents.t.sol:LARPAgentsTest\n[PASS] test_AContractWalletSignsWithERC1271() (gas: 431060)\n[PASS] test_ASignatureWorksOnce() (gas: 230440)\n[PASS] test_AnAgentCantNameAgentsOrTheWallet() (gas: 195871)\n[PASS] test_AnAgentDressesTheIdentityWithTheOwnersNFTs() (gas: 396334)\n[PASS] test_AnAgentLapsesOnASale() (gas: 317701)\n[PASS] test_AnAgentLinksTheOwnersNameAndSetsTexts() (gas: 977882)\n[PASS] test_AnAgentResigns() (gas: 193582)\n[PASS] test_AnAgentRunsFrensAndCrews() (gas: 1223086)\n[PASS] test_AnyAgentChangeVoidsOutstandingSignatures() (gas: 188002)\n[PASS] test_BadSignatures() (gas: 364692)\n[PASS] test_OnlyTheOwnerSetsTheAgent() (gas: 40977)\n[PASS] test_SignaturesExpire() (gas: 49228)\n[PASS] test_TheOwnerConnectsAnAgentInOneCall() (gas: 188975)\n[PASS] test_TheOwnerSignsTheAgentSends() (gas: 176447)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 7.75ms (7.56ms CPU time)\n\nRan 17 tests for test/SwarmPrices.t.sol:SwarmPricesTest\n[PASS] test_AProposalForOldPricesGoesStale() (gas: 3674220)\n[PASS] test_AProposalMustChangeAPrice() (gas: 2199983)\n[PASS] test_ARejectedProposalChangesNothing() (gas: 2232965)\n[PASS] test_AVerdictMustBeUsedWithinTwoWeeks() (gas: 2209636)\n[PASS] test_AWeakPanelIsARejection() (gas: 6238058)\n[PASS] test_AnApprovedChangeCantBeStaledByANoOp() (gas: 2279207)\n[PASS] test_AnExpiredVerdictIsARejection() (gas: 2192812)\n[PASS] test_AnyoneProposesAndTheContractWritesTheQuestion() (gas: 2851091)\n[PASS] test_ApprovedThenAnyoneExecutes() (gas: 3555871)\n[PASS] test_ExecutedOnce() (gas: 2253590)\n[PASS] test_Guardrails() (gas: 210912)\n[PASS] test_NoVerdictClosesTheProposal() (gas: 2225495)\n[PASS] test_OneChangeAWeek() (gas: 3736376)\n[PASS] test_OnlyTheIntakeDeliversAndOnlyForItsOwnProposals() (gas: 2219400)\n[PASS] test_OnlyTheOraclesSignatureForThisContractCounts() (gas: 2357817)\n[PASS] test_StartPrices() (gas: 58594)\n[PASS] test_TheOracleMustBePaid() (gas: 221190)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 8.57ms (21.47ms CPU time)\n\nRan 24 tests for test/LARPLinks.t.sol:LARPLinksTest\n[PASS] test_AGasHungryTokenCantSinkTheBoard() (gas: 1737463)\n[PASS] test_AnInnerNodeIsNotALeaf() (gas: 1448373)\n[PASS] test_AnUnreadableTokenCountsAsHeld() (gas: 1784660)\n[PASS] test_BadAllocations() (gas: 1754999)\n[PASS] test_CaptainsRun() (gas: 955418)\n[PASS] test_Card() (gas: 1629478)\n[PASS] test_CrewFoundingRules() (gas: 909037)\n[PASS] test_Disband() (gas: 1536439)\n[PASS] test_FoundACrewWithImd() (gas: 1176613)\n[PASS] test_FoundingACrewBurnsIMD() (gas: 741665)\n[PASS] test_FrenRules() (gas: 383139)\n[PASS] test_FrensPassWithTheIdentity() (gas: 302573)\n[PASS] test_FrensTakeTwo() (gas: 266329)\n[PASS] test_JeetsAreReadLive() (gas: 2364108)\n[PASS] test_JeetsInPages() (gas: 8424463)\n[PASS] test_OpenAndClosedCrews() (gas: 1681391)\n[PASS] test_PassTheCaptaincy() (gas: 940496)\n[PASS] test_ProveAnAllocation() (gas: 1534389)\n[PASS] test_RanksAcrossLaunches() (gas: 5184173)\n[PASS] test_TheCaptaincyPassesWithTheIdentity() (gas: 760414)\n[PASS] test_TheRankIsTheHoldersNow() (gas: 1748137)\n[PASS] test_Tiers() (gas: 80885)\n[PASS] test_Unfren() (gas: 271974)\n[PASS] test_WithdrawAndDeclineAsks() (gas: 244060)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 10.06ms (21.06ms CPU time)\n\nRan 3 tests for test/OracleConformance.t.sol:OracleConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 2190922)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 2253067)\n[PASS] test_callbackSelectorIsCanonical() (gas: 4107)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 14.92ms (1.36ms CPU time)\n\nRan 30 tests for test/EntryPoints.t.sol:EntryPointsTest\n[PASS] testFuzz_NothingButExecuteMovesAPrice(uint64,uint64,uint64,uint64,uint256) (runs: 256, μ: 174945, ~: 174791)\nLogs:\n  Bound result 299524275\n\n[PASS] test_AgentEdges() (gas: 501365)\n[PASS] test_ArtistEdges() (gas: 766003)\n[PASS] test_BurnImdByAStrangerBurnsEverythingHeld() (gas: 281009)\n[PASS] test_BurnRefusesAMinimumItCannotMeet() (gas: 370645)\n[PASS] test_BurnSpendsExactlyWhatItSaysAndOnlyToThePoolManager() (gas: 241052)\n[PASS] test_BurnWithNothingIsANoOp() (gas: 91264)\n[PASS] test_BurnerConstants() (gas: 98457)\n[PASS] test_BurnerReceivesPlainEthFromAnyone() (gas: 494117)\n[PASS] test_ConstructorsRefuseZeroAddresses() (gas: 10022)\n[PASS] test_CrewEdges() (gas: 2999502)\n[PASS] test_Erc721Surface() (gas: 1796311)\n[PASS] test_FoundCrewWithImdEdges() (gas: 1116710)\n[PASS] test_FrenEdges() (gas: 1021820)\n[PASS] test_JeetBoardEdges() (gas: 2653033)\n[PASS] test_LarpConstantsAndDomain() (gas: 65758)\n[PASS] test_LinkEdges() (gas: 2083290)\n[PASS] test_LinksConstants() (gas: 141471)\n[PASS] test_NamesConstants() (gas: 242424)\n[PASS] test_PlacementEdges() (gas: 1823615)\n[PASS] test_ProposeEdges() (gas: 5430652)\n[PASS] test_QuoteScalesLinearlyAndNeedsBothPools() (gas: 66567)\n[PASS] test_RegisterEdges() (gas: 1173621)\n[PASS] test_RegisterWithImdEdges() (gas: 915059)\n[PASS] test_ResolveAndPrimaryAndTextEdges() (gas: 1000957)\n[PASS] test_RoyaltyEdges() (gas: 339052)\n[PASS] test_SetAgentBySigEdges() (gas: 588218)\n[PASS] test_TierBoundaries() (gas: 171055)\n[PASS] test_UnlockCallbackRefusesEveryoneButThePoolManager() (gas: 98261)\n[PASS] test_VerdictEdges() (gas: 8284673)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 15.47ms (36.65ms CPU time)\n\nRan 28 tests for test/IMDNames.t.sol:IMDNamesTest\n[PASS] test_ABrokenRendererFallsBackToTheCard() (gas: 10710728)\n[PASS] test_AFeeParksWhenNoPoolCanTakeIt() (gas: 8868921)\n[PASS] test_ANewOwnerPaysTheTollToLink() (gas: 1022372)\n[PASS] test_ARoyaltyPaymentIsBurned() (gas: 537465)\n[PASS] test_AnyoneRegistersAnyFreeName() (gas: 614240)\n[PASS] test_BadNames() (gas: 75963)\n[PASS] test_LinkRules() (gas: 227615)\n[PASS] test_LinkTheNameToAnIdentity() (gas: 188843)\n[PASS] test_NoImdPaymentWithoutBothPools() (gas: 233452)\n[PASS] test_OneNamePerIdentityOneIdentityPerName() (gas: 929703)\n[PASS] test_Prices() (gas: 63586)\n[PASS] test_Primary() (gas: 249650)\n[PASS] test_RegisterForSomeoneElse() (gas: 605215)\n[PASS] test_RegisterWithImd() (gas: 955032)\n[PASS] test_RegisterWithImdRespectsMaxImd() (gas: 784770)\n[PASS] test_RegisteringMintsTheNameAndBurnsTheFee() (gas: 650026)\n[PASS] test_RegistrationRules() (gas: 227789)\n[PASS] test_RoyaltiesGoToTheBurner() (gas: 40917)\n[PASS] test_SellingTheIdentityTakesItDown() (gas: 170604)\n[PASS] test_SellingTheNameTakesItDown() (gas: 207919)\n[PASS] test_ShortNamesHaveShortNameTolls() (gas: 653230)\n[PASS] test_TextRecordsStartOverWithANewHolder() (gas: 217164)\n[PASS] test_TheArtistChangesTheArtAndOnlyTheArt() (gas: 409849)\n[PASS] test_TheBuiltInCard() (gas: 3442034)\n[PASS] test_TheNamesNewOwnerUnlinksAStaleLink() (gas: 235869)\n[PASS] test_TheTollFollowsEveryChangeOfHands() (gas: 214656)\n[PASS] test_TheTollInImd() (gas: 1089241)\n[PASS] test_Unlink() (gas: 207574)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 24.13ms (41.46ms CPU time)\n\nRan 14 tests for test/LARPItems.t.sol:LARPItemsTest\n[PASS] test_AFaceBecomesAnItem() (gas: 321185)\n[PASS] test_AnItemBecomesAnotherIdentitysFace() (gas: 306295)\n[PASS] test_EquipAnERC1155Copy() (gas: 195226)\n[PASS] test_EquipAnERC721() (gas: 228623)\n[PASS] test_OneCopyOnePlacement() (gas: 372050)\n[PASS] test_ReequippingTheSameCopyInTheSameSlot() (gas: 213412)\n[PASS] test_RefusedItems() (gas: 220243)\n[PASS] test_ReplacingAnItemFreesTheOldOne() (gas: 291522)\n[PASS] test_SellingACopyDarkensItsPlacementsUntilOneComesOff() (gas: 456264)\n[PASS] test_SellingTheIdentityDarkensItsItems() (gas: 360711)\n[PASS] test_SlotsAreOneToEight() (gas: 224747)\n[PASS] test_StrangersCantTakeItemsOff() (gas: 174966)\n[PASS] test_TheNewOwnerClearsTheOldItems() (gas: 343634)\n[PASS] test_ThePlacerTakesItsCopyBackAfterSellingTheIdentity() (gas: 399525)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 27.99ms (2.68ms CPU time)\n\nRan 20 tests for test/LARPBurner.t.sol:LARPBurnerTest\n[PASS] test_ANestedSwapOutOfGasReverts() (gas: 3158509)\n[PASS] test_ASwapOutOfGasReverts() (gas: 3106126)\n[PASS] test_AWethThatRefusesChangesNothing() (gas: 1089220)\n[PASS] test_AnEmptyPairPoolMeansItAllBurnsAsIMD() (gas: 816882)\n[PASS] test_AnIMD6900ThatWontBurnMeansItAllBurnsAsIMD() (gas: 779316)\n[PASS] test_AtMostMaxBurnPerCall() (gas: 2230521)\n[PASS] test_BurnImdBurnsWhatArrivesInIMD() (gas: 513332)\n[PASS] test_BuysOnPool4First() (gas: 1063211)\n[PASS] test_MinImd() (gas: 954983)\n[PASS] test_NoGasLimitSkipsARoute() (gas: 15731738)\n[PASS] test_NoQuoteWithoutBothPools() (gas: 297210)\n[PASS] test_NoReentry() (gas: 464706)\n[PASS] test_OnlyThePoolManagerCallsBack() (gas: 32791)\n[PASS] test_ParkedWhenNoPoolCanAndBurnedLater() (gas: 1348299)\n[PASS] test_QuoteIsTheHigherOfTheTwoPools() (gas: 1119381)\n[PASS] test_RoyaltiesArriveByPlainTransfer() (gas: 43927)\n[PASS] test_ShareBuysIMD6900AndBurnsIt() (gas: 841522)\n[PASS] test_TheHooklessPoolIfPool4CantTakeIt() (gas: 1175117)\n[PASS] test_WethJoinsTheEthAndTheCapHolds() (gas: 1086627)\n[PASS] test_WethRoyaltiesBurnToo() (gas: 1115908)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 28.02ms (64.77ms CPU time)\n\nRan 24 tests for test/LARP.t.sol:LARPFaceTest\n[PASS] testFuzz_OnlyTheHolderOfBothSetsAFace(address,uint256,uint256) (runs: 256, μ: 55984, ~: 56504)\nLogs:\n  Bound result 2\n  Bound result 10\n\n[PASS] test_AFaceComesBackWithBothTokens() (gas: 220934)\n[PASS] test_AMaskMovesToTheIdentityThatPutsItOn() (gas: 323750)\n[PASS] test_AvatarFormat() (gas: 249931)\n[PASS] test_ChangingMasksFreesTheOldOne() (gas: 274960)\n[PASS] test_ClearFace() (gas: 200738)\n[PASS] test_ClearingNoFaceDoesNothing() (gas: 36612)\n[PASS] test_FaceURIFallsBackOnABrokenTokenURI() (gas: 2152591)\n[PASS] test_OnlyTheIdentitysOwnerClears() (gas: 173845)\n[PASS] test_PuttingTheSameMaskOnAgain() (gas: 240094)\n[PASS] test_RefusesAMaskThatIsNotYours() (gas: 49187)\n[PASS] test_RefusesAnIdentityAsAMask() (gas: 41585)\n[PASS] test_RefusesAnIdentityThatDoesNotExist() (gas: 41653)\n[PASS] test_RefusesAnIdentityThatIsNotYours() (gas: 43653)\n[PASS] test_RefusesWhatIsNotAnNFT() (gas: 510494)\n[PASS] test_SellingTheIdentityTakesTheFaceDown() (gas: 252506)\n[PASS] test_SellingTheMaskTakesTheFaceDown() (gas: 223250)\n[PASS] test_SetFace() (gas: 266231)\n[PASS] test_SupportsInterface() (gas: 27637)\n[PASS] test_TheIdentitysNewOwnerClearsTheOldFace() (gas: 225470)\n[PASS] test_TheNewHolderOfAMaskTakesItOff() (gas: 321718)\n[PASS] test_TheNewOwnerMustChooseAgain() (gas: 327564)\n[PASS] test_WearerOfAnUnwornMask() (gas: 14020)\n[PASS] test_ZeroIdentityRefused() (gas: 4446)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 28.05ms (16.51ms CPU time)\n\nRan 4 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_DeploysOnAFreshChain() (gas: 190674)\n[PASS] test_FitsOneTransaction() (gas: 23313)\nLogs:\n  launch gas, four creations: 7030\n\n[PASS] test_PassesTheAdmissionScan() (gas: 17163361)\n[PASS] test_UnderTheCodeSizeLimit() (gas: 9813)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 31.84ms (33.34ms CPU time)\n\nRan 2 tests for test/LARPBurner.invariant.t.sol:LARPBurnerInvariantTest\n[PASS]\nLARPBurnerInvariantTest invariants:\n[PASS] invariant_EthIsHereOrSoldNeverElsewhere\n[PASS] invariant_EveryCallKeptItsRules\n[PASS] invariant_Imd6900OnlyFallsAndNeverStays\n[PASS] invariant_ImdIsHereOrBurnedOrSoldForImd6900\n[PASS] invariant_NoImdWaitsAfterABurn\n LARPBurnerInvariantTest invariants (runs: 48, calls: 1152, reverts: 0)\n\n╭---------------+-----------+-------+---------+----------╮\n| Contract      | Selector  | Calls | Reverts | Discards |\n+========================================================+\n| BurnerHandler | burn      | 192   | 0       | 0        |\n|---------------+-----------+-------+---------+----------|\n| BurnerHandler | burnImd   | 172   | 0       | 0        |\n|---------------+-----------+-------+---------+----------|\n| BurnerHandler | fund      | 197   | 0       | 0        |\n|---------------+-----------+-------+---------+----------|\n| BurnerHandler | sendImd   | 174   | 0       | 0        |\n|---------------+-----------+-------+---------+----------|\n| BurnerHandler | trade     | 213   | 0       | 0        |\n|---------------+-----------+-------+---------+----------|\n| BurnerHandler | tradePair | 204   | 0       | 0        |\n╰---------------+-----------+-------+---------+----------╯\n\nLogs:\n  Bound result 131867352280402971\n  Bound result 775763728329\n  Bound result 5318\n  Bound result 9999000000000000019409\n  Bound result 2285\n  Bound result 99999999999999999667\n  Bound result 10280\n  Bound result 9999000000003363526366\n  Bound result 3786\n  Bound result 16514242780\n  Bound result 239562861735274596795\n  Bound result 3999999999999999996\n  Bound result 9999000000003236205236\n  Bound result 6161\n  Bound result 6900000000000000000\n  Bound result 34350478800396526471918\n  Bound result 4907\n  Bound result 340000000000000\n  Bound result 911755906175039\n  Bound result 9999000000000000005001\n  Bound result 39999007000000000000001\n  Bound result 39999000000000000018589\n  Bound result 2983\n  Bound result 9999000000000000000785\n  Bound result 9999000000000000000243\n  Bound result 19999000001512832250\n  Bound result 1\n  Bound result 1533\n\n[PASS] test_HandlerDrivesEveryPath() (gas: 1510393)\nLogs:\n  Bound result 50000000000000000\n  Bound result 20000000000000000\n  Bound result 0\n  Bound result 100000000000000000000\n  Bound result 5000000000000000000\n  Bound result 10000000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 300000000000000000\n  Bound result 300000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 215.93ms (214.17ms CPU time)\n\nRan 2 tests for test/SwarmPrices.invariant.t.sol:SwarmPricesInvariantTest\n[PASS]\nSwarmPricesInvariantTest invariants:\n[PASS] invariant_EveryStepWasApprovedBoundedAndSpaced\n[PASS] invariant_OnlyAnExecutedVerdictMovesAPrice\n[PASS] invariant_PricesStayWithinTheGuardrails\n[PASS] invariant_TheContractKeepsNoImd\n SwarmPricesInvariantTest invariants (runs: 64, calls: 2560, reverts: 0)\n\n╭---------------+----------+-------+---------+----------╮\n| Contract      | Selector | Calls | Reverts | Discards |\n+=======================================================+\n| PricesHandler | deliver  | 517   | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| PricesHandler | execute  | 517   | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| PricesHandler | fail     | 560   | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| PricesHandler | propose  | 494   | 0       | 0        |\n|---------------+----------+-------+---------+----------|\n| PricesHandler | warp     | 472   | 0       | 0        |\n╰---------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 169\n  Bound result 41\n  Bound result 43\n  Bound result 187\n  Bound result 400000013860435810\n  Bound result 153902\n  Bound result 15381\n  Bound result 4440\n  Bound result 688105\n  Bound result 95\n  Bound result 204\n  Bound result 57\n  Bound result 203\n  Bound result 400000000000004718\n  Bound result 147\n  Bound result 139\n  Bound result 160\n  Bound result 87\n  Bound result 400000000000000009\n  Bound result 80\n  Bound result 98\n  Bound result 221\n  Bound result 237\n  Bound result 412298816980325935\n  Bound result 146\n  Bound result 145\n  Bound result 246\n  Bound result 125\n  Bound result 400000000000011870\n  Bound result 181\n  Bound result 65\n  Bound result 160\n  Bound result 99\n  Bound result 400000000000007581\n  Bound result 220\n  Bound result 141\n  Bound result 91\n  Bound result 133\n  Bound result 599999999999975003\n  Bound result 551783\n  Bound result 155\n  Bound result 167\n  Bound result 128\n  Bound result 84\n  Bound result 400000000000057008\n  Bound result 42\n  Bound result 197\n  Bound result 249\n  Bound result 145\n  Bound result 400000000000683593\n  Bound result 62\n  Bound result 42\n  Bound result 161\n  Bound result 68\n  Bound result 400000000931467892\n  Bound result 9968\n  Bound result 100000\n  Bound result 83\n  Bound result 209\n  Bound result 104\n  Bound result 127\n  Bound result 408000000000000002\n  Bound result 687606\n\n[PASS] test_HandlerDrivesEveryPath() (gas: 6178429)\nLogs:\n  Bound result 150\n  Bound result 150\n  Bound result 150\n  Bound result 150\n  Bound result 500000000000000000\n  Bound result 250\n  Bound result 100\n  Bound result 100\n  Bound result 100\n  Bound result 500000000000000000\n  Bound result 100\n  Bound result 100\n  Bound result 100\n  Bound result 120\n  Bound result 500000000000000000\n  Bound result 604800\n  Bound result 100\n  Bound result 100\n  Bound result 100\n  Bound result 80\n  Bound result 500000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 428.72ms (428.98ms CPU time)\n\nRan 1 test for test/LARP.invariant.t.sol:LARPInvariantTest\n[PASS]\nLARPInvariantTest invariants:\n[PASS] invariant_LiveMeansThePlacerHoldsIt\n[PASS] invariant_NoMoreLiveCopiesThanHeld\n[PASS] invariant_OneTokenOneSpot\n LARPInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+--------------+-------+---------+----------╮\n| Contract    | Selector     | Calls | Reverts | Discards |\n+=========================================================+\n| LarpHandler | equip1155    | 1164  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | equip721     | 1168  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | giveCopy     | 1187  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | giveIdentity | 1133  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | giveMask     | 1181  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | setFace      | 1171  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | takeOff      | 1188  | 0       | 0        |\n╰-------------+--------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 27.50s (27.50s CPU time)\n\nRan 14 test suites in 27.50s (28.34s CPU time): 183 tests passed, 0 failed, 11 skipped (194 total tests)\n","passed":true},{"durationMs":67,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDNames.approve(address,uint256)\",\"IMDNames.execute(bytes32)\",\"IMDNames.link(uint256,uint256,uint256)\",\"IMDNames.linkWithImd(uint256,uint256,uint256)\",\"IMDNames.lockRenderer()\",\"IMDNames.onNoVerdict(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"IMDNames.onVerdict(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"IMDNames.propose((uint64,uint64,uint64,uint64),uint256)\",\"IMDNames.register(bytes32,address,uint256)\",\"IMDNames.registerWithImd(bytes32,address,uint256)\",\"IMDNames.safeTransferFrom(address,address,uint256)\",\"IMDNames.safeTransferFrom(address,address,uint256,bytes)\",\"IMDNames.setApprovalForAll(address,bool)\",\"IMDNames.setArtist(address)\",\"IMDNames.setPrimary(uint256)\",\"IMDNames.setRenderer(address)\",\"IMDNames.setText(uint256,string,string)\",\"IMDNames.transferFrom(address,address,uint256)\",\"IMDNames.unlink(uint256)\",\"LARP.clearFace(uint256)\",\"LARP.equip(uint256,uint256,address,uint256,uint8)\",\"LARP.resignAgent(uint256)\",\"LARP.setAgent(uint256,address)\",\"LARP.setAgentBySig(uint256,address,uint256,bytes)\",\"LARP.setFace(uint256,address,uint256)\",\"LARP.unequip(uint256,uint256)\",\"LARPBurner.burn(uint256)\",\"LARPBurner.burnImd()\",\"LARPBurner.receive()\",\"LARPBurner.unlockCallback(bytes)\",\"LARPLinks.disband(uint256)\",\"LARPLinks.foundCrew(uint256,bytes32,bool,uint256)\",\"LARPLinks.foundCrewWithImd(uint256,bytes32,bool,uint256)\",\"LARPLinks.fren(uint256,uint256)\",\"LARPLinks.invite(uint256,uint256,bool)\",\"LARPLinks.join(uint256,uint256)\",\"LARPLinks.kick(uint256,uint256)\",\"LARPLinks.leave(uint256)\",\"LARPLinks.passCaptain(uint256,uint256)\",\"LARPLinks.proveAlloc(uint64,uint256,address,uint256,bytes32[])\",\"LARPLinks.setOpen(uint256,bool)\",\"LARPLinks.unfren(uint256,uint256)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":44,\"AUDIT.md\":162,\"README.md\":181,\"foundry.toml\":30,\"src/IIMDNames.sol\":112,\"src/ILARP.sol\":120,\"src/IMDNames.sol\":358,\"src/LARP.sol\":330,\"src/LARPBurner.sol\":279,\"src/LARPLinks.sol\":457,\"src/Labels.sol\":53,\"src/SafeReads.sol\":63,\"src/SwarmPrices.sol\":338,\"test/Base.sol\":292,\"test/EntryPoints.t.sol\":1423,\"test/IMDNames.t.sol\":481,\"test/LARP.invariant.t.sol\":184,\"test/LARP.t.sol\":324,\"test/LARPAgents.t.sol\":269,\"test/LARPBurner.invariant.t.sol\":285,\"test/LARPBurner.t.sol\":305,\"test/LARPItems.t.sol\":236,\"test/LARPLinks.t.sol\":515,\"test/Launch.t.sol\":134,\"test/MainnetFork.t.sol\":344,\"test/Mocks.sol\":89,\"test/OracleConformance.t.sol\":148,\"test/SwarmPrices.invariant.t.sol\":295,\"test/SwarmPrices.t.sol\":366,\"test/fixtures/allocs.json\":118},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"9b92bcc9d27e4a456a3903fd9bf7c7cbabae7d13ff9a88c436be6fe20533e3a2","verifiedTreeHash":"1b9e168e7004cc3d46861fa57f20dc3880bf4e2e","verifierVersion":"0.1.0+fb8278c5"},{"checks":[{"durationMs":60947,"exitCode":0,"name":"build","output":"Compiling 93 files with Solc 0.8.26\nSolc 0.8.26 finished in 60.78s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARP.sol:111:33\n    │\n111 │         if (at == 0) return (0, false);\n    │                                 ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARP.sol:120:64\n    │\n120 │         if (holder == address(0) || who == address(0)) return (false, holder);\n    │                                                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARP.sol:121:36\n    │\n121 │         if (who == holder) return (true, holder);\n    │                                    ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARP.sol:265:36\n    │\n265 │         if (at == 0) return (0, 0, false);\n    │                                    ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SafeReads.sol:21:46\n   │\n21 │         return ok && w >> 160 == 0 ? address(uint160(w)) : address(0);\n   │                                              ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/SwarmPrices.sol:82:38\n   │\n82 │     bytes32 public constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n   ╭▸ src/SafeReads.sol:47:40\n   │\n47 │         (bool ok, bytes memory data) = target.staticcall{gas: gasCap}(call);\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/Labels.sol:23:16\n   │\n23 │         while (n < 32 && label[n] != 0) ++n;\n   │                ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/SwarmPrices.sol:131:33\n    │\n131 │     constructor(address intake, address oracleSigner, Prices memory start) {\n    │                                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/SwarmPrices.sol:131:17\n    │\n131 │     constructor(address intake, address oracleSigner, Prices memory start) {\n    │                 ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARPBurner.sol:243:21\n    │\n243 │             return (true, r);\n    │                     ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/LARPBurner.sol:246:21\n    │\n246 │             return (false, \"\");\n    │                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:220:33\n    │\n220 │         if (at == 0) return (0, false);\n    │                                 ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:228:42\n    │\n228 │         if (owner == address(0)) return (false, address(0), 0, false);\n    │                                          ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:228:64\n    │\n228 │         if (owner == address(0)) return (false, address(0), 0, false);\n    │                                                                ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:240:33\n    │\n240 │         if (label == 0) return (false, address(0), 0, false);\n    │                                 ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:240:55\n    │\n240 │         if (label == 0) return (false, address(0), 0, false);\n    │                                                       ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n    ╭▸ src/IMDNames.sol:247:37\n    │\n247 │         if (at == 0) return (0, \"\", false);\n    │                                     ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/LARP.sol:78:13\n   │\n78 │         if (block.timestamp > deadline) revert Expired();\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/LARP.sol:138:9\n    │\n138 │         emit AgentSet(imdId, holder, agent);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/LARPBurner.sol:107:9\n    │\n107 │         address pairHook\n    │         ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/LARPBurner.sol:101:9\n    │\n101 │         address pool4Hook,\n    │         ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPLinks.sol:208:9\n    │\n208 │         LARPBurner(payable(BURNER)).burn{value: msg.value}(minImd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/IMDNames.sol:67:63\n   │\n67 │     constructor(address identity, ILARP larp, address burner, address artist_, address intake, address oracleSigner)\n   │                                                               ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmPrices.sol:174:9\n    │\n174 │         emit Proposed(requestId, number, msg.sender, next);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/LARPBurner.sol:242:13\n    │\n242 │         try POOL_MANAGER.unlock(abi.encode(route, amount)) returns (bytes memory r) {\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/LARPBurner.sol:157:21\n    │\n157 │                     emit Bought(eth, imd, route);\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/LARPBurner.sol:161:27\n    │\n161 │             if (imd == 0) emit Parked(eth);\n    │                           ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/LARPBurner.sol:231:9\n    │\n231 │         emit Burned(rest, share, burned6900);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMDNames.sol:109:9\n    │\n109 │         LARPBurner(payable(BURNER)).burn{value: price}(minImd);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/LARPBurner.sol:245:55\n    │\n245 │             if (gasleft() <= gasBefore / OOG_DIVISOR) revert TooLittleGas();\n    │                                                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMDNames.sol:123:24\n    │\n123 │         if (toll != 0) LARPBurner(payable(BURNER)).burn{value: toll}(minImd);\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARP.sol:159:45\n    │\n159 │         return ok && answer.length >= 32 && bytes4(abi.decode(answer, (bytes32))) == 0x1626ba7e;\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes4' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPLinks.sol:327:22\n    │\n327 │         (bool ok,) = LARP.canAct(c.captain, msg.sender);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMDNames.sol:137:9\n    │\n137 │         emit NameRegistered(tokenId, label, to, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMDNames.sol:153:13\n    │\n153 │             emit NameUnlinked(old, imdId);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMDNames.sol:158:13\n    │\n158 │             emit NameUnlinked(tokenId, was - 1);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPLinks.sol:342:39\n    │\n342 │         address distributor = address(uint160(w));\n    │                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMDNames.sol:162:9\n    │\n162 │         emit NameLinked(tokenId, imdId, holder, toll);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPLinks.sol:380:31\n    │\n380 │             j.token = address(uint160(t));\n    │                               ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint160' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/IMDNames.sol:185:9\n    │\n185 │         emit NameUnlinked(tokenId, imdId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/IMDNames.sol:181:22\n    │\n181 │         (bool ok,) = LARP.canAct(imdId, msg.sender);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:193:43\n    │\n193 │                 pair, SwapParams(imdIs0, -int256(amount), imdIs0 ? MIN_PRICE_LIMIT : MAX_PRICE_LIMIT), \"\"\n    │                                           ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:196:27\n    │\n196 │                 imdIs0 ? (int128(delta >> 128), int128(delta)) : (int128(delta), int128(delta >> 128));\n    │                           ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:196:49\n    │\n196 │                 imdIs0 ? (int128(delta >> 128), int128(delta)) : (int128(delta), int128(delta >> 128));\n    │                                                 ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:196:67\n    │\n196 │                 imdIs0 ? (int128(delta >> 128), int128(delta)) : (int128(delta), int128(delta >> 128));\n    │                                                                   ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:196:82\n    │\n196 │                 imdIs0 ? (int128(delta >> 128), int128(delta)) : (int128(delta), int128(delta >> 128));\n    │                                                                                  ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:197:30\n    │\n197 │             if (imdDelta != -int128(int256(amount)) || outDelta <= 0) revert Unfilled();\n    │                              ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/LARP.sol:310:15\n    │\n310 │             ++digits;\n    │               ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPLinks.sol:443:9\n    │\n443 │         (, c.faceCollection, c.faceTokenId, c.faceLive) = LARP.faceOf(imdId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPLinks.sol:454:22\n    │\n454 │         (bool ok,) = LARP.canAct(imdId, msg.sender);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARP.sol:314:36\n    │\n314 │             out[--digits] = bytes1(uint8(48 + value % 10));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:197:37\n    │\n197 │             if (imdDelta != -int128(int256(amount)) || outDelta <= 0) revert Unfilled();\n    │                                     ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPBurner.sol:200:13\n    │\n200 │             POOL_MANAGER.settle();\n    │             ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:201:27\n    │\n201 │             uint256 out = uint128(outDelta);\n    │                           ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARP.sol:325:22\n    │\n325 │             out[i] = bytes16(\"0123456789abcdef\")[v & 15];\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes16' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:209:61\n    │\n209 │         int256 d = POOL_MANAGER.swap(key, SwapParams(true, -int256(amount), MIN_PRICE_LIMIT), \"\");\n    │                                                             ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:210:27\n    │\n210 │         int128 ethDelta = int128(d >> 128);\n    │                           ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:211:25\n    │\n211 │         int128 bought = int128(d);\n    │                         ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:212:26\n    │\n212 │         if (ethDelta != -int128(int256(amount)) || bought <= 0) revert Unfilled();\n    │                          ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:212:33\n    │\n212 │         if (ethDelta != -int128(int256(amount)) || bought <= 0) revert Unfilled();\n    │                                 ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/LARPBurner.sol:213:9\n    │\n213 │         POOL_MANAGER.settle{value: amount}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:214:47\n    │\n214 │         POOL_MANAGER.take(IMD, address(this), uint128(bought));\n    │                                               ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:215:27\n    │\n215 │         return abi.encode(uint256(uint128(bought)));\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/LARPBurner.sol:215:35\n    │\n215 │         return abi.encode(uint256(uint128(bought)));\n    │                                   ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/LARPBurner.sol:231:34\n    │\n231 │         emit Burned(rest, share, burned6900);\n    │                                  ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmPrices.sol:187:16\n    │\n187 │             && block.timestamp <= a.expiresAt && a.answer.length == 32 && uint256(bytes32(a.answer)) == 1;\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/SwarmPrices.sol:190:9\n    │\n190 │         emit Verdict(requestId, approved, a.agreed, a.panelSize);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmPrices.sol:187:83\n    │\n187 │             && block.timestamp <= a.expiresAt && a.answer.length == 32 && uint256(bytes32(a.answer)) == 1;\n    │                                                                                   ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmPrices.sol:189:23\n    │\n189 │         p.decidedAt = uint64(block.timestamp);\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMDNames.sol:306:26\n    │\n306 │     function setRenderer(address renderer_) external {\n    │                          ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/IMDNames.sol:314:24\n    │\n314 │     function setArtist(address artist_) external {\n    │                        ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmPrices.sol:207:44\n    │\n207 │         if (p.status != Status.Approved || block.timestamp > p.decidedAt + EXECUTE_WINDOW) revert NotApproved();\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/SwarmPrices.sol:209:32\n    │\n209 │         if (lastChange != 0 && block.timestamp < lastChange + COOLDOWN) revert Cooling();\n    │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmPrices.sol:213:22\n    │\n213 │         lastChange = uint64(block.timestamp);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmPrices.sol:309:36\n    │\n309 │             digits[i - 1] = bytes1(uint8(48 + frac % 10));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/SwarmPrices.sol:325:15\n    │\n325 │             ++digits;\n    │               ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/SwarmPrices.sol:329:36\n    │\n329 │             out[--digits] = bytes1(uint8(48 + value % 10));\n    │                                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/LARPAgents.t.sol:139:28\n    │\n139 │         uint256 deadline = block.timestamp + 1 hours;\n    │                            ━━━━━━━━━━━━━━━\n140 │         bytes memory sig = _sign(ownerKey, 7, agent, owner, 0, deadline);\n141 │         vm.warp(deadline + 1);\n    │         ───────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":27250,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/MainnetFork.t.sol:MainnetForkTest\n[SKIP] test_ACrewBuysAndBurnsRealIMD() (gas: 0)\n[SKIP] test_ANameBuysRealIMDOnPool4AndBurnsIt() (gas: 0)\n[SKIP] test_ANameChangesHandsAndBurns() (gas: 0)\n[SKIP] test_ANamePaidInRealImd() (gas: 0)\n[SKIP] test_APriceProposalThroughIMDsRealIntake() (gas: 0)\n[SKIP] test_AnAgentRunsTheTreasurysIdentity() (gas: 0)\n[SKIP] test_AnIdentityWearsAWorkerFren() (gas: 0)\n[SKIP] test_RealProofsRefuseTampering() (gas: 0)\n[SKIP] test_TheHooklessPoolTakesWhatPool4Cant() (gas: 0)\n[SKIP] test_TheRealJeetBoard() (gas: 0)\n[SKIP] test_TheTreasurysCard() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 11 skipped; finished in 829.53µs (822.80µs CPU time)\n\nRan 3 tests for test/OracleConformance.t.sol:OracleConformanceTest\n[PASS] test_acceptsAFreshSignatureFromTheVectorKey() (gas: 2190922)\n[PASS] test_acceptsTheProtocolSignatureAsDelivered() (gas: 2253067)\n[PASS] test_callbackSelectorIsCanonical() (gas: 4107)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 5.62ms (1.61ms CPU time)\n\nRan 24 tests for test/LARP.t.sol:LARPFaceTest\n[PASS] testFuzz_OnlyTheHolderOfBothSetsAFace(address,uint256,uint256) (runs: 256, μ: 55821, ~: 56413)\nLogs:\n  Bound result 3\n  Bound result 9\n\n[PASS] test_AFaceComesBackWithBothTokens() (gas: 220934)\n[PASS] test_AMaskMovesToTheIdentityThatPutsItOn() (gas: 323750)\n[PASS] test_AvatarFormat() (gas: 249931)\n[PASS] test_ChangingMasksFreesTheOldOne() (gas: 274960)\n[PASS] test_ClearFace() (gas: 200738)\n[PASS] test_ClearingNoFaceDoesNothing() (gas: 36612)\n[PASS] test_FaceURIFallsBackOnABrokenTokenURI() (gas: 2152591)\n[PASS] test_OnlyTheIdentitysOwnerClears() (gas: 173845)\n[PASS] test_PuttingTheSameMaskOnAgain() (gas: 240094)\n[PASS] test_RefusesAMaskThatIsNotYours() (gas: 49187)\n[PASS] test_RefusesAnIdentityAsAMask() (gas: 41585)\n[PASS] test_RefusesAnIdentityThatDoesNotExist() (gas: 41653)\n[PASS] test_RefusesAnIdentityThatIsNotYours() (gas: 43653)\n[PASS] test_RefusesWhatIsNotAnNFT() (gas: 510494)\n[PASS] test_SellingTheIdentityTakesTheFaceDown() (gas: 252506)\n[PASS] test_SellingTheMaskTakesTheFaceDown() (gas: 223250)\n[PASS] test_SetFace() (gas: 266231)\n[PASS] test_SupportsInterface() (gas: 27637)\n[PASS] test_TheIdentitysNewOwnerClearsTheOldFace() (gas: 225470)\n[PASS] test_TheNewHolderOfAMaskTakesItOff() (gas: 321718)\n[PASS] test_TheNewOwnerMustChooseAgain() (gas: 327564)\n[PASS] test_WearerOfAnUnwornMask() (gas: 14020)\n[PASS] test_ZeroIdentityRefused() (gas: 4446)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 6.64ms (10.29ms CPU time)\n\nRan 24 tests for test/LARPLinks.t.sol:LARPLinksTest\n[PASS] test_AGasHungryTokenCantSinkTheBoard() (gas: 1737463)\n[PASS] test_AnInnerNodeIsNotALeaf() (gas: 1448373)\n[PASS] test_AnUnreadableTokenCountsAsHeld() (gas: 1784660)\n[PASS] test_BadAllocations() (gas: 1754999)\n[PASS] test_CaptainsRun() (gas: 955418)\n[PASS] test_Card() (gas: 1629478)\n[PASS] test_CrewFoundingRules() (gas: 909037)\n[PASS] test_Disband() (gas: 1536439)\n[PASS] test_FoundACrewWithImd() (gas: 1176613)\n[PASS] test_FoundingACrewBurnsIMD() (gas: 741665)\n[PASS] test_FrenRules() (gas: 383139)\n[PASS] test_FrensPassWithTheIdentity() (gas: 302573)\n[PASS] test_FrensTakeTwo() (gas: 266329)\n[PASS] test_JeetsAreReadLive() (gas: 2364108)\n[PASS] test_JeetsInPages() (gas: 8424463)\n[PASS] test_OpenAndClosedCrews() (gas: 1681391)\n[PASS] test_PassTheCaptaincy() (gas: 940496)\n[PASS] test_ProveAnAllocation() (gas: 1534389)\n[PASS] test_RanksAcrossLaunches() (gas: 5184173)\n[PASS] test_TheCaptaincyPassesWithTheIdentity() (gas: 760414)\n[PASS] test_TheRankIsTheHoldersNow() (gas: 1748137)\n[PASS] test_Tiers() (gas: 80885)\n[PASS] test_Unfren() (gas: 271974)\n[PASS] test_WithdrawAndDeclineAsks() (gas: 244060)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 8.41ms (21.22ms CPU time)\n\nRan 14 tests for test/LARPAgents.t.sol:LARPAgentsTest\n[PASS] test_AContractWalletSignsWithERC1271() (gas: 431060)\n[PASS] test_ASignatureWorksOnce() (gas: 230440)\n[PASS] test_AnAgentCantNameAgentsOrTheWallet() (gas: 195871)\n[PASS] test_AnAgentDressesTheIdentityWithTheOwnersNFTs() (gas: 396334)\n[PASS] test_AnAgentLapsesOnASale() (gas: 317701)\n[PASS] test_AnAgentLinksTheOwnersNameAndSetsTexts() (gas: 977882)\n[PASS] test_AnAgentResigns() (gas: 193582)\n[PASS] test_AnAgentRunsFrensAndCrews() (gas: 1223086)\n[PASS] test_AnyAgentChangeVoidsOutstandingSignatures() (gas: 188002)\n[PASS] test_BadSignatures() (gas: 364692)\n[PASS] test_OnlyTheOwnerSetsTheAgent() (gas: 40977)\n[PASS] test_SignaturesExpire() (gas: 49228)\n[PASS] test_TheOwnerConnectsAnAgentInOneCall() (gas: 188975)\n[PASS] test_TheOwnerSignsTheAgentSends() (gas: 176447)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 8.48ms (6.03ms CPU time)\n\nRan 28 tests for test/IMDNames.t.sol:IMDNamesTest\n[PASS] test_ABrokenRendererFallsBackToTheCard() (gas: 10710728)\n[PASS] test_AFeeParksWhenNoPoolCanTakeIt() (gas: 8868921)\n[PASS] test_ANewOwnerPaysTheTollToLink() (gas: 1022372)\n[PASS] test_ARoyaltyPaymentIsBurned() (gas: 537465)\n[PASS] test_AnyoneRegistersAnyFreeName() (gas: 614240)\n[PASS] test_BadNames() (gas: 75963)\n[PASS] test_LinkRules() (gas: 227615)\n[PASS] test_LinkTheNameToAnIdentity() (gas: 188843)\n[PASS] test_NoImdPaymentWithoutBothPools() (gas: 233452)\n[PASS] test_OneNamePerIdentityOneIdentityPerName() (gas: 929703)\n[PASS] test_Prices() (gas: 63586)\n[PASS] test_Primary() (gas: 249650)\n[PASS] test_RegisterForSomeoneElse() (gas: 605215)\n[PASS] test_RegisterWithImd() (gas: 955032)\n[PASS] test_RegisterWithImdRespectsMaxImd() (gas: 784770)\n[PASS] test_RegisteringMintsTheNameAndBurnsTheFee() (gas: 650026)\n[PASS] test_RegistrationRules() (gas: 227789)\n[PASS] test_RoyaltiesGoToTheBurner() (gas: 40917)\n[PASS] test_SellingTheIdentityTakesItDown() (gas: 170604)\n[PASS] test_SellingTheNameTakesItDown() (gas: 207919)\n[PASS] test_ShortNamesHaveShortNameTolls() (gas: 653230)\n[PASS] test_TextRecordsStartOverWithANewHolder() (gas: 217164)\n[PASS] test_TheArtistChangesTheArtAndOnlyTheArt() (gas: 409849)\n[PASS] test_TheBuiltInCard() (gas: 3442034)\n[PASS] test_TheNamesNewOwnerUnlinksAStaleLink() (gas: 235869)\n[PASS] test_TheTollFollowsEveryChangeOfHands() (gas: 214656)\n[PASS] test_TheTollInImd() (gas: 1089241)\n[PASS] test_Unlink() (gas: 207574)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 21.00ms (35.59ms CPU time)\n\nRan 17 tests for test/SwarmPrices.t.sol:SwarmPricesTest\n[PASS] test_AProposalForOldPricesGoesStale() (gas: 3674220)\n[PASS] test_AProposalMustChangeAPrice() (gas: 2199983)\n[PASS] test_ARejectedProposalChangesNothing() (gas: 2232965)\n[PASS] test_AVerdictMustBeUsedWithinTwoWeeks() (gas: 2209636)\n[PASS] test_AWeakPanelIsARejection() (gas: 6238058)\n[PASS] test_AnApprovedChangeCantBeStaledByANoOp() (gas: 2279207)\n[PASS] test_AnExpiredVerdictIsARejection() (gas: 2192812)\n[PASS] test_AnyoneProposesAndTheContractWritesTheQuestion() (gas: 2851091)\n[PASS] test_ApprovedThenAnyoneExecutes() (gas: 3555871)\n[PASS] test_ExecutedOnce() (gas: 2253590)\n[PASS] test_Guardrails() (gas: 210912)\n[PASS] test_NoVerdictClosesTheProposal() (gas: 2225495)\n[PASS] test_OneChangeAWeek() (gas: 3736376)\n[PASS] test_OnlyTheIntakeDeliversAndOnlyForItsOwnProposals() (gas: 2219400)\n[PASS] test_OnlyTheOraclesSignatureForThisContractCounts() (gas: 2357817)\n[PASS] test_StartPrices() (gas: 58594)\n[PASS] test_TheOracleMustBePaid() (gas: 221190)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 21.62ms (22.92ms CPU time)\n\nRan 20 tests for test/LARPBurner.t.sol:LARPBurnerTest\n[PASS] test_ANestedSwapOutOfGasReverts() (gas: 3158509)\n[PASS] test_ASwapOutOfGasReverts() (gas: 3106126)\n[PASS] test_AWethThatRefusesChangesNothing() (gas: 1089220)\n[PASS] test_AnEmptyPairPoolMeansItAllBurnsAsIMD() (gas: 816882)\n[PASS] test_AnIMD6900ThatWontBurnMeansItAllBurnsAsIMD() (gas: 779316)\n[PASS] test_AtMostMaxBurnPerCall() (gas: 2230521)\n[PASS] test_BurnImdBurnsWhatArrivesInIMD() (gas: 513332)\n[PASS] test_BuysOnPool4First() (gas: 1063211)\n[PASS] test_MinImd() (gas: 954983)\n[PASS] test_NoGasLimitSkipsARoute() (gas: 15731738)\n[PASS] test_NoQuoteWithoutBothPools() (gas: 297210)\n[PASS] test_NoReentry() (gas: 464706)\n[PASS] test_OnlyThePoolManagerCallsBack() (gas: 32791)\n[PASS] test_ParkedWhenNoPoolCanAndBurnedLater() (gas: 1348299)\n[PASS] test_QuoteIsTheHigherOfTheTwoPools() (gas: 1119381)\n[PASS] test_RoyaltiesArriveByPlainTransfer() (gas: 43927)\n[PASS] test_ShareBuysIMD6900AndBurnsIt() (gas: 841522)\n[PASS] test_TheHooklessPoolIfPool4CantTakeIt() (gas: 1175117)\n[PASS] test_WethJoinsTheEthAndTheCapHolds() (gas: 1086627)\n[PASS] test_WethRoyaltiesBurnToo() (gas: 1115908)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 21.64ms (58.48ms CPU time)\n\nRan 14 tests for test/LARPItems.t.sol:LARPItemsTest\n[PASS] test_AFaceBecomesAnItem() (gas: 321185)\n[PASS] test_AnItemBecomesAnotherIdentitysFace() (gas: 306295)\n[PASS] test_EquipAnERC1155Copy() (gas: 195226)\n[PASS] test_EquipAnERC721() (gas: 228623)\n[PASS] test_OneCopyOnePlacement() (gas: 372050)\n[PASS] test_ReequippingTheSameCopyInTheSameSlot() (gas: 213412)\n[PASS] test_RefusedItems() (gas: 220243)\n[PASS] test_ReplacingAnItemFreesTheOldOne() (gas: 291522)\n[PASS] test_SellingACopyDarkensItsPlacementsUntilOneComesOff() (gas: 456264)\n[PASS] test_SellingTheIdentityDarkensItsItems() (gas: 360711)\n[PASS] test_SlotsAreOneToEight() (gas: 224747)\n[PASS] test_StrangersCantTakeItemsOff() (gas: 174966)\n[PASS] test_TheNewOwnerClearsTheOldItems() (gas: 343634)\n[PASS] test_ThePlacerTakesItsCopyBackAfterSellingTheIdentity() (gas: 399525)\nSuite result: ok. 14 passed; 0 failed; 0 skipped; finished in 21.77ms (3.92ms CPU time)\n\nRan 4 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_DeploysOnAFreshChain() (gas: 190674)\n[PASS] test_FitsOneTransaction() (gas: 23313)\nLogs:\n  launch gas, four creations: 7030\n\n[PASS] test_PassesTheAdmissionScan() (gas: 17163361)\n[PASS] test_UnderTheCodeSizeLimit() (gas: 9813)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 28.55ms (29.25ms CPU time)\n\nRan 1 test for test/LARP.invariant.t.sol:LARPInvariantTest\n[PASS]\nLARPInvariantTest invariants:\n[PASS] invariant_LiveMeansThePlacerHoldsIt\n[PASS] invariant_NoMoreLiveCopiesThanHeld\n[PASS] invariant_OneTokenOneSpot\n LARPInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+--------------+-------+---------+----------╮\n| Contract    | Selector     | Calls | Reverts | Discards |\n+=========================================================+\n| LarpHandler | equip1155    | 1148  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | equip721     | 1173  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | giveCopy     | 1172  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | giveIdentity | 1175  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | giveMask     | 1188  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | setFace      | 1173  | 0       | 0        |\n|-------------+--------------+-------+---------+----------|\n| LarpHandler | takeOff      | 1163  | 0       | 0        |\n╰-------------+--------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 27.14s (27.14s CPU time)\n\nRan 11 test suites in 27.14s (27.28s CPU time): 149 tests passed, 0 failed, 11 skipped (160 total tests)\n","passed":true},{"durationMs":67,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDNames.approve(address,uint256)\",\"IMDNames.execute(bytes32)\",\"IMDNames.link(uint256,uint256,uint256)\",\"IMDNames.linkWithImd(uint256,uint256,uint256)\",\"IMDNames.lockRenderer()\",\"IMDNames.onNoVerdict(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"IMDNames.onVerdict(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"IMDNames.propose((uint64,uint64,uint64,uint64),uint256)\",\"IMDNames.register(bytes32,address,uint256)\",\"IMDNames.registerWithImd(bytes32,address,uint256)\",\"IMDNames.safeTransferFrom(address,address,uint256)\",\"IMDNames.safeTransferFrom(address,address,uint256,bytes)\",\"IMDNames.setApprovalForAll(address,bool)\",\"IMDNames.setArtist(address)\",\"IMDNames.setPrimary(uint256)\",\"IMDNames.setRenderer(address)\",\"IMDNames.setText(uint256,string,string)\",\"IMDNames.transferFrom(address,address,uint256)\",\"IMDNames.unlink(uint256)\",\"LARP.clearFace(uint256)\",\"LARP.equip(uint256,uint256,address,uint256,uint8)\",\"LARP.resignAgent(uint256)\",\"LARP.setAgent(uint256,address)\",\"LARP.setAgentBySig(uint256,address,uint256,bytes)\",\"LARP.setFace(uint256,address,uint256)\",\"LARP.unequip(uint256,uint256)\",\"LARPBurner.burn(uint256)\",\"LARPBurner.burnImd()\",\"LARPBurner.receive()\",\"LARPBurner.unlockCallback(bytes)\",\"LARPLinks.disband(uint256)\",\"LARPLinks.foundCrew(uint256,bytes32,bool,uint256)\",\"LARPLinks.foundCrewWithImd(uint256,bytes32,bool,uint256)\",\"LARPLinks.fren(uint256,uint256)\",\"LARPLinks.invite(uint256,uint256,bool)\",\"LARPLinks.join(uint256,uint256)\",\"LARPLinks.kick(uint256,uint256)\",\"LARPLinks.leave(uint256)\",\"LARPLinks.passCaptain(uint256,uint256)\",\"LARPLinks.proveAlloc(uint64,uint256,address,uint256,bytes32[])\",\"LARPLinks.setOpen(uint256,bool)\",\"LARPLinks.unfren(uint256,uint256)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":44,\"AUDIT.md\":162,\"README.md\":181,\"foundry.toml\":30,\"src/IIMDNames.sol\":112,\"src/ILARP.sol\":120,\"src/IMDNames.sol\":358,\"src/LARP.sol\":330,\"src/LARPBurner.sol\":279,\"src/LARPLinks.sol\":457,\"src/Labels.sol\":53,\"src/SafeReads.sol\":63,\"src/SwarmPrices.sol\":338,\"test/Base.sol\":292,\"test/IMDNames.t.sol\":481,\"test/LARP.invariant.t.sol\":184,\"test/LARP.t.sol\":324,\"test/LARPAgents.t.sol\":269,\"test/LARPBurner.t.sol\":305,\"test/LARPItems.t.sol\":236,\"test/LARPLinks.t.sol\":515,\"test/Launch.t.sol\":134,\"test/MainnetFork.t.sol\":344,\"test/Mocks.sol\":89,\"test/OracleConformance.t.sol\":148,\"test/SwarmPrices.t.sol\":366,\"test/fixtures/allocs.json\":118},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":4809,"exitCode":0,"name":"slither","output":"[medium/high] incorrect-equality at src/LARPBurner.sol:148: LARPBurner.burn(uint256) (src/LARPBurner.sol#148-165) uses a dangerous strict equality:\n[medium/medium] uninitialized-local at src/SwarmPrices.sol:323: SwarmPrices._decimal(uint256).digits (src/SwarmPrices.sol#323) is a local variable never initialized\n[medium/medium] uninitialized-local at src/LARP.sol:308: LARP._decimal(uint256).digits (src/LARP.sol#308) is a local variable never initialized\n[medium/medium] uninitialized-local at src/LARPBurner.sol:223: LARPBurner._burnImd().burned6900 (src/LARPBurner.sol#223) is a local variable never initialized\n[medium/medium] unused-return at src/IMDNames.sol:105: IMDNames.register(bytes32,address,uint256) (src/IMDNames.sol#105-110) ignores return value by LARPBurner(address(BURNER)).burn{value: price}(minImd) (src/IMDNames.sol#109)\n[medium/medium] unused-return at src/IMDNames.sol:120: IMDNames.link(uint256,uint256,uint256) (src/IMDNames.sol#120-124) ignores return value by LARPBurner(address(BURNER)).burn{value: toll}(minImd) (src/IMDNames.sol#123)\n[medium/medium] unused-return at src/LARPLinks.sol:453: LARPLinks._own(uint256) (src/LARPLinks.sol#453-456) ignores return value by (ok,None) = LARP.canAct(imdId,msg.sender) (src/LARPLinks.sol#454)\n[medium/medium] unused-return at src/LARPLinks.sol:324: LARPLinks._captain(uint256) (src/LARPLinks.sol#324-329) ignores return value by (ok,None) = LARP.canAct(c.captain,msg.sender) (src/LARPLinks.sol#327)\n[medium/medium] unused-return at src/LARPLinks.sol:201: LARPLinks.foundCrew(uint256,bytes32,bool,uint256) (src/LARPLinks.sol#201-209) ignores return value by LARPBurner(address(BURNER)).burn{value: msg.value}(minImd) (src/LARPLinks.sol#208)\n[medium/medium] unused-return at src/LARPBurner.sol:184: LARPBurner.unlockCallback(bytes) (src/LARPBurner.sol#184-216) ignores return value by POOL_MANAGER.settle() (src/LARPBurner.sol#200)\n[medium/medium] unused-return at src/LARPBurner.sol:184: LARPBurner.unlockCallback(bytes) (src/LARPBurner.sol#184-216) ignores return value by POOL_MANAGER.settle{value: amount}() (src/LARPBurner.sol#213)\n[medium/medium] unused-return at src/IMDNames.sol:178: IMDNames.unlink(uint256) (src/IMDNames.sol#178-186) ignores return value by (ok,None) = LARP.canAct(imdId,msg.sender) (src/IMDNames.sol#181)\n[medium/medium] unused-return at src/LARPLinks.sol:439: LARPLinks.cardOf(uint256) (src/LARPLinks.sol#439-450) ignores return value by (None,c.faceCollection,c.faceTokenId,c.faceLive) = LARP.faceOf(imdId) (src/LARPLinks.sol#443)\n[low/medium] missing-zero-check at src/IMDNames.sol:306: IMDNames.setRenderer(address).renderer_ (src/IMDNames.sol#306) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMDNames.sol:67: IMDNames.constructor(address,ILARP,address,address,address,address).artist_ (src/IMDNames.sol#67) lacks a zero-check on :\n[low/medium] missing-zero-check at src/LARPBurner.sol:107: LARPBurner.constructor(address,address,uint24,int24,address,uint24,int24,address,uint24,int24,address).pairHook (src/LARPBurner.sol#107) lacks a zero-check on :\n[low/medium] missing-zero-check at src/IMDNames.sol:314: IMDNames.setArtist(address).artist_ (src/IMDNames.sol#314) lacks a zero-check on :\n[low/medium] missing-zero-check at src/LARPBurner.sol:101: LARPBurner.constructor(address,address,uint24,int24,address,uint24,int24,address,uint24,int24,address).pool4Hook (src/LARPBurner.sol#101) lacks a zero-check on :\n[low/medium] calls-loop at src/LARPBurner.sol:240: LARPBurner._tryUnlock(uint8,uint256) (src/LARPBurner.sol#240-248) has external calls inside a loop: r = POOL_MANAGER.unlock(abi.encode(route,amount)) (src/LARPBurner.sol#242-247)\n[low/medium] reentrancy-benign at src/SwarmPrices.sol:148: Reentrancy in SwarmPrices.propose(SwarmPrices.Prices,uint256) (src/SwarmPrices.sol#148-175):\n[low/medium] reentrancy-events at src/LARPBurner.sol:148: Reentrancy in LARPBurner.burn(uint256) (src/LARPBurner.sol#148-165):\n[low/medium] reentrancy-events at src/LARPBurner.sol:219: Reentrancy in LARPBurner._burnImd() (src/LARPBurner.sol#219-232):\n[low/medium] reentrancy-events at src/LARPBurner.sol:148: Reentrancy in LARPBurner.burn(uint256) (src/LARPBurner.sol#148-165):\n[low/medium] reentrancy-events at src/SwarmPrices.sol:148: Reentrancy in SwarmPrices.propose(SwarmPrices.Prices,uint256) (src/SwarmPrices.sol#148-175):\n[low/medium] timestamp at src/SwarmPrices.sol:180: SwarmPrices.onVerdict(bytes32,Attestation,bytes) (src/SwarmPrices.sol#180-191) uses timestamp for comparisons\n[low/medium] timestamp at src/SwarmPrices.sol:205: SwarmPrices.execute(bytes32) (src/SwarmPrices.sol#205-215) uses timestamp for comparisons\n[low/medium] timestamp at src/LARP.sol:77: LARP.setAgentBySig(uint256,address,uint256,bytes) (src/LARP.sol#77-91) uses timestamp for comparisons","passed":true},{"durationMs":498,"exitCode":0,"name":"aderyn","output":"[high] contract-locks-ether at src/IMDNames.sol:21: Contract locks Ether without a withdraw function (3 places)\n[high] reentrancy-state-change at src/IMDNames.sol:181: Reentrancy: State change after external call (3 places)\n[low] ecrecover at src/LARP.sol:153: `ecrecover` Signature Malleability (2 places)\n[low] internal-function-used-once at src/Labels.sol:9: Internal Function Used Only Once (2 places)\n[low] large-numeric-literal at src/IMDNames.sol:34: Large Numeric Literal (5 places)\n[low] literal-instead-of-constant at src/IMDNames.sol:68: Literal Instead of Constant (56 places)\n[low] missing-inheritance at src/LARPBurner.sol:44: Missing Inheritance\n[low] push-zero-opcode at src/IIMDNames.sol:2: PUSH0 Opcode (9 places)\n[low] require-revert-in-loop at src/LARPBurner.sol:153: Loop Contains `require`/`revert`\n[low] state-no-address-check at src/IMDNames.sol:74: Address State Variable Set Without Checks (3 places)\n[low] unchecked-return at src/LARPBurner.sol:200: Unchecked Return\n[low] uninitialized-local-variable at src/LARPBurner.sol:153: Uninitialized Local Variable (5 places)\n[low] unspecific-solidity-pragma at src/IIMDNames.sol:2: Unspecific Solidity Pragma (7 places)\n[low] unused-public-function at src/IMDNames.sol:98: Public Function Not Used Internally","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"e229981aa30bfa372196c1a66e936dbf4f107c17150803cf361fa9b572ab8969","verifiedTreeHash":"da1ed514f07eb5d865614c5d108667d8e465c3be","verifierVersion":"0.1.0+fb8278c5"}]}