{"assessments":[],"deployments":[{"attestationHash":"03cf67e31cb79dddd51b2707e676e3d6c211ebf1a2717eab75bed2542547b664","chainId":11155111,"contracts":[{"address":"0xc2b91847e5316a7caf77d152af69908d058b0aed","blockNumber":11920753,"name":"OGClubBox","role":"other","txHash":"0x6c43078460a32cc3e989b2970a67f85eedc732f085656063334a07e37d55f554"},{"address":"0x200492a563816fb7974caec52a3e53f1e1bbc329","blockNumber":11920753,"name":"OGClubFurniture","role":"other","txHash":"0x6c43078460a32cc3e989b2970a67f85eedc732f085656063334a07e37d55f554"},{"address":"0xc4e3aa89c0958b836edc4ff10d815e55dd91a233","blockNumber":11920753,"name":"MockOG","role":"other","txHash":"0x6c43078460a32cc3e989b2970a67f85eedc732f085656063334a07e37d55f554"}],"id":"29f56906-f148-473f-9ed1-21867c720f2f","manifestHash":"76f50e0b9cd9d116b7726e8db75cb9994a5b7d97b28377d11b98fcdaca9dd81b","status":"live"}],"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":"49fb5781-4e08-452d-9832-629463434e9a","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"d91947614345584afa225d6710be28e4b558b50ef086515ce8e461c2e7f3648f","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":"3b6570fd9ab2704faf16c5da0bbb1467657828081063f7a0c939e73d39aa15cc","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":"52c17265dde86d0b33acd6c57cfd94d53f0b41ad8695c099a15746a454e5380d","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":"83c1b88aa7cb9f89ff1b2e879bd8f819c41fff7f3dad3c9b4c65fd2b1e9b1caa","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":"a3a20f68dd4af2c62ef93faa873857245cd848c2ee23716acd432d248316da7e","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":"accepted"},{"acceptedSubmissionHash":"db2535cf4d2287d678107c0c4ad697c9149a695c91c13491a8327c2956623db8","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":"3042dee5496dbd91f541d22f68d762bcf2bfbef51eb95ca5cfcb416f3caa93e0","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":"38f9786f514a1d4bc6795f599cd7a6524f91878cac9bf6d815437856a5beebe4","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"5b4518e00745c4e1db5708317b0ced4818530f134cd385b66f1df07ad83fb809","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Continue from the delivered OG Club lootbox repo (OGClubBox, OGClubFurniture; 89 tests pass at cef6e9514a19241cee4c098c8709ea6f72c7d00b). Make the two changes below and keep every other behavior and guarantee exactly as it is. Update the affected tests and the README; forge build, forge test and forge fmt --check must pass. Do not deploy.\n \n## 1. Delay before a new minter can mint (OGClubFurniture)\nToday the owner can authorize any address with setMinter and mint any piece without limit, bypassing the box's odds and caps. Replace setMinter with:\n- grantMinter(address): owner only. While nothing has ever been minted (totalSupply() == 0) it takes effect immediately and emits MinterSet(minter, true), so a fresh deployment can authorize its box and the full minter list can always be rebuilt from events. Otherwise it only records activatesAt = block.timestamp + MINTER_DELAY (constant, 7 days) and emits MinterProposed(minter, activatesAt).\n- activateMinter(address): anyone, once activatesAt has passed; sets minters[minter] = true; emits MinterSet(minter, true).\n- cancelMinter(address): owner; drops a pending proposal; emits MinterProposalCancelled(minter).\n- revokeMinter(address): owner; immediate; also clears any pending proposal; emits MinterSet(minter, false).\n- Keep the public minters(address) view (the box's buy check uses it); add a view for pending activation times.\n \n## 2. Record the roll at open, deliver separately (OGClubBox)\nToday, if minting fails (the box's minter role is revoked, or the buyer is a contract that rejects ERC-1155), open reverts, and once the 256-block window passes the paid roll can only become the fallback. Make the roll independent of delivery:\n- open(purchaseId, header): same checks, randomness, picks, caps and BoxOpened events as now. Mark opened and count minted (caps reserve the pieces) before any external call. Then call furniture.mintBatch(buyer, ids, amounts) inside try/catch. On success mark the purchase delivered and emit Delivered(purchaseId, buyer). On failure store the purchase's rolled itemIds and emit DeliveryFailed(purchaseId); open itself must not revert because of delivery.\n- deliver(purchaseId): anyone; mints an opened, undelivered purchase's stored items to its buyer.\n- deliverTo(purchaseId, to): buyer only, to nonzero; mints the stored items to `to` (lets a contract buyer receive at another address).\n- deliver and deliverTo: nonReentrant; mark delivered before minting; revert if not opened, already delivered or nothing is stored. A purchase is delivered at most once.\n- Store itemIds only on the failure path; the normal path adds no storage. Add views for delivered status and stored items.\n- Expiry is unchanged: a purchase nobody opens within 256 blocks of its target still becomes fallbacks. Once opened, a roll is never lost.\n \n## Tests (add these; update existing tests whose expectations change)\n- Furniture: before any mint grantMinter is immediate; after the first mint a granted minter cannot mint for 7 days and can after activateMinter; cancelMinter stops a proposal; revokeMinter is immediate and clears proposals; only the owner grants, cancels and revokes; anyone may activate after the delay.\n- The owner cannot mint a capped piece past its cap within 7 days of proposing a new minter.\n- Box minter revoked, then the reveal window passes: open still records the honest roll (equal to previewOpen just before opening); after the minter is restored, deliver mints exactly those items, not fallbacks.\n- A contract buyer without ERC-1155 receiver support: open succeeds with DeliveryFailed; deliver keeps failing; deliverTo an EOA by the buyer succeeds; deliverTo by anyone else reverts.\n- A receiver that rejects only its first delivery: a later deliver succeeds; delivering twice reverts.\n- Caps count undelivered rolls: a stored, undelivered piece still blocks later picks beyond its cap.\n- Invariants: minted per item == supply delivered + stored undelivered items; each purchase delivered at most once; the box's token balance stays 0.\n \n## README\nUpdate the open and delivery flow, the owner powers (once anything exists a new minter waits 7 days; revoking the box only delays delivery and never changes a recorded roll), and the post-deploy steps (grantMinter(box) right after deployment, before any mint).","parentJobId":null,"planHash":"48bba2c8766cd36de61746a73682ac87575a9f8ebfc63557db119353c5aaf7f9","previousHash":"21e09b81f83e1833bb90b466f0887d6180249314e55dc30d5dbdda0402eb45f6","projectId":"49fb5781-4e08-452d-9832-629463434e9a","publication":{"commit":"3cf22eb2e28a40bc21bfe7f3becdb632c4a088a1","deliveredAt":"2026-10-15T13:32:56.290Z","repoUrl":"https://github.com/identity-md-launches/launch-1847-continue-delivered-og-club"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"93ea21a2ef37fc19a83cf9a2955584400efb12300597e9549403bb45fa4684a9","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"13603a08ada71730","findings":[],"hash":"298a04b2ae605f1f0eb9b7116f896f4d4bf841ce72ecc2668ebaa71411451d27","nodeId":"bc4b80f7-86d0-4bbb-9d54-7de5006d6464","outcome":"failed","summary":"Failed to authenticate: OAuth session expired and could not be refreshed","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":null,"outputTokens":0,"runtime":"claude","turns":1,"wallClockMs":3317}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ddcecd7483f623f7","findings":[{"citation":"resolved","description":"open() computes the gas it forwards to furniture.mintBatch as min(1,000,000, gasleft() - 300,000) and swallows the mint's failure in catch. Whether a healthy delivery (EOA buyer, box authorized, receiver fine) succeeds therefore depends only on how much gas the opener attached, and the catch path (store up to ten IDs) is by construction cheaper than the mint and always fits whenever the reserve is left. Two consequences. (1) Ordinary callers: eth_estimateGas searches for the lowest gas at which the transaction does not revert; because the inner out-of-gas is caught, that lowest value is the DeliveryFailed path. Measured on this tree: a successful 1-box open uses 221,684 gas, but any limit from 1.0x up to 2.1x that value succeeds with DeliveryFailed; delivery only starts at 487,704 (2.19x). For 10 boxes a successful open uses 454,838; 1.0x reverts, 1.5x succeeds with DeliveryFailed, delivery starts at 727,740 (1.59x). A wallet that sends the estimate plus the usual 10-50% buffer never delivers a single box and usually does not deliver a ten-pack; the buyer then needs a second transaction (deliver) and open has written the 10-slot stored-items array that the brief says the normal path must never add. (2) Asymmetry/access: open is permissionless, so any third party can choose the buyer's path by attaching ~1.0-2.0x gas: the purchase is marked opened and caps are reserved (correct), but the buyer is left undelivered and must pay for deliver. No funds are lost and the roll is honest, but the guarantees 'on success mark delivered' and 'the normal path adds no storage' are broken under default tooling, and the README's 'supply enough transaction gas' gives no number because the required amount is 1.6-2.2x what estimation reports. Fix that preserves the design: revert at the top of open when gasleft() is below a published minimum (e.g. OPEN_MINT_GAS_LIMIT + DELIVERY_RESERVE_GAS plus the roll's own cost, with a dedicated error such as InsufficientGas). The check runs before any state change and is a caller-side precondition, not a delivery failure, so 'open must not revert because of delivery' still holds; estimation then lands above the threshold and the mint always receives the full OPEN_MINT_GAS_LIMIT. Document the minimum in the README.","line":250,"path":"src/OGClubBox.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {OGClubBox} from \"src/OGClubBox.sol\";\nimport {OGClubFurniture} from \"src/OGClubFurniture.sol\";\nimport {MockOG} from \"src/mocks/MockOG.sol\";\n\n/// @dev Minimal RLP header builder: 16 fields, field 8 = number, field 13 = mixHash.\nlibrary MiniHeader {\n    function rlpBytes(bytes memory s) internal pure returns (bytes memory) {\n        if (s.length == 1 && uint8(s[0]) < 0x80) return s;\n        return bytes.concat(prefix(s.length, 0x80), s);\n    }\n\n    function prefix(uint256 len, uint8 base) internal pure returns (bytes memory) {\n        if (len < 56) return abi.encodePacked(uint8(base + len));\n        bytes memory lenBytes = uintBytes(len);\n        return bytes.concat(abi.encodePacked(uint8(base + 55 + lenBytes.length)), lenBytes);\n    }\n\n    function uintBytes(uint256 v) internal pure returns (bytes memory out) {\n        if (v == 0) return out;\n        uint256 n;\n        for (uint256 t = v; t != 0; t >>= 8) ++n;\n        out = new bytes(n);\n        for (uint256 i; i < n; ++i) {\n            out[n - 1 - i] = bytes1(uint8(v >> (8 * i)));\n        }\n    }\n\n    function header(uint256 number, bytes32 mixHash) internal pure returns (bytes memory) {\n        bytes memory payload;\n        for (uint256 i; i < 16; ++i) {\n            bytes memory field;\n            if (i == 8) field = uintBytes(number);\n            else if (i == 13) field = abi.encodePacked(mixHash);\n            else if (i == 2) field = abi.encodePacked(address(0xBEEF));\n            else if (i == 0 || i == 1 || i == 3 || i == 4 || i == 5) field = abi.encodePacked(bytes32(uint256(i + 1)));\n            else if (i == 6) field = new bytes(256);\n            else field = uintBytes(i + 1);\n            payload = bytes.concat(payload, rlpBytes(field));\n        }\n        return bytes.concat(prefix(payload.length, 0xc0), payload);\n    }\n}\n\n/// @notice An EOA buyer whose box is an authorized minter must either be delivered at open or see open revert.\n///         Today a caller that supplies 1.5x the gas a successful open consumes gets DeliveryFailed instead,\n///         because the mint is starved of gas inside try/catch while the catch path still fits.\ncontract OpenGasDeliveryTest is Test {\n    MockOG internal token;\n    OGClubFurniture internal furniture;\n    OGClubBox internal box;\n    address internal buyer = makeAddr(\"buyer\");\n    uint256 internal seasonId;\n\n    function setUp() public {\n        vm.roll(100);\n        vm.warp(1000);\n        token = new MockOG(address(this));\n        furniture = new OGClubFurniture(address(this), address(this));\n        box = new OGClubBox(token, furniture, makeAddr(\"vault\"), address(this));\n        furniture.grantMinter(address(box));\n        token.mint(buyer, 1_000_000 ether);\n        vm.prank(buyer);\n        token.approve(address(box), type(uint256).max);\n        OGClubBox.Entry[] memory entries = new OGClubBox.Entry[](3);\n        entries[0] = OGClubBox.Entry(1, 0, 60, 0);\n        entries[1] = OGClubBox.Entry(2, 1, 30, 4);\n        entries[2] = OGClubBox.Entry(3, 2, 10, 3);\n        seasonId = box.createSeason(101, 1000, 100_000, 3333, 1, entries);\n    }\n\n    function _ready(uint256 purchaseId, bytes32 randao) internal returns (bytes memory header) {\n        (,,, uint256 targetBlock,) = box.purchases(purchaseId);\n        vm.roll(targetBlock + 1);\n        header = MiniHeader.header(targetBlock, randao);\n        vm.setBlockhash(targetBlock, keccak256(header));\n    }\n\n    function test_OpenWithEstimatedGasPlusHalfMustDeliverOrRevert() public {\n        vm.prank(buyer);\n        uint256 purchase = box.buy(seasonId, 10);\n        bytes memory header = _ready(purchase, keccak256(\"gas estimate\"));\n\n        // Measure what a fully funded, successful open consumes: this is what eth_estimateGas reports.\n        uint256 snapshot = vm.snapshotState();\n        uint256 before = gasleft();\n        box.open(purchase, header);\n        uint256 used = before - gasleft();\n        assertTrue(box.delivered(purchase), \"fully funded open delivers\");\n        assertTrue(vm.revertToState(snapshot));\n\n        // Same call with 1.5x that measurement, as a wallet with a generous buffer would send it.\n        uint256 limit = used * 3 / 2;\n        (bool ok,) = address(box).call{gas: limit}(abi.encodeCall(box.open, (purchase, header)));\n        (,,,, bool opened) = box.purchases(purchase);\n        if (ok) {\n            assertTrue(opened);\n            assertTrue(\n                box.delivered(purchase),\n                \"open succeeded with 1.5x the measured gas but silently took the DeliveryFailed path\"\n            );\n            assertEq(box.getStoredItems(purchase).length, 0, \"normal path must add no storage\");\n        }\n    }\n}","reproduction":"State: default BoxTestBase setup (box granted as minter, EOA buyer). buyer calls box.buy(seasonId, 10); roll to targetBlock+1 and set the header hash. Snapshot; call box.open(purchase, header) with ample gas and measure gas used U (=454,838 here); revert the snapshot. Then call address(box).call{gas: U*3/2}(abi.encodeCall(box.open,(purchase, header))). Expected: either revert, or delivered(purchase)==true and getStoredItems(purchase).length==0. Actual: the call returns true, purchases(purchase).opened==true, delivered(purchase)==false, getStoredItems(purchase) holds the ten rolled IDs and DeliveryFailed was emitted; furniture.totalSupply()==0. Same with 1 box: U=221,684, every limit in [U, 2.1U] gives DeliveryFailed; 487,704 is the first limit that delivers. Proof test: test/scratch/OpenGasDelivery.t.sol (fails now with 'open succeeded with 1.5x the measured gas but silently took the DeliveryFailed path'; passes once open reverts below a minimum gas or otherwise cannot starve a healthy mint).","severity":"medium","snippet":"        uint256 mintGas = gasleft();\n        mintGas = mintGas > DELIVERY_RESERVE_GAS ? Math.min(OPEN_MINT_GAS_LIMIT, mintGas - DELIVERY_RESERVE_GAS) : 0;\n        try furniture.mintBatch{gas: mintGas}(purchase.buyer, ids, amounts) {","title":"open forwards caller-dependent gas to the mint inside try/catch, so estimated-gas callers (and any griefer) land on the DeliveryFailed path instead of delivering"},{"citation":"resolved","description":"grantMinter takes effect immediately whenever furniture.totalSupply()==0. That matches the brief's literal condition, but the condition the feature is meant to enforce ('once anything exists a new minter waits 7 days', README) is not armed by sales or by recorded rolls, only by a delivered mint. Sales do not require any supply (buy only checks minters(box)), and with change 2 every open now succeeds even when the box is revoked, storing the roll instead of minting. So the furniture owner can: let sales run, revoke the box before the first open (or simply act before anyone opens), have every open record rolls and reserve caps with totalSupply still 0, then grantMinter(anyAddress) with zero notice, mint any capped piece past its season cap, and re-grant the box, also with zero notice. The requested test 'the owner cannot mint a capped piece past its cap within 7 days of proposing a new minter' passes only because the existing test mints first; in the state above it does not hold. This is owner-driven (no unprivileged amplifier), so it is a trust-gap note rather than an exploit, but it is the exact window the notice period was commissioned to close, and it opens the moment real money has been paid. Possible fix (a scope decision, since it tightens the brief's condition): arm the delay on the first grant rather than the first mint, e.g. a one-way 'delayArmed' flag set by the first grantMinter (a fresh deployment still authorizes its box immediately and the event-rebuild property is unchanged), or arm it when any minter has been granted (minterCount>0). Either keeps 'grantMinter(box) right after deployment' working.","line":51,"path":"src/OGClubFurniture.sol","reproduction":"Fresh deployment; owner grantMinter(box) (immediate, supply 0); createSeason with entries (1: common weight 1 cap 0, 2: legendary weight 1 cap 1). buyer buy(season,10) and pays. Roll past targetBlock, set header. Owner revokeMinter(box). Anyone open(purchase, header): succeeds, minted(season,2)==1 (legendary reserved), delivered==false, furniture.totalSupply()==0. Owner grantMinter(insider): expected a MinterProposed with a 7-day activatesAt; actual minters(insider)==true, pendingMinters(insider)==0 immediately. Owner grantMinter(box): also immediate. insider mintBatch(insider,[2],[100]) succeeds: totalSupply(2)==100 with zero notice after sales began; box.deliver(purchase) then mints the buyer's legendary as #101. Verified with a scratch test on this tree (sequence above passes as written).","severity":"low","snippet":"        if (totalSupply() == 0) {","title":"Minter delay is armed by the first delivered mint, not by the first sale: after buyers have paid and rolls reserve capped pieces, the owner still grants minters instantly while totalSupply()==0"},{"citation":"resolved","description":"The manifest's notes still say 'Post-deploy steps for the owner: furniture.setMinter(box, true) so the box can mint'. setMinter(address,bool) no longer exists on OGClubFurniture (test_ZeroAddressesAndLegacyMinterSelectorCannotGrant confirms the selector reverts). An operator following the manifest gets a revert and, if they first mint anything else (e.g. a team minter granted and used before the box), the box then needs grantMinter plus seven days plus activateMinter before any sale can start. The README and ADAPTATION.md already carry the correct step ('grantMinter(box) right after deployment, before any mint'); ADAPTATION.md notes the stale manifest text was left for the manifest step. Schema-wise the manifest is otherwise consistent with the accepted tree (three contracts in dependency order, one string per constructor parameter, $owner for every owner/beneficiary, no extra keys). Fix: update the notes to name grantMinter(box) before any mint.","line":27,"path":"launch.json","reproduction":"Deploy per launch.json. Owner sends furniture.setMinter(box, true) as the notes direct: the call reverts (no such function). Expected: the notes name the function that exists, grantMinter(box), and the 'before any mint' ordering.","severity":"low","snippet":"  \"notes\": \"Sepolia testnet launch of the OG Club lootbox application. MockOG (src/mocks/MockOG.sol) is the testnet payment token requested by the brief: ERC-20 'Mock OG', symbol mockog, 18 decimals, 1,000,000,000,000 tokens minted to the owner at construction, public mint for test funds; constructor(initialRecipient) = $owner. Its mint(address,uint256) is open to anyone and nobody, including the owner, can restrict it, so the token carries no economic value and is for this testnet launch only. OGClubFurniture (src/OGClubFurniture.sol) is the ERC-1155 furniture collection 'OG Club Furniture' / OGFURNI with ERC1155Supply, ERC2981 royalties and Ownable2Step; constructor(initialOwner, royaltyReceiver) = ($owner, $owner): the brief names no royalty wallet, so the owner receives the 5% default royalty and may change receiver/bps up to 10% later. OGClubBox (src/OGClubBox.sol) sells lootboxes for MockOG and opens them with commit-reveal randomness from the target block's prevRandao; construct","title":"launch.json notes instruct the operator to call the removed furniture.setMinter(box, true); the post-deploy step is now grantMinter(box)"}],"hash":"3042dee5496dbd91f541d22f68d762bcf2bfbef51eb95ca5cfcb416f3caa93e0","nodeId":"bc0d21c5-e606-4825-9217-cd2dc46cc30c","outcome":"completed","summary":"The review is complete. No tracked file was modified; the findings file is at the repository root and the only scratch artifact is the proof test under `test/scratch/`.\n\n**Outcome**\n\nThe permission model of both contracts holds up: every owner function is guarded, `deliverTo` is buyer-only, `activateMinter` needs a recorded proposal past its deadline, and `totalSupply()` cannot be driven back to zero because no burn path exists. Three defects were substantiated and written to `.imd-findings.json`, with coverage rows for all 26 entry points plus the delivery invariant and the manifest.\n\n**Findings**\n\n- **Medium, `open` gas-starves its own delivery.** The mint is forwarded `min(1M, gasleft − 300k)` inside `try/catch`, and the catch path is cheaper than the mint, so the lowest gas at which the transaction succeeds is the `DeliveryFailed` path. That is exactly what gas estimators return. Measured on this tree, a 1-box open consumes about 222k gas but only delivers when the caller attaches 2.19× that; everything from 1.0× to 2.1× succeeds with the roll stored and undelivered. A 10-box open needs 1.59× its measured cost. Any third party can also pick the failure path for a buyer by choosing the gas. No funds are lost, but the \"normal path adds no storage\" and \"on success mark delivered\" guarantees break under default tooling. The attached proof fails now and passes with a minimum-gas precondition at the top of `open`, which I verified by patching and restoring the file.\n- **Low, instant-grant window after sales.** The immediate branch of `grantMinter` keys on `totalSupply() == 0`, which is armed by the first delivered mint rather than the first sale. Since opens now succeed even when the box is revoked, the owner can let buyers pay, revoke the box, have rolls recorded with caps reserved, then grant any minter with zero notice and mint a capped piece past its cap. This is within the letter of the brief and owner-driven, so it is reported as a trust-gap note with a scope decision for the author.\n- **Low, stale manifest note.** The `launch.json` notes still tell the operator to call `setMinter(box, true)`, which no longer exists.\n\n**Coverage**\n\nAll entry points are answered. Two carry findings; the other 24 are marked `holds` with a one-line reason each. Areas I did not reach in depth are the RLP header parser internals and the statistical odds test, which belong to other specialists.","treeHash":null,"usage":{"cachedInputTokens":2157609,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":45998,"runtime":"claude","turns":37,"wallClockMs":756902}},{"artifacts":[],"attempt":1,"bundleHash":"8c33ec5ddd2a825aaaffb6942678991810c56a320cd13f9b8e77f228ccf6d0cf","device":"b38bea3c04869138","findings":[],"hash":"38f9786f514a1d4bc6795f599cd7a6524f91878cac9bf6d815437856a5beebe4","nodeId":"5a08eaa5-af67-4411-8ab7-73ab0a34107c","outcome":"completed","summary":"The existing launch.json is already correct for the accepted tree, so no edit was needed.\n\n**What I verified**\n\n- The manifest has exactly the keys kind, contracts and notes, and its notes are 2,068 characters.\n- Contract order is MockOG, then OGClubFurniture, then OGClubBox, which matches constructor dependency order.\n- Each constructorArgs list matches the declared constructor, one word per parameter:\n  - MockOG(initialRecipient) gets `$owner`.\n  - OGClubFurniture(initialOwner, royaltyReceiver) gets `$owner`, `$owner`.\n  - OGClubBox(token, furniture, vault, initialOwner) gets the two `$contract:` references plus `$owner`, `$owner`.\n- Every privileged or beneficiary argument resolves to `$owner`, never the factory. The vault and royalty receiver fall to the owner because the brief names no wallet for either.\n- The notes describe only contracts in src, and the facts they state match the source: 7-day minter delay, 5% default royalty capped at 10%, open-mint testnet token, try/catch delivery with deliver and deliverTo, grantMinter(box) as the first post-deploy step.\n- Constructors are nonpayable, make no external calls, and only check for nonzero addresses, so the protected deployment probe on an empty chain succeeds.\n\n**Checks run on this tree**\n\n```\nforge build        ok\nforge test         99 passed, 0 failed (with the verifier's FOUNDRY_FUZZ_SEED)\nforge fmt --check  clean\n```\n\nThe working tree is unchanged and git status is clean. No file other than launch.json is in scope, and launch.json needed no revision.","treeHash":"e08e64f5effac983b3ca8163022c4a346e3ad4ac","usage":{"cachedInputTokens":175145,"inputTokens":130,"model":"claude-fable-5-1","outputTokens":3131,"runtime":"claude","turns":8,"wallClockMs":94665}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7591760a616c6429","findings":[{"citation":"resolved","description":"Change 1 exists so that, once the collection has supply, nobody can gain a new 'mint any piece without limit' power without a seven-day public notice (grantMinter -> MinterProposed -> 7 days -> activateMinter). That notice is hollow because the box, an already-active minter, mints whatever its owner's season says, and createSeason has no limit on which item IDs a season may contain. The only structural constraint on a season is that its fallback entry is tier 0 with cap 0 (line 158): any item ID is accepted as that fallback, including a piece that an earlier season sold as a cap-1 Legendary. The box owner can therefore: setVault(self), createSeason(price=1, burnBps=0, fallbackItem=<legendary id>, entries=[{legendary id, tier 0, weight 1, cap 0}]), buy(s, 10) repeatedly (the self-transfer leg of _pay costs nothing because recipient == msg.sender passes with expected = 0) and open each purchase after three blocks, or just let them expire, because the expiry path mints the fallback, i.e. the Legendary. Ten pieces per purchase, any number of purchases per block, zero tokens spent, zero waiting. The README documents caps as per-season and says other seasons may mint the same ID, but the requested guarantee ('once anything exists a new minter waits 7 days'; the test 'the owner cannot mint a capped piece past its cap within 7 days of proposing a new minter') is defeated end-to-end by the box path with no notice at all: the 7-day delay only slows the owner when they choose the slow door. Holders of the capped piece are diluted with no warning. Severity is medium rather than high because it needs the (trusted) box owner and the per-season cap semantics are documented; it is reported because the delay is the explicit deliverable of this revision and this path makes it ineffective. Minimal fix that keeps the design: reject, in createSeason, an uncapped entry whose itemId was ever capped in a previous season (or require every entry of a new season to carry a cap at least as strict as any earlier season's cap for that itemId), and document that the delay cannot stop owner-created seasons; or route owner-created seasons through the same 7-day notice (a SeasonProposed/activate step) when they reuse an itemId that already has supply.","line":158,"path":"src/OGClubBox.sol","reproduction":"State: furniture and box deployed, furniture.grantMinter(box) at zero supply; season 1 = {fallback item 1 (tier 0, weight 99, cap 0), item 5 (tier 4 Legendary, weight 1, cap 1)}; one real buyer buys and opens so totalSupply() > 0 and furniture.grantMinter(owner) now only records a proposal (minters(owner) == false). Owner then: box.setVault(owner); s2 = box.createSeason(1, 1000, 100_000, 0, 5, [{itemId 5, tier 0, weight 1, cap 0}]) -> accepted (line 158 only checks tier 0 and cap 0). token.approve(box, max); five times box.buy(s2, 10) -> owner's token balance unchanged (self-pay leg, _pay expected = 0). vm.roll(+300) and box.open(id, \"\") for each (expired path mints the fallback = item 5) -> furniture.balanceOf(owner, 5) == 50, furniture.totalSupply(5) == 50 + minted(season1, 5), block.timestamp unchanged (no seven-day wait). Expected per the delivered guarantee: a capped piece cannot be minted past its cap without a seven-day public notice. Actual: 50 Legendaries minted in four blocks at zero cost with no MinterProposed event. (Test run locally in test/scratch/Leads.t.sol::test_OwnerMintsCappedPieceWithoutDelayThroughNewSeason, passes on this tree, i.e. the bypass works.)","severity":"medium","snippet":"            if (entry.itemId == fallbackItem && entry.cap == 0 && entry.tier == 0) validFallback = true;","title":"Owner mints any piece in any quantity instantly and for free through createSeason, bypassing the 7-day minter notice"},{"citation":"resolved","description":"open is permissionless and every pending roll is public once the target header exists (previewOpen). The guaranteed tenth pick first selects over the full rare weight; only if that selection has sold out does it re-roll among the remaining rares (lines 446-449). A ten-pack holder can therefore preview both outcomes and pick the better one: if the re-roll is better than the original selection, they open any other pending purchase that consumes the last unit of the originally selected rare before opening their own; if it is worse, they open their own first. The other purchase receives exactly what it rolled, so there is no direct victim; the loser is the published odds (more high-tier pieces than the weights imply, chosen by the holder, not by chance). Cost: one extra open transaction. The README accepts that ordering affects availability and that the tenth pick is state-dependent, so this is reported as a documented residual rather than a broken guarantee. Fix options if the owner wants to close it: resolve the guaranteed tenth pick only against the state at the purchase's own opening with the re-roll removed (degrade to the ordinary roll instead of re-rolling), or let only the buyer open during the first N blocks of the window.","line":446,"path":"src/OGClubBox.sol","reproduction":"Season: fallback item 1 (tier 0, weight 1000, cap 0), item 2 (tier 2 Rare, weight 10, cap 1), item 3 (tier 4 Legendary, weight 1, cap 0). Alice buys a ten-pack pA, victim buys a single box pV in the same block (same target block and header). After the target block, search prevRandao values (the test loops synthetic headers via vm.setBlockhash) until previewOpen(pA)[9] == 2 and previewOpen(pV)[0] == 2. Alice calls open(pV, header) first (anyone may): victim receives item 2 and the Rare is sold out. previewOpen(pA)[9] is now 3. Alice calls open(pA, header): she receives item 3 (Legendary) and no item 2. Had Alice opened pA first she would have received item 2 (Rare) and the victim the fallback. Expected: the tenth pick's tier does not depend on a choice the holder makes after seeing both outcomes. Actual: the holder picks the better of two tiers. (test/scratch/Option.t.sol::test_TenPackHolderChoosesOpeningOrderToUpgradeGuaranteedPick passes on this tree.)","severity":"low","snippet":"        if (!_available(entries[picked], counts[picked])) {\n            uint256 retry = uint256(keccak256(abi.encode(seed)));\n            picked = _walk(entries, counts, retry % availableRareWeight, true, true);\n        }","title":"Ten-pack holder has a free option on the guaranteed tenth pick by choosing the opening order of other purchases"},{"citation":"resolved","description":"The gas forwarded to the initial mintBatch is min(OPEN_MINT_GAS_LIMIT, gasleft() - 300_000) (line 250), i.e. it is chosen by whoever calls open. A third party can call open with a transaction gas limit just large enough for the roll and the catch path but too small for the mint: the mint runs out of gas, the catch stores the ten item IDs (about 250k gas of SSTOREs paid by the opener) and emits DeliveryFailed, and the buyer receives nothing until someone calls deliver. The roll itself is safe (it is recorded, caps are reserved, and deliver is permissionless), so this is griefing with no theft: it costs the buyer one more transaction and leaves a ten-slot stored array for a purchase that could have been delivered. It also means the DeliveryFailed event is not a reliable signal that the buyer cannot receive. Fix: treat an out-of-gas in the initial mint differently from a receiver revert by requiring a minimum forwarded gas (revert open with InsufficientGas when gasleft() - DELIVERY_RESERVE_GAS < OPEN_MINT_GAS_LIMIT, or at least below a measured floor for a ten-item EOA mint of ~250k), so an opener cannot steer a deliverable purchase into the stored path.","line":250,"path":"src/OGClubBox.sol","reproduction":"Default two-entry season (fallback item 1 uncapped, item 5 cap 1), EOA buyer buys a ten-pack p; after the target block build and register the header. previewOpen(p, randao) gives the expected ten IDs. A stranger calls box.open{gas: 480_000}(p, header). Expected: delivery to an EOA that costs about 120k-250k gas succeeds (the whole open costs ~370k gas when fully funded, measured in test/scratch/Leads.t.sol::test_MeasureTenPackDeliveryGas). Actual: open succeeds, emits DeliveryFailed(p), delivered(p) == false, getStoredItems(p) == expected, furniture.balanceOf(buyer, 1) == 0; the buyer only receives after a further box.deliver(p). With 420_000 gas the open reverts instead; with 700_000 it delivers. (test/scratch/Leads.t.sol::test_UnderfundedOpenForcesStoredPath with GAS = 480_000 passes on this tree.)","severity":"low","snippet":"        uint256 mintGas = gasleft();\n        mintGas = mintGas > DELIVERY_RESERVE_GAS ? Math.min(OPEN_MINT_GAS_LIMIT, mintGas - DELIVERY_RESERVE_GAS) : 0;\n        try furniture.mintBatch{gas: mintGas}(purchase.buyer, ids, amounts) {","title":"Any opener can force the stored-delivery path by under-funding gas, so the buyer needs a second transaction and the normal path's zero-storage property is lost"},{"citation":"resolved","description":"The manifest's notes still tell the owner to call furniture.setMinter(box, true) after deployment. setMinter no longer exists on OGClubFurniture (test_ZeroAddressesAndLegacyMinterSelectorCannotGrant confirms the selector reverts); the README's post-deploy step is grantMinter(box) right after deployment, before any mint. Notes are explanatory, not deployment authority, but an operator following them will fail the first post-deploy step, and if they mint anything else first (for example to test metadata) the box grant then needs seven days. The constructor arguments and contract order in the manifest are otherwise consistent with the current constructors. Fix: replace the sentence with the README's instruction: furniture.grantMinter(box) immediately after deployment and before any mint; if anything was minted first, wait MINTER_DELAY (7 days) and call activateMinter(box).","line":27,"path":"launch.json","reproduction":"Read launch.json line 27: it contains 'Post-deploy steps for the owner: furniture.setMinter(box, true) so the box can mint'. Call furniture.setMinter(box, true) against the compiled OGClubFurniture: the call reverts (no such selector; see test/OGClubFurniture.t.sol::test_ZeroAddressesAndLegacyMinterSelectorCannotGrant). Expected: the note names an existing function (grantMinter). Actual: it names a removed one.","severity":"low","snippet":"  \"notes\": \"Sepolia testnet launch of the OG Club lootbox application. MockOG (src/mocks/MockOG.sol) is the testnet payment token requested by the brief: ERC-20 'Mock OG', symbol mockog, 18 decimals, 1,000,000,000,000 tokens minted to the owner at construction, public mint for test funds; constructor(initialRecipient) = $owner. Its mint(address,uint256) is open to anyone and nobody, including the owner, can restrict it, so the token carries no economic value and is for this testnet launch only. OGClubFurniture (src/OGClubFurniture.sol) is the ERC-1155 furniture collection 'OG Club Furniture' / OGFURNI with ERC1155Supply, ERC2981 royalties and Ownable2Step; constructor(initialOwner, royaltyReceiver) = ($owner, $owner): the brief names no royalty wallet, so the owner receives the 5% default royalty and may change receiver/bps up to 10% later. OGClubBox (src/OGClubBox.sol) sells lootboxes for MockOG and opens them with commit-reveal randomness from the target block's prevRandao; construct","title":"launch.json post-deploy note instructs furniture.setMinter(box, true), a function this revision removed"}],"hash":"3b6570fd9ab2704faf16c5da0bbb1467657828081063f7a0c939e73d39aa15cc","nodeId":"bc4b80f7-86d0-4bbb-9d54-7de5006d6464","outcome":"completed","summary":"Review complete. The findings file is written and validated against the tree. No tracked file was changed; only the permitted `.imd-findings.json` and `test/scratch/` were created.\n\n**Result: one medium and three low findings, no critical or high.** All 95 existing tests pass, and the core guarantees of the revision hold: a recorded roll is never lost, caps reserve undelivered pieces, each purchase is delivered at most once, the box never holds tokens, and preview matches open.\n\nFindings, each reproduced with a scratch test that passes on this tree:\n\n1. **Medium. The 7-day minter notice is bypassable through the box itself.** `createSeason` accepts any item ID as an uncapped Common fallback. The owner can set the vault to themselves, create a 1-wei season whose fallback is a previously cap-1 Legendary, buy ten-packs at zero net cost (self-pay leg), and open or simply let them expire. The scratch test mints 50 of the capped Legendary in four blocks with no `MinterProposed` event and no time elapsed. Per-season caps are documented, but the explicit deliverable of change 1 is defeated end to end.\n2. **Low. Free option on the guaranteed tenth pick.** Since `open` is permissionless and rolls are public, a ten-pack holder previews both orderings and opens another pending purchase first when that sells out their selected Rare and re-rolls them into a Legendary. The README accepts ordering effects, so this is a documented residual.\n3. **Low. Under-funded `open` forces the stored path.** A stranger calling `open` with about 480k gas makes the bounded mint run out of gas, so a deliverable EOA purchase emits `DeliveryFailed` and needs a second `deliver` transaction. Griefing only, no loss.\n4. **Low. `launch.json` notes still instruct `furniture.setMinter(box, true)`,** a function this revision removed. The README correctly says `grantMinter(box)`.\n\nCoverage: all 26 entry points have rows, 24 hold, `createSeason` and `open` carry findings, plus five invariant rows. Areas covered in depth: payment conservation, cap and reservation invariants, delivery state machine, minter delay lifecycle, expiry boundary, and the gas-bounded try/catch. Not reached in depth: the RLP header parser and metadata or royalty functions, which are outside the economics area.","treeHash":null,"usage":{"cachedInputTokens":1454574,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":38322,"runtime":"claude","turns":30,"wallClockMs":551440}},{"artifacts":[],"attempt":1,"bundleHash":"06c86c6df4433507bc78016617db89c917d037cdb5cf2ecf3c43aeeff27de89b","device":"6ed09c2eb1ff6aec","findings":[],"hash":"44463fefd440659cf79237679368c1d4616847835dba5137df713ea87a68bc51","nodeId":"5a08eaa5-af67-4411-8ab7-73ab0a34107c","outcome":"completed","summary":"I updated `launch.json`, and it's the only file I changed. `forge build` passes, and `forge test` passes all 95 tests with the verifier's fuzz seed. Nothing in this run validates the manifest itself, so I checked it by reading it against the source.\n\n**What stays the same:** the existing manifest already matched the accepted constructors, so the contracts and their arguments are unchanged:\n- **`MockOG`:** `$owner` receives the initial token mint.\n- **`OGClubFurniture`:** `$owner` as owner and as royalty receiver.\n- **`OGClubBox`:** `$contract:MockOG`, `$contract:OGClubFurniture`, `$owner` as vault, `$owner` as owner.\n\n**What changed:** the notes were out of date. They told the owner to call `setMinter`, which no longer exists. The notes (2,068 characters, under the 4,000 limit) now say:\n- **Post-deploy step:** call `grantMinter(box)` right after deployment, before anything is minted. That takes effect immediately.\n- **Later minters:** once anything has been minted, a new minter waits 7 days and needs `activateMinter`. `revokeMinter` takes effect immediately.\n- **Opening a box:** `open` records the roll and reserves capped pieces before minting. If the mint fails, the items are stored and can be minted later with `deliver`, or with `deliverTo` by the buyer only. Revoking the box's minter role only delays delivery; it never changes a recorded roll.","treeHash":"bfb31f9cc5d7953dfd08cc6c87e53d0f4bcf709b","usage":{"cachedInputTokens":189029,"inputTokens":12,"model":"claude-opus-5-5","outputTokens":1425,"runtime":"claude","turns":6,"wallClockMs":87420}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"1ec9f666356a7ad7","findings":[{"citation":"resolved","description":"The manifest's notes tell the operator to run `furniture.setMinter(box, true)` after deployment. Change 1 removed setMinter (test_ZeroAddressesAndLegacyMinterSelectorCannotGrant asserts the selector reverts). The correct step is `furniture.grantMinter(box)` right after deployment and before any mint; if anything has been minted first, the grant becomes a 7-day proposal that must then be activated with `activateMinter(box)`. An operator who follows the note as written gets a reverting call, and one who mints metadata-test pieces first would lock sales for a week. ADAPTATION.md acknowledges the note is stale but the file in the tree was not updated. Notes are explanatory text, not deployment authority, so this is a documentation defect, not a code defect; constructor names, argument counts and order in the manifest were checked and are correct.","line":27,"path":"launch.json","reproduction":"State: contracts deployed per launch.json. Call furniture.setMinter(box, true) as the note instructs -> the call reverts (no such selector; see test/OGClubFurniture.t.sol:282-283). Expected: the note names grantMinter(box) and warns it must happen before any mint. Fix: replace the clause with `furniture.grantMinter(box) immediately after deployment, before any mint (buy reverts with BoxNotMinter until then)`.","severity":"low","snippet":"  \"notes\": \"Sepolia testnet launch of the OG Club lootbox application. MockOG (src/mocks/MockOG.sol) is the testnet payment token requested by the brief: ERC-20 'Mock OG', symbol mockog, 18 decimals, 1,000,000,000,000 tokens minted to the owner at construction, public mint for test funds; constructor(initialRecipient) = $owner. Its mint(address,uint256) is open to anyone and nobody, including the owner, can restrict it, so the token carries no economic value and is for this testnet launch only. OGClubFurniture (src/OGClubFurniture.sol) is the ERC-1155 furniture collection 'OG Club Furniture' / OGFURNI with ERC1155Supply, ERC2981 royalties and Ownable2Step; constructor(initialOwner, royaltyReceiver) = ($owner, $owner): the brief names no royalty wallet, so the owner receives the 5% default royalty and may change receiver/bps up to 10% later. OGClubBox (src/OGClubBox.sol) sells lootboxes for MockOG and opens them with commit-reveal randomness from the target block's prevRandao; construct","title":"launch.json post-deploy note still instructs furniture.setMinter(box, true), a function that no longer exists"},{"citation":"resolved","description":"open() is permissionless and never reverts because of delivery. The gas forwarded to furniture.mintBatch is whatever the caller left above DELIVERY_RESERVE_GAS, down to zero. A stranger who calls open with just enough gas for the roll but not for the mint makes an otherwise-deliverable purchase (EOA buyer, box authorized) fail delivery: the roll is stored (~250k gas of new storage, paid by the stranger), DeliveryFailed is emitted and the buyer receives nothing until someone calls deliver(). No roll or funds are lost and anyone can finish delivery, so impact is a forced extra transaction and a misleading DeliveryFailed signal for monitoring. Execution-trace note: the degraded path is reachable with honest receiver, honest minter and no error on the buyer's side, purely from the opener's gas choice. A design-preserving mitigation is to refuse to run the open when the caller supplies less than the normal path needs (e.g. revert unless mintGas == OPEN_MINT_GAS_LIMIT, or at least a documented minimum), so a low-gas open reverts and can be resubmitted instead of silently degrading.","line":250,"path":"src/OGClubBox.sol","reproduction":"Setup as test/helpers/BoxTestBase.sol (box granted, EOA buyer). buyer: box.buy(seasonId, 1). Roll to target+1, set blockhash to the header hash. stranger: box.open{gas: 420_000}(purchaseId, header). Actual: DeliveryFailed(purchaseId) emitted, box.delivered(purchaseId) == false, getStoredItems(purchaseId).length == 1, buyer's furniture balance 0; a later box.deliver(purchaseId) by anyone succeeds. Expected for an honest EOA buyer with an authorized box: Delivered on open. Reproduced in test/scratch/Leads.t.sol test_LeadA_StrangerLowGasOpenForcesStoragePath (passes = behavior confirmed).","severity":"low","snippet":"        mintGas = mintGas > DELIVERY_RESERVE_GAS ? Math.min(OPEN_MINT_GAS_LIMIT, mintGas - DELIVERY_RESERVE_GAS) : 0;","title":"Any third party can force an EOA buyer's open onto the storage/DeliveryFailed path by submitting it with little gas"},{"citation":"resolved","description":"Change 1's stated purpose is that the owner cannot mint a capped piece past its cap within 7 days of proposing a new minter, and the suite's test_OwnerCannotMintCappedPieceWithinSevenDaysOfProposal checks exactly the direct-mint route. But the box is a permanent, already-active minter, caps are per season and per item (minted[seasonId][itemId]), and createSeason is owner-only with no delay. When the same account owns both contracts (launch.json sets both to $owner), the owner creates a 1-wei season in which the capped Legendary ID is an uncapped entry with overwhelming weight, sets the vault to itself, buys ten boxes and opens them: the capped piece's supply goes from 1 to 11 in the same hour the owner's own minter proposal is still pending. The README documents that caps are per season, so this is a trust assumption rather than a permission bypass, and it is reported here because the delivered guarantee ('the owner cannot mint a capped piece past its cap within 7 days') is narrower than it reads. Closing it would need a scope decision (e.g. a season-creation notice period, or a collection-level per-item cap in OGClubFurniture); either changes agreed behavior, so it is flagged, not prescribed.","line":145,"path":"src/OGClubBox.sol","reproduction":"Setup as test/scratch/Leads.t.sol: season 1 entries {id 1 Common uncapped w1, id 2 Legendary cap 1 w1}. buyer buys 10 and opens -> furniture.totalSupply(2) == 1, box.minted(1,2) == 1. Owner: furniture.grantMinter(owner) -> pending, minters(owner) == false (7-day wait). Owner: box.createSeason(1, 1000, 100000, 0, 7, [{2, tier 4, weight 1e9, cap 0}, {7, tier 0, weight 1, cap 0}]); box.setVault(owner); approve; box.buy(s2, 10); open after target. Actual: furniture.totalSupply(2) == 11 within the delay. Expected per the stated guarantee: no new supply of the capped piece until a proposal activates. Confirmed by test_LeadB_OwnerBypassesDelayViaNewSeason (passes = behavior confirmed).","severity":"low","snippet":"    ) external onlyOwner returns (uint256 seasonId) {","title":"The seven-day minter delay does not bound the owner: a new season through the already-authorized box mints any capped piece past its cap immediately"}],"hash":"52c17265dde86d0b33acd6c57cfd94d53f0b41ad8695c099a15746a454e5380d","nodeId":"8c87d994-13cb-4f0f-a3c1-77cf26b36ad8","outcome":"completed","summary":"The review is complete and `.imd-findings.json` is written with three low-severity findings and a 32-row coverage record. No source file was changed; the only files I created are the findings file and a scratch test, both git-ignored.\n\n**What I checked (Execution Trace, Periphery, First Principles)**\n\n- Traced `open` end to end: header hash and number checks, RLP decode, opened flag and cap counts written before the external call, the try/catch gas reserve, and both the success and failure branches. Preview and open share one roll path. The roll survives gas exhaustion, large revert payloads, a revoked minter and receiver rejection.\n- Traced `deliver` and `deliverTo`: flag set and stored items cleared before the mint, atomic revert on failure, buyer-only redirection, and callback re-entry blocked by the shared guard.\n- Traced `grantMinter`, `activateMinter`, `cancelMinter`, `revokeMinter`: the immediate path depends on `totalSupply() == 0`, and supply is monotonic because there is no burn and no transfer to zero, so the immediate path cannot recur after the first mint.\n- Periphery: the RLP parser is bounds-checked and canonical, and the off-chain `encode_header.py` re-encodes all three mainnet fixtures to their published block hashes. The manifest's constructor names, counts and order are correct.\n- Confirmed all spec-required tests exist and `forge build`, `forge test` (95 passing) and `forge fmt --check` pass.\n\n**Findings (all low, each reproduced)**\n\n1. **launch.json still says `setMinter(box, true)`** as the post-deploy step. That function was removed, so the instruction reverts. It should read `grantMinter(box)` before any mint.\n2. **A stranger can force the storage path on open.** Calling `open` with 420k gas for an EOA buyer with an authorized box yields `DeliveryFailed` and stored items instead of delivery. No roll is lost and anyone can call `deliver`, so impact is one extra transaction and a misleading signal. Confirmed in `test/scratch/Leads.t.sol`.\n3. **The seven-day delay does not bound a combined owner.** Caps are per season, the box is a permanent minter, and `createSeason` has no delay. The owner created a new season with the cap-1 Legendary uncapped and raised its supply from 1 to 11 while their own minter proposal was pending. The README documents per-season caps, so this is a trust-assumption gap against the stated guarantee rather than a permission bypass.\n\n**Not reached**: the stateful invariant handlers were read for what they assert but not independently re-derived, and the protected factory harness needs verifier inputs so it was not executed.","treeHash":null,"usage":{"cachedInputTokens":1048038,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":35633,"runtime":"claude","turns":29,"wallClockMs":649679}},{"artifacts":[],"attempt":1,"bundleHash":"dd7f383fe55c54e185fec89d4e0cea7c05eee26f2a1e2321a7da10548d98e355","device":"fc87c05048aca47d","findings":[{"description":"grantMinter keys the immediate path on totalSupply() == 0, exactly as the brief specifies. Because OGClubBox.open now records a roll on the failure path without minting, supply can remain zero after boxes have been sold and opened: revoke the box before any delivery, open the purchases (DeliveryFailed, rolls stored, caps reserved), and totalSupply() is still 0. In that window the owner can still authorize any address instantly and that address can mint capped pieces beyond the box's caps, while buyers hold paid, recorded rolls. Zero-amount mintBatch calls also leave supply at zero. This matches the requested behavior (the delay is defined by 'nothing has ever been minted'), so no test asserts otherwise; it is recorded so the owner powers section of the README and any reviewer know the window exists. Once the first real mint lands the window closes permanently: there is no burn and transfers to the zero address revert, so supply never returns to zero. Covered by test_ImmediateGrantStaysOpenWhileOnlyUndeliveredRollsExist, test_ZeroAmountMintsLeaveSupplyZeroAndGrantsImmediate and test_SupplyCannotReturnToZeroSoTheDelayIsPermanent in test/DeliveryEdges.t.sol.","line":51,"path":"src/OGClubFurniture.sol","reproduction":"Deploy furniture and box; furniture.grantMinter(box); create a season; buyer buys 10 boxes; owner calls furniture.revokeMinter(box); after the target block anyone calls box.open(purchaseId, header) -> DeliveryFailed, getStoredItems(purchaseId).length == 10, furniture.totalSupply() == 0. Owner then calls furniture.grantMinter(attacker): expected under a 'nothing sold yet' reading would be a 7-day proposal; actual (and as specified by the brief) is minters[attacker] == true immediately and pendingMinters[attacker] == 0, so attacker.mintBatch(attacker, [3], [100]) succeeds past the season cap of 3 for item 3.","severity":"info","title":"Immediate minter grants stay available while paid rolls are stored but undelivered"}],"hash":"5b4518e00745c4e1db5708317b0ced4818530f134cd385b66f1df07ad83fb809","nodeId":"7b32a06a-f36a-4f50-8652-c3809a4ab5d7","outcome":"completed","summary":"Done. The suite is green again against the implementer's latest change, and nothing outside `test/` was touched.\n\n**What was wrong.** The implementer's last commit made `open` revert with `InsufficientGas` when fewer than 1.3 million gas remain at delivery time, instead of letting a starved mint fall onto the stored-roll path. One of my tests in `test/DeliveryEdges.t.sol` still expected the old behaviour and failed.\n\n**What I changed, all in `test/DeliveryEdges.t.sol`:**\n- Replaced the stale gas-starved test. It now checks that a stranger sending short gas gets `InsufficientGas` with the purchase, caps, stored items and preview roll untouched, both with the box authorized and with it revoked. It then opens with full gas on the revoked path, confirms the stored roll equals the preview, re-grants the box and has a stranger deliver exactly those items.\n- Tightened the any-gas fuzz property. For a healthy externally owned buyer, any outcome must now be either an atomic revert, which is plain out-of-gas or `InsufficientGas` naming the published budget, or a full delivery. The stored path is no longer accepted for an honest buyer, and after a revert the purchase must still open normally with the same roll.\n\n**Verification.** `forge build`, the full `forge test` with the verifier's fuzz seed, and `forge fmt --check` all pass.\n\n| Check | Result |\n|---|---|\n| forge test (seeded) | 111 passed, 0 failed |\n| forge fmt --check | clean |\n\n**Findings.** I rewrote `.imd-findings.json` with one info-level note that a test comment already refers to: because stored rolls do not mint, the owner can still grant a minter instantly while sold boxes sit undelivered and supply is zero. This matches the brief's \"nothing has ever been minted\" rule, so it is recorded rather than asserted against. No critical or high defects were found in the revised implementation.","treeHash":"7ac78a93d0eced3f5e76343187b4b2ce7778fd7e","usage":{"cachedInputTokens":838799,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":13012,"runtime":"claude","turns":20,"wallClockMs":222018}},{"artifacts":[],"attempt":1,"bundleHash":"2a8bfa0538ac02ea64fa9e8adeb0313912f73316c344facef83f20ce2535e019","device":"c9743cd9807c4c3a","findings":[{"description":"grantMinter takes effect immediately whenever totalSupply() == 0, exactly as the brief specifies. Supply only counts delivered furniture, so the immediate path stays open after sales have happened as long as every opened purchase is still stored and undelivered (box revoked, or buyers that reject delivery), and after mints of zero amounts. In that window the owner can authorize any address at once and mint capped pieces outside the box's odds, while buyers already hold recorded rolls for those pieces. The box's own minted() caps are unaffected and the roll itself cannot change. This matches the agreed design and is covered by test_ImmediateGrantStaysOpenWhileOnlyUndeliveredRollsExist and test_ZeroAmountMintsLeaveSupplyZeroAndGrantsImmediate in test/DeliveryEdges.t.sol; it is reported so the requester can decide whether 'nothing has ever been minted' should also mean 'no purchase has been opened'. If so, the furniture would need a signal from the box (e.g. a counter of recorded rolls), which is a design change rather than a bug.","line":51,"path":"src/OGClubFurniture.sol","reproduction":"Fresh deployment, box granted. buy(season, 10); revokeMinter(box); open(purchase, header) -> DeliveryFailed, getStoredItems(purchase).length == 10, totalSupply() == 0. Owner calls grantMinter(owner). Expected under a stricter reading: MinterProposed with a 7-day delay. Actual: MinterSet(owner, true) immediately and owner can mintBatch capped item ids with no limit.","severity":"info","title":"Immediate minter grants remain available while paid, undelivered rolls exist (supply-keyed rule as specified)"},{"description":"open forwards min(OPEN_MINT_GAS_LIMIT, gasleft - 300000) to mintBatch and swallows the failure. A third party calling open with roughly 500k to 700k gas (3-entry season, 10 boxes) makes the honest mint run out of gas, so the purchase lands in the stored, undelivered state and the buyer or anyone else must send a second deliver transaction. The roll is recorded correctly, caps are reserved, and deliver succeeds afterwards, so no value is lost and the griefer pays more gas than the victim; below ~500k gas open reverts atomically. This is the behavior the brief asks for (open must not revert because of delivery) and is pinned by test_GasStarvedOpenOfHonestBuyerStoresRollAndAnyoneDeliversLater and testFuzz_OpenWithAnyGasIsAtomicOrRecordsThePreview in test/DeliveryEdges.t.sol. Reported for awareness only: off-chain operators monitoring DeliveryFailed should expect it even for EOA buyers.","line":249,"path":"src/OGClubBox.sol","reproduction":"Default test season, buyer is an EOA. buy(season, 10); after the target block, stranger calls open{gas: 600000}(purchase, header). Expected by a casual reader: Delivered. Actual: DeliveryFailed, getStoredItems(purchase) == previewOpen(purchase, randao), furniture.totalSupply() == 0; a later deliver(purchase) from anyone mints exactly those ten items.","severity":"info","title":"Anyone can force the stored-delivery path for an honest EOA buyer by calling open with little gas"}],"hash":"676f34ccce154fc8bb23c5b1958ab4bc193dffaeced5dba555b3a248247fb96c","nodeId":"7b32a06a-f36a-4f50-8652-c3809a4ab5d7","outcome":"completed","summary":"Work is complete and verified. Here is the recap.\n\n**State of the repo.** The implementation of both changes, the README update, and most of the requested tests were already in HEAD from the earlier contributor. The suite passed at 95 tests when I started. I added two test files under `test/` and reported two spec-level observations in `.imd-findings.json`. No source, config or README files were touched.\n\n**New tests in `test/DeliveryEdges.t.sol`** (11 tests, unit plus fuzz):\n- A gas-starved `open` for an honest EOA buyer still records the preview roll, reserves caps, emits `DeliveryFailed`, and anyone delivers later. A fuzz over forwarded gas proves `open` is either atomic or records exactly the preview.\n- The success path writes nothing to the stored-items slots, the failure path writes exactly the roll, and delivery clears every slot. This is checked with recorded storage accesses and direct slot loads.\n- `deliverTo` to the box, the furniture or a hook-less contract reverts and leaves the roll stored. A holder contract receives and `Delivered` carries the real recipient.\n- Fuzzed callers: only the buyer redirects, anyone delivers.\n- A stored roll survives any delay, season close, pause, vault and ownership change. Expiry only ever applies to unopened purchases.\n- The supply-keyed grant rule: immediate while supply is zero even with undelivered rolls or zero-amount mints, permanent delay once supply exists, exact activation boundary at the deadline.\n\n**New invariant suite in `test/MinterLifecycleInvariant.t.sol`.** A handler interleaves grant, activate, cancel, revoke, stranger attempts, direct mints by other minters, buys, opens, rejected and redirected deliveries, with random callers and bounded time. Invariants: live and pending minter state matches ghosts and never activates early; minted per item equals delivered supply plus stored items minus direct mints; each purchase delivered at most once and only after opening; the box holds no tokens or furniture and payments are conserved. Every call is checked, none revert.\n\n**Verification results.**\n\n| Check | Result |\n|---|---|\n| forge build | passes (lint hints only, pre-existing) |\n| forge test with the verifier's fuzz seed | 108 passed, 0 failed |\n| forge fmt --check | clean |\n\n**Findings reported, both info level, no proofs needed.** First, the immediate-grant path stays open while only undelivered rolls exist, exactly as the brief keys it on supply. Second, a caller can force the stored-delivery path for an EOA buyer by starving `open` of gas. Neither loses a roll or breaks a cap, so they are recorded for the requester's awareness rather than as defects.","treeHash":"49c461722ffe000237609e18ebd698a822336dbf","usage":{"cachedInputTokens":2773585,"inputTokens":770,"model":"claude-fable-5-1","outputTokens":48019,"runtime":"claude","turns":43,"wallClockMs":692753}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fa2b7fcb5f53535a","findings":[{"citation":"resolved","description":"open() performs the roll and the mint in one transaction. If furniture.mintBatch reverts, every accounting effect is rolled back and the purchase stays unopened. While OGClubFurniture.minters[box] is false (furniture owner called setMinter(box,false), or the furniture ownership was renounced after a revoke), mintBatch reverts with NotMinter(box), so open() reverts for every pending purchase. Once block.number - targetBlock > 256 (line 218) the header is ignored and _roll returns only the season fallback, so the buyer who paid for a live roll receives fallbacks although the honest result was observable (previewOpen) inside the window. The roll is lost by an action of a privileged account that is not the box owner and may be a different wallet; the README (lines 161-167) documents it as an operational duty, but the contract gives the buyer no way to preserve the result and there is no refund. Impact: value of every pending box in the window is reduced to the fallback piece. This is the defect the requester's change 2 targets: mark opened and count minted, then call mintBatch inside try/catch, store the rolled itemIds on failure, and expose deliver(purchaseId) / deliverTo(purchaseId,to).","line":235,"path":"src/OGClubBox.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {OGClubBox} from \"src/OGClubBox.sol\";\nimport {OGClubFurniture} from \"src/OGClubFurniture.sol\";\nimport {MockOG} from \"src/mocks/MockOG.sol\";\n\n/// @notice A paid, honest roll must survive the furniture owner revoking the box's minter role.\n/// @dev Fails on the current code: `open` reverts with NotMinter while the box is revoked, and once the\n///      256-block window passes the only possible outcome is the fallback piece. Passes once `open` records\n///      the roll independently of delivery and `deliver(purchaseId)` mints the stored items later.\ncontract MinterRevokedRollLostTest is Test {\n    MockOG internal token;\n    OGClubFurniture internal furniture;\n    OGClubBox internal box;\n    address internal buyer = makeAddr(\"buyer\");\n    address internal vault = makeAddr(\"vault\");\n    uint256 internal seasonId;\n\n    uint256 internal constant FALLBACK = 1;\n    uint256 internal constant COMMON_PIECE = 2;\n\n    function setUp() public {\n        vm.roll(100);\n        vm.warp(1000);\n        token = new MockOG(address(this));\n        furniture = new OGClubFurniture(address(this), vault);\n        box = new OGClubBox(token, furniture, vault, address(this));\n        _grant(address(box));\n        token.mint(buyer, 1_000_000 ether);\n        vm.prank(buyer);\n        token.approve(address(box), type(uint256).max);\n\n        OGClubBox.Entry[] memory entries = new OGClubBox.Entry[](2);\n        entries[0] = OGClubBox.Entry(FALLBACK, 0, 1, 0);\n        entries[1] = OGClubBox.Entry(COMMON_PIECE, 0, 1_000_000, 0);\n        seasonId = box.createSeason(1, 1000, 100_000, 0, FALLBACK, entries);\n    }\n\n    function test_rollRecordedAtOpenSurvivesRevokedMinterAndExpiry() public {\n        vm.prank(buyer);\n        uint256 purchaseId = box.buy(seasonId, 3);\n        (,,, uint256 targetBlock,) = box.purchases(purchaseId);\n\n        // Furniture owner revokes the box while the purchase is pending.\n        _revoke(address(box));\n\n        // Target header is available; this is the honest roll the buyer paid for.\n        bytes32 randao = keccak256(\"og-club-proof\");\n        bytes memory header = _header(targetBlock, randao);\n        vm.roll(targetBlock + 1);\n        vm.setBlockhash(targetBlock, keccak256(header));\n        uint256[] memory expected = box.previewOpen(purchaseId, randao);\n        uint256 expectedCommon;\n        for (uint256 i; i < expected.length; ++i) {\n            if (expected[i] == COMMON_PIECE) ++expectedCommon;\n        }\n        assertGt(expectedCommon, 0, \"fixture: honest roll must contain a non-fallback piece\");\n\n        // Anyone tries to open inside the window. On the current code this reverts (NotMinter).\n        (bool openedInWindow,) = address(box).call(abi.encodeCall(box.open, (purchaseId, header)));\n\n        // The window passes, then the furniture owner restores the box.\n        vm.roll(targetBlock + 257 + 10);\n        _grant(address(box));\n\n        (,,,, bool opened) = box.purchases(purchaseId);\n        if (!opened) {\n            // Current code: the only remaining path, which mints fallbacks.\n            box.open(purchaseId, header);\n        } else {\n            assertTrue(openedInWindow, \"open must not revert because of delivery\");\n            (bool ok, bytes memory reason) =\n                address(box).call(abi.encodeWithSignature(\"deliver(uint256)\", purchaseId));\n            require(ok, string(reason));\n        }\n\n        // The buyer must receive exactly the roll recorded in the window, not fallbacks.\n        assertEq(furniture.balanceOf(buyer, COMMON_PIECE), expectedCommon, \"honest roll was lost\");\n        assertEq(furniture.balanceOf(buyer, FALLBACK), expected.length - expectedCommon, \"fallbacks replaced the roll\");\n    }\n\n    // ---- helpers that work before and after the minter API change ----\n\n    function _grant(address minter) internal {\n        (bool ok,) = address(furniture).call(abi.encodeWithSignature(\"setMinter(address,bool)\", minter, true));\n        if (!ok) {\n            (ok,) = address(furniture).call(abi.encodeWithSignature(\"grantMinter(address)\", minter));\n            if (ok && !furniture.minters(minter)) {\n                vm.warp(block.timestamp + 7 days + 1);\n                (ok,) = address(furniture).call(abi.encodeWithSignature(\"activateMinter(address)\", minter));\n            }\n        }\n        require(ok && furniture.minters(minter), \"grant failed\");\n    }\n\n    function _revoke(address minter) internal {\n        (bool ok,) = address(furniture).call(abi.encodeWithSignature(\"setMinter(address,bool)\", minter, false));\n        if (!ok) (ok,) = address(furniture).call(abi.encodeWithSignature(\"revokeMinter(address)\", minter));\n        require(ok && !furniture.minters(minter), \"revoke failed\");\n    }\n\n    // Minimal RLP header with 14 fields: field 8 = number, field 13 = prevRandao.\n    function _header(uint256 number, bytes32 randao) internal pure returns (bytes memory) {\n        bytes memory payload;\n        for (uint256 i; i < 14; ++i) {\n            if (i == 8) payload = bytes.concat(payload, _str(_uintBytes(number)));\n            else if (i == 13) payload = bytes.concat(payload, _str(abi.encodePacked(randao)));\n            else payload = bytes.concat(payload, hex\"80\");\n        }\n        return bytes.concat(_prefix(payload.length, 0xc0), payload);\n    }\n\n    function _uintBytes(uint256 value) internal pure returns (bytes memory result) {\n        uint256 length;\n        for (uint256 n = value; n != 0; n >>= 8) {\n            ++length;\n        }\n        result = new bytes(length);\n        for (uint256 i; i < length; ++i) {\n            result[length - 1 - i] = bytes1(uint8(value >> (8 * i)));\n        }\n    }\n\n    function _str(bytes memory value) internal pure returns (bytes memory) {\n        if (value.length == 1 && uint8(value[0]) < 0x80) return value;\n        return bytes.concat(_prefix(value.length, 0x80), value);\n    }\n\n    function _prefix(uint256 length, uint8 base) internal pure returns (bytes memory) {\n        if (length < 56) return abi.encodePacked(bytes1(uint8(length) + base));\n        bytes memory size = _uintBytes(length);\n        return bytes.concat(abi.encodePacked(bytes1(base + 55 + uint8(size.length))), size);\n    }\n}","reproduction":"State: furniture.setMinter(box,true); season with fallback item 1 (tier 0, weight 1, cap 0) and item 2 (tier 0, weight 1_000_000, cap 0); buyer approves and calls buy(seasonId, 3) at block 100 -> targetBlock 103. Furniture owner calls setMinter(box,false). At block 104 with the target header (prevRandao = keccak256('og-club-proof')): previewOpen(1, randao) returns [2,2,2]. open(1, header) reverts NotMinter(box). Roll to block 370 (target+267), setMinter(box,true), open(1, header): succeeds, mints 3 x item 1, emits BoxOpened(..., expired=true). Expected: the buyer eventually receives [2,2,2] (the roll that was final at block 104). Actual: buyer holds 3 x fallback item 1 and 0 x item 2. Proof: test/scratch/MinterRevokedRollLost.t.sol fails with 'honest roll was lost: 0 != 3'.","severity":"medium","snippet":"        furniture.mintBatch(purchase.buyer, ids, amounts);","title":"open couples the paid roll to delivery: a revoked box minter turns a pending honest roll into fallbacks after 256 blocks"},{"citation":"resolved","description":"buy() records msg.sender as the only possible recipient and takes full payment, but open() can deliver only through furniture.mintBatch(purchase.buyer, ...) (line 235), which runs OpenZeppelin's ERC1155 receiver check. A buyer contract without onERC1155BatchReceived (a plain multisig, a vault, a contract wallet not implementing ERC-1155 hooks) makes every open() revert with ERC1155InvalidReceiver(buyer). The expired path (fallback-only) runs the same mint, so it reverts as well. The tokens paid to vault and the burn address are not refundable; the purchase stays pending forever. The README documents this as a hard limitation, but it is a loss of the whole payment for a foreseeable class of buyers and the existing test test_ContractBuyerWithoutReceiverCannotBeOpenedButStateIsUntouched codifies the loss as expected. Requester's change 2 (try/catch delivery, deliverTo by the buyer) is the fix.","line":207,"path":"src/OGClubBox.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {OGClubBox} from \"src/OGClubBox.sol\";\nimport {OGClubFurniture} from \"src/OGClubFurniture.sol\";\nimport {MockOG} from \"src/mocks/MockOG.sol\";\n\n/// @dev A buyer contract with no ERC-1155 receiver hooks (a plain multisig-style wallet or a vault).\ncontract PlainWalletBuyer {\n    OGClubBox public immutable box;\n\n    constructor(OGClubBox box_, IERC20 token_) {\n        box = box_;\n        token_.approve(address(box_), type(uint256).max);\n    }\n\n    function buy(uint256 seasonId, uint256 count) external returns (uint256) {\n        return box.buy(seasonId, count);\n    }\n\n    function deliverTo(uint256 purchaseId, address to) external {\n        (bool ok, bytes memory reason) =\n            address(box).call(abi.encodeWithSignature(\"deliverTo(uint256,address)\", purchaseId, to));\n        require(ok, string(reason));\n    }\n}\n\n/// @notice The box accepts payment from a contract buyer that cannot receive ERC-1155 tokens, then can never\n///         open its purchase: every `open` reverts in the receiver check, before and after expiry, so the\n///         payment is lost and the roll is never recorded.\n/// @dev Fails on the current code at the first assertion (open reverts because delivery fails). Passes once\n///      `open` records the roll and reports DeliveryFailed, and the buyer can `deliverTo` another address.\ncontract NonReceiverBuyerLosesPurchaseTest is Test {\n    MockOG internal token;\n    OGClubFurniture internal furniture;\n    OGClubBox internal box;\n    PlainWalletBuyer internal wallet;\n    address internal vault = makeAddr(\"vault\");\n    address internal eoa = makeAddr(\"eoa\");\n    uint256 internal seasonId;\n\n    function setUp() public {\n        vm.roll(100);\n        vm.warp(1000);\n        token = new MockOG(address(this));\n        furniture = new OGClubFurniture(address(this), vault);\n        box = new OGClubBox(token, furniture, vault, address(this));\n        _grant(address(box));\n        wallet = new PlainWalletBuyer(box, token);\n        token.mint(address(wallet), 1_000_000 ether);\n\n        OGClubBox.Entry[] memory entries = new OGClubBox.Entry[](2);\n        entries[0] = OGClubBox.Entry(1, 0, 60, 0);\n        entries[1] = OGClubBox.Entry(2, 1, 40, 0);\n        seasonId = box.createSeason(100, 1000, 100_000, 5000, 1, entries);\n    }\n\n    function test_openDoesNotRevertForNonReceiverBuyerAndBuyerCanRedirectDelivery() public {\n        uint256 balanceBefore = token.balanceOf(address(wallet));\n        uint256 purchaseId = wallet.buy(seasonId, 2);\n        assertEq(token.balanceOf(address(wallet)), balanceBefore - 200, \"buyer paid in full\");\n        (,,, uint256 targetBlock,) = box.purchases(purchaseId);\n\n        bytes32 randao = keccak256(\"og-club-proof-2\");\n        bytes memory header = _header(targetBlock, randao);\n        vm.roll(targetBlock + 1);\n        vm.setBlockhash(targetBlock, keccak256(header));\n        uint256[] memory expected = box.previewOpen(purchaseId, randao);\n\n        (bool ok,) = address(box).call(abi.encodeCall(box.open, (purchaseId, header)));\n        assertTrue(ok, \"open reverted because the buyer cannot receive ERC-1155: paid roll is unrecoverable\");\n\n        (,,,, bool opened) = box.purchases(purchaseId);\n        assertTrue(opened, \"purchase must be marked opened\");\n\n        // The buyer redirects delivery to an address that can hold the pieces.\n        wallet.deliverTo(purchaseId, eoa);\n        uint256 total;\n        for (uint256 i; i < expected.length; ++i) {\n            total += 1;\n            assertGt(furniture.balanceOf(eoa, expected[i]), 0, \"expected piece not delivered\");\n        }\n        assertEq(furniture.balanceOf(eoa, 1) + furniture.balanceOf(eoa, 2), total, \"delivered count\");\n    }\n\n    function _grant(address minter) internal {\n        (bool ok,) = address(furniture).call(abi.encodeWithSignature(\"setMinter(address,bool)\", minter, true));\n        if (!ok) (ok,) = address(furniture).call(abi.encodeWithSignature(\"grantMinter(address)\", minter));\n        require(ok && furniture.minters(minter), \"grant failed\");\n    }\n\n    function _header(uint256 number, bytes32 randao) internal pure returns (bytes memory) {\n        bytes memory payload;\n        for (uint256 i; i < 14; ++i) {\n            if (i == 8) payload = bytes.concat(payload, _str(_uintBytes(number)));\n            else if (i == 13) payload = bytes.concat(payload, _str(abi.encodePacked(randao)));\n            else payload = bytes.concat(payload, hex\"80\");\n        }\n        return bytes.concat(_prefix(payload.length, 0xc0), payload);\n    }\n\n    function _uintBytes(uint256 value) internal pure returns (bytes memory result) {\n        uint256 length;\n        for (uint256 n = value; n != 0; n >>= 8) {\n            ++length;\n        }\n        result = new bytes(length);\n        for (uint256 i; i < length; ++i) {\n            result[length - 1 - i] = bytes1(uint8(value >> (8 * i)));\n        }\n    }\n\n    function _str(bytes memory value) internal pure returns (bytes memory) {\n        if (value.length == 1 && uint8(value[0]) < 0x80) return value;\n        return bytes.concat(_prefix(value.length, 0x80), value);\n    }\n\n    function _prefix(uint256 length, uint8 base) internal pure returns (bytes memory) {\n        if (length < 56) return abi.encodePacked(bytes1(uint8(length) + base));\n        bytes memory size = _uintBytes(length);\n        return bytes.concat(abi.encodePacked(bytes1(base + 55 + uint8(size.length))), size);\n    }\n}","reproduction":"State: furniture.setMinter(box,true); season price 100, burnBps 5000, entries item 1 (tier 0, w 60) and item 2 (tier 1, w 40). PlainWalletBuyer (no ERC-1155 hooks) approves the box and calls buy(seasonId, 2): 200 tokens leave the wallet (100 burned, 100 to vault). At block targetBlock+1 with the target header (prevRandao keccak256('og-club-proof-2')): open(1, header) reverts ERC1155InvalidReceiver(wallet). At block targetBlock+300: open(1, '') reverts the same way. Expected: a paid purchase can be opened and its pieces reach a recipient the buyer controls. Actual: 200 tokens paid, open() reverts forever, nothing is ever minted. Proof: test/scratch/NonReceiverBuyerLosesPurchase.t.sol fails at 'open reverted because the buyer cannot receive ERC-1155: paid roll is unrecoverable'.","severity":"medium","snippet":"        purchases[purchaseId] = Purchase(msg.sender, seasonId, count, targetBlock, false);","title":"buy accepts payment from a contract buyer that cannot receive ERC-1155; that purchase can never be opened, before or after expiry"},{"citation":"resolved","description":"setMinter takes effect in the same transaction and mintBatch (line 49-52) has no per-id limit, so the furniture owner (or any address it authorizes) can mint unlimited copies of any itemId at any time, including pieces a season sells with a cap. The box's caps live only in OGClubBox.minted and are not known to the furniture contract, so a capped Legendary with cap 1 can exist in 101 copies one block after the owner decides so. Holders have no notice period to react. This is an intentional owner role and is documented in the README (line 161-162), so it is reported as a trust assumption that breaks the published scarcity guarantee rather than a permission bypass. It also matches the launch rule against unbounded post-launch minting by a privileged account. The requester's change 1 (grantMinter with a 7-day MINTER_DELAY once totalSupply() > 0, immediate only on a fresh deployment, plus activate/cancel/revoke) is a minimal fix that preserves the box's own minting.","line":42,"path":"src/OGClubFurniture.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {OGClubFurniture} from \"src/OGClubFurniture.sol\";\n\n/// @notice Once the collection exists, the furniture owner can authorize itself and mint any piece, in any\n///         quantity, in the same block, bypassing every season cap and the box's odds.\n/// @dev Fails on the current code: `setMinter(owner, true)` then `mintBatch` succeeds immediately. Passes once a\n///      new minter proposed after the first mint must wait MINTER_DELAY before it can mint.\ncontract OwnerMintsImmediatelyTest is Test {\n    OGClubFurniture internal furniture;\n    address internal firstMinter = makeAddr(\"box\");\n    address internal holder = makeAddr(\"holder\");\n    address internal royalty = makeAddr(\"royalty\");\n    uint256 internal constant CAPPED_PIECE = 3;\n\n    function setUp() public {\n        vm.warp(1000);\n        furniture = new OGClubFurniture(address(this), royalty);\n        // Fresh deployment: authorizing the box is immediate in both designs.\n        _grant(firstMinter);\n        // The collection now exists: one copy of a piece the box sells with a cap of 1.\n        uint256[] memory ids = new uint256[](1);\n        uint256[] memory amounts = new uint256[](1);\n        ids[0] = CAPPED_PIECE;\n        amounts[0] = 1;\n        vm.prank(firstMinter);\n        furniture.mintBatch(holder, ids, amounts);\n        assertEq(furniture.totalSupply(CAPPED_PIECE), 1);\n    }\n\n    function test_ownerCannotMintPastCapImmediatelyAfterAuthorizingItself() public {\n        // Owner authorizes itself (setMinter today, grantMinter after the change).\n        (bool ok,) = address(furniture).call(abi.encodeWithSignature(\"setMinter(address,bool)\", address(this), true));\n        if (!ok) (ok,) = address(furniture).call(abi.encodeWithSignature(\"grantMinter(address)\", address(this)));\n        require(ok, \"owner could not request minter role\");\n\n        // Same block: owner mints 100 more copies of the capped piece.\n        uint256[] memory ids = new uint256[](1);\n        uint256[] memory amounts = new uint256[](1);\n        ids[0] = CAPPED_PIECE;\n        amounts[0] = 100;\n        (bool minted,) = address(furniture).call(abi.encodeCall(furniture.mintBatch, (holder, ids, amounts)));\n\n        assertFalse(minted, \"owner minted a capped piece past its cap with no delay\");\n        assertEq(furniture.totalSupply(CAPPED_PIECE), 1, \"supply inflated by the owner\");\n    }\n\n    function _grant(address minter) internal {\n        (bool ok,) = address(furniture).call(abi.encodeWithSignature(\"setMinter(address,bool)\", minter, true));\n        if (!ok) (ok,) = address(furniture).call(abi.encodeWithSignature(\"grantMinter(address)\", minter));\n        require(ok && furniture.minters(minter), \"grant failed\");\n    }\n}","reproduction":"State: furniture deployed with owner O; O calls setMinter(boxAddr,true); boxAddr mints 1 x item 3 (totalSupply(3) == 1, e.g. a cap-1 piece sold by a season). Then in one block O calls setMinter(O,true) and mintBatch(holder, [3], [100]). Expected: a new minter authorized after the collection exists cannot mint before a public delay. Actual: both calls succeed, totalSupply(3) == 101. Proof: test/scratch/OwnerMintsImmediately.t.sol fails with 'owner minted a capped piece past its cap with no delay'.","severity":"medium","snippet":"    function setMinter(address minter, bool allowed) external onlyOwner {\n        if (minter == address(0)) revert ZeroAddress();\n        minters[minter] = allowed;\n        emit MinterSet(minter, allowed);\n    }","title":"Furniture owner can authorize itself with setMinter and mint any piece in any quantity immediately, bypassing season caps and box odds"},{"citation":"resolved","description":"Because open() delivers in the same call (line 235), a buyer contract that reverts in onERC1155BatchReceived blocks its own opening without losing the purchase; nobody else can open it. The guaranteed tenth box is the one state-dependent pick: when the rare it selected over the full rare weight has sold out, a derived seed re-rolls among the rares still available. Both outcomes are computable in advance from previewOpen, so a rejecting buyer can hold out exactly when the re-roll is better than the selected rare and accept once another purchase sells that rare out. The README (lines 44-46, 80-88) states that holding out never earns a better roll; this state contradicts it. Risk to the buyer: other picks may degrade to fallback meanwhile, and after 256 blocks everything becomes fallback. Requester's change 2 removes the lever because open() can no longer be blocked by the buyer's receiver; note for the adapter: a receiver that burns all forwarded gas can still make the catch path run out of gas, so the try/catch delivery should forward a bounded gas amount (for example a fixed gas limit on furniture.mintBatch{gas: ...}) or the roll should be stored before the call.","line":376,"path":"src/OGClubBox.sol","reproduction":"State: setUp at block 100, season price 1, entries [fallback item 1 tier 0 w60 cap 0], [item 3 tier 2 w10 cap 1], [item 4 tier 4 w1 cap 0]. PickyBuyer (ERC1155Holder that reverts while reject==true) calls buy(seasonId,10) -> purchase 1; EOA 'other' calls buy(seasonId,1) -> purchase 2, same target block 103. Target header with prevRandao = 0x000000000000000000000000000000000000000000000000000000000000002b (found by searching 1..2000). At block 104: previewOpen(1) gives tenth box = item 3 (Rare) and no item 3 in boxes 0-8; previewOpen(2) = [3]. PickyBuyer sets reject=true; open(1, header) reverts in the receiver. Anyone calls open(2, header): minted[season][3] == 1. previewOpen(1) now gives tenth box = item 4 (Legendary). PickyBuyer sets reject=false; open(1, header) mints item 4 to it. Expected per README: a buyer cannot improve a roll by holding out. Actual: the same purchase yields Legendary instead of Rare because the buyer chose when it would accept. Reproduced by test/scratch/TenPackRerollSearch.t.sol (passes, i.e. the upgrade happens).","severity":"low","snippet":"            picked = _walk(entries, counts, retry % availableRareWeight, true, true);","title":"A contract buyer that rejects its own delivery can wait for a rare to sell out and collect a better ten-pack re-roll"},{"citation":"resolved","description":"This test asserts that a DeafBuyer's purchase reverts in open() both inside the window and at target+300, i.e. it locks in the permanent loss described in finding 2 as the intended behavior and will need to be rewritten with the requester's change 2. No test exercises setMinter(box,false) with a pending purchase, lets the window expire, restores the minter and checks what the buyer gets (finding 1); the two revoke tests restore the minter inside the window (test/Opening.t.sol line 171, test_MinterRevocationFailsAtomicallyUntilRestored) or only check that buy() reverts with BoxNotMinter (test/Seasons.t.sol line 111). No test exercises a rejecting receiver that later accepts after a sell-out of the tenth box's selected rare (finding 4); FixedOdds covers a rejected delivery retried after a sell-out only for degradation to fallback. The invariant suites assert supply == box-minted counts, which the new stored/undelivered state breaks unless updated as the requester's test list describes.","line":261,"path":"test/EdgeCases.t.sol","reproduction":"Run FOUNDRY_FUZZ_SEED=0xd128ae280d16b8fe9fae2867fece2294232031c7e2780fa9c5d34bf71f39fb9d forge test: 81 tests pass at cef6e95 (the task text says 89; the tree holds 81). Then run forge test --match-path 'test/scratch/*': MinterRevokedRollLost, NonReceiverBuyerLosesPurchase and OwnerMintsImmediately fail on the current code, showing the untested behaviors. Expected: a suite that fails on these states. Actual: the suite is green while a paid roll can be lost by the furniture owner's revoke or by a contract buyer's missing hooks.","severity":"low","snippet":"    function test_ContractBuyerWithoutReceiverCannotBeOpenedButStateIsUntouched() public {","title":"Test suite codifies the non-receiver loss as expected and has no test for a revoked box minter across the reveal window"},{"citation":"resolved","description":"Two trust/configuration notes for the adapter and the manifest review, not defects in the code as written. (a) OGClubFurniture cannot know the box address in its constructor because the box takes the furniture address as a constructor argument and the manifest only references earlier contracts, so the requester keeps grantMinter(box) as a post-deploy step. Until it runs, buy() reverts with BoxNotMinter (src/OGClubBox.sol line 199), so no payment is taken; after the requester's change 1 it must run before any mint or it incurs the 7-day delay. (b) launch.json deploys MockOG as the payment token with an unrestricted mint(address,uint256) (src/mocks/MockOG.sol line 18) and uses $owner as vault and royalty receiver; anyone can mint themselves tokens and buy boxes for free. The notes state this is a Sepolia testnet launch, which is consistent, but the same manifest must not be reused for a mainnet launch. No proxies, delegatecall, selfdestruct, holder-balance freezing or seizure were found in src/: setPaused stops only buy(), never transfers or open(). Coverage: Contracts read in full: src/OGClubBox.sol, src/OGClubFurniture.sol, src/libraries/BlockHeader.sol, src/mocks/MockOG.sol, script/Deploy.s.sol, launch.json, README.md, test/helpers/*, test/EdgeCases.t.sol (partially), the two protected tests. Vendored OpenZeppelin 5.0.2 (ERC1155, ERC1155Supply, ERC2981, Ownable2Step, ReentrancyGuard, SafeERC20) was relied on, not re-audited. Passes applied: entry-point inventory (buy, open, createSeason, closeSeason, cancelSeason, setPaused, setVault, setMinter, mintBatch, setBaseURI, freezeMetadata, setRoyalty, ownership), reentrancy (both guards hold; callback re-entry into buy/open blocked), payment accounting (_pay balance checks, box balance stays 0, vault self-pay), randomness/time (blockhash window boundary at target+256 correct; prevRandao one-bit proposer bias documented), RLP parser (canonical checks, authenticated by blockhash), weighted roll and cap simulation (totals consistent, _walk cannot revert). Not done: Slither/Aderyn (not installed on this worker), fuzzing beyond the project's own invariant suites.","line":196,"path":"README.md","reproduction":"After deployment per launch.json: any address A calls MockOG.mint(A, 1e30) then approve(box) and buy(seasonId,10) at no cost. Before furniture.setMinter(box,true): buy(seasonId,1) reverts BoxNotMinter. Expected and actual agree with the documentation; recorded so the adapter keeps grantMinter(box) in the post-deploy steps and the manifest review treats MockOG as testnet-only.","severity":"info","snippet":"1. Call `furniture.setMinter(box, true)` with the confirmed box address. Until","title":"Box minter authorization is a post-deployment owner call rather than constructor configuration; payment token on this launch is a free-mint mock"}],"hash":"83c1b88aa7cb9f89ff1b2e879bd8f819c41fff7f3dad3c9b4c65fd2b1e9b1caa","nodeId":"23d4b534-a050-4da0-8de8-ea89a94d4c88","outcome":"completed","summary":"The README references in the descriptions match the tree. The review is complete and the findings file is final.\n\n**Outcome:** `.imd-findings.json` holds 6 findings against commit cef6e95. No file in the tree was changed; the scratch tests and the generator script live in the gitignored `test/scratch/` directory.\n\n**Findings, most severe first**\n\n- **Medium, OGClubBox open at line 235:** the roll and the mint are one transaction. While the furniture owner has revoked the box, every open reverts, and after 256 blocks the paid roll becomes fallbacks. Proof attached. It fails on the current code with \"honest roll was lost: 0 != 3\".\n- **Medium, OGClubBox buy at line 207:** a contract buyer without ERC-1155 receiver hooks pays in full and can never open, before or after expiry. Proof attached. It fails at the open call.\n- **Medium, OGClubFurniture setMinter at line 42:** the owner can authorize itself and mint a capped piece past its cap in the same block. Reported as a trust assumption that breaks the published scarcity guarantee. Proof attached.\n- **Low, OGClubBox line 376:** a contract buyer that rejects its own delivery can wait for its tenth box's selected rare to sell out and collect a better re-roll. Concrete input found: prevRandao `0x2b` with the season in the scratch test upgrades Rare to Legendary. The scratch test reproduces it. The description also warns the adapter that a gas-burning receiver can starve the catch path of the planned try/catch, so delivery should forward bounded gas or store the roll before the call.\n- **Low, test suite:** the existing non-receiver test codifies the loss as expected, and no test covers a revoke that spans the reveal window.\n- **Info, README line 196:** post-deploy grantMinter(box) is unavoidable given constructor ordering, and the manifest's MockOG payment token is free-mint testnet-only. This entry also carries the coverage statement.\n\n**Checks actually run**\n\n```\nforge build                       # ok\nFOUNDRY_FUZZ_SEED=0xd128... forge test   # 81 passed, 0 failed (task text says 89; tree holds 81)\nforge test --match-path 'test/scratch/*' # 3 proofs fail as stated, 1 search test passes\n```\n\n**Coverage:** read in full were both application contracts, the BlockHeader library, MockOG, the deploy script, the manifest, the README, the test helpers and the protected tests. OpenZeppelin 5.0.2 was relied on, not re-audited. Slither and Aderyn are not installed on this worker, so no static analysis ran. The three medium findings are exactly the behaviours the requester's two requested changes address, so the adapter can use the proofs as acceptance tests for that work.","treeHash":null,"usage":{"cachedInputTokens":1875518,"inputTokens":674,"model":"claude-fable-5-1","outputTokens":37285,"runtime":"claude","turns":40,"wallClockMs":546822}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"da7ed792c3bf5b80","findings":[],"hash":"a3a20f68dd4af2c62ef93faa873857245cd848c2ee23716acd432d248316da7e","nodeId":"bfd86e97-529a-49b3-a7b5-e4999f9d07fc","outcome":"completed","summary":"This round's review is done. Both questions from last round are settled: the one blocking finding is fixed, and none of the advisory points needs a code change. `.imd-findings.json` has no findings and a coverage row for each of the 26 entry points, all marked `holds`.\n\n**Blocking finding: gas-starved opens took the delivery-failure path (a01cf289). Fixed.**\n- **What changed:** in `src/OGClubBox.sol:257-259`, `open` now checks the remaining gas just before delivery. If less than `OPEN_DELIVERY_GAS` (1,300,000) is left, it reverts with `InsufficientGas` and the whole call is undone. Otherwise the mint always gets its full 1,000,000 gas. EVM call rules hold back 1/64 of the gas, so about 1.28M is available and the full 1M budget always fits. The remaining 300,000 is enough to store a ten-item roll if the mint fails.\n- **Why it still meets the brief:** a short gas limit is the caller's mistake, not a delivery failure, so \"open must not revert because of delivery\" still holds. Gas estimation now finds the lowest limit that passes the check, and at that limit the purchase is delivered.\n- **Proofs:** I copied both supplied proofs (`Proof_a01cf2893652`, `Proof_10ee1bb96996`) into `test/scratch/` and ran them against the revised code. Both pass now; both failed before the fix.\n- **Checks:** `forge test` passes 113 tests, 0 failing, and `forge fmt --check` is clean. I deleted the scratch copies afterwards; the repository is unchanged.\n\n**Advisory points: no code change needed.**\n- **The 7-day minter delay doesn't stop a new season from reusing a capped piece:** this is how the delivered design already worked: caps are per season, and the brief said to keep existing behaviour. The README now names it as a trust assumption on the owner. I'm not raising it again.\n- **The delay only starts at the first delivered mint:** this is the brief's own rule (immediate while `totalSupply() == 0`). The README now says opened rolls that weren't delivered don't start the 7-day delay.\n- **A ten-pack holder can choose the opening order to improve the guaranteed tenth pick:** this behaviour predates this change and the README already documents it. Recorded as residual, not a defect.\n- **`launch.json` told the owner to call the removed `setMinter`:** four specialists raised this; it's fixed. The note now says `grantMinter(box)` right after deployment, before any mint.\n\n**Static-analysis leads:** I checked all of them and none hold up.\n- The reentrancy warnings are covered by `nonReentrant` on `buy`, `open` and `deliver`. The purchase is recorded and opened before any external call, and delivered is marked before minting.\n- The \"uninitialized local\" and \"strict equality\" lines are deliberate zero-starts and sentinel checks.\n\nI found no new defects in the changed code.","treeHash":null,"usage":{"cachedInputTokens":648682,"inputTokens":16,"model":"claude-opus-5-5","outputTokens":5331,"runtime":"claude","turns":9,"wallClockMs":219133}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"0ef0cddb99617930","findings":[{"citation":"resolved","description":"Merged from audit_permissions (medium), audit_economics (low), audit_flow (low) and write_foundry_tests (info): one root cause. open() forwards min(1,000,000, gasleft() - 300,000) to furniture.mintBatch and swallows any failure, including the inner out-of-gas. Whether an EOA buyer with an authorized box is delivered at open therefore depends only on the gas the opener attached, and the catch path (storing up to ten IDs) is cheaper than the mint, so it always fits once the reserve is left. Two consequences. (1) Default tooling: eth_estimateGas searches for the lowest gas at which the transaction does not revert; because the inner OOG is caught, that lowest value is the DeliveryFailed path. Measured on this tree: a fully funded 10-box open uses 454,838 gas, and 1.5x that limit (682,257) still succeeds with DeliveryFailed; delivery starts at about 727,740 (1.59x). For one box, delivery needs about 2.2x the estimate. So a wallet sending the estimate plus the usual buffer never delivers, writes the ten-slot stored-items array the brief says the normal path must never add, and the buyer needs a second deliver transaction. (2) Griefing: open is permissionless, so any third party can choose the buyer's path by attaching ~1.0-1.5x gas. No funds or roll are lost (the roll is recorded, caps reserved, deliver is permissionless), so this is medium: a broken guarantee under default conditions ('on success mark delivered', 'the normal path adds no storage') and a misleading DeliveryFailed signal, not a loss. Minimal design-preserving fix: revert at the top of open, before any state change, when gasleft() is below a published minimum (for example OPEN_MINT_GAS_LIMIT + DELIVERY_RESERVE_GAS plus the roll's cost, with an InsufficientGas error). That is a caller precondition, not a delivery failure, so 'open must not revert because of delivery' still holds; estimation then lands above the threshold and the mint always receives the full OPEN_MINT_GAS_LIMIT. Document the minimum in the README, which today only says 'supply enough transaction gas'.","line":250,"path":"src/OGClubBox.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {OGClubBox} from \"src/OGClubBox.sol\";\nimport {OGClubFurniture} from \"src/OGClubFurniture.sol\";\nimport {MockOG} from \"src/mocks/MockOG.sol\";\n\n/// @dev Minimal RLP header builder: 16 fields, field 8 = number, field 13 = mixHash.\nlibrary MiniHeader {\n    function rlpBytes(bytes memory s) internal pure returns (bytes memory) {\n        if (s.length == 1 && uint8(s[0]) < 0x80) return s;\n        return bytes.concat(prefix(s.length, 0x80), s);\n    }\n\n    function prefix(uint256 len, uint8 base) internal pure returns (bytes memory) {\n        if (len < 56) return abi.encodePacked(uint8(base + len));\n        bytes memory lenBytes = uintBytes(len);\n        return bytes.concat(abi.encodePacked(uint8(base + 55 + lenBytes.length)), lenBytes);\n    }\n\n    function uintBytes(uint256 v) internal pure returns (bytes memory out) {\n        if (v == 0) return out;\n        uint256 n;\n        for (uint256 t = v; t != 0; t >>= 8) ++n;\n        out = new bytes(n);\n        for (uint256 i; i < n; ++i) {\n            out[n - 1 - i] = bytes1(uint8(v >> (8 * i)));\n        }\n    }\n\n    function header(uint256 number, bytes32 mixHash) internal pure returns (bytes memory) {\n        bytes memory payload;\n        for (uint256 i; i < 16; ++i) {\n            bytes memory field;\n            if (i == 8) field = uintBytes(number);\n            else if (i == 13) field = abi.encodePacked(mixHash);\n            else if (i == 2) field = abi.encodePacked(address(0xBEEF));\n            else if (i == 0 || i == 1 || i == 3 || i == 4 || i == 5) field = abi.encodePacked(bytes32(uint256(i + 1)));\n            else if (i == 6) field = new bytes(256);\n            else field = uintBytes(i + 1);\n            payload = bytes.concat(payload, rlpBytes(field));\n        }\n        return bytes.concat(prefix(payload.length, 0xc0), payload);\n    }\n}\n\n/// @notice An EOA buyer whose box is an authorized minter must either be delivered at open or see open revert.\n///         Today a caller that supplies 1.5x the gas a successful open consumes gets DeliveryFailed instead,\n///         because the mint is starved of gas inside try/catch while the catch path still fits.\ncontract OpenGasDeliveryTest is Test {\n    MockOG internal token;\n    OGClubFurniture internal furniture;\n    OGClubBox internal box;\n    address internal buyer = makeAddr(\"buyer\");\n    uint256 internal seasonId;\n\n    function setUp() public {\n        vm.roll(100);\n        vm.warp(1000);\n        token = new MockOG(address(this));\n        furniture = new OGClubFurniture(address(this), address(this));\n        box = new OGClubBox(token, furniture, makeAddr(\"vault\"), address(this));\n        furniture.grantMinter(address(box));\n        token.mint(buyer, 1_000_000 ether);\n        vm.prank(buyer);\n        token.approve(address(box), type(uint256).max);\n        OGClubBox.Entry[] memory entries = new OGClubBox.Entry[](3);\n        entries[0] = OGClubBox.Entry(1, 0, 60, 0);\n        entries[1] = OGClubBox.Entry(2, 1, 30, 4);\n        entries[2] = OGClubBox.Entry(3, 2, 10, 3);\n        seasonId = box.createSeason(101, 1000, 100_000, 3333, 1, entries);\n    }\n\n    function _ready(uint256 purchaseId, bytes32 randao) internal returns (bytes memory header) {\n        (,,, uint256 targetBlock,) = box.purchases(purchaseId);\n        vm.roll(targetBlock + 1);\n        header = MiniHeader.header(targetBlock, randao);\n        vm.setBlockhash(targetBlock, keccak256(header));\n    }\n\n    function test_OpenWithEstimatedGasPlusHalfMustDeliverOrRevert() public {\n        vm.prank(buyer);\n        uint256 purchase = box.buy(seasonId, 10);\n        bytes memory header = _ready(purchase, keccak256(\"gas estimate\"));\n\n        // Measure what a fully funded, successful open consumes: this is what eth_estimateGas reports.\n        uint256 snapshot = vm.snapshotState();\n        uint256 before = gasleft();\n        box.open(purchase, header);\n        uint256 used = before - gasleft();\n        assertTrue(box.delivered(purchase), \"fully funded open delivers\");\n        assertTrue(vm.revertToState(snapshot));\n\n        // Same call with 1.5x that measurement, as a wallet with a generous buffer would send it.\n        uint256 limit = used * 3 / 2;\n        (bool ok,) = address(box).call{gas: limit}(abi.encodeCall(box.open, (purchase, header)));\n        (,,,, bool opened) = box.purchases(purchase);\n        if (ok) {\n            assertTrue(opened);\n            assertTrue(\n                box.delivered(purchase),\n                \"open succeeded with 1.5x the measured gas but silently took the DeliveryFailed path\"\n            );\n            assertEq(box.getStoredItems(purchase).length, 0, \"normal path must add no storage\");\n        }\n    }\n}","reproduction":"State: test/helpers/BoxTestBase.sol setup (furniture.grantMinter(box) at zero supply, EOA buyer, 3-entry season). buyer: box.buy(seasonId, 10). Roll to targetBlock+1, vm.setBlockhash(targetBlock, keccak256(header)). Snapshot; box.open(purchase, header) with ample gas; measure gas used U = 454,838; delivered(purchase) == true; revert the snapshot. Then address(box).call{gas: U*3/2}(abi.encodeCall(box.open, (purchase, header))). Expected: either the call reverts, or delivered(purchase) == true and getStoredItems(purchase).length == 0. Actual: the call returns true, purchases(purchase).opened == true, delivered(purchase) == false, getStoredItems(purchase) holds the ten rolled IDs, DeliveryFailed(purchase) was emitted and furniture.totalSupply() == 0. Same behaviour from a stranger with box.open{gas: 600_000}(purchase, header) (the permanent test test_GasStarvedOpenOfHonestBuyerStoresRollAndAnyoneDeliversLater pins it). The attached proof (the specialist's, rerun here) fails on this tree with 'open succeeded with 1.5x the measured gas but silently took the DeliveryFailed path'.","severity":"medium","snippet":"        mintGas = mintGas > DELIVERY_RESERVE_GAS ? Math.min(OPEN_MINT_GAS_LIMIT, mintGas - DELIVERY_RESERVE_GAS) : 0;","title":"open forwards caller-chosen gas to the mint inside try/catch, so gas-estimated and low-gas opens of a healthy purchase land on the DeliveryFailed path instead of delivering"},{"citation":"resolved","description":"Merged from audit_economics (medium) and audit_flow (low). createSeason is owner-only with no notice period and accepts any itemId as an uncapped tier-0 fallback, including an ID an earlier season sold as a cap-1 Legendary; caps are per season (minted[seasonId][itemId]). The box is a permanent, already-active minter, so when the same account owns both contracts (launch.json gives both to $owner) the owner can mint a capped piece in any quantity while their own direct-minter proposal is still pending, and at zero token cost: setVault(owner) is allowed (only the box address is rejected) and _pay's self-transfer leg requires no gain (expected = 0), and burnBps = 0 skips the burn leg. The requested guarantee ('the owner cannot mint a capped piece past its cap within 7 days of proposing a new minter') therefore only covers the direct furniture route that test_OwnerCannotMintCappedPieceWithinSevenDaysOfProposal exercises. The README documents that caps are per season and that the delay 'provides public notice for new permissions, not global collection caps', and the brief asked to keep every other behaviour unchanged, so this is recorded as a trust assumption on the box owner rather than a permission bypass: low, not medium. Closing it needs a scope decision (a season-creation notice period, rejecting an uncapped entry for an itemId an earlier season capped, or a collection-level cap in the furniture); none is prescribed here.","line":158,"path":"src/OGClubBox.sol","reproduction":"State: season 1 = {item 1 tier 0 weight 99 cap 0 (fallback), item 5 tier 4 weight 1 cap 1}; buyer buys and opens one box so totalSupply() > 0; owner calls furniture.grantMinter(owner) -> minters(owner) == false, pendingMinters(owner) == now + 7 days. Owner then: box.setVault(owner); s2 = box.createSeason(1, 1000, 100_000, 0, 5, [{itemId 5, tier 0, weight 1, cap 0}]) -> accepted (line 158 checks only tier 0 and cap 0); token.approve(box, max); five times box.buy(s2, 10) -> owner's token balance unchanged; vm.roll(+300); box.open(id, \"\") for each (expired path mints the fallback = item 5). Expected per the stated guarantee: no new supply of the capped piece before a proposal activates. Actual: furniture.balanceOf(owner, 5) == 50, block.timestamp unchanged, no MinterProposed needed. Reproduced in test/scratch/Judge.t.sol::test_OwnerMintsCappedPieceViaNewSeasonWithoutDelay (passes on this tree, i.e. the behaviour is confirmed; the owner contract must be an ERC1155Holder or use deliverTo, otherwise the roll is stored, not delivered).","severity":"low","snippet":"            if (entry.itemId == fallbackItem && entry.cap == 0 && entry.tier == 0) validFallback = true;","title":"The seven-day minter notice does not bound the owner: a new season through the already-authorized box mints any earlier-capped piece past its cap at once and for free"},{"citation":"resolved","description":"Merged from audit_permissions (low) and write_foundry_tests (info). grantMinter is immediate whenever ERC1155Supply.totalSupply() == 0, which is the brief's literal condition. Supply counts only delivered furniture, and with change 2 every open now succeeds even when the box is revoked, storing the roll instead of minting. So after real money has been paid and capped pieces have been reserved by recorded rolls, the furniture owner can still grant any address with zero notice as long as every opened purchase is undelivered (box revoked before the first open, or buyers that reject delivery), mint capped pieces past their season caps, and re-grant the box, also instantly. Zero-amount mints also leave supply at zero. This matches the agreed design (the permanent tests test_ImmediateGrantStaysOpenWhileOnlyUndeliveredRollsExist and test_ZeroAmountMintsLeaveSupplyZeroAndGrantsImmediate pin it) and is owner-driven, so it is a trust-gap note, not an exploit; it is reported because it is the exact window the notice period was commissioned to close and it opens the moment sales start. A possible scope decision: arm the delay on the first grant (a one-way flag set by the first grantMinter keeps 'grantMinter(box) right after deployment' immediate and the event-rebuild property) or when any minter is active.","line":51,"path":"src/OGClubFurniture.sol","reproduction":"Fresh deployment; owner grantMinter(box) (immediate). Season {item 1 tier 0 weight 99 cap 0, item 5 tier 4 weight 1 cap 1}. buyer buy(season, 10) and pays. Roll past targetBlock, set header. Owner revokeMinter(box). open(purchase, header): succeeds, DeliveryFailed, getStoredItems(purchase).length == 10, furniture.totalSupply() == 0. Owner grantMinter(stranger): expected under a stricter reading MinterProposed with a 7-day activatesAt; actual minters(stranger) == true immediately. Owner grantMinter(box): also immediate. stranger mintBatch(stranger, [5], [100]) succeeds: totalSupply(5) == 100 with zero notice after sales began; box.deliver(purchase) then delivers the buyer's roll. Reproduced in test/scratch/Judge.t.sol::test_ImmediateGrantAfterSalesWhileRollsUndelivered (passes on this tree).","severity":"low","snippet":"        if (totalSupply() == 0) {","title":"Minter delay is armed by the first delivered mint, not by the first sale: paid, opened, undelivered rolls leave grantMinter immediate while totalSupply() == 0"},{"citation":"resolved","description":"From audit_economics (low), recalibrated to info. open is permissionless and every pending roll is public via previewOpen. The guaranteed tenth pick first selects over the full rare weight and only re-rolls among the remaining rares when that selection has sold out (lines 446-448). A ten-pack holder can preview both outcomes and, when the re-roll is better, first open another pending purchase that consumes the last unit of the originally selected rare, then open their own. The other purchase receives exactly its own roll, so there is no direct victim; what degrades is the published odds (the holder picks the better of two tiers). This is pre-existing behaviour the brief asked to keep unchanged, and the README already documents the tenth pick as state-dependent and that ordering affects availability, so it is recorded as a documented residual only. If the owner wants to close it: degrade a sold-out tenth selection to the ordinary roll instead of re-rolling.","line":446,"path":"src/OGClubBox.sol","reproduction":"Season: fallback item 1 (tier 0, weight 1000, cap 0), item 2 (tier 2 Rare, weight 10, cap 1), item 3 (tier 4 Legendary, weight 1, cap 0). alice buys a ten-pack pA and victim buys one box pV in the same block (same target). After the target block, search randao values until previewOpen(pA, randao)[9] == 2 and previewOpen(pV, randao)[0] == 2, then set the header for that randao. Order 1: alice opens pA first -> alice receives item 2 (Rare). Order 2 (from the same snapshot): alice opens pV first (anyone may) -> victim receives item 2, the Rare sells out, previewOpen(pA)[9] becomes 3; alice opens pA -> alice receives item 3 (Legendary) and no item 2. Expected: the tenth pick's tier does not depend on a choice made after seeing both outcomes. Actual: the holder chooses the better tier. Reproduced in test/scratch/Judge.t.sol::test_TenPackHolderOrdersOpensToUpgradeTenthPick (passes on this tree).","severity":"info","snippet":"        if (!_available(entries[picked], counts[picked])) {","title":"Ten-pack holder has a free option on the guaranteed tenth pick by choosing the opening order of other pending purchases"}],"hash":"c0a695b5dd623a75ac780643cd7e22fd4a1e4b17974ee4190bc78b41b2bc3675","nodeId":"bfd86e97-529a-49b3-a7b5-e4999f9d07fc","outcome":"completed","summary":"The review is complete. `.imd-findings.json` holds four findings and a 29-row coverage record (all 26 entry points plus three invariant rows). The tree has no other changes; git status is clean apart from the findings file, which is gitignored.\n\n**What I kept, after reproducing each against the code**\n\n- **Medium, open gas starvation** (src/OGClubBox.sol:250). Four specialists reported the same root cause and I merged them. The mint inside try/catch gets caller-chosen gas, so a healthy EOA purchase lands on DeliveryFailed whenever the opener sends the gas estimate plus a normal buffer, and any stranger can force that path. The specialist's proof fails on this tree for exactly the stated reason, so it is attached. No funds or roll are lost, so medium rather than high.\n- **Low, owner bypasses the notice via a new season** (src/OGClubBox.sol:158). Merged from economics and flow. An earlier-capped item can be re-listed as an uncapped fallback in a 1-wei season with the owner as vault, and self-pay costs nothing. Confirmed with a scratch test. The README documents per-season caps and the brief kept this behavior, so it is a trust assumption, not a bypass.\n- **Low, delay armed by delivered supply, not sales** (src/OGClubFurniture.sol:51). Merged from permissions and the tester. Opened but undelivered rolls leave the immediate grant open. Confirmed with a scratch test. It matches the brief's literal condition, so it is a scope note.\n- **Info, ten-pack opening-order option** (src/OGClubBox.sol:446). Reproduced with a randao search. Pre-existing and documented in the README as state-dependent.\n\n**What I dropped**\n\n- The launch.json setMinter note, reported by four specialists, does not reproduce. Line 27 of the manifest in this tree already instructs grantMinter(box) before any mint.\n\n**My own pass** found nothing beyond the specialists' leads. The suite passes (107 tests) and forge fmt --check passes. I traced open, deliver, deliverTo and the four minter functions: state is settled before every external call, all delivery paths share the guard, and a failed retry restores both the flag and the stored items.","treeHash":null,"usage":{"cachedInputTokens":841195,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":24135,"runtime":"claude","turns":25,"wallClockMs":350134}},{"artifacts":[],"attempt":1,"bundleHash":"5bb0a54c38be13a713260b4ca0f4cdb3f659907bcf068e2f52ee61297460457e","device":"c0d25825e3f9518b","findings":[],"hash":"d239ced88fb69fadb2993ee0c86b3a2c999c31421b02630528ec873a12d2af8a","nodeId":"50003871-0028-4fc1-b896-3dfabf395c74","outcome":"completed","summary":"Implemented the seven-day minter delay and recoverable, one-time delivery. Updated tests, README, and ADAPTATION.md.\n\nValidation passed:\n\n- `forge build`\n- `forge test`: 95 permanent tests, using the supplied fuzz seed\n- All three supplied audit proofs\n- `forge fmt --check`\n\nProtected configuration and dependencies remain unchanged. No deployment performed.","treeHash":"922673fbb6c9a67ea60c02e5557f6e8ba5e41b07","usage":{"cachedInputTokens":1709952,"inputTokens":109318,"model":"gpt-6-astra","outputTokens":27715,"runtime":"codex","turns":8,"wallClockMs":965907}},{"artifacts":[],"attempt":1,"bundleHash":"1e65a383526ddb5bd7c18a7a1ebca5e1bf0baabe57fc004f34c7323d45d31433","device":"771f83f312eace21","findings":[],"hash":"d91947614345584afa225d6710be28e4b558b50ef086515ce8e461c2e7f3648f","nodeId":"50003871-0028-4fc1-b896-3dfabf395c74","outcome":"completed","summary":"The revision is complete. The reopened finding reproduced and is fixed; the three advisory findings are answered as disputed with reasons.\n\n**What reproduced.** The reviewer's proof failed on the starting tree exactly as reported. `open` forwarded whatever gas was left minus the reserve to the mint, and caught a starved mint as a delivery failure. A caller attaching the estimated gas plus a buffer therefore stored a healthy buyer's roll instead of delivering it.\n\n**What changed.**\n- `src/OGClubBox.sol`: `open` now reverts with `InsufficientGas(required, available)` when fewer than the new public constant `OPEN_DELIVERY_GAS` (mint budget plus reserve, 1.3M) remain at the delivery step. The mint always receives the full 1M budget. `DELIVERY_RESERVE_GAS` is now public. The check sits at the delivery step rather than the top so it is exact for every season size, and the revert undoes the whole call, so a short caller records nothing.\n- `test/OpenGas.t.sol` (new): short limits revert untouched with the explicit error; for every count and fuzzed randao the lowest succeeding limit delivers and stores nothing while one unit less reverts; at that exact boundary a receiver that burns the whole mint budget or returns a huge revert payload still has ten distinct IDs stored, proving the reserve holds; constants are consistent.\n- `test/Delivery.t.sol`: the hostile-receiver test no longer hard-codes a 1.2M limit, which the precondition rejects for a 32-entry ten-pack.\n- `README.md`: documents the precondition, constants and measured minimum limits, that supply counts delivered furniture only so undelivered rolls do not arm the minter delay, and that a new season may reuse a capped ID as a trust assumption on the box owner.\n- `ADAPTATION.md`: revision section and updated change table.\n- `.imd-responses.json`: one fixed, three disputed with detail.\n\n**Advisory findings.** Reusing a capped ID in a new season, arming the delay on delivered supply only, and the tenth-pick ordering effect all reproduce but are either the brief's literal rule or pre-existing documented behavior the brief asked to keep, so I changed documentation only.\n\n**Verification.** Build, formatting check and whitespace check pass. The full suite passes with the verifier seed.\n\n| Run | Result |\n| --- | --- |\n| Permanent suite | 99 passed, 0 failed |\n| Suite plus the reviewer's proof in scratch | 101 passed, 0 failed |\n\nNothing is blocked and no deployment was performed.","treeHash":"13e6d60c3154160173c3aa47f92de617df55fd06","usage":{"cachedInputTokens":1375629,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":31567,"runtime":"claude","turns":41,"wallClockMs":561065}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"809ae05b6282abad","findings":[{"citation":"resolved","description":"The manifest's notes still instruct the operator to run furniture.setMinter(box, true) after deployment. This delivery removed setMinter(address,bool) from OGClubFurniture (replaced by grantMinter/activateMinter/cancelMinter/revokeMinter, src/OGClubFurniture.sol:49-85), so the manifest's own post-deploy step no longer describes the accepted implementation: the call reverts (no such selector, no fallback) and buy() keeps reverting BoxNotMinter, so an operator following the manifest cannot enable sales. A fresh deployment is exactly the case the new grantMinter handles immediately (totalSupply() == 0 emits MinterSet(box, true)); ADAPTATION.md acknowledges the legacy note should be updated, but the accepted manifest text currently contradicts the accepted ABI.","line":27,"path":"launch.json","reproduction":"Deploy MockOG, OGClubFurniture and OGClubBox with the manifest's constructorArgs as $owner, then follow the manifest's own post-deploy note as the owner: furniture.setMinter(box, true) reverts with empty revert data (no function with that selector; OGClubFurniture has no fallback), and a subsequent box.buy(seasonId, 1) still reverts OGClubBox.BoxNotMinter. Expected: furniture.grantMinter(box), which before any mint is immediate and emits MinterSet(box, true), after which buy succeeds. Evidence: forge inspect src/OGClubFurniture.sol:OGClubFurniture methods lists grantMinter/activateMinter/cancelMinter/revokeMinter and no setMinter; test/OGClubFurniture.t.sol::test_ZeroAddressesAndLegacyMinterSelectorCannotGrant asserts a call to setMinter(address,bool) reverts (assertFalse(ok)).","severity":"low","snippet":"Post-deploy steps for the owner: furniture.setMinter(box, true) so the box can mint (buy reverts with BoxNotMinter until this is done), furniture.setBaseURI(...), then box.createSeason(...).","title":"launch.json post-deploy note calls the removed setMinter function"}],"hash":"db2535cf4d2287d678107c0c4ad697c9149a695c91c13491a8327c2956623db8","nodeId":"48dafe07-0142-4bc3-8c6b-32e47231579c","outcome":"completed","summary":"Review complete. Findings and coverage are written to `.imd-findings.json`, the tracked tree is unchanged, and everything I checked is recorded.\n\n**What I found**\n\nOne low-severity defect, in the manifest rather than the math. The post-deploy note in `launch.json` (line 27) still tells the operator to call `furniture.setMinter(box, true)`, but that function was removed in this delivery. The compiled ABI has only `grantMinter/activateMinter/cancelMinter/revokeMinter`, and the contract has no fallback, so following the manifest's own instructions reverts and `buy` keeps reverting `BoxNotMinter`. On a fresh deployment the correct call is `grantMinter(box)`, which is immediate while nothing is minted. The snippet is quoted verbatim in the file, so the citation resolves.\n\n**What I checked and found sound**\n\nThe assigned area (math precision, boundary, numerical gap) is clean, and I verified it rather than assuming it:\n\n- Payment math is exact: the overflow guard is equivalent to no-overflow, burn uses floor division with the vault taking the dust, and `burn + vault = price * count` conserves to the wei.\n- The reveal boundary is exactly right: expiry turns on only at `target + 257`, matching `blockhash` validity (live and hash-readable at `target + 256`).\n- Cap accounting, the fixed-odds roll, and the ten-pack guarantee (including its sell-out re-roll path) behave as documented, with the modulo bias bounded at 2⁻¹²⁸ by the `MAX_TOTAL_WEIGHT` check.\n- I probed the two riskiest gas boundaries with scratch tests: a receiver reverting with up to 672 KiB of returndata never makes `open` revert, and the sub-reserve `mintGas = 0` branch still stores the roll. Both documented guarantees hold empirically.\n- All 26 entry points got a traced verdict, plus five invariant rows; delivery runs at most once, undelivered rolls still reserve caps, and the box's token balance stays zero.\n\n`forge build`, `forge fmt --check` and `forge test` pass (98 tests, including my three probe tests; 95 are the delivered suite). The only files I created are the findings file and the sanctioned scratch probes under `test/scratch/`, which is gitignored.","treeHash":null,"usage":{"cachedInputTokens":3265664,"inputTokens":219745,"model":"claude-fable-5-1","outputTokens":101509,"runtime":"claude","turns":53,"wallClockMs":667195}}],"verification":[{"checks":[{"durationMs":6956,"exitCode":0,"name":"build","output":"Compiling 69 files with Solc 0.8.26\nSolc 0.8.26 finished in 6.85s\nCompiler run successful!\n","passed":true},{"durationMs":12141,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 9 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_AllOwnerFunctionsProtected() (gas: 205698)\n[PASS] test_BuyRequiresTheBoxToBeAnAuthorizedMinter() (gas: 452707)\n[PASS] test_BuyWindowCountPauseAndClose() (gas: 820739)\n[PASS] test_CancelOnlyBeforeOpeningAndTerminal() (gas: 1021489)\n[PASS] test_CreateValidation() (gas: 2060670)\n[PASS] test_MaximumEntryCountAndIdZeroSupported() (gas: 7259036)\n[PASS] test_OverlappingSeasonsIndependentAndTermsUnchanged() (gas: 3021445)\n[PASS] test_OwnershipRequiresAcceptanceAndCanCancelPending() (gas: 370701)\n[PASS] test_UnknownSeasonCannotBeUsed() (gas: 213263)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 13.98ms (13.53ms CPU time)\n\nRan 4 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_ConstructorsDoNotCallDependencies() (gas: 20105)\n[PASS] test_DeployExplicitParametersNoEnvironment() (gas: 22885930)\n[PASS] test_InvalidConstructorAddresses() (gas: 5913)\n[PASS] test_MockSupplySymbolDecimalsAndPublicMint() (gas: 92805)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 74.34ms (40.71ms CPU time)\n\nRan 5 tests for test/FixedOdds.t.sol:FixedOddsTest\n[PASS] testFuzz_OtherOpensOnlyDegradeSoldOutPicks(bytes32,uint8,uint8) (runs: 256, μ: 2391492, ~: 2377028)\nLogs:\n  Bound result 7\n  Bound result 10\n\n[PASS] test_RejectedDeliveryCannotBeRetriedForABetterRoll() (gas: 2813846)\n[PASS] test_RejectedTenPackReservesRareAndCannotUpgradeAfterAnotherOpen() (gas: 4920698)\n[PASS] test_SellOutOnlyDegradesTheSoldOutPickAndNeverRemapsOthers() (gas: 3302980)\n[PASS] test_TenPackGuaranteeRerollsOnlyWhenItsOwnRareSellsOut() (gas: 3142399)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 158.18ms (162.07ms CPU time)\n\nRan 7 tests for test/Delivery.t.sol:DeliveryTest\n[PASS] testFuzz_FirstDeliveryRejectionThenAnyoneCanRetryOnlyOnce(uint8) (runs: 256, μ: 1739928, ~: 1730953)\nLogs:\n  Bound result 1\n\n[PASS] test_DeliveryChecksUnknownUnopenedAndAlreadyDelivered() (gas: 723193)\n[PASS] test_ExpiredUnopenedPurchaseStillRecordsOnlyFallbacksWhenDeliveryFails() (gas: 1091731)\n[PASS] test_HostileReceiverCannotVetoTenDistinctRolledItems() (gas: 11640506)\n[PASS] test_OwnerCannotMintCappedPieceWithinSevenDaysOfProposal() (gas: 1100148)\n[PASS] test_RedirectedDeliveryRejectsReentryAndMarksDeliveredBeforeCallback() (gas: 2403496)\n[PASS] test_ZeroItemIdAndDuplicateStoredItemsDeliverExactlyOnce() (gas: 999782)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 361.94ms (380.80ms CPU time)\n\nRan 4 tests for test/OpenGas.t.sol:OpenGasTest\n[PASS] testFuzz_LowestSucceedingGasDeliversAndStoresNothing(uint8,bytes32) (runs: 256, μ: 6936597, ~: 6937634)\nLogs:\n  Bound result 5\n\n[PASS] test_GasConstantsArePublishedAndConsistent() (gas: 35215)\n[PASS] test_ReserveSavesTenDistinctItemsAtLowestDeliveryGas() (gas: 41364778)\n[PASS] test_ShortGasOpenRevertsInsteadOfRecordingDeliveryFailure() (gas: 2344960)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 418.98ms (461.88ms CPU time)\n\nRan 11 tests for test/Opening.t.sol:OpeningTest\n[PASS] testFuzz_ExpiredAlwaysFallback(uint8,bytes32,uint16) (runs: 256, μ: 856324, ~: 850362)\nLogs:\n  Bound result 10\n  Bound result 6945\n\n[PASS] testFuzz_PreviewMatchesOpenAndCaps(bytes32,uint8) (runs: 256, μ: 3583215, ~: 3572581)\nLogs:\n  Bound result 3\n\n[PASS] test_AuthenticatedHeaderMustHaveCorrectNumber() (gas: 346675)\n[PASS] test_BuilderFieldsDoNotAffectRoll() (gas: 2466129)\n[PASS] test_ExactExpiryBoundaryAndIgnoredHeader() (gas: 1978557)\n[PASS] test_MaturityWrongHeadersAndAlreadyOpened() (gas: 1436668)\n[PASS] test_OpenWhileClosedPausedAndPastSaleEnd() (gas: 1298702)\n[PASS] test_ReceiverReentrancySingleAndBatch() (gas: 5469688)\n[PASS] test_RejectedFirstDeliveryRecordsOpenedAndCapsAndCanRetry() (gas: 3292072)\n[PASS] test_RevokedMinterRecordsRollAndDeliversAfterExpiryAndDelayedRestoration() (gas: 2234162)\n[PASS] test_UnknownPurchase() (gas: 100382)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 470.29ms (759.28ms CPU time)\n\nRan 13 tests for test/OGClubFurniture.t.sol:FurnitureTest\n[PASS] testFuzz_AfterFirstMintMustWaitAndAnyoneCanActivate(uint32) (runs: 256, μ: 575602, ~: 575429)\nLogs:\n  Bound result 4411\n\n[PASS] test_AllOwnerFunctionsProtected() (gas: 227156)\n[PASS] test_CancelStopsActivationEvenAfterDeadline() (gas: 374352)\n[PASS] test_FreshGrantsAreImmediateAndEmitTheFullMinterList() (gas: 408451)\n[PASS] test_IdentityInterfacesMintAndSupply() (gas: 428603)\n[PASS] test_InvalidAddressesAndBatchLengths() (gas: 3989)\n[PASS] test_MetadataFreezesPermanently() (gas: 195182)\n[PASS] test_NoOwnerSeizureOrBurn() (gas: 398447)\n[PASS] test_OwnershipTwoStepAndRenounce() (gas: 244222)\n[PASS] test_ReproposalRestartsDelayAndCancelDoesNotRevokeExistingRole() (gas: 436763)\n[PASS] test_RevokeIsImmediateClearsProposalsAndRegrantWaitsAgain() (gas: 515201)\n[PASS] test_RoyaltyDefaultAndLimits() (gas: 161463)\n[PASS] test_ZeroAddressesAndLegacyMinterSelectorCannotGrant() (gas: 320477)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 473.69ms (477.11ms CPU time)\n\nRan 11 tests for test/Payments.t.sol:PaymentsTest\n[PASS] testFuzz_SplitConservesPayment(uint128,uint16,uint8) (runs: 256, μ: 752948, ~: 758875)\nLogs:\n  Bound result 26417219323777785527591191417025\n  Bound result 0\n  Bound result 2\n\n[PASS] test_ChangingVaultAndSameRecipient() (gas: 553226)\n[PASS] test_ExactSplitsAndEvents() (gas: 17893159)\n[PASS] test_FalseReturnTokenRejected() (gas: 1125744)\n[PASS] test_FeeOnEitherLegRevertsBothTransfers() (gas: 3002454)\n[PASS] test_InsufficientAllowanceRollsBackFirstLeg() (gas: 330254)\n[PASS] test_NoReturnTokenSupported() (gas: 1081712)\n[PASS] test_PriceMultiplicationOverflowHasCustomError() (gas: 463906)\n[PASS] test_TokenCallbackCannotReenter() (gas: 1683561)\n[PASS] test_VaultCanBuyAndOnlyPartsWithTheBurnShare() (gas: 1843298)\n[PASS] test_VaultCannotBeBoxOrZero() (gas: 57044)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 473.63ms (75.25ms CPU time)\n\nRan 9 tests for test/BlockHeader.t.sol:BlockHeaderTest\n[PASS] testFuzz_AnyMalformedInputRevertsWithCustomError(bytes) (runs: 256, μ: 32486, ~: 32061)\n[PASS] testFuzz_ArbitraryTrailingFieldCount(uint8,uint256,bytes32) (runs: 256, μ: 94133, ~: 74652)\nLogs:\n  Bound result 0\n\n[PASS] test_MalformedAuthenticatedHeaderCannotMint() (gas: 345411)\n[PASS] test_MalformedRLPBoundsAndCanonicalLengths() (gas: 147761)\n[PASS] test_MissingFieldsAndInvalidNumberOrMixHash() (gas: 237560)\n[PASS] test_RealMainnetCancunHeader() (gas: 1230367)\n[PASS] test_RealMainnetPragueHeader() (gas: 1234870)\n[PASS] test_RealMainnetShanghaiHeader() (gas: 1227593)\n[PASS] test_ZeroNumberAndZeroMixHashAreValidRLP() (gas: 40758)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 473.89ms (44.89ms CPU time)\n\nRan 17 tests for test/EdgeCases.t.sol:EdgeCasesTest\n[PASS] testFuzz_CreateSeasonRoundTripsTermsAndEntries(uint64,uint32,uint32,uint16,uint8,bytes32) (runs: 512, μ: 1553118, ~: 1157152)\nLogs:\n  Bound result 20\n  Bound result 23775\n  Bound result 30\n  Bound result 1\n\n[PASS] testFuzz_TenPackBoxNineIsRareExactlyWhenARareRemains(bytes32,uint8,uint8) (runs: 512, μ: 5721557, ~: 5722740)\nLogs:\n  Bound result 1\n  Bound result 4\n\n[PASS] test_BuyerCanOpenTheirOwnPurchase() (gas: 703424)\n[PASS] test_CapsAreTrackedPerSeasonNotPerItem() (gas: 4191664)\n[PASS] test_CloseIsAllowedBeforeOpeningAndCancelIsNotAfterClose() (gas: 535953)\n[PASS] test_ContractBuyerWithoutReceiverOpensAndCanRedirectDelivery() (gas: 2010529)\n[PASS] test_ExpiredOpenStillRespectsReentrancyAndOnlyMintsFallback() (gas: 575352)\n[PASS] test_ExpiryIsMeasuredFromTargetNotFromPurchase() (gas: 1046645)\n[PASS] test_InsufficientBalanceRevertsWithoutRecordingPurchase() (gas: 354460)\n[PASS] test_ListShapedTrailingFieldsAcceptedButListAtNumberOrMixHashRejected() (gas: 507928)\n[PASS] test_NumberFieldOfThirtyTwoBytesAndSingleByteAreCanonical() (gas: 513865)\n[PASS] test_OpeningOrderIsFreeButCapsStillHold() (gas: 2009946)\n[PASS] test_PauseDoesNotBlockOwnerActionsOrViews() (gas: 1724032)\n[PASS] test_PurchasesInTheSameBlockShareTheTargetAndHeader() (gas: 2551219)\n[PASS] test_SeasonLifecycleEventsAreEmittedExactly() (gas: 620975)\n[PASS] test_SingleEntrySeasonAlwaysMintsFallbackEvenInTenPack() (gas: 1194303)\n[PASS] test_TotalWeightMayEqualMaxTotalWeightButNotExceedIt() (gas: 1914781)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 473.81ms (949.92ms CPU time)\n\nRan 6 tests for test/Rolls.t.sol:RollsTest\n[PASS] testFuzz_OddsOver20000Randao(bytes32) (runs: 1, μ: 737128, ~: 737128)\n[PASS] testFuzz_RandomizedCapsNeverExceeded(bytes32,uint8,uint8) (runs: 256, μ: 6215329, ~: 6216040)\nLogs:\n  Bound result 4\n  Bound result 1\n\n[PASS] testFuzz_TenPackGuarantee(bytes32) (runs: 256, μ: 1654834, ~: 1657920)\n[PASS] test_CapsExhaustedWithinPackAndNeverRollAgain() (gas: 2395730)\n[PASS] test_GuaranteedRollUsesRelativeRareWeights() (gas: 13243155)\n[PASS] test_SeedDomainMatchesSpecification() (gas: 869490)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.28s (2.10s CPU time)\n\nRan 1 test for test/BoxInvariant.t.sol:BoxInvariantTest\n[PASS]\nBoxInvariantTest invariants:\n[PASS] invariant_CapsAndDeliveredSupplyPlusStoredItemsMatchPerSeasonMints\n[PASS] invariant_EachPurchaseOpenedOnceAndEveryOpenMatchedPreview\n[PASS] invariant_PaymentsAreConservedWithoutBoxCustody\n BoxInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭------------+-------------------+-------+---------+----------╮\n| Contract   | Selector          | Calls | Reverts | Discards |\n+=============================================================+\n| BoxHandler | advance           | 1387  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | pause             | 1371  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | purchase          | 1358  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | retryDelivery     | 1351  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | reveal            | 1312  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | setRejectDelivery | 1413  | 0       | 0        |\n╰------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 200\n  Bound result 3\n  Bound result 241\n  Bound result 1\n  Bound result 133\n  Bound result 200\n  Bound result 5\n  Bound result 192\n  Bound result 8\n  Bound result 156\n  Bound result 100\n  Bound result 226\n  Bound result 150\n  Bound result 4\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.11s (4.11s CPU time)\n\nRan 1 test for test/FurnitureInvariant.t.sol:FurnitureInvariantTest\n[PASS]\nFurnitureInvariantTest invariants:\n[PASS] invariant_BalancesAndSupplyMatchGhosts\n[PASS] invariant_FrozenMetadataNeverChangesAndRoyaltyIsBounded\n[PASS] invariant_OwnerNeverHoldsOrDestroysAnything\n FurnitureInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭------------------+--------------------------+-------+---------+----------╮\n| Contract         | Selector                 | Calls | Reverts | Discards |\n+==========================================================================+\n| FurnitureHandler | mint                     | 1071  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | operatorBatchTransfer    | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerMetadata            | 1045  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerTriesToSeize        | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | revokeApproval           | 1081  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | strangerCannotAdminister | 1117  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | transfer                 | 1068  | 0       | 0        |\n╰------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 5\n  Bound result 14\n  Bound result 1\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 4\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 9\n  Bound result 8\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 7\n  Bound result 0\n  Bound result 14\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 9\n  Bound result 0\n  Bound result 1090\n  Bound result 11\n  Bound result 0\n  Bound result 0\n  Bound result 12\n  Bound result 5\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 14\n  Bound result 1\n  Bound result 899\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 14\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 9\n  Bound result 3\n  Bound result 24\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 10\n  Bound result 0\n  Bound result 12\n  Bound result 14\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.45s (4.45s CPU time)\n\nRan 1 test for test/MultiActorInvariant.t.sol:MultiActorInvariantTest\n[PASS]\nMultiActorInvariantTest invariants:\n[PASS] invariant_BoxNeverHoldsTheToken\n[PASS] invariant_EveryTokenPaidIsAccountedToBurnOrAVault\n[PASS] invariant_HandlerExercisedFailurePathsAndGuarantee\n[PASS] invariant_MintedNeverExceedsCapAndMatchesSupply\n[PASS] invariant_PurchasesOpenOnceAndFinishedStatesNeverReopen\n MultiActorInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭-------------------+--------------------------+-------+---------+----------╮\n| Contract          | Selector                 | Calls | Reverts | Discards |\n+===========================================================================+\n| MultiActorHandler | advanceBlocks            | 660   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | buy                      | 1289  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | cancelSeason             | 649   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | closeSeason              | 652   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | createSeason             | 632   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | open                     | 1282  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setPaused                | 640   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setVault                 | 611   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | strangerCannotAdminister | 673   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | warp                     | 592   | 0       | 0        |\n╰-------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 339606\n  Bound result 0\n  Bound result 1\n  Bound result 239\n  Bound result 12743\n  Bound result 4\n  Bound result 19794\n  Bound result 268\n  Bound result 10\n  Bound result 15876\n  Bound result 70\n  Bound result 95\n  Bound result 234\n  Bound result 18630\n  Bound result 183\n  Bound result 2\n  Bound result 101\n  Bound result 50\n  Bound result 1001\n  Bound result 50000\n  Bound result 9835\n  Bound result 4\n  Bound result 1434\n  Bound result 20528\n  Bound result 1000000000000\n  Bound result 6209\n  Bound result 6\n  Bound result 2658\n  Bound result 4832\n  Bound result 174\n  Bound result 7853\n  Bound result 6\n  Bound result 7\n  Bound result 1205\n  Bound result 3\n  Bound result 3629\n  Bound result 10001\n  Bound result 208\n  Bound result 1305\n  Bound result 0\n  Bound result 1\n  Bound result 4\n  Bound result 35\n  Bound result 8\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.01s (12.00s CPU time)\n\nRan 14 test suites in 12.01s (25.25s CPU time): 99 tests passed, 0 failed, 0 skipped (99 total tests)\n","passed":true},{"durationMs":98,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubBox.acceptOwnership()\",\"OGClubBox.buy(uint256,uint256)\",\"OGClubBox.cancelSeason(uint256)\",\"OGClubBox.closeSeason(uint256)\",\"OGClubBox.createSeason(uint256,uint256,uint256,uint256,uint256,(uint256,uint8,uint256,uint256)[])\",\"OGClubBox.deliver(uint256)\",\"OGClubBox.deliverTo(uint256,address)\",\"OGClubBox.open(uint256,bytes)\",\"OGClubBox.renounceOwnership()\",\"OGClubBox.setPaused(bool)\",\"OGClubBox.setVault(address)\",\"OGClubBox.transferOwnership(address)\",\"OGClubFurniture.acceptOwnership()\",\"OGClubFurniture.activateMinter(address)\",\"OGClubFurniture.cancelMinter(address)\",\"OGClubFurniture.freezeMetadata()\",\"OGClubFurniture.grantMinter(address)\",\"OGClubFurniture.mintBatch(address,uint256[],uint256[])\",\"OGClubFurniture.renounceOwnership()\",\"OGClubFurniture.revokeMinter(address)\",\"OGClubFurniture.safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\",\"OGClubFurniture.safeTransferFrom(address,address,uint256,uint256,bytes)\",\"OGClubFurniture.setApprovalForAll(address,bool)\",\"OGClubFurniture.setBaseURI(string)\",\"OGClubFurniture.setRoyalty(address,uint96)\",\"OGClubFurniture.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":114,\"README.md\":340,\"VENDOR.md\":13,\"foundry.toml\":22,\"launch.json\":28,\"script/Deploy.s.sol\":38,\"script/encode_header.py\":80,\"src/OGClubBox.sol\":480,\"src/OGClubFurniture.sol\":132,\"src/libraries/BlockHeader.sol\":70,\"src/mocks/MockOG.sol\":21,\"test/BlockHeader.t.sol\":132,\"test/BoxInvariant.t.sol\":278,\"test/Delivery.t.sol\":207,\"test/Deployment.t.sol\":86,\"test/EdgeCases.t.sol\":482,\"test/FixedOdds.t.sol\":252,\"test/FurnitureInvariant.t.sol\":248,\"test/MultiActorInvariant.t.sol\":561,\"test/OGClubFurniture.t.sol\":286,\"test/OpenGas.t.sol\":188,\"test/Opening.t.sol\":249,\"test/Payments.t.sol\":202,\"test/Rolls.t.sol\":128,\"test/Seasons.t.sol\":221,\"test/fixtures/MainnetHeaders.sol\":32,\"test/fixtures/SOURCES.md\":42,\"test/fixtures/mainnet-cancun.json\":24,\"test/fixtures/mainnet-prague.json\":25,\"test/fixtures/mainnet-shanghai.json\":21,\"test/helpers/Adversaries.sol\":230,\"test/helpers/BoxTestBase.sol\":120,\"test/helpers/HeaderBuilder.sol\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"38f9786f514a1d4bc6795f599cd7a6524f91878cac9bf6d815437856a5beebe4","verifiedTreeHash":"e08e64f5effac983b3ca8163022c4a346e3ad4ac","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":6534,"exitCode":0,"name":"build","output":"Compiling 68 files with Solc 0.8.26\nSolc 0.8.26 finished in 6.43s\nCompiler run successful!\n","passed":true},{"durationMs":11839,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_ConstructorsDoNotCallDependencies() (gas: 20061)\n[PASS] test_DeployExplicitParametersNoEnvironment() (gas: 22837277)\n[PASS] test_InvalidConstructorAddresses() (gas: 5913)\n[PASS] test_MockSupplySymbolDecimalsAndPublicMint() (gas: 92805)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 37.78ms (38.91ms CPU time)\n\nRan 7 tests for test/Delivery.t.sol:DeliveryTest\n[PASS] testFuzz_FirstDeliveryRejectionThenAnyoneCanRetryOnlyOnce(uint8) (runs: 256, μ: 1744864, ~: 1731009)\nLogs:\n  Bound result 1\n\n[PASS] test_DeliveryChecksUnknownUnopenedAndAlreadyDelivered() (gas: 723182)\n[PASS] test_ExpiredUnopenedPurchaseStillRecordsOnlyFallbacksWhenDeliveryFails() (gas: 1091765)\n[PASS] test_HostileReceiverCannotVetoTenDistinctRolledItems() (gas: 8763088)\n[PASS] test_OwnerCannotMintCappedPieceWithinSevenDaysOfProposal() (gas: 1100205)\n[PASS] test_RedirectedDeliveryRejectsReentryAndMarksDeliveredBeforeCallback() (gas: 2403685)\n[PASS] test_ZeroItemIdAndDuplicateStoredItemsDeliverExactlyOnce() (gas: 999772)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 141.74ms (151.69ms CPU time)\n\nRan 5 tests for test/FixedOdds.t.sol:FixedOddsTest\n[PASS] testFuzz_OtherOpensOnlyDegradeSoldOutPicks(bytes32,uint8,uint8) (runs: 256, μ: 2393744, ~: 2389109)\nLogs:\n  Bound result 7\n  Bound result 10\n\n[PASS] test_RejectedDeliveryCannotBeRetriedForABetterRoll() (gas: 2814025)\n[PASS] test_RejectedTenPackReservesRareAndCannotUpgradeAfterAnotherOpen() (gas: 4920171)\n[PASS] test_SellOutOnlyDegradesTheSoldOutPickAndNeverRemapsOthers() (gas: 3302017)\n[PASS] test_TenPackGuaranteeRerollsOnlyWhenItsOwnRareSellsOut() (gas: 3141411)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 150.95ms (164.00ms CPU time)\n\nRan 9 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_AllOwnerFunctionsProtected() (gas: 205653)\n[PASS] test_BuyRequiresTheBoxToBeAnAuthorizedMinter() (gas: 452751)\n[PASS] test_BuyWindowCountPauseAndClose() (gas: 820937)\n[PASS] test_CancelOnlyBeforeOpeningAndTerminal() (gas: 1021265)\n[PASS] test_CreateValidation() (gas: 2060308)\n[PASS] test_MaximumEntryCountAndIdZeroSupported() (gas: 7255000)\n[PASS] test_OverlappingSeasonsIndependentAndTermsUnchanged() (gas: 3020677)\n[PASS] test_OwnershipRequiresAcceptanceAndCanCancelPending() (gas: 370769)\n[PASS] test_UnknownSeasonCannotBeUsed() (gas: 213261)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 222.03ms (8.76ms CPU time)\n\nRan 9 tests for test/BlockHeader.t.sol:BlockHeaderTest\n[PASS] testFuzz_AnyMalformedInputRevertsWithCustomError(bytes) (runs: 256, μ: 32490, ~: 32093)\n[PASS] testFuzz_ArbitraryTrailingFieldCount(uint8,uint256,bytes32) (runs: 256, μ: 95226, ~: 75084)\nLogs:\n  Bound result 43\n\n[PASS] test_MalformedAuthenticatedHeaderCannotMint() (gas: 345499)\n[PASS] test_MalformedRLPBoundsAndCanonicalLengths() (gas: 147761)\n[PASS] test_MissingFieldsAndInvalidNumberOrMixHash() (gas: 237560)\n[PASS] test_RealMainnetCancunHeader() (gas: 1230005)\n[PASS] test_RealMainnetPragueHeader() (gas: 1234508)\n[PASS] test_RealMainnetShanghaiHeader() (gas: 1227231)\n[PASS] test_ZeroNumberAndZeroMixHashAreValidRLP() (gas: 40758)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 324.08ms (477.85ms CPU time)\n\nRan 11 tests for test/Payments.t.sol:PaymentsTest\n[PASS] testFuzz_SplitConservesPayment(uint128,uint16,uint8) (runs: 256, μ: 752671, ~: 758891)\nLogs:\n  Bound result 26417219323777785527591191417025\n  Bound result 0\n  Bound result 2\n\n[PASS] test_ChangingVaultAndSameRecipient() (gas: 553270)\n[PASS] test_ExactSplitsAndEvents() (gas: 17894259)\n[PASS] test_FalseReturnTokenRejected() (gas: 1125766)\n[PASS] test_FeeOnEitherLegRevertsBothTransfers() (gas: 3002498)\n[PASS] test_InsufficientAllowanceRollsBackFirstLeg() (gas: 330276)\n[PASS] test_NoReturnTokenSupported() (gas: 1081734)\n[PASS] test_PriceMultiplicationOverflowHasCustomError() (gas: 463928)\n[PASS] test_TokenCallbackCannotReenter() (gas: 1683627)\n[PASS] test_VaultCanBuyAndOnlyPartsWithTheBurnShare() (gas: 1843364)\n[PASS] test_VaultCannotBeBoxOrZero() (gas: 57044)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 334.98ms (346.26ms CPU time)\n\nRan 13 tests for test/OGClubFurniture.t.sol:FurnitureTest\n[PASS] testFuzz_AfterFirstMintMustWaitAndAnyoneCanActivate(uint32) (runs: 256, μ: 575586, ~: 575429)\nLogs:\n  Bound result 4411\n\n[PASS] test_AllOwnerFunctionsProtected() (gas: 227156)\n[PASS] test_CancelStopsActivationEvenAfterDeadline() (gas: 374352)\n[PASS] test_FreshGrantsAreImmediateAndEmitTheFullMinterList() (gas: 408451)\n[PASS] test_IdentityInterfacesMintAndSupply() (gas: 428603)\n[PASS] test_InvalidAddressesAndBatchLengths() (gas: 3989)\n[PASS] test_MetadataFreezesPermanently() (gas: 195182)\n[PASS] test_NoOwnerSeizureOrBurn() (gas: 398447)\n[PASS] test_OwnershipTwoStepAndRenounce() (gas: 244222)\n[PASS] test_ReproposalRestartsDelayAndCancelDoesNotRevokeExistingRole() (gas: 436763)\n[PASS] test_RevokeIsImmediateClearsProposalsAndRegrantWaitsAgain() (gas: 515201)\n[PASS] test_RoyaltyDefaultAndLimits() (gas: 161463)\n[PASS] test_ZeroAddressesAndLegacyMinterSelectorCannotGrant() (gas: 320477)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 348.89ms (353.16ms CPU time)\n\nRan 17 tests for test/EdgeCases.t.sol:EdgeCasesTest\n[PASS] testFuzz_CreateSeasonRoundTripsTermsAndEntries(uint64,uint32,uint32,uint16,uint8,bytes32) (runs: 512, μ: 1555907, ~: 1137065)\nLogs:\n  Bound result 23139307111447\n  Bound result 5\n  Bound result 2\n  Bound result 13\n\n[PASS] testFuzz_TenPackBoxNineIsRareExactlyWhenARareRemains(bytes32,uint8,uint8) (runs: 512, μ: 5717754, ~: 5718162)\nLogs:\n  Bound result 1\n  Bound result 4\n\n[PASS] test_BuyerCanOpenTheirOwnPurchase() (gas: 703569)\n[PASS] test_CapsAreTrackedPerSeasonNotPerItem() (gas: 4190832)\n[PASS] test_CloseIsAllowedBeforeOpeningAndCancelIsNotAfterClose() (gas: 535930)\n[PASS] test_ContractBuyerWithoutReceiverOpensAndCanRedirectDelivery() (gas: 2010230)\n[PASS] test_ExpiredOpenStillRespectsReentrancyAndOnlyMintsFallback() (gas: 575409)\n[PASS] test_ExpiryIsMeasuredFromTargetNotFromPurchase() (gas: 1046283)\n[PASS] test_InsufficientBalanceRevertsWithoutRecordingPurchase() (gas: 354482)\n[PASS] test_ListShapedTrailingFieldsAcceptedButListAtNumberOrMixHashRejected() (gas: 507928)\n[PASS] test_NumberFieldOfThirtyTwoBytesAndSingleByteAreCanonical() (gas: 513865)\n[PASS] test_OpeningOrderIsFreeButCapsStillHold() (gas: 2009530)\n[PASS] test_PauseDoesNotBlockOwnerActionsOrViews() (gas: 1723736)\n[PASS] test_PurchasesInTheSameBlockShareTheTargetAndHeader() (gas: 2550517)\n[PASS] test_SeasonLifecycleEventsAreEmittedExactly() (gas: 620908)\n[PASS] test_SingleEntrySeasonAlwaysMintsFallbackEvenInTenPack() (gas: 1194271)\n[PASS] test_TotalWeightMayEqualMaxTotalWeightButNotExceedIt() (gas: 1914485)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 349.50ms (462.72ms CPU time)\n\nRan 11 tests for test/Opening.t.sol:OpeningTest\n[PASS] testFuzz_ExpiredAlwaysFallback(uint8,bytes32,uint16) (runs: 256, μ: 856880, ~: 850228)\nLogs:\n  Bound result 10\n  Bound result 6945\n\n[PASS] testFuzz_PreviewMatchesOpenAndCaps(bytes32,uint8) (runs: 256, μ: 3568747, ~: 3556909)\nLogs:\n  Bound result 2\n\n[PASS] test_AuthenticatedHeaderMustHaveCorrectNumber() (gas: 346719)\n[PASS] test_BuilderFieldsDoNotAffectRoll() (gas: 2465405)\n[PASS] test_ExactExpiryBoundaryAndIgnoredHeader() (gas: 1977811)\n[PASS] test_MaturityWrongHeadersAndAlreadyOpened() (gas: 1436328)\n[PASS] test_OpenWhileClosedPausedAndPastSaleEnd() (gas: 1298340)\n[PASS] test_ReceiverReentrancySingleAndBatch() (gas: 5469140)\n[PASS] test_RejectedFirstDeliveryRecordsOpenedAndCapsAndCanRetry() (gas: 3291753)\n[PASS] test_RevokedMinterRecordsRollAndDeliversAfterExpiryAndDelayedRestoration() (gas: 2234362)\n[PASS] test_UnknownPurchase() (gas: 100382)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 362.28ms (591.70ms CPU time)\n\nRan 6 tests for test/Rolls.t.sol:RollsTest\n[PASS] testFuzz_OddsOver20000Randao(bytes32) (runs: 1, μ: 737172, ~: 737172)\n[PASS] testFuzz_RandomizedCapsNeverExceeded(bytes32,uint8,uint8) (runs: 256, μ: 6211915, ~: 6212443)\nLogs:\n  Bound result 5\n  Bound result 2\n\n[PASS] testFuzz_TenPackGuarantee(bytes32) (runs: 256, μ: 1655537, ~: 1657624)\n[PASS] test_CapsExhaustedWithinPackAndNeverRollAgain() (gas: 2395336)\n[PASS] test_GuaranteedRollUsesRelativeRareWeights() (gas: 13243199)\n[PASS] test_SeedDomainMatchesSpecification() (gas: 869534)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.20s (1.72s CPU time)\n\nRan 1 test for test/BoxInvariant.t.sol:BoxInvariantTest\n[PASS]\nBoxInvariantTest invariants:\n[PASS] invariant_CapsAndDeliveredSupplyPlusStoredItemsMatchPerSeasonMints\n[PASS] invariant_EachPurchaseOpenedOnceAndEveryOpenMatchedPreview\n[PASS] invariant_PaymentsAreConservedWithoutBoxCustody\n BoxInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭------------+-------------------+-------+---------+----------╮\n| Contract   | Selector          | Calls | Reverts | Discards |\n+=============================================================+\n| BoxHandler | advance           | 1387  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | pause             | 1371  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | purchase          | 1358  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | retryDelivery     | 1351  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | reveal            | 1312  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | setRejectDelivery | 1413  | 0       | 0        |\n╰------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 200\n  Bound result 1\n  Bound result 141\n  Bound result 1\n  Bound result 133\n  Bound result 200\n  Bound result 4\n  Bound result 192\n  Bound result 8\n  Bound result 17\n  Bound result 88\n  Bound result 227\n  Bound result 54\n  Bound result 4\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.00s (3.99s CPU time)\n\nRan 1 test for test/FurnitureInvariant.t.sol:FurnitureInvariantTest\n[PASS]\nFurnitureInvariantTest invariants:\n[PASS] invariant_BalancesAndSupplyMatchGhosts\n[PASS] invariant_FrozenMetadataNeverChangesAndRoyaltyIsBounded\n[PASS] invariant_OwnerNeverHoldsOrDestroysAnything\n FurnitureInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭------------------+--------------------------+-------+---------+----------╮\n| Contract         | Selector                 | Calls | Reverts | Discards |\n+==========================================================================+\n| FurnitureHandler | mint                     | 1071  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | operatorBatchTransfer    | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerMetadata            | 1045  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerTriesToSeize        | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | revokeApproval           | 1081  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | strangerCannotAdminister | 1117  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | transfer                 | 1068  | 0       | 0        |\n╰------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 5\n  Bound result 14\n  Bound result 1\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 4\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 9\n  Bound result 8\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 7\n  Bound result 0\n  Bound result 14\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 9\n  Bound result 0\n  Bound result 1090\n  Bound result 11\n  Bound result 0\n  Bound result 0\n  Bound result 12\n  Bound result 5\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 14\n  Bound result 1\n  Bound result 639\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 14\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 9\n  Bound result 3\n  Bound result 24\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 10\n  Bound result 0\n  Bound result 12\n  Bound result 14\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.51s (4.51s CPU time)\n\nRan 1 test for test/MultiActorInvariant.t.sol:MultiActorInvariantTest\n[PASS]\nMultiActorInvariantTest invariants:\n[PASS] invariant_BoxNeverHoldsTheToken\n[PASS] invariant_EveryTokenPaidIsAccountedToBurnOrAVault\n[PASS] invariant_HandlerExercisedFailurePathsAndGuarantee\n[PASS] invariant_MintedNeverExceedsCapAndMatchesSupply\n[PASS] invariant_PurchasesOpenOnceAndFinishedStatesNeverReopen\n MultiActorInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭-------------------+--------------------------+-------+---------+----------╮\n| Contract          | Selector                 | Calls | Reverts | Discards |\n+===========================================================================+\n| MultiActorHandler | advanceBlocks            | 660   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | buy                      | 1289  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | cancelSeason             | 649   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | closeSeason              | 652   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | createSeason             | 632   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | open                     | 1282  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setPaused                | 640   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setVault                 | 611   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | strangerCannotAdminister | 673   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | warp                     | 592   | 0       | 0        |\n╰-------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 339606\n  Bound result 0\n  Bound result 1\n  Bound result 239\n  Bound result 12743\n  Bound result 4\n  Bound result 7253\n  Bound result 151\n  Bound result 10\n  Bound result 15716\n  Bound result 70\n  Bound result 172\n  Bound result 132\n  Bound result 2380\n  Bound result 183\n  Bound result 2\n  Bound result 101\n  Bound result 50\n  Bound result 3456\n  Bound result 16\n  Bound result 9663\n  Bound result 2\n  Bound result 1434\n  Bound result 20316\n  Bound result 242\n  Bound result 6090\n  Bound result 6\n  Bound result 3558\n  Bound result 258\n  Bound result 279\n  Bound result 7499\n  Bound result 4\n  Bound result 7\n  Bound result 1024\n  Bound result 1\n  Bound result 3448\n  Bound result 10001\n  Bound result 196\n  Bound result 1549\n  Bound result 1\n  Bound result 1\n  Bound result 4\n  Bound result 35\n  Bound result 8\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 11.72s (11.72s CPU time)\n\nRan 13 test suites in 11.73s (23.70s CPU time): 95 tests passed, 0 failed, 0 skipped (95 total tests)\n","passed":true},{"durationMs":51,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubBox.acceptOwnership()\",\"OGClubBox.buy(uint256,uint256)\",\"OGClubBox.cancelSeason(uint256)\",\"OGClubBox.closeSeason(uint256)\",\"OGClubBox.createSeason(uint256,uint256,uint256,uint256,uint256,(uint256,uint8,uint256,uint256)[])\",\"OGClubBox.deliver(uint256)\",\"OGClubBox.deliverTo(uint256,address)\",\"OGClubBox.open(uint256,bytes)\",\"OGClubBox.renounceOwnership()\",\"OGClubBox.setPaused(bool)\",\"OGClubBox.setVault(address)\",\"OGClubBox.transferOwnership(address)\",\"OGClubFurniture.acceptOwnership()\",\"OGClubFurniture.activateMinter(address)\",\"OGClubFurniture.cancelMinter(address)\",\"OGClubFurniture.freezeMetadata()\",\"OGClubFurniture.grantMinter(address)\",\"OGClubFurniture.mintBatch(address,uint256[],uint256[])\",\"OGClubFurniture.renounceOwnership()\",\"OGClubFurniture.revokeMinter(address)\",\"OGClubFurniture.safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\",\"OGClubFurniture.safeTransferFrom(address,address,uint256,uint256,bytes)\",\"OGClubFurniture.setApprovalForAll(address,bool)\",\"OGClubFurniture.setBaseURI(string)\",\"OGClubFurniture.setRoyalty(address,uint96)\",\"OGClubFurniture.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":85,\"README.md\":319,\"VENDOR.md\":13,\"foundry.toml\":22,\"launch.json\":28,\"script/Deploy.s.sol\":38,\"script/encode_header.py\":80,\"src/OGClubBox.sol\":472,\"src/OGClubFurniture.sol\":132,\"src/libraries/BlockHeader.sol\":70,\"src/mocks/MockOG.sol\":21,\"test/BlockHeader.t.sol\":132,\"test/BoxInvariant.t.sol\":278,\"test/Delivery.t.sol\":207,\"test/Deployment.t.sol\":86,\"test/EdgeCases.t.sol\":482,\"test/FixedOdds.t.sol\":252,\"test/FurnitureInvariant.t.sol\":248,\"test/MultiActorInvariant.t.sol\":561,\"test/OGClubFurniture.t.sol\":286,\"test/Opening.t.sol\":249,\"test/Payments.t.sol\":202,\"test/Rolls.t.sol\":128,\"test/Seasons.t.sol\":221,\"test/fixtures/MainnetHeaders.sol\":32,\"test/fixtures/SOURCES.md\":42,\"test/fixtures/mainnet-cancun.json\":24,\"test/fixtures/mainnet-prague.json\":25,\"test/fixtures/mainnet-shanghai.json\":21,\"test/helpers/Adversaries.sol\":230,\"test/helpers/BoxTestBase.sol\":120,\"test/helpers/HeaderBuilder.sol\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"44463fefd440659cf79237679368c1d4616847835dba5137df713ea87a68bc51","verifiedTreeHash":"bfb31f9cc5d7953dfd08cc6c87e53d0f4bcf709b","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":8204,"exitCode":0,"name":"build","output":"Compiling 71 files with Solc 0.8.26\nSolc 0.8.26 finished in 8.08s\nCompiler run successful!\n","passed":true},{"durationMs":12867,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 9 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_AllOwnerFunctionsProtected() (gas: 205698)\n[PASS] test_BuyRequiresTheBoxToBeAnAuthorizedMinter() (gas: 452707)\n[PASS] test_BuyWindowCountPauseAndClose() (gas: 820739)\n[PASS] test_CancelOnlyBeforeOpeningAndTerminal() (gas: 1021489)\n[PASS] test_CreateValidation() (gas: 2060670)\n[PASS] test_MaximumEntryCountAndIdZeroSupported() (gas: 7259036)\n[PASS] test_OverlappingSeasonsIndependentAndTermsUnchanged() (gas: 3021445)\n[PASS] test_OwnershipRequiresAcceptanceAndCanCancelPending() (gas: 370701)\n[PASS] test_UnknownSeasonCannotBeUsed() (gas: 213263)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 13.90ms (16.37ms CPU time)\n\nRan 11 tests for test/Payments.t.sol:PaymentsTest\n[PASS] testFuzz_SplitConservesPayment(uint128,uint16,uint8) (runs: 256, μ: 752838, ~: 758881)\nLogs:\n  Bound result 26417219323777785527591191417025\n  Bound result 0\n  Bound result 2\n\n[PASS] test_ChangingVaultAndSameRecipient() (gas: 553226)\n[PASS] test_ExactSplitsAndEvents() (gas: 17893159)\n[PASS] test_FalseReturnTokenRejected() (gas: 1125744)\n[PASS] test_FeeOnEitherLegRevertsBothTransfers() (gas: 3002454)\n[PASS] test_InsufficientAllowanceRollsBackFirstLeg() (gas: 330254)\n[PASS] test_NoReturnTokenSupported() (gas: 1081712)\n[PASS] test_PriceMultiplicationOverflowHasCustomError() (gas: 463906)\n[PASS] test_TokenCallbackCannotReenter() (gas: 1683561)\n[PASS] test_VaultCanBuyAndOnlyPartsWithTheBurnShare() (gas: 1843298)\n[PASS] test_VaultCannotBeBoxOrZero() (gas: 57044)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 75.75ms (68.26ms CPU time)\n\nRan 7 tests for test/Delivery.t.sol:DeliveryTest\n[PASS] testFuzz_FirstDeliveryRejectionThenAnyoneCanRetryOnlyOnce(uint8) (runs: 256, μ: 1734534, ~: 1730953)\nLogs:\n  Bound result 1\n\n[PASS] test_DeliveryChecksUnknownUnopenedAndAlreadyDelivered() (gas: 723193)\n[PASS] test_ExpiredUnopenedPurchaseStillRecordsOnlyFallbacksWhenDeliveryFails() (gas: 1091731)\n[PASS] test_HostileReceiverCannotVetoTenDistinctRolledItems() (gas: 11640506)\n[PASS] test_OwnerCannotMintCappedPieceWithinSevenDaysOfProposal() (gas: 1100148)\n[PASS] test_RedirectedDeliveryRejectsReentryAndMarksDeliveredBeforeCallback() (gas: 2403496)\n[PASS] test_ZeroItemIdAndDuplicateStoredItemsDeliverExactlyOnce() (gas: 999782)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 298.97ms (306.12ms CPU time)\n\nRan 11 tests for test/Opening.t.sol:OpeningTest\n[PASS] testFuzz_ExpiredAlwaysFallback(uint8,bytes32,uint16) (runs: 256, μ: 856737, ~: 850641)\nLogs:\n  Bound result 10\n  Bound result 6945\n\n[PASS] testFuzz_PreviewMatchesOpenAndCaps(bytes32,uint8) (runs: 256, μ: 3583275, ~: 3572581)\nLogs:\n  Bound result 2\n\n[PASS] test_AuthenticatedHeaderMustHaveCorrectNumber() (gas: 346675)\n[PASS] test_BuilderFieldsDoNotAffectRoll() (gas: 2466129)\n[PASS] test_ExactExpiryBoundaryAndIgnoredHeader() (gas: 1978557)\n[PASS] test_MaturityWrongHeadersAndAlreadyOpened() (gas: 1436668)\n[PASS] test_OpenWhileClosedPausedAndPastSaleEnd() (gas: 1298702)\n[PASS] test_ReceiverReentrancySingleAndBatch() (gas: 5469688)\n[PASS] test_RejectedFirstDeliveryRecordsOpenedAndCapsAndCanRetry() (gas: 3292072)\n[PASS] test_RevokedMinterRecordsRollAndDeliversAfterExpiryAndDelayedRestoration() (gas: 2234162)\n[PASS] test_UnknownPurchase() (gas: 100382)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 377.08ms (670.77ms CPU time)\n\nRan 4 tests for test/OpenGas.t.sol:OpenGasTest\n[PASS] testFuzz_LowestSucceedingGasDeliversAndStoresNothing(uint8,bytes32) (runs: 256, μ: 6976226, ~: 7026754)\nLogs:\n  Bound result 8\n\n[PASS] test_GasConstantsArePublishedAndConsistent() (gas: 35215)\n[PASS] test_ReserveSavesTenDistinctItemsAtLowestDeliveryGas() (gas: 41364778)\n[PASS] test_ShortGasOpenRevertsInsteadOfRecordingDeliveryFailure() (gas: 2344960)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 381.05ms (433.91ms CPU time)\n\nRan 9 tests for test/BlockHeader.t.sol:BlockHeaderTest\n[PASS] testFuzz_AnyMalformedInputRevertsWithCustomError(bytes) (runs: 256, μ: 32489, ~: 32061)\n[PASS] testFuzz_ArbitraryTrailingFieldCount(uint8,uint256,bytes32) (runs: 256, μ: 94376, ~: 75111)\nLogs:\n  Bound result 0\n\n[PASS] test_MalformedAuthenticatedHeaderCannotMint() (gas: 345411)\n[PASS] test_MalformedRLPBoundsAndCanonicalLengths() (gas: 147761)\n[PASS] test_MissingFieldsAndInvalidNumberOrMixHash() (gas: 237560)\n[PASS] test_RealMainnetCancunHeader() (gas: 1230367)\n[PASS] test_RealMainnetPragueHeader() (gas: 1234870)\n[PASS] test_RealMainnetShanghaiHeader() (gas: 1227593)\n[PASS] test_ZeroNumberAndZeroMixHashAreValidRLP() (gas: 40758)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 436.99ms (58.48ms CPU time)\n\nRan 13 tests for test/OGClubFurniture.t.sol:FurnitureTest\n[PASS] testFuzz_AfterFirstMintMustWaitAndAnyoneCanActivate(uint32) (runs: 256, μ: 575608, ~: 575429)\nLogs:\n  Bound result 50016\n\n[PASS] test_AllOwnerFunctionsProtected() (gas: 227156)\n[PASS] test_CancelStopsActivationEvenAfterDeadline() (gas: 374352)\n[PASS] test_FreshGrantsAreImmediateAndEmitTheFullMinterList() (gas: 408451)\n[PASS] test_IdentityInterfacesMintAndSupply() (gas: 428603)\n[PASS] test_InvalidAddressesAndBatchLengths() (gas: 3989)\n[PASS] test_MetadataFreezesPermanently() (gas: 195182)\n[PASS] test_NoOwnerSeizureOrBurn() (gas: 398447)\n[PASS] test_OwnershipTwoStepAndRenounce() (gas: 244222)\n[PASS] test_ReproposalRestartsDelayAndCancelDoesNotRevokeExistingRole() (gas: 436763)\n[PASS] test_RevokeIsImmediateClearsProposalsAndRegrantWaitsAgain() (gas: 515201)\n[PASS] test_RoyaltyDefaultAndLimits() (gas: 161463)\n[PASS] test_ZeroAddressesAndLegacyMinterSelectorCannotGrant() (gas: 320477)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 437.00ms (106.59ms CPU time)\n\nRan 4 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_ConstructorsDoNotCallDependencies() (gas: 20105)\n[PASS] test_DeployExplicitParametersNoEnvironment() (gas: 22885930)\n[PASS] test_InvalidConstructorAddresses() (gas: 5913)\n[PASS] test_MockSupplySymbolDecimalsAndPublicMint() (gas: 92805)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 449.57ms (29.11ms CPU time)\n\nRan 5 tests for test/FixedOdds.t.sol:FixedOddsTest\n[PASS] testFuzz_OtherOpensOnlyDegradeSoldOutPicks(bytes32,uint8,uint8) (runs: 256, μ: 2390334, ~: 2385114)\nLogs:\n  Bound result 4\n  Bound result 5\n\n[PASS] test_RejectedDeliveryCannotBeRetriedForABetterRoll() (gas: 2813846)\n[PASS] test_RejectedTenPackReservesRareAndCannotUpgradeAfterAnotherOpen() (gas: 4920698)\n[PASS] test_SellOutOnlyDegradesTheSoldOutPickAndNeverRemapsOthers() (gas: 3302980)\n[PASS] test_TenPackGuaranteeRerollsOnlyWhenItsOwnRareSellsOut() (gas: 3142399)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 449.63ms (457.16ms CPU time)\n\nRan 11 tests for test/DeliveryEdges.t.sol:DeliveryEdgesTest\n[PASS] testFuzz_ActivationBoundaryIsExact(uint32) (runs: 256, μ: 666288, ~: 666288)\n[PASS] testFuzz_OnlyTheBuyerRedirectsButAnyoneDelivers(bytes32,bytes32) (runs: 200, μ: 1856098, ~: 1856235)\n[PASS] testFuzz_OpenWithAnyGasIsAtomicOrDeliversThePreview(uint32,uint8,bytes32) (runs: 200, μ: 1179298, ~: 1176076)\nLogs:\n  Bound result 2\n  Bound result 614111\n\n[PASS] testFuzz_StoredRollSurvivesAnyDelayAndSeasonChanges(uint64,uint64,bytes32) (runs: 200, μ: 1712342, ~: 1715375)\nLogs:\n  Bound result 5328709\n  Bound result 191230208\n\n[PASS] test_ExpiryOnlyAppliesToUnopenedPurchasesEvenWhenDeliveryIsPending() (gas: 2055588)\n[PASS] test_GasStarvedOpenRevertsUntouchedAndNeverParksAnHonestRoll() (gas: 2412224)\n[PASS] test_ImmediateGrantStaysOpenWhileOnlyUndeliveredRollsExist() (gas: 1121154)\n[PASS] test_RedirectToNonReceiverContractsRevertsAndLeavesTheRollStored() (gas: 3149153)\n[PASS] test_SuccessfulOpenWritesNoStoredItemsAndFailureWritesExactlyTheRoll() (gas: 2003785)\n[PASS] test_SupplyCannotReturnToZeroSoTheDelayIsPermanent() (gas: 695724)\n[PASS] test_ZeroAmountMintsLeaveSupplyZeroAndGrantsImmediate() (gas: 387924)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 456.51ms (1.55s CPU time)\n\nRan 17 tests for test/EdgeCases.t.sol:EdgeCasesTest\n[PASS] testFuzz_CreateSeasonRoundTripsTermsAndEntries(uint64,uint32,uint32,uint16,uint8,bytes32) (runs: 512, μ: 1557509, ~: 1195839)\nLogs:\n  Bound result 23139307111447\n  Bound result 5\n  Bound result 2\n  Bound result 13\n\n[PASS] testFuzz_TenPackBoxNineIsRareExactlyWhenARareRemains(bytes32,uint8,uint8) (runs: 512, μ: 5721277, ~: 5722627)\nLogs:\n  Bound result 4\n  Bound result 1\n\n[PASS] test_BuyerCanOpenTheirOwnPurchase() (gas: 703424)\n[PASS] test_CapsAreTrackedPerSeasonNotPerItem() (gas: 4191664)\n[PASS] test_CloseIsAllowedBeforeOpeningAndCancelIsNotAfterClose() (gas: 535953)\n[PASS] test_ContractBuyerWithoutReceiverOpensAndCanRedirectDelivery() (gas: 2010529)\n[PASS] test_ExpiredOpenStillRespectsReentrancyAndOnlyMintsFallback() (gas: 575352)\n[PASS] test_ExpiryIsMeasuredFromTargetNotFromPurchase() (gas: 1046645)\n[PASS] test_InsufficientBalanceRevertsWithoutRecordingPurchase() (gas: 354460)\n[PASS] test_ListShapedTrailingFieldsAcceptedButListAtNumberOrMixHashRejected() (gas: 507928)\n[PASS] test_NumberFieldOfThirtyTwoBytesAndSingleByteAreCanonical() (gas: 513865)\n[PASS] test_OpeningOrderIsFreeButCapsStillHold() (gas: 2009946)\n[PASS] test_PauseDoesNotBlockOwnerActionsOrViews() (gas: 1724032)\n[PASS] test_PurchasesInTheSameBlockShareTheTargetAndHeader() (gas: 2551219)\n[PASS] test_SeasonLifecycleEventsAreEmittedExactly() (gas: 620975)\n[PASS] test_SingleEntrySeasonAlwaysMintsFallbackEvenInTenPack() (gas: 1194303)\n[PASS] test_TotalWeightMayEqualMaxTotalWeightButNotExceedIt() (gas: 1914781)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 456.48ms (855.10ms CPU time)\n\nRan 6 tests for test/Rolls.t.sol:RollsTest\n[PASS] testFuzz_OddsOver20000Randao(bytes32) (runs: 1, μ: 737128, ~: 737128)\n[PASS] testFuzz_RandomizedCapsNeverExceeded(bytes32,uint8,uint8) (runs: 256, μ: 6215038, ~: 6215440)\nLogs:\n  Bound result 1\n  Bound result 10\n\n[PASS] testFuzz_TenPackGuarantee(bytes32) (runs: 256, μ: 1654620, ~: 1657920)\n[PASS] test_CapsExhaustedWithinPackAndNeverRollAgain() (gas: 2395730)\n[PASS] test_GuaranteedRollUsesRelativeRareWeights() (gas: 13243155)\n[PASS] test_SeedDomainMatchesSpecification() (gas: 869490)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.31s (2.16s CPU time)\n\nRan 1 test for test/BoxInvariant.t.sol:BoxInvariantTest\n[PASS]\nBoxInvariantTest invariants:\n[PASS] invariant_CapsAndDeliveredSupplyPlusStoredItemsMatchPerSeasonMints\n[PASS] invariant_EachPurchaseOpenedOnceAndEveryOpenMatchedPreview\n[PASS] invariant_PaymentsAreConservedWithoutBoxCustody\n BoxInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭------------+-------------------+-------+---------+----------╮\n| Contract   | Selector          | Calls | Reverts | Discards |\n+=============================================================+\n| BoxHandler | advance           | 1387  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | pause             | 1371  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | purchase          | 1358  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | retryDelivery     | 1351  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | reveal            | 1312  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | setRejectDelivery | 1413  | 0       | 0        |\n╰------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 255\n  Bound result 3\n  Bound result 93\n  Bound result 1\n  Bound result 133\n  Bound result 200\n  Bound result 5\n  Bound result 192\n  Bound result 8\n  Bound result 127\n  Bound result 88\n  Bound result 227\n  Bound result 250\n  Bound result 4\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.30s (4.29s CPU time)\n\nRan 1 test for test/MinterLifecycleInvariant.t.sol:MinterLifecycleInvariantTest\n[PASS]\nMinterLifecycleInvariantTest invariants:\n[PASS] invariant_BoxHoldsNothingAndPaymentsAreConserved\n[PASS] invariant_EachPurchaseDeliveredAtMostOnceAndOnlyAfterOpening\n[PASS] invariant_MintedPerItemEqualsDeliveredSupplyPlusStoredMinusDirectMints\n[PASS] invariant_MinterRolesMatchGhostsAndNeverActivateEarly\n MinterLifecycleInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭------------------------+--------------------------+-------+---------+----------╮\n| Contract               | Selector                 | Calls | Reverts | Discards |\n+================================================================================+\n| MinterLifecycleHandler | activate                 | 511   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | advance                  | 547   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | buy                      | 578   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | cancel                   | 562   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | deliver                  | 1054  | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | directMint               | 574   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | grant                    | 551   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | open                     | 1117  | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | revoke                   | 548   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | setRejectDelivery        | 546   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | strangerCannotAdminister | 546   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | warp                     | 546   | 0       | 0        |\n╰------------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 3\n  Bound result 3\n  Bound result 1\n  Bound result 11418\n  Bound result 33\n  Bound result 203175\n  Bound result 303\n  Bound result 14\n  Bound result 100\n  Bound result 1\n  Bound result 2\n  Bound result 292\n  Bound result 135\n  Bound result 200\n  Bound result 4\n  Bound result 1\n  Bound result 67\n  Bound result 154\n  Bound result 15864\n  Bound result 51\n  Bound result 31\n  Bound result 5\n  Bound result 272\n  Bound result 4\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.45s (4.44s CPU time)\n\nRan 1 test for test/FurnitureInvariant.t.sol:FurnitureInvariantTest\n[PASS]\nFurnitureInvariantTest invariants:\n[PASS] invariant_BalancesAndSupplyMatchGhosts\n[PASS] invariant_FrozenMetadataNeverChangesAndRoyaltyIsBounded\n[PASS] invariant_OwnerNeverHoldsOrDestroysAnything\n FurnitureInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭------------------+--------------------------+-------+---------+----------╮\n| Contract         | Selector                 | Calls | Reverts | Discards |\n+==========================================================================+\n| FurnitureHandler | mint                     | 1071  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | operatorBatchTransfer    | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerMetadata            | 1045  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerTriesToSeize        | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | revokeApproval           | 1081  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | strangerCannotAdminister | 1117  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | transfer                 | 1068  | 0       | 0        |\n╰------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 5\n  Bound result 14\n  Bound result 41\n  Bound result 0\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 9\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 11\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 20\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 13\n  Bound result 14\n  Bound result 11\n  Bound result 0\n  Bound result 7\n  Bound result 9\n  Bound result 5\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 14\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 10\n  Bound result 12\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 7\n  Bound result 4\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 4\n  Bound result 4\n  Bound result 14\n  Bound result 0\n  Bound result 0\n  Bound result 8\n  Bound result 5\n  Bound result 14\n  Bound result 12\n  Bound result 14\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.85s (4.85s CPU time)\n\nRan 1 test for test/MultiActorInvariant.t.sol:MultiActorInvariantTest\n[PASS]\nMultiActorInvariantTest invariants:\n[PASS] invariant_BoxNeverHoldsTheToken\n[PASS] invariant_EveryTokenPaidIsAccountedToBurnOrAVault\n[PASS] invariant_HandlerExercisedFailurePathsAndGuarantee\n[PASS] invariant_MintedNeverExceedsCapAndMatchesSupply\n[PASS] invariant_PurchasesOpenOnceAndFinishedStatesNeverReopen\n MultiActorInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭-------------------+--------------------------+-------+---------+----------╮\n| Contract          | Selector                 | Calls | Reverts | Discards |\n+===========================================================================+\n| MultiActorHandler | advanceBlocks            | 660   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | buy                      | 1289  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | cancelSeason             | 649   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | closeSeason              | 652   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | createSeason             | 632   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | open                     | 1282  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setPaused                | 640   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setVault                 | 611   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | strangerCannotAdminister | 673   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | warp                     | 592   | 0       | 0        |\n╰-------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 8\n  Bound result 339606\n  Bound result 0\n  Bound result 1\n  Bound result 239\n  Bound result 12743\n  Bound result 4\n  Bound result 9325\n  Bound result 267\n  Bound result 8\n  Bound result 15790\n  Bound result 70\n  Bound result 95\n  Bound result 235\n  Bound result 18631\n  Bound result 183\n  Bound result 1\n  Bound result 101\n  Bound result 5000\n  Bound result 42\n  Bound result 20000\n  Bound result 9976\n  Bound result 1\n  Bound result 1434\n  Bound result 20346\n  Bound result 127\n  Bound result 2182\n  Bound result 6\n  Bound result 521\n  Bound result 4550\n  Bound result 207\n  Bound result 10763\n  Bound result 2\n  Bound result 19426589\n  Bound result 3866\n  Bound result 4\n  Bound result 2506\n  Bound result 10001\n  Bound result 183\n  Bound result 1460\n  Bound result 6\n  Bound result 1\n  Bound result 5\n  Bound result 35\n  Bound result 8\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.73s (12.72s CPU time)\n\nRan 16 test suites in 12.73s (31.47s CPU time): 111 tests passed, 0 failed, 0 skipped (111 total tests)\n","passed":true},{"durationMs":74,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubBox.acceptOwnership()\",\"OGClubBox.buy(uint256,uint256)\",\"OGClubBox.cancelSeason(uint256)\",\"OGClubBox.closeSeason(uint256)\",\"OGClubBox.createSeason(uint256,uint256,uint256,uint256,uint256,(uint256,uint8,uint256,uint256)[])\",\"OGClubBox.deliver(uint256)\",\"OGClubBox.deliverTo(uint256,address)\",\"OGClubBox.open(uint256,bytes)\",\"OGClubBox.renounceOwnership()\",\"OGClubBox.setPaused(bool)\",\"OGClubBox.setVault(address)\",\"OGClubBox.transferOwnership(address)\",\"OGClubFurniture.acceptOwnership()\",\"OGClubFurniture.activateMinter(address)\",\"OGClubFurniture.cancelMinter(address)\",\"OGClubFurniture.freezeMetadata()\",\"OGClubFurniture.grantMinter(address)\",\"OGClubFurniture.mintBatch(address,uint256[],uint256[])\",\"OGClubFurniture.renounceOwnership()\",\"OGClubFurniture.revokeMinter(address)\",\"OGClubFurniture.safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\",\"OGClubFurniture.safeTransferFrom(address,address,uint256,uint256,bytes)\",\"OGClubFurniture.setApprovalForAll(address,bool)\",\"OGClubFurniture.setBaseURI(string)\",\"OGClubFurniture.setRoyalty(address,uint96)\",\"OGClubFurniture.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":114,\"README.md\":340,\"VENDOR.md\":13,\"foundry.toml\":22,\"launch.json\":28,\"script/Deploy.s.sol\":38,\"script/encode_header.py\":80,\"src/OGClubBox.sol\":480,\"src/OGClubFurniture.sol\":132,\"src/libraries/BlockHeader.sol\":70,\"src/mocks/MockOG.sol\":21,\"test/BlockHeader.t.sol\":132,\"test/BoxInvariant.t.sol\":278,\"test/Delivery.t.sol\":207,\"test/DeliveryEdges.t.sol\":454,\"test/Deployment.t.sol\":86,\"test/EdgeCases.t.sol\":482,\"test/FixedOdds.t.sol\":252,\"test/FurnitureInvariant.t.sol\":248,\"test/MinterLifecycleInvariant.t.sol\":454,\"test/MultiActorInvariant.t.sol\":561,\"test/OGClubFurniture.t.sol\":286,\"test/OpenGas.t.sol\":188,\"test/Opening.t.sol\":249,\"test/Payments.t.sol\":202,\"test/Rolls.t.sol\":128,\"test/Seasons.t.sol\":221,\"test/fixtures/MainnetHeaders.sol\":32,\"test/fixtures/SOURCES.md\":42,\"test/fixtures/mainnet-cancun.json\":24,\"test/fixtures/mainnet-prague.json\":25,\"test/fixtures/mainnet-shanghai.json\":21,\"test/helpers/Adversaries.sol\":230,\"test/helpers/BoxTestBase.sol\":120,\"test/helpers/HeaderBuilder.sol\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"5b4518e00745c4e1db5708317b0ced4818530f134cd385b66f1df07ad83fb809","verifiedTreeHash":"7ac78a93d0eced3f5e76343187b4b2ce7778fd7e","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":6922,"exitCode":0,"name":"build","output":"Compiling 70 files with Solc 0.8.26\nSolc 0.8.26 finished in 6.84s\nCompiler run successful!\n","passed":true},{"durationMs":11453,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 9 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_AllOwnerFunctionsProtected() (gas: 205653)\n[PASS] test_BuyRequiresTheBoxToBeAnAuthorizedMinter() (gas: 452751)\n[PASS] test_BuyWindowCountPauseAndClose() (gas: 820937)\n[PASS] test_CancelOnlyBeforeOpeningAndTerminal() (gas: 1021265)\n[PASS] test_CreateValidation() (gas: 2060308)\n[PASS] test_MaximumEntryCountAndIdZeroSupported() (gas: 7255000)\n[PASS] test_OverlappingSeasonsIndependentAndTermsUnchanged() (gas: 3020677)\n[PASS] test_OwnershipRequiresAcceptanceAndCanCancelPending() (gas: 370769)\n[PASS] test_UnknownSeasonCannotBeUsed() (gas: 213261)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 10.69ms (10.07ms CPU time)\n\nRan 4 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_ConstructorsDoNotCallDependencies() (gas: 20061)\n[PASS] test_DeployExplicitParametersNoEnvironment() (gas: 22837277)\n[PASS] test_InvalidConstructorAddresses() (gas: 5913)\n[PASS] test_MockSupplySymbolDecimalsAndPublicMint() (gas: 92805)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 56.01ms (53.83ms CPU time)\n\nRan 9 tests for test/BlockHeader.t.sol:BlockHeaderTest\n[PASS] testFuzz_AnyMalformedInputRevertsWithCustomError(bytes) (runs: 256, μ: 32494, ~: 32114)\n[PASS] testFuzz_ArbitraryTrailingFieldCount(uint8,uint256,bytes32) (runs: 256, μ: 95284, ~: 75543)\nLogs:\n  Bound result 0\n\n[PASS] test_MalformedAuthenticatedHeaderCannotMint() (gas: 345499)\n[PASS] test_MalformedRLPBoundsAndCanonicalLengths() (gas: 147761)\n[PASS] test_MissingFieldsAndInvalidNumberOrMixHash() (gas: 237560)\n[PASS] test_RealMainnetCancunHeader() (gas: 1230005)\n[PASS] test_RealMainnetPragueHeader() (gas: 1234508)\n[PASS] test_RealMainnetShanghaiHeader() (gas: 1227231)\n[PASS] test_ZeroNumberAndZeroMixHashAreValidRLP() (gas: 40758)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 97.95ms (144.41ms CPU time)\n\nRan 13 tests for test/OGClubFurniture.t.sol:FurnitureTest\n[PASS] testFuzz_AfterFirstMintMustWaitAndAnyoneCanActivate(uint32) (runs: 256, μ: 575608, ~: 575429)\nLogs:\n  Bound result 4411\n\n[PASS] test_AllOwnerFunctionsProtected() (gas: 227156)\n[PASS] test_CancelStopsActivationEvenAfterDeadline() (gas: 374352)\n[PASS] test_FreshGrantsAreImmediateAndEmitTheFullMinterList() (gas: 408451)\n[PASS] test_IdentityInterfacesMintAndSupply() (gas: 428603)\n[PASS] test_InvalidAddressesAndBatchLengths() (gas: 3989)\n[PASS] test_MetadataFreezesPermanently() (gas: 195182)\n[PASS] test_NoOwnerSeizureOrBurn() (gas: 398447)\n[PASS] test_OwnershipTwoStepAndRenounce() (gas: 244222)\n[PASS] test_ReproposalRestartsDelayAndCancelDoesNotRevokeExistingRole() (gas: 436763)\n[PASS] test_RevokeIsImmediateClearsProposalsAndRegrantWaitsAgain() (gas: 515201)\n[PASS] test_RoyaltyDefaultAndLimits() (gas: 161463)\n[PASS] test_ZeroAddressesAndLegacyMinterSelectorCannotGrant() (gas: 320477)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 138.57ms (139.30ms CPU time)\n\nRan 11 tests for test/Payments.t.sol:PaymentsTest\n[PASS] testFuzz_SplitConservesPayment(uint128,uint16,uint8) (runs: 256, μ: 752671, ~: 758891)\nLogs:\n  Bound result 26417219323777785527591191417025\n  Bound result 0\n  Bound result 2\n\n[PASS] test_ChangingVaultAndSameRecipient() (gas: 553270)\n[PASS] test_ExactSplitsAndEvents() (gas: 17894259)\n[PASS] test_FalseReturnTokenRejected() (gas: 1125766)\n[PASS] test_FeeOnEitherLegRevertsBothTransfers() (gas: 3002498)\n[PASS] test_InsufficientAllowanceRollsBackFirstLeg() (gas: 330276)\n[PASS] test_NoReturnTokenSupported() (gas: 1081734)\n[PASS] test_PriceMultiplicationOverflowHasCustomError() (gas: 463928)\n[PASS] test_TokenCallbackCannotReenter() (gas: 1683627)\n[PASS] test_VaultCanBuyAndOnlyPartsWithTheBurnShare() (gas: 1843364)\n[PASS] test_VaultCannotBeBoxOrZero() (gas: 57044)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 152.60ms (161.07ms CPU time)\n\nRan 11 tests for test/Opening.t.sol:OpeningTest\n[PASS] testFuzz_ExpiredAlwaysFallback(uint8,bytes32,uint16) (runs: 256, μ: 856880, ~: 850228)\nLogs:\n  Bound result 10\n  Bound result 6945\n\n[PASS] testFuzz_PreviewMatchesOpenAndCaps(bytes32,uint8) (runs: 256, μ: 3567421, ~: 3556909)\nLogs:\n  Bound result 2\n\n[PASS] test_AuthenticatedHeaderMustHaveCorrectNumber() (gas: 346719)\n[PASS] test_BuilderFieldsDoNotAffectRoll() (gas: 2465405)\n[PASS] test_ExactExpiryBoundaryAndIgnoredHeader() (gas: 1977811)\n[PASS] test_MaturityWrongHeadersAndAlreadyOpened() (gas: 1436328)\n[PASS] test_OpenWhileClosedPausedAndPastSaleEnd() (gas: 1298340)\n[PASS] test_ReceiverReentrancySingleAndBatch() (gas: 5469140)\n[PASS] test_RejectedFirstDeliveryRecordsOpenedAndCapsAndCanRetry() (gas: 3291753)\n[PASS] test_RevokedMinterRecordsRollAndDeliversAfterExpiryAndDelayedRestoration() (gas: 2234362)\n[PASS] test_UnknownPurchase() (gas: 100382)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 341.45ms (416.35ms CPU time)\n\nRan 5 tests for test/FixedOdds.t.sol:FixedOddsTest\n[PASS] testFuzz_OtherOpensOnlyDegradeSoldOutPicks(bytes32,uint8,uint8) (runs: 256, μ: 2397721, ~: 2392165)\nLogs:\n  Bound result 7\n  Bound result 10\n\n[PASS] test_RejectedDeliveryCannotBeRetriedForABetterRoll() (gas: 2814025)\n[PASS] test_RejectedTenPackReservesRareAndCannotUpgradeAfterAnotherOpen() (gas: 4920171)\n[PASS] test_SellOutOnlyDegradesTheSoldOutPickAndNeverRemapsOthers() (gas: 3302017)\n[PASS] test_TenPackGuaranteeRerollsOnlyWhenItsOwnRareSellsOut() (gas: 3141411)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 341.43ms (263.24ms CPU time)\n\nRan 11 tests for test/DeliveryEdges.t.sol:DeliveryEdgesTest\n[PASS] testFuzz_ActivationBoundaryIsExact(uint32) (runs: 256, μ: 666411, ~: 666411)\n[PASS] testFuzz_OnlyTheBuyerRedirectsButAnyoneDelivers(bytes32,bytes32) (runs: 200, μ: 1859012, ~: 1857138)\n[PASS] testFuzz_OpenWithAnyGasIsAtomicOrRecordsThePreview(uint32,uint8,bytes32) (runs: 200, μ: 835386, ~: 823904)\nLogs:\n  Bound result 7\n  Bound result 1355990\n\n[PASS] testFuzz_StoredRollSurvivesAnyDelayAndSeasonChanges(uint64,uint64,bytes32) (runs: 200, μ: 1711225, ~: 1714750)\nLogs:\n  Bound result 5328709\n  Bound result 191230208\n\n[PASS] test_ExpiryOnlyAppliesToUnopenedPurchasesEvenWhenDeliveryIsPending() (gas: 2055678)\n[PASS] test_GasStarvedOpenOfHonestBuyerStoresRollAndAnyoneDeliversLater() (gas: 1605721)\n[PASS] test_ImmediateGrantStaysOpenWhileOnlyUndeliveredRollsExist() (gas: 1121210)\n[PASS] test_RedirectToNonReceiverContractsRevertsAndLeavesTheRollStored() (gas: 3149075)\n[PASS] test_SuccessfulOpenWritesNoStoredItemsAndFailureWritesExactlyTheRoll() (gas: 2004009)\n[PASS] test_SupplyCannotReturnToZeroSoTheDelayIsPermanent() (gas: 695847)\n[PASS] test_ZeroAmountMintsLeaveSupplyZeroAndGrantsImmediate() (gas: 387924)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 357.98ms (968.56ms CPU time)\n\nRan 7 tests for test/Delivery.t.sol:DeliveryTest\n[PASS] testFuzz_FirstDeliveryRejectionThenAnyoneCanRetryOnlyOnce(uint8) (runs: 256, μ: 1744864, ~: 1731009)\nLogs:\n  Bound result 2\n\n[PASS] test_DeliveryChecksUnknownUnopenedAndAlreadyDelivered() (gas: 723182)\n[PASS] test_ExpiredUnopenedPurchaseStillRecordsOnlyFallbacksWhenDeliveryFails() (gas: 1091765)\n[PASS] test_HostileReceiverCannotVetoTenDistinctRolledItems() (gas: 8763088)\n[PASS] test_OwnerCannotMintCappedPieceWithinSevenDaysOfProposal() (gas: 1100205)\n[PASS] test_RedirectedDeliveryRejectsReentryAndMarksDeliveredBeforeCallback() (gas: 2403685)\n[PASS] test_ZeroItemIdAndDuplicateStoredItemsDeliverExactlyOnce() (gas: 999772)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 392.86ms (398.55ms CPU time)\n\nRan 17 tests for test/EdgeCases.t.sol:EdgeCasesTest\n[PASS] testFuzz_CreateSeasonRoundTripsTermsAndEntries(uint64,uint32,uint32,uint16,uint8,bytes32) (runs: 512, μ: 1554857, ~: 1128232)\nLogs:\n  Bound result 150000\n  Bound result 23664\n  Bound result 30\n  Bound result 26\n\n[PASS] testFuzz_TenPackBoxNineIsRareExactlyWhenARareRemains(bytes32,uint8,uint8) (runs: 512, μ: 5718442, ~: 5720038)\nLogs:\n  Bound result 1\n  Bound result 1\n\n[PASS] test_BuyerCanOpenTheirOwnPurchase() (gas: 703569)\n[PASS] test_CapsAreTrackedPerSeasonNotPerItem() (gas: 4190832)\n[PASS] test_CloseIsAllowedBeforeOpeningAndCancelIsNotAfterClose() (gas: 535930)\n[PASS] test_ContractBuyerWithoutReceiverOpensAndCanRedirectDelivery() (gas: 2010230)\n[PASS] test_ExpiredOpenStillRespectsReentrancyAndOnlyMintsFallback() (gas: 575409)\n[PASS] test_ExpiryIsMeasuredFromTargetNotFromPurchase() (gas: 1046283)\n[PASS] test_InsufficientBalanceRevertsWithoutRecordingPurchase() (gas: 354482)\n[PASS] test_ListShapedTrailingFieldsAcceptedButListAtNumberOrMixHashRejected() (gas: 507928)\n[PASS] test_NumberFieldOfThirtyTwoBytesAndSingleByteAreCanonical() (gas: 513865)\n[PASS] test_OpeningOrderIsFreeButCapsStillHold() (gas: 2009530)\n[PASS] test_PauseDoesNotBlockOwnerActionsOrViews() (gas: 1723736)\n[PASS] test_PurchasesInTheSameBlockShareTheTargetAndHeader() (gas: 2550517)\n[PASS] test_SeasonLifecycleEventsAreEmittedExactly() (gas: 620908)\n[PASS] test_SingleEntrySeasonAlwaysMintsFallbackEvenInTenPack() (gas: 1194271)\n[PASS] test_TotalWeightMayEqualMaxTotalWeightButNotExceedIt() (gas: 1914485)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 393.10ms (801.48ms CPU time)\n\nRan 6 tests for test/Rolls.t.sol:RollsTest\n[PASS] testFuzz_OddsOver20000Randao(bytes32) (runs: 1, μ: 737172, ~: 737172)\n[PASS] testFuzz_RandomizedCapsNeverExceeded(bytes32,uint8,uint8) (runs: 256, μ: 6211185, ~: 6211662)\nLogs:\n  Bound result 1\n  Bound result 10\n\n[PASS] testFuzz_TenPackGuarantee(bytes32) (runs: 256, μ: 1655745, ~: 1657624)\n[PASS] test_CapsExhaustedWithinPackAndNeverRollAgain() (gas: 2395336)\n[PASS] test_GuaranteedRollUsesRelativeRareWeights() (gas: 13243199)\n[PASS] test_SeedDomainMatchesSpecification() (gas: 869534)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.17s (1.97s CPU time)\n\nRan 1 test for test/BoxInvariant.t.sol:BoxInvariantTest\n[PASS]\nBoxInvariantTest invariants:\n[PASS] invariant_CapsAndDeliveredSupplyPlusStoredItemsMatchPerSeasonMints\n[PASS] invariant_EachPurchaseOpenedOnceAndEveryOpenMatchedPreview\n[PASS] invariant_PaymentsAreConservedWithoutBoxCustody\n BoxInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭------------+-------------------+-------+---------+----------╮\n| Contract   | Selector          | Calls | Reverts | Discards |\n+=============================================================+\n| BoxHandler | advance           | 1387  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | pause             | 1371  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | purchase          | 1358  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | retryDelivery     | 1351  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | reveal            | 1312  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | setRejectDelivery | 1413  | 0       | 0        |\n╰------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 200\n  Bound result 1\n  Bound result 140\n  Bound result 1\n  Bound result 133\n  Bound result 200\n  Bound result 3\n  Bound result 192\n  Bound result 8\n  Bound result 106\n  Bound result 100\n  Bound result 226\n  Bound result 150\n  Bound result 4\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.77s (3.76s CPU time)\n\nRan 1 test for test/MinterLifecycleInvariant.t.sol:MinterLifecycleInvariantTest\n[PASS]\nMinterLifecycleInvariantTest invariants:\n[PASS] invariant_BoxHoldsNothingAndPaymentsAreConserved\n[PASS] invariant_EachPurchaseDeliveredAtMostOnceAndOnlyAfterOpening\n[PASS] invariant_MintedPerItemEqualsDeliveredSupplyPlusStoredMinusDirectMints\n[PASS] invariant_MinterRolesMatchGhostsAndNeverActivateEarly\n MinterLifecycleInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭------------------------+--------------------------+-------+---------+----------╮\n| Contract               | Selector                 | Calls | Reverts | Discards |\n+================================================================================+\n| MinterLifecycleHandler | activate                 | 511   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | advance                  | 547   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | buy                      | 578   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | cancel                   | 562   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | deliver                  | 1054  | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | directMint               | 574   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | grant                    | 551   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | open                     | 1117  | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | revoke                   | 548   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | setRejectDelivery        | 546   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | strangerCannotAdminister | 546   | 0       | 0        |\n|------------------------+--------------------------+-------+---------+----------|\n| MinterLifecycleHandler | warp                     | 546   | 0       | 0        |\n╰------------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 3\n  Bound result 3\n  Bound result 1\n  Bound result 11319\n  Bound result 33\n  Bound result 14414\n  Bound result 697\n  Bound result 14\n  Bound result 100\n  Bound result 1\n  Bound result 2\n  Bound result 139\n  Bound result 135\n  Bound result 200\n  Bound result 9\n  Bound result 3\n  Bound result 68\n  Bound result 154\n  Bound result 15990\n  Bound result 10\n  Bound result 31\n  Bound result 5\n  Bound result 142\n  Bound result 4\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.02s (4.01s CPU time)\n\nRan 1 test for test/FurnitureInvariant.t.sol:FurnitureInvariantTest\n[PASS]\nFurnitureInvariantTest invariants:\n[PASS] invariant_BalancesAndSupplyMatchGhosts\n[PASS] invariant_FrozenMetadataNeverChangesAndRoyaltyIsBounded\n[PASS] invariant_OwnerNeverHoldsOrDestroysAnything\n FurnitureInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭------------------+--------------------------+-------+---------+----------╮\n| Contract         | Selector                 | Calls | Reverts | Discards |\n+==========================================================================+\n| FurnitureHandler | mint                     | 1071  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | operatorBatchTransfer    | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerMetadata            | 1045  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerTriesToSeize        | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | revokeApproval           | 1081  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | strangerCannotAdminister | 1117  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | transfer                 | 1068  | 0       | 0        |\n╰------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 5\n  Bound result 14\n  Bound result 1\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 4\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 9\n  Bound result 8\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 7\n  Bound result 0\n  Bound result 14\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 9\n  Bound result 0\n  Bound result 1090\n  Bound result 11\n  Bound result 0\n  Bound result 0\n  Bound result 12\n  Bound result 5\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 14\n  Bound result 1\n  Bound result 320\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 14\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 9\n  Bound result 3\n  Bound result 24\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 10\n  Bound result 0\n  Bound result 12\n  Bound result 14\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.36s (4.36s CPU time)\n\nRan 1 test for test/MultiActorInvariant.t.sol:MultiActorInvariantTest\n[PASS]\nMultiActorInvariantTest invariants:\n[PASS] invariant_BoxNeverHoldsTheToken\n[PASS] invariant_EveryTokenPaidIsAccountedToBurnOrAVault\n[PASS] invariant_HandlerExercisedFailurePathsAndGuarantee\n[PASS] invariant_MintedNeverExceedsCapAndMatchesSupply\n[PASS] invariant_PurchasesOpenOnceAndFinishedStatesNeverReopen\n MultiActorInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭-------------------+--------------------------+-------+---------+----------╮\n| Contract          | Selector                 | Calls | Reverts | Discards |\n+===========================================================================+\n| MultiActorHandler | advanceBlocks            | 660   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | buy                      | 1289  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | cancelSeason             | 649   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | closeSeason              | 652   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | createSeason             | 632   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | open                     | 1282  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setPaused                | 640   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setVault                 | 611   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | strangerCannotAdminister | 673   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | warp                     | 592   | 0       | 0        |\n╰-------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 339606\n  Bound result 0\n  Bound result 1\n  Bound result 239\n  Bound result 12743\n  Bound result 4\n  Bound result 7253\n  Bound result 151\n  Bound result 10\n  Bound result 15716\n  Bound result 70\n  Bound result 172\n  Bound result 132\n  Bound result 2380\n  Bound result 183\n  Bound result 2\n  Bound result 101\n  Bound result 50\n  Bound result 519\n  Bound result 12\n  Bound result 9663\n  Bound result 2\n  Bound result 1434\n  Bound result 20316\n  Bound result 95\n  Bound result 6090\n  Bound result 6\n  Bound result 3558\n  Bound result 258\n  Bound result 279\n  Bound result 7499\n  Bound result 4\n  Bound result 19426589\n  Bound result 1024\n  Bound result 1\n  Bound result 3448\n  Bound result 10001\n  Bound result 198\n  Bound result 6473\n  Bound result 12\n  Bound result 1\n  Bound result 4\n  Bound result 35\n  Bound result 8\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 11.36s (11.35s CPU time)\n\nRan 15 test suites in 11.36s (26.96s CPU time): 107 tests passed, 0 failed, 0 skipped (107 total tests)\n","passed":true},{"durationMs":58,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubBox.acceptOwnership()\",\"OGClubBox.buy(uint256,uint256)\",\"OGClubBox.cancelSeason(uint256)\",\"OGClubBox.closeSeason(uint256)\",\"OGClubBox.createSeason(uint256,uint256,uint256,uint256,uint256,(uint256,uint8,uint256,uint256)[])\",\"OGClubBox.deliver(uint256)\",\"OGClubBox.deliverTo(uint256,address)\",\"OGClubBox.open(uint256,bytes)\",\"OGClubBox.renounceOwnership()\",\"OGClubBox.setPaused(bool)\",\"OGClubBox.setVault(address)\",\"OGClubBox.transferOwnership(address)\",\"OGClubFurniture.acceptOwnership()\",\"OGClubFurniture.activateMinter(address)\",\"OGClubFurniture.cancelMinter(address)\",\"OGClubFurniture.freezeMetadata()\",\"OGClubFurniture.grantMinter(address)\",\"OGClubFurniture.mintBatch(address,uint256[],uint256[])\",\"OGClubFurniture.renounceOwnership()\",\"OGClubFurniture.revokeMinter(address)\",\"OGClubFurniture.safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\",\"OGClubFurniture.safeTransferFrom(address,address,uint256,uint256,bytes)\",\"OGClubFurniture.setApprovalForAll(address,bool)\",\"OGClubFurniture.setBaseURI(string)\",\"OGClubFurniture.setRoyalty(address,uint96)\",\"OGClubFurniture.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":85,\"README.md\":319,\"VENDOR.md\":13,\"foundry.toml\":22,\"launch.json\":28,\"script/Deploy.s.sol\":38,\"script/encode_header.py\":80,\"src/OGClubBox.sol\":472,\"src/OGClubFurniture.sol\":132,\"src/libraries/BlockHeader.sol\":70,\"src/mocks/MockOG.sol\":21,\"test/BlockHeader.t.sol\":132,\"test/BoxInvariant.t.sol\":278,\"test/Delivery.t.sol\":207,\"test/DeliveryEdges.t.sol\":410,\"test/Deployment.t.sol\":86,\"test/EdgeCases.t.sol\":482,\"test/FixedOdds.t.sol\":252,\"test/FurnitureInvariant.t.sol\":248,\"test/MinterLifecycleInvariant.t.sol\":454,\"test/MultiActorInvariant.t.sol\":561,\"test/OGClubFurniture.t.sol\":286,\"test/Opening.t.sol\":249,\"test/Payments.t.sol\":202,\"test/Rolls.t.sol\":128,\"test/Seasons.t.sol\":221,\"test/fixtures/MainnetHeaders.sol\":32,\"test/fixtures/SOURCES.md\":42,\"test/fixtures/mainnet-cancun.json\":24,\"test/fixtures/mainnet-prague.json\":25,\"test/fixtures/mainnet-shanghai.json\":21,\"test/helpers/Adversaries.sol\":230,\"test/helpers/BoxTestBase.sol\":120,\"test/helpers/HeaderBuilder.sol\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"676f34ccce154fc8bb23c5b1958ab4bc193dffaeced5dba555b3a248247fb96c","verifiedTreeHash":"49c461722ffe000237609e18ebd698a822336dbf","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":6106,"exitCode":0,"name":"build","output":"Compiling 68 files with Solc 0.8.26\nSolc 0.8.26 finished in 6.01s\nCompiler run successful!\n","passed":true},{"durationMs":11433,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 7 tests for test/Delivery.t.sol:DeliveryTest\n[PASS] testFuzz_FirstDeliveryRejectionThenAnyoneCanRetryOnlyOnce(uint8) (runs: 256, μ: 1744864, ~: 1731009)\nLogs:\n  Bound result 1\n\n[PASS] test_DeliveryChecksUnknownUnopenedAndAlreadyDelivered() (gas: 723182)\n[PASS] test_ExpiredUnopenedPurchaseStillRecordsOnlyFallbacksWhenDeliveryFails() (gas: 1091765)\n[PASS] test_HostileReceiverCannotVetoTenDistinctRolledItems() (gas: 8763088)\n[PASS] test_OwnerCannotMintCappedPieceWithinSevenDaysOfProposal() (gas: 1100205)\n[PASS] test_RedirectedDeliveryRejectsReentryAndMarksDeliveredBeforeCallback() (gas: 2403685)\n[PASS] test_ZeroItemIdAndDuplicateStoredItemsDeliverExactlyOnce() (gas: 999772)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 174.38ms (188.42ms CPU time)\n\nRan 5 tests for test/FixedOdds.t.sol:FixedOddsTest\n[PASS] testFuzz_OtherOpensOnlyDegradeSoldOutPicks(bytes32,uint8,uint8) (runs: 256, μ: 2393744, ~: 2389109)\nLogs:\n  Bound result 7\n  Bound result 10\n\n[PASS] test_RejectedDeliveryCannotBeRetriedForABetterRoll() (gas: 2814025)\n[PASS] test_RejectedTenPackReservesRareAndCannotUpgradeAfterAnotherOpen() (gas: 4920171)\n[PASS] test_SellOutOnlyDegradesTheSoldOutPickAndNeverRemapsOthers() (gas: 3302017)\n[PASS] test_TenPackGuaranteeRerollsOnlyWhenItsOwnRareSellsOut() (gas: 3141411)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 174.41ms (188.66ms CPU time)\n\nRan 4 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_ConstructorsDoNotCallDependencies() (gas: 20061)\n[PASS] test_DeployExplicitParametersNoEnvironment() (gas: 22837277)\n[PASS] test_InvalidConstructorAddresses() (gas: 5913)\n[PASS] test_MockSupplySymbolDecimalsAndPublicMint() (gas: 92805)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 239.22ms (32.93ms CPU time)\n\nRan 11 tests for test/Payments.t.sol:PaymentsTest\n[PASS] testFuzz_SplitConservesPayment(uint128,uint16,uint8) (runs: 256, μ: 752671, ~: 758891)\nLogs:\n  Bound result 26417219323777785527591191417025\n  Bound result 0\n  Bound result 2\n\n[PASS] test_ChangingVaultAndSameRecipient() (gas: 553270)\n[PASS] test_ExactSplitsAndEvents() (gas: 17894259)\n[PASS] test_FalseReturnTokenRejected() (gas: 1125766)\n[PASS] test_FeeOnEitherLegRevertsBothTransfers() (gas: 3002498)\n[PASS] test_InsufficientAllowanceRollsBackFirstLeg() (gas: 330276)\n[PASS] test_NoReturnTokenSupported() (gas: 1081734)\n[PASS] test_PriceMultiplicationOverflowHasCustomError() (gas: 463928)\n[PASS] test_TokenCallbackCannotReenter() (gas: 1683627)\n[PASS] test_VaultCanBuyAndOnlyPartsWithTheBurnShare() (gas: 1843364)\n[PASS] test_VaultCannotBeBoxOrZero() (gas: 57044)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 239.22ms (50.25ms CPU time)\n\nRan 11 tests for test/Opening.t.sol:OpeningTest\n[PASS] testFuzz_ExpiredAlwaysFallback(uint8,bytes32,uint16) (runs: 256, μ: 856880, ~: 850228)\nLogs:\n  Bound result 10\n  Bound result 6945\n\n[PASS] testFuzz_PreviewMatchesOpenAndCaps(bytes32,uint8) (runs: 256, μ: 3568747, ~: 3556909)\nLogs:\n  Bound result 3\n\n[PASS] test_AuthenticatedHeaderMustHaveCorrectNumber() (gas: 346719)\n[PASS] test_BuilderFieldsDoNotAffectRoll() (gas: 2465405)\n[PASS] test_ExactExpiryBoundaryAndIgnoredHeader() (gas: 1977811)\n[PASS] test_MaturityWrongHeadersAndAlreadyOpened() (gas: 1436328)\n[PASS] test_OpenWhileClosedPausedAndPastSaleEnd() (gas: 1298340)\n[PASS] test_ReceiverReentrancySingleAndBatch() (gas: 5469140)\n[PASS] test_RejectedFirstDeliveryRecordsOpenedAndCapsAndCanRetry() (gas: 3291753)\n[PASS] test_RevokedMinterRecordsRollAndDeliversAfterExpiryAndDelayedRestoration() (gas: 2234362)\n[PASS] test_UnknownPurchase() (gas: 100382)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 240.12ms (340.57ms CPU time)\n\nRan 13 tests for test/OGClubFurniture.t.sol:FurnitureTest\n[PASS] testFuzz_AfterFirstMintMustWaitAndAnyoneCanActivate(uint32) (runs: 256, μ: 575586, ~: 575429)\nLogs:\n  Bound result 50016\n\n[PASS] test_AllOwnerFunctionsProtected() (gas: 227156)\n[PASS] test_CancelStopsActivationEvenAfterDeadline() (gas: 374352)\n[PASS] test_FreshGrantsAreImmediateAndEmitTheFullMinterList() (gas: 408451)\n[PASS] test_IdentityInterfacesMintAndSupply() (gas: 428603)\n[PASS] test_InvalidAddressesAndBatchLengths() (gas: 3989)\n[PASS] test_MetadataFreezesPermanently() (gas: 195182)\n[PASS] test_NoOwnerSeizureOrBurn() (gas: 398447)\n[PASS] test_OwnershipTwoStepAndRenounce() (gas: 244222)\n[PASS] test_ReproposalRestartsDelayAndCancelDoesNotRevokeExistingRole() (gas: 436763)\n[PASS] test_RevokeIsImmediateClearsProposalsAndRegrantWaitsAgain() (gas: 515201)\n[PASS] test_RoyaltyDefaultAndLimits() (gas: 161463)\n[PASS] test_ZeroAddressesAndLegacyMinterSelectorCannotGrant() (gas: 320477)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 279.30ms (48.16ms CPU time)\n\nRan 9 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_AllOwnerFunctionsProtected() (gas: 205653)\n[PASS] test_BuyRequiresTheBoxToBeAnAuthorizedMinter() (gas: 452751)\n[PASS] test_BuyWindowCountPauseAndClose() (gas: 820937)\n[PASS] test_CancelOnlyBeforeOpeningAndTerminal() (gas: 1021265)\n[PASS] test_CreateValidation() (gas: 2060308)\n[PASS] test_MaximumEntryCountAndIdZeroSupported() (gas: 7255000)\n[PASS] test_OverlappingSeasonsIndependentAndTermsUnchanged() (gas: 3020677)\n[PASS] test_OwnershipRequiresAcceptanceAndCanCancelPending() (gas: 370769)\n[PASS] test_UnknownSeasonCannotBeUsed() (gas: 213261)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 297.94ms (14.46ms CPU time)\n\nRan 9 tests for test/BlockHeader.t.sol:BlockHeaderTest\n[PASS] testFuzz_AnyMalformedInputRevertsWithCustomError(bytes) (runs: 256, μ: 32490, ~: 32093)\n[PASS] testFuzz_ArbitraryTrailingFieldCount(uint8,uint256,bytes32) (runs: 256, μ: 95226, ~: 75084)\nLogs:\n  Bound result 43\n\n[PASS] test_MalformedAuthenticatedHeaderCannotMint() (gas: 345499)\n[PASS] test_MalformedRLPBoundsAndCanonicalLengths() (gas: 147761)\n[PASS] test_MissingFieldsAndInvalidNumberOrMixHash() (gas: 237560)\n[PASS] test_RealMainnetCancunHeader() (gas: 1230005)\n[PASS] test_RealMainnetPragueHeader() (gas: 1234508)\n[PASS] test_RealMainnetShanghaiHeader() (gas: 1227231)\n[PASS] test_ZeroNumberAndZeroMixHashAreValidRLP() (gas: 40758)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 303.17ms (433.63ms CPU time)\n\nRan 17 tests for test/EdgeCases.t.sol:EdgeCasesTest\n[PASS] testFuzz_CreateSeasonRoundTripsTermsAndEntries(uint64,uint32,uint32,uint16,uint8,bytes32) (runs: 512, μ: 1555907, ~: 1137065)\nLogs:\n  Bound result 1200000\n  Bound result 23664\n  Bound result 30\n  Bound result 26\n\n[PASS] testFuzz_TenPackBoxNineIsRareExactlyWhenARareRemains(bytes32,uint8,uint8) (runs: 512, μ: 5717754, ~: 5718162)\nLogs:\n  Bound result 4\n  Bound result 1\n\n[PASS] test_BuyerCanOpenTheirOwnPurchase() (gas: 703569)\n[PASS] test_CapsAreTrackedPerSeasonNotPerItem() (gas: 4190832)\n[PASS] test_CloseIsAllowedBeforeOpeningAndCancelIsNotAfterClose() (gas: 535930)\n[PASS] test_ContractBuyerWithoutReceiverOpensAndCanRedirectDelivery() (gas: 2010230)\n[PASS] test_ExpiredOpenStillRespectsReentrancyAndOnlyMintsFallback() (gas: 575409)\n[PASS] test_ExpiryIsMeasuredFromTargetNotFromPurchase() (gas: 1046283)\n[PASS] test_InsufficientBalanceRevertsWithoutRecordingPurchase() (gas: 354482)\n[PASS] test_ListShapedTrailingFieldsAcceptedButListAtNumberOrMixHashRejected() (gas: 507928)\n[PASS] test_NumberFieldOfThirtyTwoBytesAndSingleByteAreCanonical() (gas: 513865)\n[PASS] test_OpeningOrderIsFreeButCapsStillHold() (gas: 2009530)\n[PASS] test_PauseDoesNotBlockOwnerActionsOrViews() (gas: 1723736)\n[PASS] test_PurchasesInTheSameBlockShareTheTargetAndHeader() (gas: 2550517)\n[PASS] test_SeasonLifecycleEventsAreEmittedExactly() (gas: 620908)\n[PASS] test_SingleEntrySeasonAlwaysMintsFallbackEvenInTenPack() (gas: 1194271)\n[PASS] test_TotalWeightMayEqualMaxTotalWeightButNotExceedIt() (gas: 1914485)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 324.62ms (590.20ms CPU time)\n\nRan 6 tests for test/Rolls.t.sol:RollsTest\n[PASS] testFuzz_OddsOver20000Randao(bytes32) (runs: 1, μ: 737172, ~: 737172)\n[PASS] testFuzz_RandomizedCapsNeverExceeded(bytes32,uint8,uint8) (runs: 256, μ: 6211915, ~: 6212443)\nLogs:\n  Bound result 1\n  Bound result 10\n\n[PASS] testFuzz_TenPackGuarantee(bytes32) (runs: 256, μ: 1655537, ~: 1657624)\n[PASS] test_CapsExhaustedWithinPackAndNeverRollAgain() (gas: 2395336)\n[PASS] test_GuaranteedRollUsesRelativeRareWeights() (gas: 13243199)\n[PASS] test_SeedDomainMatchesSpecification() (gas: 869534)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.15s (1.71s CPU time)\n\nRan 1 test for test/BoxInvariant.t.sol:BoxInvariantTest\n[PASS]\nBoxInvariantTest invariants:\n[PASS] invariant_CapsAndDeliveredSupplyPlusStoredItemsMatchPerSeasonMints\n[PASS] invariant_EachPurchaseOpenedOnceAndEveryOpenMatchedPreview\n[PASS] invariant_PaymentsAreConservedWithoutBoxCustody\n BoxInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭------------+-------------------+-------+---------+----------╮\n| Contract   | Selector          | Calls | Reverts | Discards |\n+=============================================================+\n| BoxHandler | advance           | 1387  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | pause             | 1371  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | purchase          | 1358  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | retryDelivery     | 1351  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | reveal            | 1312  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | setRejectDelivery | 1413  | 0       | 0        |\n╰------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 200\n  Bound result 1\n  Bound result 141\n  Bound result 1\n  Bound result 133\n  Bound result 200\n  Bound result 4\n  Bound result 192\n  Bound result 8\n  Bound result 17\n  Bound result 88\n  Bound result 227\n  Bound result 54\n  Bound result 4\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.89s (3.88s CPU time)\n\nRan 1 test for test/FurnitureInvariant.t.sol:FurnitureInvariantTest\n[PASS]\nFurnitureInvariantTest invariants:\n[PASS] invariant_BalancesAndSupplyMatchGhosts\n[PASS] invariant_FrozenMetadataNeverChangesAndRoyaltyIsBounded\n[PASS] invariant_OwnerNeverHoldsOrDestroysAnything\n FurnitureInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭------------------+--------------------------+-------+---------+----------╮\n| Contract         | Selector                 | Calls | Reverts | Discards |\n+==========================================================================+\n| FurnitureHandler | mint                     | 1071  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | operatorBatchTransfer    | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerMetadata            | 1045  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerTriesToSeize        | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | revokeApproval           | 1081  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | strangerCannotAdminister | 1117  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | transfer                 | 1068  | 0       | 0        |\n╰------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 5\n  Bound result 14\n  Bound result 1\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 4\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 9\n  Bound result 8\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 7\n  Bound result 0\n  Bound result 14\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 9\n  Bound result 0\n  Bound result 1090\n  Bound result 11\n  Bound result 0\n  Bound result 0\n  Bound result 12\n  Bound result 5\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 14\n  Bound result 1\n  Bound result 639\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 14\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 9\n  Bound result 3\n  Bound result 24\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 10\n  Bound result 0\n  Bound result 12\n  Bound result 14\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.30s (4.30s CPU time)\n\nRan 1 test for test/MultiActorInvariant.t.sol:MultiActorInvariantTest\n[PASS]\nMultiActorInvariantTest invariants:\n[PASS] invariant_BoxNeverHoldsTheToken\n[PASS] invariant_EveryTokenPaidIsAccountedToBurnOrAVault\n[PASS] invariant_HandlerExercisedFailurePathsAndGuarantee\n[PASS] invariant_MintedNeverExceedsCapAndMatchesSupply\n[PASS] invariant_PurchasesOpenOnceAndFinishedStatesNeverReopen\n MultiActorInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭-------------------+--------------------------+-------+---------+----------╮\n| Contract          | Selector                 | Calls | Reverts | Discards |\n+===========================================================================+\n| MultiActorHandler | advanceBlocks            | 660   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | buy                      | 1289  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | cancelSeason             | 649   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | closeSeason              | 652   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | createSeason             | 632   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | open                     | 1282  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setPaused                | 640   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setVault                 | 611   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | strangerCannotAdminister | 673   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | warp                     | 592   | 0       | 0        |\n╰-------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 339606\n  Bound result 0\n  Bound result 1\n  Bound result 239\n  Bound result 12743\n  Bound result 4\n  Bound result 7253\n  Bound result 151\n  Bound result 10\n  Bound result 15716\n  Bound result 70\n  Bound result 172\n  Bound result 132\n  Bound result 2380\n  Bound result 183\n  Bound result 2\n  Bound result 101\n  Bound result 50\n  Bound result 3456\n  Bound result 16\n  Bound result 9663\n  Bound result 2\n  Bound result 1434\n  Bound result 20316\n  Bound result 242\n  Bound result 6090\n  Bound result 6\n  Bound result 3558\n  Bound result 258\n  Bound result 279\n  Bound result 7499\n  Bound result 4\n  Bound result 7\n  Bound result 1024\n  Bound result 1\n  Bound result 3448\n  Bound result 10001\n  Bound result 196\n  Bound result 1549\n  Bound result 1\n  Bound result 1\n  Bound result 4\n  Bound result 35\n  Bound result 8\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 11.34s (11.34s CPU time)\n\nRan 13 test suites in 11.34s (22.95s CPU time): 95 tests passed, 0 failed, 0 skipped (95 total tests)\n","passed":true},{"durationMs":59,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubBox.acceptOwnership()\",\"OGClubBox.buy(uint256,uint256)\",\"OGClubBox.cancelSeason(uint256)\",\"OGClubBox.closeSeason(uint256)\",\"OGClubBox.createSeason(uint256,uint256,uint256,uint256,uint256,(uint256,uint8,uint256,uint256)[])\",\"OGClubBox.deliver(uint256)\",\"OGClubBox.deliverTo(uint256,address)\",\"OGClubBox.open(uint256,bytes)\",\"OGClubBox.renounceOwnership()\",\"OGClubBox.setPaused(bool)\",\"OGClubBox.setVault(address)\",\"OGClubBox.transferOwnership(address)\",\"OGClubFurniture.acceptOwnership()\",\"OGClubFurniture.activateMinter(address)\",\"OGClubFurniture.cancelMinter(address)\",\"OGClubFurniture.freezeMetadata()\",\"OGClubFurniture.grantMinter(address)\",\"OGClubFurniture.mintBatch(address,uint256[],uint256[])\",\"OGClubFurniture.renounceOwnership()\",\"OGClubFurniture.revokeMinter(address)\",\"OGClubFurniture.safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\",\"OGClubFurniture.safeTransferFrom(address,address,uint256,uint256,bytes)\",\"OGClubFurniture.setApprovalForAll(address,bool)\",\"OGClubFurniture.setBaseURI(string)\",\"OGClubFurniture.setRoyalty(address,uint96)\",\"OGClubFurniture.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":85,\"README.md\":319,\"VENDOR.md\":13,\"foundry.toml\":22,\"launch.json\":28,\"script/Deploy.s.sol\":38,\"script/encode_header.py\":80,\"src/OGClubBox.sol\":472,\"src/OGClubFurniture.sol\":132,\"src/libraries/BlockHeader.sol\":70,\"src/mocks/MockOG.sol\":21,\"test/BlockHeader.t.sol\":132,\"test/BoxInvariant.t.sol\":278,\"test/Delivery.t.sol\":207,\"test/Deployment.t.sol\":86,\"test/EdgeCases.t.sol\":482,\"test/FixedOdds.t.sol\":252,\"test/FurnitureInvariant.t.sol\":248,\"test/MultiActorInvariant.t.sol\":561,\"test/OGClubFurniture.t.sol\":286,\"test/Opening.t.sol\":249,\"test/Payments.t.sol\":202,\"test/Rolls.t.sol\":128,\"test/Seasons.t.sol\":221,\"test/fixtures/MainnetHeaders.sol\":32,\"test/fixtures/SOURCES.md\":42,\"test/fixtures/mainnet-cancun.json\":24,\"test/fixtures/mainnet-prague.json\":25,\"test/fixtures/mainnet-shanghai.json\":21,\"test/helpers/Adversaries.sol\":230,\"test/helpers/BoxTestBase.sol\":120,\"test/helpers/HeaderBuilder.sol\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1909,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/OGClubBox.sol:338: Reentrancy in OGClubBox._pay(address,uint256) (src/OGClubBox.sol#338-346):\n[medium/high] incorrect-equality at src/OGClubBox.sol:385: OGClubBox._picks(uint256,OGClubBox.Purchase,bytes32,OGClubBox.Entry[]) (src/OGClubBox.sol#385-403) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/OGClubFurniture.sol:63: OGClubFurniture.activateMinter(address) (src/OGClubFurniture.sol#63-70) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/OGClubBox.sol:272: OGClubBox._deliver(uint256,address) (src/OGClubBox.sol#272-288) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/OGClubBox.sol:229: Reentrancy in OGClubBox.open(uint256,bytes) (src/OGClubBox.sol#229-258):\n[medium/medium] uninitialized-local at src/OGClubBox.sol:393: OGClubBox._picks(uint256,OGClubBox.Purchase,bytes32,OGClubBox.Entry[]).fallbackIndex (src/OGClubBox.sol#393) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:420: OGClubBox._pick(OGClubBox.Entry[],uint256[],uint256,uint256,bool).totalWeight (src/OGClubBox.sol#420) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:436: OGClubBox._pickRare(OGClubBox.Entry[],uint256[],uint256).rareWeight (src/OGClubBox.sol#436) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:232: OGClubBox.open(uint256,bytes).prevRandao (src/OGClubBox.sol#232) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:148: OGClubBox.createSeason(uint256,uint256,uint256,uint256,uint256,OGClubBox.Entry[]).totalWeight (src/OGClubBox.sol#148) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:437: OGClubBox._pickRare(OGClubBox.Entry[],uint256[],uint256).availableRareWeight (src/OGClubBox.sol#437) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:149: OGClubBox.createSeason(uint256,uint256,uint256,uint256,uint256,OGClubBox.Entry[]).validFallback (src/OGClubBox.sol#149) is a local variable never initialized\n[low/medium] reentrancy-benign at src/OGClubBox.sol:229: Reentrancy in OGClubBox.open(uint256,bytes) (src/OGClubBox.sol#229-258):\n[low/medium] timestamp at src/OGClubFurniture.sol:63: OGClubFurniture.activateMinter(address) (src/OGClubFurniture.sol#63-70) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubBox.sol:204: OGClubBox.buy(uint256,uint256) (src/OGClubBox.sol#204-224) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubBox.sol:180: OGClubBox.cancelSeason(uint256) (src/OGClubBox.sol#180-187) uses timestamp for comparisons","passed":true},{"durationMs":540,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/OGClubBox.sol:211: Reentrancy: State change after external call\n[low] centralization-risk at src/OGClubBox.sol:16: Centralization Risk (13 places)\n[low] costly-loop at src/OGClubBox.sol:165: Costly operations inside loop (2 places)\n[low] large-numeric-literal at src/OGClubBox.sol:47: Large Numeric Literal (4 places)\n[low] literal-instead-of-constant at src/OGClubBox.sol:206: Literal Instead of Constant (13 places)\n[low] push-zero-opcode at src/OGClubBox.sol:2: PUSH0 Opcode (4 places)\n[low] require-revert-in-loop at src/OGClubBox.sol:150: Loop Contains `require`/`revert` (4 places)\n[low] unchecked-return at src/OGClubBox.sol:326: Unchecked Return\n[low] uninitialized-local-variable at src/OGClubBox.sol:150: Uninitialized Local Variable (8 places)\n[low] unspecific-solidity-pragma at src/OGClubBox.sol:2: Unspecific Solidity Pragma (3 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"d239ced88fb69fadb2993ee0c86b3a2c999c31421b02630528ec873a12d2af8a","verifiedTreeHash":"922673fbb6c9a67ea60c02e5557f6e8ba5e41b07","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":8370,"exitCode":0,"name":"build","output":"Compiling 69 files with Solc 0.8.26\nSolc 0.8.26 finished in 8.26s\nCompiler run successful!\n","passed":true},{"durationMs":15218,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 9 tests for test/Seasons.t.sol:SeasonsTest\n[PASS] test_AllOwnerFunctionsProtected() (gas: 205698)\n[PASS] test_BuyRequiresTheBoxToBeAnAuthorizedMinter() (gas: 452707)\n[PASS] test_BuyWindowCountPauseAndClose() (gas: 820739)\n[PASS] test_CancelOnlyBeforeOpeningAndTerminal() (gas: 1021489)\n[PASS] test_CreateValidation() (gas: 2060670)\n[PASS] test_MaximumEntryCountAndIdZeroSupported() (gas: 7259036)\n[PASS] test_OverlappingSeasonsIndependentAndTermsUnchanged() (gas: 3021445)\n[PASS] test_OwnershipRequiresAcceptanceAndCanCancelPending() (gas: 370701)\n[PASS] test_UnknownSeasonCannotBeUsed() (gas: 213263)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 11.67ms (13.15ms CPU time)\n\nRan 4 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_ConstructorsDoNotCallDependencies() (gas: 20105)\n[PASS] test_DeployExplicitParametersNoEnvironment() (gas: 22885930)\n[PASS] test_InvalidConstructorAddresses() (gas: 5913)\n[PASS] test_MockSupplySymbolDecimalsAndPublicMint() (gas: 92805)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 132.73ms (29.32ms CPU time)\n\nRan 5 tests for test/FixedOdds.t.sol:FixedOddsTest\n[PASS] testFuzz_OtherOpensOnlyDegradeSoldOutPicks(bytes32,uint8,uint8) (runs: 256, μ: 2391492, ~: 2377028)\nLogs:\n  Bound result 4\n  Bound result 1\n\n[PASS] test_RejectedDeliveryCannotBeRetriedForABetterRoll() (gas: 2813846)\n[PASS] test_RejectedTenPackReservesRareAndCannotUpgradeAfterAnotherOpen() (gas: 4920698)\n[PASS] test_SellOutOnlyDegradesTheSoldOutPickAndNeverRemapsOthers() (gas: 3302980)\n[PASS] test_TenPackGuaranteeRerollsOnlyWhenItsOwnRareSellsOut() (gas: 3142399)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 135.06ms (144.50ms CPU time)\n\nRan 13 tests for test/OGClubFurniture.t.sol:FurnitureTest\n[PASS] testFuzz_AfterFirstMintMustWaitAndAnyoneCanActivate(uint32) (runs: 256, μ: 575602, ~: 575429)\nLogs:\n  Bound result 50016\n\n[PASS] test_AllOwnerFunctionsProtected() (gas: 227156)\n[PASS] test_CancelStopsActivationEvenAfterDeadline() (gas: 374352)\n[PASS] test_FreshGrantsAreImmediateAndEmitTheFullMinterList() (gas: 408451)\n[PASS] test_IdentityInterfacesMintAndSupply() (gas: 428603)\n[PASS] test_InvalidAddressesAndBatchLengths() (gas: 3989)\n[PASS] test_MetadataFreezesPermanently() (gas: 195182)\n[PASS] test_NoOwnerSeizureOrBurn() (gas: 398447)\n[PASS] test_OwnershipTwoStepAndRenounce() (gas: 244222)\n[PASS] test_ReproposalRestartsDelayAndCancelDoesNotRevokeExistingRole() (gas: 436763)\n[PASS] test_RevokeIsImmediateClearsProposalsAndRegrantWaitsAgain() (gas: 515201)\n[PASS] test_RoyaltyDefaultAndLimits() (gas: 161463)\n[PASS] test_ZeroAddressesAndLegacyMinterSelectorCannotGrant() (gas: 320477)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 348.29ms (351.68ms CPU time)\n\nRan 11 tests for test/Payments.t.sol:PaymentsTest\n[PASS] testFuzz_SplitConservesPayment(uint128,uint16,uint8) (runs: 256, μ: 752948, ~: 758875)\nLogs:\n  Bound result 26417219323777785527591191417025\n  Bound result 0\n  Bound result 2\n\n[PASS] test_ChangingVaultAndSameRecipient() (gas: 553226)\n[PASS] test_ExactSplitsAndEvents() (gas: 17893159)\n[PASS] test_FalseReturnTokenRejected() (gas: 1125744)\n[PASS] test_FeeOnEitherLegRevertsBothTransfers() (gas: 3002454)\n[PASS] test_InsufficientAllowanceRollsBackFirstLeg() (gas: 330254)\n[PASS] test_NoReturnTokenSupported() (gas: 1081712)\n[PASS] test_PriceMultiplicationOverflowHasCustomError() (gas: 463906)\n[PASS] test_TokenCallbackCannotReenter() (gas: 1683561)\n[PASS] test_VaultCanBuyAndOnlyPartsWithTheBurnShare() (gas: 1843298)\n[PASS] test_VaultCannotBeBoxOrZero() (gas: 57044)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 355.71ms (364.46ms CPU time)\n\nRan 4 tests for test/OpenGas.t.sol:OpenGasTest\n[PASS] testFuzz_LowestSucceedingGasDeliversAndStoresNothing(uint8,bytes32) (runs: 256, μ: 6936597, ~: 6937634)\nLogs:\n  Bound result 2\n\n[PASS] test_GasConstantsArePublishedAndConsistent() (gas: 35215)\n[PASS] test_ReserveSavesTenDistinctItemsAtLowestDeliveryGas() (gas: 41364778)\n[PASS] test_ShortGasOpenRevertsInsteadOfRecordingDeliveryFailure() (gas: 2344960)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 444.32ms (507.13ms CPU time)\n\nRan 9 tests for test/BlockHeader.t.sol:BlockHeaderTest\n[PASS] testFuzz_AnyMalformedInputRevertsWithCustomError(bytes) (runs: 256, μ: 32486, ~: 32061)\n[PASS] testFuzz_ArbitraryTrailingFieldCount(uint8,uint256,bytes32) (runs: 256, μ: 94133, ~: 74652)\nLogs:\n  Bound result 53\n\n[PASS] test_MalformedAuthenticatedHeaderCannotMint() (gas: 345411)\n[PASS] test_MalformedRLPBoundsAndCanonicalLengths() (gas: 147761)\n[PASS] test_MissingFieldsAndInvalidNumberOrMixHash() (gas: 237560)\n[PASS] test_RealMainnetCancunHeader() (gas: 1230367)\n[PASS] test_RealMainnetPragueHeader() (gas: 1234870)\n[PASS] test_RealMainnetShanghaiHeader() (gas: 1227593)\n[PASS] test_ZeroNumberAndZeroMixHashAreValidRLP() (gas: 40758)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 530.45ms (149.66ms CPU time)\n\nRan 17 tests for test/EdgeCases.t.sol:EdgeCasesTest\n[PASS] testFuzz_CreateSeasonRoundTripsTermsAndEntries(uint64,uint32,uint32,uint16,uint8,bytes32) (runs: 512, μ: 1553118, ~: 1157152)\nLogs:\n  Bound result 14449\n  Bound result 697\n  Bound result 5455\n  Bound result 27\n\n[PASS] testFuzz_TenPackBoxNineIsRareExactlyWhenARareRemains(bytes32,uint8,uint8) (runs: 512, μ: 5721557, ~: 5722740)\nLogs:\n  Bound result 5\n  Bound result 2\n\n[PASS] test_BuyerCanOpenTheirOwnPurchase() (gas: 703424)\n[PASS] test_CapsAreTrackedPerSeasonNotPerItem() (gas: 4191664)\n[PASS] test_CloseIsAllowedBeforeOpeningAndCancelIsNotAfterClose() (gas: 535953)\n[PASS] test_ContractBuyerWithoutReceiverOpensAndCanRedirectDelivery() (gas: 2010529)\n[PASS] test_ExpiredOpenStillRespectsReentrancyAndOnlyMintsFallback() (gas: 575352)\n[PASS] test_ExpiryIsMeasuredFromTargetNotFromPurchase() (gas: 1046645)\n[PASS] test_InsufficientBalanceRevertsWithoutRecordingPurchase() (gas: 354460)\n[PASS] test_ListShapedTrailingFieldsAcceptedButListAtNumberOrMixHashRejected() (gas: 507928)\n[PASS] test_NumberFieldOfThirtyTwoBytesAndSingleByteAreCanonical() (gas: 513865)\n[PASS] test_OpeningOrderIsFreeButCapsStillHold() (gas: 2009946)\n[PASS] test_PauseDoesNotBlockOwnerActionsOrViews() (gas: 1724032)\n[PASS] test_PurchasesInTheSameBlockShareTheTargetAndHeader() (gas: 2551219)\n[PASS] test_SeasonLifecycleEventsAreEmittedExactly() (gas: 620975)\n[PASS] test_SingleEntrySeasonAlwaysMintsFallbackEvenInTenPack() (gas: 1194303)\n[PASS] test_TotalWeightMayEqualMaxTotalWeightButNotExceedIt() (gas: 1914781)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 542.08ms (1.04s CPU time)\n\nRan 7 tests for test/Delivery.t.sol:DeliveryTest\n[PASS] testFuzz_FirstDeliveryRejectionThenAnyoneCanRetryOnlyOnce(uint8) (runs: 256, μ: 1739928, ~: 1730953)\nLogs:\n  Bound result 5\n\n[PASS] test_DeliveryChecksUnknownUnopenedAndAlreadyDelivered() (gas: 723193)\n[PASS] test_ExpiredUnopenedPurchaseStillRecordsOnlyFallbacksWhenDeliveryFails() (gas: 1091731)\n[PASS] test_HostileReceiverCannotVetoTenDistinctRolledItems() (gas: 11640506)\n[PASS] test_OwnerCannotMintCappedPieceWithinSevenDaysOfProposal() (gas: 1100148)\n[PASS] test_RedirectedDeliveryRejectsReentryAndMarksDeliveredBeforeCallback() (gas: 2403496)\n[PASS] test_ZeroItemIdAndDuplicateStoredItemsDeliverExactlyOnce() (gas: 999782)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 542.16ms (549.82ms CPU time)\n\nRan 11 tests for test/Opening.t.sol:OpeningTest\n[PASS] testFuzz_ExpiredAlwaysFallback(uint8,bytes32,uint16) (runs: 256, μ: 856324, ~: 850362)\nLogs:\n  Bound result 10\n  Bound result 6945\n\n[PASS] testFuzz_PreviewMatchesOpenAndCaps(bytes32,uint8) (runs: 256, μ: 3583215, ~: 3572581)\nLogs:\n  Bound result 2\n\n[PASS] test_AuthenticatedHeaderMustHaveCorrectNumber() (gas: 346675)\n[PASS] test_BuilderFieldsDoNotAffectRoll() (gas: 2466129)\n[PASS] test_ExactExpiryBoundaryAndIgnoredHeader() (gas: 1978557)\n[PASS] test_MaturityWrongHeadersAndAlreadyOpened() (gas: 1436668)\n[PASS] test_OpenWhileClosedPausedAndPastSaleEnd() (gas: 1298702)\n[PASS] test_ReceiverReentrancySingleAndBatch() (gas: 5469688)\n[PASS] test_RejectedFirstDeliveryRecordsOpenedAndCapsAndCanRetry() (gas: 3292072)\n[PASS] test_RevokedMinterRecordsRollAndDeliversAfterExpiryAndDelayedRestoration() (gas: 2234162)\n[PASS] test_UnknownPurchase() (gas: 100382)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 547.16ms (849.21ms CPU time)\n\nRan 6 tests for test/Rolls.t.sol:RollsTest\n[PASS] testFuzz_OddsOver20000Randao(bytes32) (runs: 1, μ: 737128, ~: 737128)\n[PASS] testFuzz_RandomizedCapsNeverExceeded(bytes32,uint8,uint8) (runs: 256, μ: 6215329, ~: 6216040)\nLogs:\n  Bound result 5\n  Bound result 2\n\n[PASS] testFuzz_TenPackGuarantee(bytes32) (runs: 256, μ: 1654834, ~: 1657920)\n[PASS] test_CapsExhaustedWithinPackAndNeverRollAgain() (gas: 2395730)\n[PASS] test_GuaranteedRollUsesRelativeRareWeights() (gas: 13243155)\n[PASS] test_SeedDomainMatchesSpecification() (gas: 869490)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.33s (2.39s CPU time)\n\nRan 1 test for test/BoxInvariant.t.sol:BoxInvariantTest\n[PASS]\nBoxInvariantTest invariants:\n[PASS] invariant_CapsAndDeliveredSupplyPlusStoredItemsMatchPerSeasonMints\n[PASS] invariant_EachPurchaseOpenedOnceAndEveryOpenMatchedPreview\n[PASS] invariant_PaymentsAreConservedWithoutBoxCustody\n BoxInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭------------+-------------------+-------+---------+----------╮\n| Contract   | Selector          | Calls | Reverts | Discards |\n+=============================================================+\n| BoxHandler | advance           | 1387  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | pause             | 1371  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | purchase          | 1358  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | retryDelivery     | 1351  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | reveal            | 1312  | 0       | 0        |\n|------------+-------------------+-------+---------+----------|\n| BoxHandler | setRejectDelivery | 1413  | 0       | 0        |\n╰------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 200\n  Bound result 3\n  Bound result 241\n  Bound result 1\n  Bound result 133\n  Bound result 200\n  Bound result 5\n  Bound result 192\n  Bound result 8\n  Bound result 156\n  Bound result 100\n  Bound result 226\n  Bound result 150\n  Bound result 4\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.87s (4.87s CPU time)\n\nRan 1 test for test/FurnitureInvariant.t.sol:FurnitureInvariantTest\n[PASS]\nFurnitureInvariantTest invariants:\n[PASS] invariant_BalancesAndSupplyMatchGhosts\n[PASS] invariant_FrozenMetadataNeverChangesAndRoyaltyIsBounded\n[PASS] invariant_OwnerNeverHoldsOrDestroysAnything\n FurnitureInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭------------------+--------------------------+-------+---------+----------╮\n| Contract         | Selector                 | Calls | Reverts | Discards |\n+==========================================================================+\n| FurnitureHandler | mint                     | 1071  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | operatorBatchTransfer    | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerMetadata            | 1045  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | ownerTriesToSeize        | 1149  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | revokeApproval           | 1081  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | strangerCannotAdminister | 1117  | 0       | 0        |\n|------------------+--------------------------+-------+---------+----------|\n| FurnitureHandler | transfer                 | 1068  | 0       | 0        |\n╰------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 5\n  Bound result 14\n  Bound result 1\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 4\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 9\n  Bound result 8\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 7\n  Bound result 0\n  Bound result 14\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 9\n  Bound result 0\n  Bound result 1090\n  Bound result 11\n  Bound result 0\n  Bound result 0\n  Bound result 12\n  Bound result 5\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 14\n  Bound result 1\n  Bound result 899\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 14\n  Bound result 13\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 9\n  Bound result 3\n  Bound result 24\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 10\n  Bound result 0\n  Bound result 12\n  Bound result 14\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 5.68s (5.68s CPU time)\n\nRan 1 test for test/MultiActorInvariant.t.sol:MultiActorInvariantTest\n[PASS]\nMultiActorInvariantTest invariants:\n[PASS] invariant_BoxNeverHoldsTheToken\n[PASS] invariant_EveryTokenPaidIsAccountedToBurnOrAVault\n[PASS] invariant_HandlerExercisedFailurePathsAndGuarantee\n[PASS] invariant_MintedNeverExceedsCapAndMatchesSupply\n[PASS] invariant_PurchasesOpenOnceAndFinishedStatesNeverReopen\n MultiActorInvariantTest invariants (runs: 96, calls: 7680, reverts: 0)\n\n╭-------------------+--------------------------+-------+---------+----------╮\n| Contract          | Selector                 | Calls | Reverts | Discards |\n+===========================================================================+\n| MultiActorHandler | advanceBlocks            | 660   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | buy                      | 1289  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | cancelSeason             | 649   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | closeSeason              | 652   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | createSeason             | 632   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | open                     | 1282  | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setPaused                | 640   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | setVault                 | 611   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | strangerCannotAdminister | 673   | 0       | 0        |\n|-------------------+--------------------------+-------+---------+----------|\n| MultiActorHandler | warp                     | 592   | 0       | 0        |\n╰-------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10\n  Bound result 10\n  Bound result 10\n  Bound result 339606\n  Bound result 0\n  Bound result 1\n  Bound result 239\n  Bound result 12743\n  Bound result 4\n  Bound result 19794\n  Bound result 268\n  Bound result 10\n  Bound result 15876\n  Bound result 70\n  Bound result 95\n  Bound result 234\n  Bound result 18630\n  Bound result 183\n  Bound result 2\n  Bound result 101\n  Bound result 50\n  Bound result 1001\n  Bound result 50000\n  Bound result 9835\n  Bound result 4\n  Bound result 1434\n  Bound result 20528\n  Bound result 1000000000000\n  Bound result 6209\n  Bound result 6\n  Bound result 2658\n  Bound result 4832\n  Bound result 174\n  Bound result 7853\n  Bound result 6\n  Bound result 7\n  Bound result 1205\n  Bound result 3\n  Bound result 3629\n  Bound result 10001\n  Bound result 208\n  Bound result 1305\n  Bound result 0\n  Bound result 1\n  Bound result 4\n  Bound result 35\n  Bound result 8\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 15.09s (15.08s CPU time)\n\nRan 14 test suites in 15.10s (30.56s CPU time): 99 tests passed, 0 failed, 0 skipped (99 total tests)\n","passed":true},{"durationMs":71,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"OGClubBox.acceptOwnership()\",\"OGClubBox.buy(uint256,uint256)\",\"OGClubBox.cancelSeason(uint256)\",\"OGClubBox.closeSeason(uint256)\",\"OGClubBox.createSeason(uint256,uint256,uint256,uint256,uint256,(uint256,uint8,uint256,uint256)[])\",\"OGClubBox.deliver(uint256)\",\"OGClubBox.deliverTo(uint256,address)\",\"OGClubBox.open(uint256,bytes)\",\"OGClubBox.renounceOwnership()\",\"OGClubBox.setPaused(bool)\",\"OGClubBox.setVault(address)\",\"OGClubBox.transferOwnership(address)\",\"OGClubFurniture.acceptOwnership()\",\"OGClubFurniture.activateMinter(address)\",\"OGClubFurniture.cancelMinter(address)\",\"OGClubFurniture.freezeMetadata()\",\"OGClubFurniture.grantMinter(address)\",\"OGClubFurniture.mintBatch(address,uint256[],uint256[])\",\"OGClubFurniture.renounceOwnership()\",\"OGClubFurniture.revokeMinter(address)\",\"OGClubFurniture.safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\",\"OGClubFurniture.safeTransferFrom(address,address,uint256,uint256,bytes)\",\"OGClubFurniture.setApprovalForAll(address,bool)\",\"OGClubFurniture.setBaseURI(string)\",\"OGClubFurniture.setRoyalty(address,uint96)\",\"OGClubFurniture.transferOwnership(address)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":114,\"README.md\":340,\"VENDOR.md\":13,\"foundry.toml\":22,\"launch.json\":28,\"script/Deploy.s.sol\":38,\"script/encode_header.py\":80,\"src/OGClubBox.sol\":480,\"src/OGClubFurniture.sol\":132,\"src/libraries/BlockHeader.sol\":70,\"src/mocks/MockOG.sol\":21,\"test/BlockHeader.t.sol\":132,\"test/BoxInvariant.t.sol\":278,\"test/Delivery.t.sol\":207,\"test/Deployment.t.sol\":86,\"test/EdgeCases.t.sol\":482,\"test/FixedOdds.t.sol\":252,\"test/FurnitureInvariant.t.sol\":248,\"test/MultiActorInvariant.t.sol\":561,\"test/OGClubFurniture.t.sol\":286,\"test/OpenGas.t.sol\":188,\"test/Opening.t.sol\":249,\"test/Payments.t.sol\":202,\"test/Rolls.t.sol\":128,\"test/Seasons.t.sol\":221,\"test/fixtures/MainnetHeaders.sol\":32,\"test/fixtures/SOURCES.md\":42,\"test/fixtures/mainnet-cancun.json\":24,\"test/fixtures/mainnet-prague.json\":25,\"test/fixtures/mainnet-shanghai.json\":21,\"test/helpers/Adversaries.sol\":230,\"test/helpers/BoxTestBase.sol\":120,\"test/helpers/HeaderBuilder.sol\":48},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":2278,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/OGClubBox.sol:346: Reentrancy in OGClubBox._pay(address,uint256) (src/OGClubBox.sol#346-354):\n[medium/high] incorrect-equality at src/OGClubBox.sol:393: OGClubBox._picks(uint256,OGClubBox.Purchase,bytes32,OGClubBox.Entry[]) (src/OGClubBox.sol#393-411) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/OGClubFurniture.sol:63: OGClubFurniture.activateMinter(address) (src/OGClubFurniture.sol#63-70) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/OGClubBox.sol:280: OGClubBox._deliver(uint256,address) (src/OGClubBox.sol#280-296) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/OGClubBox.sol:235: Reentrancy in OGClubBox.open(uint256,bytes) (src/OGClubBox.sol#235-266):\n[medium/medium] uninitialized-local at src/OGClubBox.sol:401: OGClubBox._picks(uint256,OGClubBox.Purchase,bytes32,OGClubBox.Entry[]).fallbackIndex (src/OGClubBox.sol#401) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:428: OGClubBox._pick(OGClubBox.Entry[],uint256[],uint256,uint256,bool).totalWeight (src/OGClubBox.sol#428) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:444: OGClubBox._pickRare(OGClubBox.Entry[],uint256[],uint256).rareWeight (src/OGClubBox.sol#444) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:238: OGClubBox.open(uint256,bytes).prevRandao (src/OGClubBox.sol#238) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:153: OGClubBox.createSeason(uint256,uint256,uint256,uint256,uint256,OGClubBox.Entry[]).totalWeight (src/OGClubBox.sol#153) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:445: OGClubBox._pickRare(OGClubBox.Entry[],uint256[],uint256).availableRareWeight (src/OGClubBox.sol#445) is a local variable never initialized\n[medium/medium] uninitialized-local at src/OGClubBox.sol:154: OGClubBox.createSeason(uint256,uint256,uint256,uint256,uint256,OGClubBox.Entry[]).validFallback (src/OGClubBox.sol#154) is a local variable never initialized\n[low/medium] reentrancy-benign at src/OGClubBox.sol:235: Reentrancy in OGClubBox.open(uint256,bytes) (src/OGClubBox.sol#235-266):\n[low/medium] timestamp at src/OGClubBox.sol:185: OGClubBox.cancelSeason(uint256) (src/OGClubBox.sol#185-192) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubBox.sol:209: OGClubBox.buy(uint256,uint256) (src/OGClubBox.sol#209-229) uses timestamp for comparisons\n[low/medium] timestamp at src/OGClubFurniture.sol:63: OGClubFurniture.activateMinter(address) (src/OGClubFurniture.sol#63-70) uses timestamp for comparisons","passed":true},{"durationMs":544,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/OGClubBox.sol:216: Reentrancy: State change after external call\n[low] centralization-risk at src/OGClubBox.sol:16: Centralization Risk (13 places)\n[low] costly-loop at src/OGClubBox.sol:170: Costly operations inside loop (2 places)\n[low] large-numeric-literal at src/OGClubBox.sol:47: Large Numeric Literal (4 places)\n[low] literal-instead-of-constant at src/OGClubBox.sol:211: Literal Instead of Constant (13 places)\n[low] push-zero-opcode at src/OGClubBox.sol:2: PUSH0 Opcode (4 places)\n[low] require-revert-in-loop at src/OGClubBox.sol:155: Loop Contains `require`/`revert` (4 places)\n[low] unchecked-return at src/OGClubBox.sol:334: Unchecked Return\n[low] uninitialized-local-variable at src/OGClubBox.sol:155: Uninitialized Local Variable (8 places)\n[low] unspecific-solidity-pragma at src/OGClubBox.sol:2: Unspecific Solidity Pragma (3 places)","passed":true},{"durationMs":2194,"exitCode":0,"name":"proof a01cf2893652","output":"Compiling 54 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.55s\nCompiler run successful!\n\nRan 1 test for test/imd-proof-09bdb268/Proof_a01cf2893652.t.sol:OpenGasDeliveryTest\n[PASS] test_OpenWithEstimatedGasPlusHalfMustDeliverOrRevert() (gas: 1014319)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.46ms (658.34µs CPU time)\n\nRan 1 test suite in 19.17ms (1.46ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"d91947614345584afa225d6710be28e4b558b50ef086515ce8e461c2e7f3648f","verifiedTreeHash":"13e6d60c3154160173c3aa47f92de617df55fd06","verifierVersion":"0.1.0+8fbf00a5"}]}