{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"0d504e85-2852-4039-99eb-4a6c6c9e7544","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"763d41ef17ef8fe4477a8d377e685096ed8dc50e02a4f481fcd5c0b7289797ee","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"258282755e30509dabebdb7986b5a0fd2ac22e9fc1f8fb6b2101bf0a78b4cf56","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"9c8ac64bdb315370daa10653e6df632c84a397fa2b586af407fc90ffab1540c2","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"8b70bd9d6a285f6b90feb9c9aaf1da581a9c23bf2036201368491eb395b67074","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"bcee25d8fc400441fcfdd5d0d8bc28a8ae3476938d2d774bb7435386007e8f62","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"48d8ab357dffdcd80434d88ba75814cba8af5a5c107f0a8162814b223900e151","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b6503de65ad02f845827887c23da4c3b56ccc5df7a459db263bae6e549d92f7f","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"b6503de65ad02f845827887c23da4c3b56ccc5df7a459db263bae6e549d92f7f","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"3aa2fade4cc2b762e01bdf7febdebde7df6a1a94239e005810917e263c434d9e","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"a688a64b608f6bc69cc1991df90e6a6fffc817862d666a661dca2bd32ad754a0","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Ochre: one ERC-721 contract that sells and gives away 737 pieces of a wall painted live by workers, paid in a coin that is sent to the dead address. Deploy on Sepolia (chain id 11155111) as a rehearsal: ONE contract, Ochre; the coin is the existing Sepolia WETH 0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14; do not build or deploy a coin. Nothing is upgradeable, pausable or ownable; the contract never holds funds.\n\nCONSTRUCTOR (static values, no external calls: the verifier deploys it in an empty EVM; the coin has 18 decimals, a constant): coin 0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14; dead 0x000000000000000000000000000000000000dEaD; admin 0x7B8C742F2e1eEB3fB2C10d72967Fa6d4a22f0479; adam 0x7B8C742F2e1eEB3fB2C10d72967Fa6d4a22f0479; seatRoot 0x0a8005d6196642a338d7e5a99dc48ff300c5843bd0eb68fa9db611157af7fffb (Merkle root of keccak256(abi.encodePacked(address)) leaves, sorted pairs); startTime 1791396553 (Unix seconds); caveLength 3600 and roundLength 150 (seconds); firstPrice 4000000000000000 and floorPrice 400000000000000 (0.004 and 0.0004 coin); labels: seven bytes32, one per cave, in cave order: zto-cave-test5, -test4, -test3, -test2, -test5, -test4, -test3. It mints id 0 to adam and id 736 to admin.\n\nPIECES. Ids 0..736. Id 0 is Zero and id 736 is One. For 1..735: cave = (id-1)/105 + 1 (1..7), round = ((id-1) % 105)/5 + 1 (1..21), slot = (id-1) % 5 + 1 (1..5). Slots 1..4 are lines, slot 5 the gathering. Nothing else can ever be minted.\n\nDAYS. Cave c opens at startTime + (c-1) * caveLength and closes caveLength later, the moment the next cave opens (cave 7 closes at startTime + 7 * caveLength). Round r of cave c opens at caveOpen(c) + (r-1) * roundLength; its sale pieces cannot be bought before that. caveLength and roundLength are constructor arguments in seconds (rehearsal: 3600 and 150; the constructor requires 21 * roundLength <= caveLength). Day index d = c. caveOpen(c), caveClose(c) and roundOpen(c, r) are views.\n\nSALE PIECES. In every round, k(d) pieces are for sale, taken in this slot order: 5, 4, 3, 2, 1. k = 1,1,2,3,4,4,4 for caves 1..7, except cave 7 round 21 where k = 5. So caves sell 21,21,42,63,84,84,85 = 400 pieces. The other slots of each round are free pieces: 335 in all (315 in caves 1..6 and 20 in cave 7), every one of them for seats.\n\nPRICE. Every round has its own line: from roundOpen(c, r) the price falls from openingPrice(c, r) to floorPrice over one roundLength by HALVING, not in a straight line: K is the smallest integer with opening / 2^K <= floorPrice, the roundLength is split into K equal segments, at the end of segment k the price is opening / 2^k, linear inside a segment, never below floorPrice; after the line it waits at floorPrice until the cave closes. THE LADDER sets openings: cave 1 round 1 opens at firstPrice. Every later round looks at the round before it in week order (round r-1 of the same cave, or round 21 of the previous cave): if that round had a line sale (a buy above floorPrice) it opens at twice that round's last line-sale price, but never below half that round's opening; if it had none it opens at half that round's opening. Openings never go below 2 * floorPrice and have no cap. So the ladder moves at most 2x up or 2x down per round, and floor buys never move it. Implementation: per round store lastLineSale; openingPrice(c, r) walks back to the nearest round with a stored opening or a line sale, halving per quiet round; a round's first buy stores its opening. firstPrice and floorPrice are CONSTRUCTOR ARGUMENTS (not code constants) in coin base units: firstPrice 4000000000000000 (0.004 coin); floorPrice 400000000000000 (0.0004 coin). priceNow(c, r), openingPrice(c, r) and roundSold(c, r) are views; priceNow reverts if the cave is not open or the round has not opened. Rounds are independent: an older round's unsold pieces wait at the floor while a newer round opens at its own price.\n\nbuy(c, r): the buyer names the round; requires cave c open (opened and not yet closed), round r of cave c opened, and a sale piece of that round left; takes that round's next sale piece in slot order (5, 4, 3, 2, 1); charges price(c, r, now) by coin.transferFrom(msg.sender, dead, price), requiring the returned bool; mints to msg.sender with _mint, never _safeMint (no receiver callbacks anywhere); emits Bought(id, buyer, price). No per-wallet limit. The buyer approves the coin first; the contract never holds it. TEETH: after caveClose(c) nobody can buy that cave's sale pieces; sweep(c, max), callable by anyone after the close, mints up to max of its unsold sale pieces in id order to admin, Swept(id) each, and reverts while the cave is open or when none are left. So all 737 pieces are eventually minted.\n\nclaimSeat(proof): requires msg.sender in seatRoot and not claimed before; takes the next free piece of caves 1..7 in id order, skipping sale slots; mints to msg.sender; emits Claimed(id, wallet). Free, gas only. Available from startTime.\n\nreleaseUnclaimed(): callable by anyone after startTime + 8 * caveLength; after it, buyLeftover() takes the next still-unclaimed free piece of caves 1..7 in id order at floorPrice (same payment path as buy; no cave window; buyable until gone); emits Bought(id, buyer, price). claimSeat stops working once releaseUnclaimed has been called.\n\ntokenURI(id): before freeze, \"https://\" + label(c) + \".sites.imd.fun/\" + (\"gathering/\" if slot 5 else \"line-\" + slot + \"/\") + two-digit round + \".json\"; id 0 uses \"https://\" + label(1) + \".sites.imd.fun/zero.json\" and id 736 \"https://\" + label(7) + \".sites.imd.fun/one.json\". freeze(c, base) is admin only, once per cave: afterwards that cave's links use `base` (for example ipfs://<cid>/) in place of \"https://\" + label + \".sites.imd.fun/\". Labels hold up to 32 ASCII bytes, right-padded with zeros. contractURI() returns \"https://\" + label(1) + \".sites.imd.fun/collection.json\" (before freeze) or base(1) + \"collection.json\" (after cave 1 is frozen).\n\nRULES. supportsInterface for ERC-721, ERC-721Metadata and ERC-2981; name \"Ochre\", symbol \"OCHRE\"; royaltyInfo(id, salePrice) returns (admin, salePrice / 100): a 1% creator fee to admin, fixed at deploy, no setter. No function may move the coin anywhere but the dead address. Tests against a mock coin: the id arithmetic for every cave/round/slot, the exact sale counts per cave (400 in all), the halving line (segment ends at opening / 2^k, floor clamp), the ladder (2x last line sale; half after a quiet round; never below 2 * floor; floor buys ignored), buy before open reverts, claim with a bad proof reverts, double claim reverts, nothing mintable past 737, releaseUnclaimed timing, sweep only after close and only unsold sale pieces (never a seat piece, never twice), freeze once per cave, tokenURI strings for sample ids including 0 and 736, royaltyInfo (1% to admin), and events. README with the rules. BUILD: optimizer + via-IR (via_ir = true, optimizer_runs = 1), deployed code under 9,000 bytes (one transaction may use at most 16,777,216 gas at ~1,540 gas per byte): custom errors only, no revert strings, no ReentrancyGuard (the coin call is the last thing buy does). Slither rejects abi.encodePacked over more than one dynamic argument (use string.concat) and divide-before-multiply.","parentJobId":null,"planHash":"8400f046d5293a14f53fb5706fa85e8d4510c519b0780839e98ca3ab2ab97e1f","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"0d504e85-2852-4039-99eb-4a6c6c9e7544","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-928-ochre-one-erc-721-contract"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52173","feedbackHash":"0208360cf6bc997800ea51a20b73fd01a86395ffee64db64bc5be6f5bda72d44","nodeKey":"audit_economics","submissionHash":"763d41ef17ef8fe4477a8d377e685096ed8dc50e02a4f481fcd5c0b7289797ee","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52161","feedbackHash":"497b0f74d40578882fb77da0097be06aece9857b4f73b9cedc5df5cff3bfeb8f","nodeKey":"audit_flow","submissionHash":"258282755e30509dabebdb7986b5a0fd2ac22e9fc1f8fb6b2101bf0a78b4cf56","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51540","feedbackHash":"44fc65c68014c0b1e6faa6cb202daf9ae2a6da151b1636c8125ccc3836ed8758","nodeKey":"audit_judge","submissionHash":"9c8ac64bdb315370daa10653e6df632c84a397fa2b586af407fc90ffab1540c2","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52165","feedbackHash":"8ae1543556c0c0a757d32401652527c4c29028ab41c0fcf0fbdf088742a6a6ab","nodeKey":"audit_math","submissionHash":"8b70bd9d6a285f6b90feb9c9aaf1da581a9c23bf2036201368491eb395b67074","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52232","feedbackHash":"416ced96617751b2b2c45ed11fac50c15f8af997e8a37f3ba9de3452af7f2d97","nodeKey":"audit_permissions","submissionHash":"bcee25d8fc400441fcfdd5d0d8bc28a8ae3476938d2d774bb7435386007e8f62","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51183","feedbackHash":"e413e8e3089ec1fafaa4389db541ed762cabf76267a2e15e4aa0d28c8fb3f237","nodeKey":"build_contract_project","submissionHash":"e9280be3d58f5975a89b36a29fc18a9048ea93fab38e4f12db32afd018d41a64","tag1":"verification:checks","tag2":"acceptance-v2","value":0},{"agentId":"51199","feedbackHash":"32caf7af5c34d5069f2e7818b7f965fe31eafff6f41be00c13f7dab2c47f8d42","nodeKey":"build_contract_project","submissionHash":"48d8ab357dffdcd80434d88ba75814cba8af5a5c107f0a8162814b223900e151","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51252","feedbackHash":"227042b2a848f8334ade842e73540a229b7d87a44f3751498e7e87de4808be9c","nodeKey":"manifest","submissionHash":"3aa2fade4cc2b762e01bdf7febdebde7df6a1a94239e005810917e263c434d9e","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51087","feedbackHash":"632a40c4c55715c2fe9eb09876385ef8183ce14de2103599cec2aa121d4bdb2b","nodeKey":"write_foundry_tests","submissionHash":"a688a64b608f6bc69cc1991df90e6a6fffc817862d666a661dca2bd32ad754a0","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"33fc7323eb36b25d53c96786ca87b604125f171b8671d4dcd5b4b4aa51e7f63b","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ca075d17c94a854b","findings":[{"citation":"resolved","description":"The contract advertises ERC-721 support through supportsInterface(0x80ac58cd), but its override of safeTransferFrom(address,address,uint256,bytes) (which the 3-argument overload also routes through in OpenZeppelin 5.0.2) reverts unconditionally whenever the recipient has code. ERC-721 requires safeTransferFrom to succeed when the recipient returns the onERC721Received magic value; here a fully compliant receiver (escrow, vault, marketplace or lending contract that pulls tokens with safeTransferFrom) can never receive an Ochre piece through the safe path. The brief's 'no receiver callbacks anywhere' sentence sits next to the mint instruction ('_mint, never _safeMint'), and the README documents this override as deliberate, so this is a design-reading deviation rather than a fund-loss bug: pieces are not lost (transferFrom still works, and the owner can retry with it) but any integrator that only speaks safeTransferFrom will fail. Impact is interoperability only; no value is at risk and no state is corrupted. If the restriction is intended, the author should keep it and record it as an explicit deviation; if the brief's sentence was meant to cover minting only, the override should be dropped so OpenZeppelin's standard _checkOnERC721Received path (which has no reentrancy exposure here, since the contract holds no funds and transfers write all state before the callback) applies.","line":272,"path":"src/Ochre.sol","reproduction":"State: ALICE owns piece 5 (bought in cave 1 round 1 at startTime). Deploy a contract R that implements IERC721Receiver and returns IERC721Receiver.onERC721Received.selector. Call, as ALICE, ochre.safeTransferFrom(ALICE, address(R), 5) (3-arg) or the 4-arg overload with any data. Expected under ERC-721: transfer succeeds, ownerOf(5) == address(R), R.onERC721Received was invoked. Actual: the call reverts with ContractRecipient() and ownerOf(5) stays ALICE. Verified with a scratch Foundry test (testSafeTransferToCompliantReceiverReverts) against the current tree.","severity":"low","snippet":"    function safeTransferFrom(address from, address to, uint256 id, bytes memory) public override {\n        if (to.code.length != 0) revert ContractRecipient();\n        transferFrom(from, to, id);\n    }","title":"safeTransferFrom rejects every contract recipient, including compliant IERC721Receiver implementers (ERC-721 non-compliance)"}],"hash":"258282755e30509dabebdb7986b5a0fd2ac22e9fc1f8fb6b2101bf0a78b4cf56","nodeId":"2c20573d-028c-409e-ba30-399bc6804891","outcome":"completed","summary":"The review is complete. The findings file is written and validated, the scratch directory is removed, and the working tree holds only the review output.\n\n**Outcome: one low-severity finding, no fund-safety defects.** The control-flow area (execution trace, periphery, first principles) was covered in depth, and the contract's core logic held under both static tracing and differential fuzzing.\n\n**What I verified**\n\n- **Ladder and halving line** match the brief exactly. A scratch differential test drove random buy patterns (none, floor, one or two line buys) across all 147 rounds for 64 seeds and compared every round's opening against an independent reference. All matched, and openings were stable once the successor round opened.\n- **Buy, sweep, claim, leftover paths** were traced for guards, id arithmetic, state ordering and failure rollback. Mint and all state writes precede the single coin call, and both a false return and a revert from the coin roll back the whole purchase.\n- **Periphery** is sound. OpenZeppelin 5.0.2 and forge-std are vendored as plain files with no submodules, the ERC-721 closure has no revert strings, runtime is 8,285 bytes, and the launch checker passes. The live Sepolia coin was confirmed to be WETH9 with 18 decimals whose transferFrom returns a bool, matching the interface the contract requires.\n- **Static-analysis leads** (uninitialized locals, timestamp use, unchecked returns) were all checked and are false positives or intended design.\n\n**The one finding (low)**\n\nThe override of safeTransferFrom in `src/Ochre.sol:272` reverts for every recipient with code, including a fully compliant IERC721Receiver. The contract advertises ERC-721 support, and the standard requires the safe path to succeed when the receiver returns the magic value. No pieces are lost since transferFrom still works, but integrators that only use safeTransferFrom into a contract will fail. The README documents this as deliberate, so the judge needs to decide whether the brief's \"no receiver callbacks anywhere\" was meant to extend beyond minting.\n\n**Coverage record**: all 11 verifier-listed entry points have rows (9 hold, 2 carry the finding), plus four invariant and constructor rows. Nothing was left unreached.","treeHash":null,"usage":{"cachedInputTokens":1344498,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":32618,"runtime":"claude","turns":20,"wallClockMs":490934}},{"artifacts":[],"attempt":1,"bundleHash":"dc39116001d70ae42ef0d8ac401f2ccaaa9d6bfd07d29a1ac44d1ec9a8c313b9","device":"8cb9deeead5ce571","findings":[],"hash":"3aa2fade4cc2b762e01bdf7febdebde7df6a1a94239e005810917e263c434d9e","nodeId":"da3d82e1-2f82-4b7e-8d1b-96bf083aedc2","outcome":"completed","summary":"Updated [launch.json](/root/.identitymd/work/0d504e85-2852-4039-99eb-4a6c6c9e7544/da3d82e1-2f82-4b7e-8d1b-96bf083aedc2/launch.json), preserving all 16 verified constructor arguments and clarifying deployment notes.\n\nSchema and ABI checks passed. `forge build` succeeded; all 31 tests passed, including the protected deployment check. Runtime: 8,285 bytes.\n\nOnly `launch.json` changed outside permitted scratch files.","treeHash":"d733d1d5a9d2d7d062cac79bbabcfe2e54673a95","usage":{"cachedInputTokens":215680,"inputTokens":32569,"model":"gpt-6-astra","outputTokens":5976,"runtime":"codex","turns":4,"wallClockMs":161806}},{"artifacts":[],"attempt":2,"bundleHash":"d45023e01965e8cf15188d2a218b1317c47b5bb4a283aa7a94682272f81c39d6","device":"4fcac33561ba733d","findings":[],"hash":"48d8ab357dffdcd80434d88ba75814cba8af5a5c107f0a8162814b223900e151","nodeId":"154af4ff-5f63-433a-8c8b-f7449f60a902","outcome":"completed","summary":"Implemented Ochre, vendored dependencies, tests, documentation, and a Sepolia launch manifest with exactly **16 constructor arguments**.\n\n- `forge build`, all **30 tests**, and `forge fmt --check` pass.\n- Runtime: **8,285 bytes**; manifest and protected opcode checks pass.\n- Safe transfers reject contract recipients to honor the no-callback rule; `transferFrom` remains available.\n\nDeployment is prepared; no transaction was broadcast.","treeHash":"0d5c3bfeab4ba8b066cdbe161a11f496bfa838e2","usage":{"cachedInputTokens":865024,"inputTokens":68390,"model":"gpt-6-astra","outputTokens":31039,"runtime":"codex","turns":7,"wallClockMs":1481523}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"c2e167266d13dcf4","findings":[{"citation":"resolved","description":"Ochre advertises ERC-721 via supportsInterface(0x80ac58cd), but both safeTransferFrom overloads (the 3-arg OZ v5 variant dispatches into this override) revert for any `to` with code, regardless of whether `to` implements onERC721Received. ERC-721 requires safeTransferFrom to a contract that returns the magic value to SUCCEED. Smart-contract wallets (Safe, ERC-4337 accounts), escrow/lending contracts and any marketplace or wallet UI that moves ERC-721s with safeTransferFrom cannot receive a piece; the holder must know to fall back to transferFrom. The brief's 'no receiver callbacks anywhere' is stated for minting (_mint vs _safeMint); extending it to transfers trades standard compliance for callback avoidance. Seam: periphery (ERC-721 consumers) x first principles (claims ERC-721). Suggested fix: either keep the OZ safeTransferFrom (the callback is to the recipient the token holder chose, not a mint-time callback) or document the deviation so integrators and holders know to use transferFrom.","line":272,"path":"src/Ochre.sol","reproduction":"Deploy with rehearsal args; warp to startTime; alice calls buy(1,1) -> id 5. Deploy any contract R implementing IERC721Receiver.onERC721Received returning its selector. alice calls safeTransferFrom(alice, R, 5) or safeTransferFrom(alice, R, 5, \"\"). Expected (ERC-721): transfer succeeds, R owns 5. Actual: revert ContractRecipient(). Verified in a scratch test (test/scratch/Leads.t.sol::testSafeTransferToCompliantReceiverReverts). transferFrom(alice, R, 5) succeeds, so the piece is not stuck; only the safe path is broken.","severity":"low","snippet":"        if (to.code.length != 0) revert ContractRecipient();","title":"safeTransferFrom rejects every contract recipient, including ERC721Receiver-compliant wallets (ERC-721 compliance break)"},{"citation":"resolved","description":"The price charged is whatever _price returns in the block the tx lands, and the piece is whatever slot is next; the buyer cannot bound either. Within an open round this is safe (price only falls), but round r+1's opening is only fixed when round r's line ends, i.e. at the same instant r+1 opens. openingPrice(c, r+1) read before that moment is a projection (half of O_r while r is quiet) that a single line sale in round r can move up to 2*O_r. A buyer with an unlimited WETH approval who submits buy(c, r+1) to land in the opening block pays the moved price with no revert. Separately, in rounds with k>1 a buyer who wants the gathering (slot 5) and is front-run receives a line piece (slot 4) for the same price. Nobody profits in coin terms (payment is burned), so this is griefing / UX exposure, not extraction. Suggested fix: add an optional maxPrice (and/or expectedId) argument that reverts with a custom error when exceeded; buyers who do not care can pass type(uint256).max / 0.","line":175,"path":"src/Ochre.sol","reproduction":"Rehearsal params (firstPrice 0.004, floor 0.0004, roundLength 150). At t = startTime alice reads openingPrice(1,2) = 0.002 ether (round 1 quiet) and submits buy(1,2) for t = startTime+150 with an unlimited approval. In the same block at t = startTime bob calls buy(1,1), paying 0.004 (a line sale at the opening). openingPrice(1,2) becomes max(0.004/2, 2*0.004) = 0.008 ether. At startTime+150 alice's buy(1,2) executes and burns 0.008 ether: 4x what she quoted. Verified in test/scratch/Leads.t.sol::testProjectedOpeningMovesAfterQuoteEarlySale. Slot swap: at caveOpen(5) bob then alice each call buy(5,1): bob gets 425 (slot 5, gathering), alice gets 424 (slot 4) at the identical price (testSlotFrontRun).","severity":"low","snippet":"        uint256 price = _price(opening, block.timestamp - opens);","title":"buy(c, r) has no max-price or expected-piece guard: a pre-submitted buy for a round about to open can pay up to 4x the quoted opening, and a front-run silently swaps the buyer's slot"}],"hash":"763d41ef17ef8fe4477a8d377e685096ed8dc50e02a4f481fcd5c0b7289797ee","nodeId":"bdd0d83d-8575-47e9-8c38-bdaf80f5106e","outcome":"completed","summary":"Review complete. `.imd-findings.json` is in place with both snippets verified against the tree and all 11 entry points covered (plus 7 invariant rows).\n\n## Summary\n\n**Area covered in depth:** Economic Security, Invariant, and Flow Gap guides against `src/Ochre.sol`.\n\n**Result: the economics hold.** I traced every value flow and invariant and found no loss-of-funds, wrong-party, or permanent-breakage defect:\n\n- **Piece/sale partition** — `buy` ids are always sale slots (5→1), `_takeFree` skips exactly those, `sweep` filters by `isSalePiece`; per-cave sale counts 21/21/42/63/84/84/85 = 400, 335 free, nothing mintable outside 0..736.\n- **Halving line** — K = smallest with `opening>>K ≤ floor`; segment boundaries are rational (`mulDiv`/`mulmod`), ends land on `opening>>k`, floor-clamped, monotone.\n- **Ladder** — `_opening`'s walk-back is algebraically identical to the per-round rule (max/halve commute with the 2×floor clamp); a previous round's `lastLineSale` is frozen the instant the next round opens; a late floor buy storing an older round's opening never shifts later openings.\n- **Payment path** — the only coin call is `transferFrom(buyer, dead, price)` with the bool checked, after all state writes. I confirmed via public RPC that `0xfFf9…6B14` on Sepolia is WETH9 (`symbol()`=\"WETH\", 18 decimals, bool-returning), so the periphery assumption is sound.\n- **sweep / claimSeat / releaseUnclaimed / buyLeftover** — windows are disjoint, cursors can't double-mint, seat pieces are never swept.\n\n**Two low findings** (reproductions confirmed in `test/scratch/Leads.t.sol`; no proof required at this severity):\n\n1. `safeTransferFrom` (`src/Ochre.sol:272`) reverts for **every** contract recipient, including ones implementing `onERC721Received` — an ERC-721 compliance deviation affecting Safe/4337 wallets and safe-path marketplaces. `transferFrom` still works, so nothing is stuck.\n2. `buy` (`src/Ochre.sol:175`) has no `maxPrice`/expected-id guard. A buy pre-submitted for the opening block of round r+1 can pay up to 4× the `openingPrice` quoted moments earlier (e.g. quoted 0.002, charged 0.008 when a line sale lands at round 1's opening), and in k>1 rounds a front-run silently swaps the gathering for a line piece. Griefing/UX only — the coin is burned, so no one profits.\n\n**Not reached / out of area:** OZ ERC-721 internals (`approve`, `setApprovalForAll`, `transferFrom`) were accepted as unmodified upstream code; I did not re-audit them beyond their interaction with `sweep`'s owner check.","treeHash":null,"usage":{"cachedInputTokens":871346,"inputTokens":25,"model":"claude-fable-5-1","outputTokens":33510,"runtime":"claude","turns":13,"wallClockMs":478241}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e12f98dda6acc55f","findings":[{"citation":"resolved","description":"The brief says openings have no cap, and _opening() doubles the previous round's lastLineSale with checked arithmetic. The constructor guards `floorPrice_ > type(uint256).max / 2` (so `2 * floorPrice` can never overflow) but places no upper bound on `firstPrice_`, and lastLineSale is stored as the raw price paid. If firstPrice_ > 2^255 - 1 and a buyer pays a line price above 2^255 - 1, `2 * previous.lastLineSale` overflows and reverts; since every later round's walk-back reaches that stored round, openingPrice/priceNow/buy revert for all remaining rounds of the week. Sale pieces are not lost (sweep still mints them to admin after each cave closes), and the precondition requires a coin payment larger than 2^255 base units, which no real token (including Sepolia WETH) can supply. With the rehearsal parameters (firstPrice 4e15) the ladder stays below 4e15 * 2^146 ~ 2^198 even if every one of the 147 rounds is bought at its opening (verified by test). Reported for completeness of the numeric boundary; not a reachable defect with the deployed arguments. A symmetric guard such as `firstPrice_ > type(uint256).max / 2` would make the constructor's overflow protection consistent, at no behavioural cost.","line":285,"path":"src/Ochre.sol","reproduction":"Deploy Ochre with floorPrice_ = 1, firstPrice_ = type(uint256).max (accepted by the constructor), mock coin where ALICE holds and approves 2^256-1. vm.warp(startTime); ALICE buy(1,1) -> pays 2^256-1, _rounds[0].lastLineSale = 2^256-1. Then openingPrice(1,2), priceNow(1,2) at startTime+150, and buy(1,2) all revert with arithmetic overflow panic instead of returning an opening. At startTime+3600, sweep(1,100) still mints the 20 unsold sale pieces of cave 1 to admin. Expected per brief: 'Openings ... have no cap' is honoured up to uint256; this input exceeds it, so the practical expectation is simply that the constructor should reject it as it rejects an equally extreme floorPrice.","severity":"info","snippet":"                if (previous.lastLineSale != 0) next = Math.max(next, 2 * previous.lastLineSale);","title":"Constructor bounds floorPrice against 2x overflow but not firstPrice; an extreme firstPrice lets one line sale make every later round's opening revert (Panic 0x11)"}],"hash":"8b70bd9d6a285f6b90feb9c9aaf1da581a9c23bf2036201368491eb395b67074","nodeId":"6b4d0710-ffaa-46c0-aceb-7dbfbff9ba42","outcome":"completed","summary":"The review is complete. `.imd-findings.json` is written; no project files were changed (scratch tests removed, build artifacts are gitignored).\n\n## Summary — Math Precision / Boundary / Numerical Gap audit of `src/Ochre.sol`\n\n**Result: no reproducible defect in the assigned area.** One `info` note recorded.\n\n### What I verified (and how)\n- **Halving line `_price`** (`src/Ochre.sol:294-308`): K = smallest k with `opening>>k <= floor`; segment index and remainder come from the same `(elapsed·K, roundLength)` pair, so boundaries are exact rationals and segment ends land exactly on `opening>>k`. I wrote an independent reference model and fuzzed it (256 runs; floor 1..1e30, opening 2·floor..1e40, roundLength 1..1e6, every elapsed) — exact match, monotone, clamped at floor, floor from `elapsed >= roundLength`. Odd openings (3·floor) also checked.\n- **Ladder `_opening`** (`:276-292`): random buy/quiet/floor patterns across all 147 rounds matched an off-chain model in 256 runs. Confirmed the subtle seam: a round's line can never still be active once the next round opens (line length == round spacing), so a stored opening never diverges from a prior quote; late floor buys in quiet rounds don't shift anything; cross-cave step uses contiguous keys; 2×/round for 147 rounds stays ≈2^198 with rehearsal args.\n- **Id/slot/sale-count arithmetic, windows, constructor guards, sweep cursor, `_takeFree` cursor, payment boundary** (bool required, single external call last, revert/false rolls back, no-code coin reverts), label edge cases (32 full ASCII bytes, interior zero, >127), same-second cave boundary (buy `<` close, sweep `≥` close).\n- Existing suite: 30/30 pass; runtime 8,286 bytes (< 9,000).\n\n### Finding (info)\n`src/Ochre.sol:285` — the constructor bounds `floorPrice_ ≤ max/2` but not `firstPrice_`; with `firstPrice = 2^256-1, floor = 1` one line sale makes `2 * lastLineSale` overflow and every later round's `openingPrice/priceNow/buy` revert (sweep still recovers pieces). Requires paying >2^255 coin, so unreachable with any real token — reported only for guard consistency.\n\n### Coverage\nAll 11 listed entry points are `holds`, plus 6 invariant rows (price line, ladder, piece arithmetic, schedule guards, payment boundary, worst-case walk-back gas ≈534k for `buy(7,21)` after a fully quiet week — bounded, caller-paid, not a defect).\n\nSlither/Aderyn leads (uninitialized locals `segments`/`padding`, timestamp comparisons, unchecked `_key` return) were checked and are intentional/benign.","treeHash":null,"usage":{"cachedInputTokens":1327977,"inputTokens":33,"model":"claude-fable-5-1","outputTokens":35536,"runtime":"claude","turns":17,"wallClockMs":496612}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"589ef002581a5371","findings":[{"citation":"resolved","description":"Ochre advertises ERC-721 through supportsInterface(0x80ac58cd), but the override of safeTransferFrom(address,address,uint256,bytes) reverts with ContractRecipient() whenever `to` has code. In OpenZeppelin 5.0.2 the 3-argument overload calls this virtual 4-argument one, so both safe paths are closed. ERC-721 requires safeTransferFrom to SUCCEED when the recipient returns the onERC721Received magic value. Smart-contract wallets (Safe, ERC-4337 accounts), escrows, lending/marketplace contracts and any wallet UI that moves ERC-721s with safeTransferFrom cannot receive a piece; the holder must know to fall back to transferFrom. No funds or state are at risk and pieces are not stuck (transferFrom works). The brief's 'no receiver callbacks anywhere' sits in the mint sentence (_mint, never _safeMint); the README documents the transfer restriction as deliberate. Merged from audit_economics and audit_flow (same root cause). If the restriction is intended, record it as an explicit ERC-721 deviation for integrators; otherwise drop the override so OpenZeppelin's standard receiver check applies (the contract holds no funds and all state is written before the callback, so there is no reentrancy exposure).","line":272,"path":"src/Ochre.sol","reproduction":"Deploy with rehearsal args and a mock coin; vm.warp(startTime); alice calls buy(1,1) -> id 5. Deploy contract R implementing IERC721Receiver.onERC721Received returning its selector. As alice: safeTransferFrom(alice, R, 5) and safeTransferFrom(alice, R, 5, \"\"). Expected (ERC-721): success, ownerOf(5) == R. Actual: both revert ContractRecipient(); ownerOf(5) stays alice. transferFrom(alice, R, 5) then succeeds. Reproduced in a scratch Foundry test (test/scratch/Review.t.sol::testSafeTransferToCompliantReceiverReverts, removed after the run).","severity":"low","snippet":"        if (to.code.length != 0) revert ContractRecipient();","title":"safeTransferFrom reverts for every contract recipient, including compliant IERC721Receiver implementers (ERC-721 non-compliance)"},{"citation":"resolved","description":"The constructor rejects floorPrice_ > type(uint256).max / 2 so `2 * floorPrice` cannot overflow, but places no upper bound on firstPrice_. _opening() computes `2 * previous.lastLineSale` with checked arithmetic; if a buyer pays a line price above 2^255-1 that doubling panics, and because every later round's walk-back reaches that stored round, openingPrice/priceNow/buy revert for the rest of the week. Sale pieces are still swept to admin after each cave closes, and the precondition needs a coin payment above 2^255 base units, impossible for Sepolia WETH (the rehearsal ladder stays below 4e15 * 2^146). Not reachable with the deployed arguments; reported as a consistency gap in the numeric boundary. A symmetric `firstPrice_ > type(uint256).max / 2` check would close it at no behavioural cost.","line":92,"path":"src/Ochre.sol","reproduction":"Deploy Ochre with floorPrice_ = 1 and firstPrice_ = type(uint256).max (accepted). Mock coin: alice holds and approves 2^256-1. vm.warp(startTime); alice buy(1,1) pays 2^256-1 and stores _rounds[0].lastLineSale = 2^256-1. openingPrice(1,2) then reverts with arithmetic overflow (Panic 0x11) instead of returning an opening; priceNow(1,2) at startTime+150 and buy(1,2) revert the same way. Reproduced in a scratch Foundry test (testExtremeFirstPriceOverflow).","severity":"info","snippet":"                || floorPrice_ > type(uint256).max / 2 || firstPrice_ < 2 * floorPrice_","title":"Constructor bounds floorPrice against 2x overflow but not firstPrice; a line sale above 2^255-1 makes every later opening revert"}],"hash":"9c8ac64bdb315370daa10653e6df632c84a397fa2b586af407fc90ffab1540c2","nodeId":"d75abf3d-c39d-4990-a6fa-015748b50ae8","outcome":"completed","summary":"The review is complete and `.imd-findings.json` is written. The working tree is otherwise unchanged apart from that file.\n\n**Outcome: no critical, high or medium defects.** The Ochre contract matches the brief in every mechanism I traced, and the 45-test suite passes with the runtime at 8,285 bytes.\n\n**Findings kept (2):**\n- **Low, merged from audit_economics and audit_flow:** both `safeTransferFrom` overloads revert for any recipient with code, so a compliant ERC-721 receiver such as a Safe or an escrow cannot receive a piece through the safe path. Pieces are not stuck because `transferFrom` works. The README documents it as deliberate, so the author should either record it as an explicit ERC-721 deviation or drop the override. Reproduced in a scratch test.\n- **Info, from audit_math:** the constructor caps `floorPrice` against doubling overflow but not `firstPrice`. With `firstPrice` above 2^255 one line sale makes all later openings revert. Unreachable with WETH or the rehearsal arguments. Reproduced.\n\n**Dropped (1):** audit_economics' \"no maxPrice guard in buy\" lead. The brief fixes the `buy(c, r)` signature, the README states a quote is not a reservation, and payment is burned so nobody profits. That is a design property, not a defect.\n\n**Own verification beyond the specialists:**\n- Fuzzed all 147 rounds per run, 256 runs, against an independent recursive model of the ladder from the brief: 2x last line sale, never below half the prior opening, half after a quiet round, floor at 2x floorPrice, floor buys ignored, cross-cave carry. Every opening and every sampled halving-line price matched.\n- Traced id arithmetic, sale counts, sweep cursor, free-piece cursor shared by claim and leftover, Merkle leaf domain separation, payment path, and freeze and tokenURI logic by hand. Slither's two uninitialized-local lines are false positives on default-zero locals.\n\n**Coverage:** all 11 entry points answered, 9 hold and 2 carry finding 1, plus four invariant rows. The scratch test directory was removed since no finding warranted an attached proof.","treeHash":null,"usage":{"cachedInputTokens":431116,"inputTokens":194,"model":"claude-fable-5-1","outputTokens":22066,"runtime":"claude","turns":13,"wallClockMs":426629}},{"artifacts":[],"attempt":1,"bundleHash":"cc7ff0813fed4e3c38d83d24c95f897f9dc9c5de4d0b96f221906a792a1db008","device":"87645bda72145989","findings":[],"hash":"a688a64b608f6bc69cc1991df90e6a6fffc817862d666a661dca2bd32ad754a0","nodeId":"309ca78a-e7b3-448f-b42a-7bb664419ed7","outcome":"completed","summary":"Added tests and documentation under `test/`, covering failure paths, pricing boundaries, fuzzing, and lifecycle invariants.\n\n- `forge build` passed.\n- `forge test`: **45 passed**, none failed or skipped.\n- Invariants passed **32,768 random calls**.\n\nNo reproducible defects found. Verification used offline mocks; live Sepolia was not tested.","treeHash":"5f7334be164c8df7b9c349baeb0fb58a18ba5baf","usage":{"cachedInputTokens":1523072,"inputTokens":114540,"model":"gpt-6-astra","outputTokens":20363,"runtime":"codex","turns":6,"wallClockMs":1099594}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"82692ab5f7f7e54e","findings":[],"hash":"bcee25d8fc400441fcfdd5d0d8bc28a8ae3476938d2d774bb7435386007e8f62","nodeId":"dd1530a3-953e-4643-9f8b-ea22a98dedc5","outcome":"completed","summary":"The review is complete and the findings file is written. The scratch test directory is removed, and the working tree holds only the findings file beyond the committed state.\n\n## Scope\n\nFiles read: `src/Ochre.sol` (357 lines, in full), `test/Ochre.t.sol` (765 lines), `README.md`, `launch.json`, the vendored OpenZeppelin ERC721 transfer and mint paths, and the three assigned Pashov guides plus the Senior Auditor's Mindset. The existing suite passes with 30 tests. Nothing in my area was left unreached.\n\n**Severity counts:** 0 Critical · 0 High · 0 Medium · 0 Low\n\nI found no defect in the Access Control, Trust Gap or Asymmetry areas. The findings file carries an empty list and a coverage row for all eleven listed entry points plus three invariants, every one marked `holds` with the reason.\n\n**What I checked and how I concluded it holds**\n\n- **Permission model.** The only role is admin, fixed in the constructor with no setter, and its only power is the once-per-cave metadata freeze. Every other state-changing function is permissionless by the brief and gated by time, a Merkle proof bound to the caller, or the one-shot release flag. No storage slot has two writers with different guards: the shared seat cursor is written by claim and leftover, which the release flag makes mutually exclusive.\n- **Confused deputy and value flow.** The single coin call always debits the caller to the constant dead address, so nobody can spend another buyer's allowance and the contract never holds funds. Reentry through the coin finds the sale already recorded. The inherited ERC-721 functions are stock OpenZeppelin, and both safeTransferFrom overloads route through the override that rejects contract recipients without any callback. I confirmed the 3-argument overload empirically.\n- **Paired surfaces.** The buy gate and the sweep gate are exact complements at the cave close, so a cave can never be bought and swept in the same state. Sweep's ownership check excludes sold pieces even after transfer, and burn is not exposed, so no id can return to the unminted state. Sale and free piece sets are disjoint in every mint path.\n- **Ladder and trust seams.** A 256-run fuzz compared the contract's lazily computed opening against a direct implementation of the brief's ladder rule after random buys at random times across the whole week. Every round matched, floor buys never moved an opening, and no buy altered another open round's opening. A predecessor's late line sale can still raise a round's quote before that round opens. The README documents that at line 89 and the brief defines the ladder this way, so it stays an observation, not a finding.\n\n**Observations, non-blocking**\n\n- Admin may freeze a cave's base before the cave opens and the contract does not verify content. The README states both.\n- Static analysis leads on uninitialized locals and timestamp comparisons are intentional zero defaults and the brief's own time gates. None reproduces as a defect.\n\nFindings and coverage are in `.imd-findings.json` at the repository root.","treeHash":null,"usage":{"cachedInputTokens":843249,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":26038,"runtime":"claude","turns":22,"wallClockMs":398183}},{"artifacts":[],"attempt":1,"bundleHash":"95bff25c5f410ba81dec800172ce631ff0aac9312365e2ac77155fe25f3463b2","device":"1ebf032d4201b2fc","findings":[],"hash":"e9280be3d58f5975a89b36a29fc18a9048ea93fab38e4f12db32afd018d41a64","nodeId":"154af4ff-5f63-433a-8c8b-f7449f60a902","outcome":"completed","summary":"Implemented Ochre, tests, vendored dependencies, and Sepolia deployment files.\n\n- Build, 24 tests, and formatting check pass.\n- Runtime: **8,895 bytes**.\n- Local deployment simulation passes; no live transaction broadcast.\n\nStrict no-callback behavior means safe transfers reject contract recipients. Rules, parameters, and operational responsibilities are documented in [README.md](/home/ubuntu/.identitymd/work/0d504e85-2852-4039-99eb-4a6c6c9e7544/154af4ff-5f63-433a-8c8b-f7449f60a902/README.md).","treeHash":"693fd26a728af2d3a2d9a9d4d5db81fd3d36e325","usage":{"cachedInputTokens":2244480,"inputTokens":97174,"model":"gpt-6-astra","outputTokens":37385,"runtime":"codex","turns":10,"wallClockMs":1495755}}],"verification":[{"checks":[{"durationMs":6969,"exitCode":0,"name":"build","output":"Compiling 32 files with Solc 0.8.26\nSolc 0.8.26 finished in 6.86s\nCompiler run successful!\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:339:34\n    │\n339 │         if (label == bytes32(0)) revert InvalidConfig();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:344:50\n    │\n344 │             else if (padding || character > 127) revert InvalidConfig();\n    │                                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:164:13\n    │\n164 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:164:40\n    │\n164 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:171:13\n    │\n171 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:171:40\n    │\n171 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Ochre.sol:181:9\n    │\n181 │         emit Bought(id, msg.sender, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:186:13\n    │\n186 │         if (block.timestamp < startTime) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:202:13\n    │\n202 │         if (block.timestamp < startTime + 8 * caveLength) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:218:13\n    │\n218 │         if (block.timestamp < caveClose(c)) revert NotClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:129:23\n    │\n129 │         if (id > 736) revert InvalidPiece();\n    │                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:349:30\n    │\n349 │         if (c == 0 || c > 7) revert InvalidCave();\n    │                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:354:31\n    │\n354 │         if (r == 0 || r > 21) revert InvalidRound();\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:240:61\n    │\n240 │         if (value.length == 0 || value[value.length - 1] != bytes1(\"/\")) revert InvalidBase();\n    │                                                             ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes1' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:253:87\n    │\n253 │             slot == 5 ? \"gathering/\" : string.concat(\"line-\", string(abi.encodePacked(uint8(48 + slot))), \"/\");\n    │                                                                                       ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:254:66\n    │\n254 │         return string.concat(base, path, string(abi.encodePacked(uint8(48 + r / 10), uint8(48 + r % 10))), \".json\");\n    │                                                                  ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:254:86\n    │\n254 │         return string.concat(base, path, string(abi.encodePacked(uint8(48 + r / 10), uint8(48 + r % 10))), \".json\");\n    │                                                                                      ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:286:57\n    │\n286 │                 return Math.max(2 * floorPrice, next >> quiet);\n    │                                                         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:300:15\n    │\n300 │             ++segments;\n    │               ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-oz-erc721-mint]: `ERC721._mint` does not check that the recipient can receive the token; use `_safeMint`\n    ╭▸ src/Ochre.sol:323:9\n    │\n323 │         _mint(to, id);\n    │         ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-oz-erc721-mint\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:330:16\n    │\n330 │         while (length < 32 && label[length] != 0) ++length;\n    │                ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:344:22\n    │\n344 │             else if (padding || character > 127) revert InvalidConfig();\n    │                      ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\n","passed":true},{"durationMs":133,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 30 tests for test/Ochre.t.sol:OchreTest\n[PASS] testAll335SeatsInIdOrderAndMerkleExhaustion() (gas: 49642033)\n[PASS] testAll737EventuallyMintedExactlyOnce() (gas: 57915702)\n[PASS] testBuyAndQuoteTimeBoundaries() (gas: 691279)\n[PASS] testBuyEventAndDirectBurnPayment() (gas: 320903)\n[PASS] testClaimProofStartAndDuplicate() (gas: 315086)\n[PASS] testCoinReentrySeesCompletedSaleAndCannotDuplicatePiece() (gas: 751690)\n[PASS] testConstructorWithoutCoinCodeAndFixedDeployment() (gas: 174218)\n[PASS] testERC721TransfersApprovalsAndNoReceiverCallbacks() (gas: 811912)\n[PASS] testEveryPieceAndSaleCount() (gas: 9470948)\n[PASS] testEverySaleSlotBoughtInOrderAndAllSalesExhausted() (gas: 63856939)\n[PASS] testFalseAndRevertingCoinRollbackEntireBuy() (gas: 1275690)\n[PASS] testFreezeOnlyAdminOnceAndValidBase() (gas: 233830)\n[PASS] testFuzzHalvingPriceIsBoundedAndMonotone(uint256) (runs: 256, μ: 51806, ~: 51660)\nLogs:\n  Bound result 2385\n\n[PASS] testHalvingSegmentEndsAndInterior() (gas: 188850)\n[PASS] testInterfacesRoyaltyAndNonexistentURI() (gas: 83965)\n[PASS] testInvalidConfiguration() (gas: 5582)\n[PASS] testLadderAcrossCavesAndUnboughtRoundNotSnapshot() (gas: 635856)\n[PASS] testLadderDoublesLastLineSaleAndHalvesQuietRounds() (gas: 903635)\n[PASS] testLadderFloorBuysIgnoredAndStoredOpeningStable() (gas: 1013662)\n[PASS] testLastLineSaleReplacesEarlierSaleAndHalfOpeningMinimum() (gas: 1170907)\n[PASS] testLeftoverFailureRollsBackCursorAndReentryUsesNextPiece() (gas: 808452)\n[PASS] testMintToContractWithoutReceiver() (gas: 518998)\n[PASS] testMissingBoolOrMissingAllowanceRejectsBuy() (gas: 428452)\n[PASS] testQuietFirstBuyAtFloorDoesNotRaiseNextOpening() (gas: 271073)\n[PASS] testRehearsalFractionalSegments() (gas: 94065)\n[PASS] testReleaseTimingPermissionlessAndClaimStopsOnlyOnRelease() (gas: 543108)\n[PASS] testRuntimePassesProtectedOpcodeScanAndSizeLimit() (gas: 3630547)\n[PASS] testSweepBoundariesPartialBatchesAndEvents() (gas: 1936589)\n[PASS] testURIsIncludingEndpointsRoundsSlotsAndFrozenCaves() (gas: 12549467)\n[PASS] testWindowsAndInvalidIndices() (gas: 2286269)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 32.61ms (129.93ms CPU time)\n\nRan 1 test suite in 33.47ms (32.61ms CPU time): 30 tests passed, 0 failed, 0 skipped (30 total tests)\n","passed":true},{"durationMs":46,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Ochre.approve(address,uint256)\",\"Ochre.buy(uint256,uint256)\",\"Ochre.buyLeftover()\",\"Ochre.claimSeat(bytes32[])\",\"Ochre.freeze(uint256,string)\",\"Ochre.releaseUnclaimed()\",\"Ochre.safeTransferFrom(address,address,uint256)\",\"Ochre.safeTransferFrom(address,address,uint256,bytes)\",\"Ochre.setApprovalForAll(address,bool)\",\"Ochre.sweep(uint256,uint256)\",\"Ochre.transferFrom(address,address,uint256)\"],\"files\":{\"README.md\":109,\"foundry.toml\":18,\"launch.json\":27,\"remappings.txt\":2,\"script/check_launch.py\":50,\"src/Ochre.sol\":357,\"test/Ochre.t.sol\":765},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"3aa2fade4cc2b762e01bdf7febdebde7df6a1a94239e005810917e263c434d9e","verifiedTreeHash":"d733d1d5a9d2d7d062cac79bbabcfe2e54673a95","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":7937,"exitCode":0,"name":"build","output":"Compiling 32 files with Solc 0.8.26\nSolc 0.8.26 finished in 7.83s\nCompiler run successful!\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:339:34\n    │\n339 │         if (label == bytes32(0)) revert InvalidConfig();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:344:50\n    │\n344 │             else if (padding || character > 127) revert InvalidConfig();\n    │                                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:164:13\n    │\n164 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:164:40\n    │\n164 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:171:13\n    │\n171 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:171:40\n    │\n171 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Ochre.sol:181:9\n    │\n181 │         emit Bought(id, msg.sender, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:186:13\n    │\n186 │         if (block.timestamp < startTime) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:202:13\n    │\n202 │         if (block.timestamp < startTime + 8 * caveLength) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:218:13\n    │\n218 │         if (block.timestamp < caveClose(c)) revert NotClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:129:23\n    │\n129 │         if (id > 736) revert InvalidPiece();\n    │                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:349:30\n    │\n349 │         if (c == 0 || c > 7) revert InvalidCave();\n    │                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:354:31\n    │\n354 │         if (r == 0 || r > 21) revert InvalidRound();\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:240:61\n    │\n240 │         if (value.length == 0 || value[value.length - 1] != bytes1(\"/\")) revert InvalidBase();\n    │                                                             ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes1' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:253:87\n    │\n253 │             slot == 5 ? \"gathering/\" : string.concat(\"line-\", string(abi.encodePacked(uint8(48 + slot))), \"/\");\n    │                                                                                       ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:254:66\n    │\n254 │         return string.concat(base, path, string(abi.encodePacked(uint8(48 + r / 10), uint8(48 + r % 10))), \".json\");\n    │                                                                  ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:254:86\n    │\n254 │         return string.concat(base, path, string(abi.encodePacked(uint8(48 + r / 10), uint8(48 + r % 10))), \".json\");\n    │                                                                                      ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:286:57\n    │\n286 │                 return Math.max(2 * floorPrice, next >> quiet);\n    │                                                         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:300:15\n    │\n300 │             ++segments;\n    │               ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-oz-erc721-mint]: `ERC721._mint` does not check that the recipient can receive the token; use `_safeMint`\n    ╭▸ src/Ochre.sol:323:9\n    │\n323 │         _mint(to, id);\n    │         ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-oz-erc721-mint\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:330:16\n    │\n330 │         while (length < 32 && label[length] != 0) ++length;\n    │                ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:344:22\n    │\n344 │             else if (padding || character > 127) revert InvalidConfig();\n    │                      ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\n","passed":true},{"durationMs":151,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 30 tests for test/Ochre.t.sol:OchreTest\n[PASS] testAll335SeatsInIdOrderAndMerkleExhaustion() (gas: 49642033)\n[PASS] testAll737EventuallyMintedExactlyOnce() (gas: 57915702)\n[PASS] testBuyAndQuoteTimeBoundaries() (gas: 691279)\n[PASS] testBuyEventAndDirectBurnPayment() (gas: 320903)\n[PASS] testClaimProofStartAndDuplicate() (gas: 315086)\n[PASS] testCoinReentrySeesCompletedSaleAndCannotDuplicatePiece() (gas: 751690)\n[PASS] testConstructorWithoutCoinCodeAndFixedDeployment() (gas: 174218)\n[PASS] testERC721TransfersApprovalsAndNoReceiverCallbacks() (gas: 811912)\n[PASS] testEveryPieceAndSaleCount() (gas: 9470948)\n[PASS] testEverySaleSlotBoughtInOrderAndAllSalesExhausted() (gas: 63856939)\n[PASS] testFalseAndRevertingCoinRollbackEntireBuy() (gas: 1275690)\n[PASS] testFreezeOnlyAdminOnceAndValidBase() (gas: 233830)\n[PASS] testFuzzHalvingPriceIsBoundedAndMonotone(uint256) (runs: 256, μ: 51794, ~: 51660)\nLogs:\n  Bound result 630\n\n[PASS] testHalvingSegmentEndsAndInterior() (gas: 188850)\n[PASS] testInterfacesRoyaltyAndNonexistentURI() (gas: 83965)\n[PASS] testInvalidConfiguration() (gas: 5582)\n[PASS] testLadderAcrossCavesAndUnboughtRoundNotSnapshot() (gas: 635856)\n[PASS] testLadderDoublesLastLineSaleAndHalvesQuietRounds() (gas: 903635)\n[PASS] testLadderFloorBuysIgnoredAndStoredOpeningStable() (gas: 1013662)\n[PASS] testLastLineSaleReplacesEarlierSaleAndHalfOpeningMinimum() (gas: 1170907)\n[PASS] testLeftoverFailureRollsBackCursorAndReentryUsesNextPiece() (gas: 808452)\n[PASS] testMintToContractWithoutReceiver() (gas: 518998)\n[PASS] testMissingBoolOrMissingAllowanceRejectsBuy() (gas: 428452)\n[PASS] testQuietFirstBuyAtFloorDoesNotRaiseNextOpening() (gas: 271073)\n[PASS] testRehearsalFractionalSegments() (gas: 94065)\n[PASS] testReleaseTimingPermissionlessAndClaimStopsOnlyOnRelease() (gas: 543108)\n[PASS] testRuntimePassesProtectedOpcodeScanAndSizeLimit() (gas: 3630547)\n[PASS] testSweepBoundariesPartialBatchesAndEvents() (gas: 1936589)\n[PASS] testURIsIncludingEndpointsRoundsSlotsAndFrozenCaves() (gas: 12549467)\n[PASS] testWindowsAndInvalidIndices() (gas: 2286269)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 39.68ms (126.15ms CPU time)\n\nRan 1 test suite in 41.26ms (39.68ms CPU time): 30 tests passed, 0 failed, 0 skipped (30 total tests)\n","passed":true},{"durationMs":53,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Ochre.approve(address,uint256)\",\"Ochre.buy(uint256,uint256)\",\"Ochre.buyLeftover()\",\"Ochre.claimSeat(bytes32[])\",\"Ochre.freeze(uint256,string)\",\"Ochre.releaseUnclaimed()\",\"Ochre.safeTransferFrom(address,address,uint256)\",\"Ochre.safeTransferFrom(address,address,uint256,bytes)\",\"Ochre.setApprovalForAll(address,bool)\",\"Ochre.sweep(uint256,uint256)\",\"Ochre.transferFrom(address,address,uint256)\"],\"files\":{\"README.md\":109,\"foundry.toml\":18,\"launch.json\":27,\"remappings.txt\":2,\"script/check_launch.py\":50,\"src/Ochre.sol\":357,\"test/Ochre.t.sol\":765},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1678,"exitCode":0,"name":"slither","output":"[medium/medium] uninitialized-local at src/Ochre.sol:296: Ochre._price(uint256,uint256).segments (src/Ochre.sol#296) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Ochre.sol:340: Ochre._checkLabel(bytes32).padding (src/Ochre.sol#340) is a local variable never initialized\n[low/medium] timestamp at src/Ochre.sol:294: Ochre._price(uint256,uint256) (src/Ochre.sol#294-308) uses timestamp for comparisons\n[low/medium] timestamp at src/Ochre.sol:201: Ochre.releaseUnclaimed() (src/Ochre.sol#201-206) uses timestamp for comparisons\n[low/medium] timestamp at src/Ochre.sol:168: Ochre.buy(uint256,uint256) (src/Ochre.sol#168-183) uses timestamp for comparisons\n[low/medium] timestamp at src/Ochre.sol:162: Ochre.priceNow(uint256,uint256) (src/Ochre.sol#162-166) uses timestamp for comparisons\n[low/medium] timestamp at src/Ochre.sol:217: Ochre.sweep(uint256,uint256) (src/Ochre.sol#217-233) uses timestamp for comparisons\n[low/medium] timestamp at src/Ochre.sol:185: Ochre.claimSeat(bytes32[]) (src/Ochre.sol#185-199) uses timestamp for comparisons","passed":true},{"durationMs":329,"exitCode":0,"name":"aderyn","output":"[low] costly-loop at src/Ochre.sol:223: Costly operations inside loop\n[low] literal-instead-of-constant at src/Ochre.sol:90: Literal Instead of Constant (37 places)\n[low] require-revert-in-loop at src/Ochre.sol:223: Loop Contains `require`/`revert` (2 places)\n[low] state-variable-could-be-immutable at src/Ochre.sol:42: State Variable Could Be Immutable (9 places)\n[low] unchecked-return at src/Ochre.sol:123: Unchecked Return (3 places)\n[low] uninitialized-local-variable at src/Ochre.sol:190: Uninitialized Local Variable (5 places)\n[low] unsafe-oz-erc721-mint at src/Ochre.sol:323: Unsafe `ERC721::_mint()`\n[low] unused-public-function at src/Ochre.sol:158: Public Function Not Used Internally (2 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"48d8ab357dffdcd80434d88ba75814cba8af5a5c107f0a8162814b223900e151","verifiedTreeHash":"0d5c3bfeab4ba8b066cdbe161a11f496bfa838e2","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":18402,"exitCode":0,"name":"build","output":"Compiling 35 files with Solc 0.8.26\nSolc 0.8.26 finished in 18.25s\nCompiler run successful!\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:339:34\n    │\n339 │         if (label == bytes32(0)) revert InvalidConfig();\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:344:50\n    │\n344 │             else if (padding || character > 127) revert InvalidConfig();\n    │                                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:164:13\n    │\n164 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:164:40\n    │\n164 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:171:13\n    │\n171 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:171:40\n    │\n171 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert NotOpen();\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Ochre.sol:181:9\n    │\n181 │         emit Bought(id, msg.sender, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:186:13\n    │\n186 │         if (block.timestamp < startTime) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:202:13\n    │\n202 │         if (block.timestamp < startTime + 8 * caveLength) revert TooEarly();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:218:13\n    │\n218 │         if (block.timestamp < caveClose(c)) revert NotClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:129:23\n    │\n129 │         if (id > 736) revert InvalidPiece();\n    │                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:349:30\n    │\n349 │         if (c == 0 || c > 7) revert InvalidCave();\n    │                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:354:31\n    │\n354 │         if (r == 0 || r > 21) revert InvalidRound();\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:240:61\n    │\n240 │         if (value.length == 0 || value[value.length - 1] != bytes1(\"/\")) revert InvalidBase();\n    │                                                             ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes1' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:253:87\n    │\n253 │             slot == 5 ? \"gathering/\" : string.concat(\"line-\", string(abi.encodePacked(uint8(48 + slot))), \"/\");\n    │                                                                                       ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:254:66\n    │\n254 │         return string.concat(base, path, string(abi.encodePacked(uint8(48 + r / 10), uint8(48 + r % 10))), \".json\");\n    │                                                                  ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:254:86\n    │\n254 │         return string.concat(base, path, string(abi.encodePacked(uint8(48 + r / 10), uint8(48 + r % 10))), \".json\");\n    │                                                                                      ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:286:57\n    │\n286 │                 return Math.max(2 * floorPrice, next >> quiet);\n    │                                                         ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:300:15\n    │\n300 │             ++segments;\n    │               ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-oz-erc721-mint]: `ERC721._mint` does not check that the recipient can receive the token; use `_safeMint`\n    ╭▸ src/Ochre.sol:323:9\n    │\n323 │         _mint(to, id);\n    │         ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-oz-erc721-mint\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:330:16\n    │\n330 │         while (length < 32 && label[length] != 0) ++length;\n    │                ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Ochre.sol:344:22\n    │\n344 │             else if (padding || character > 127) revert InvalidConfig();\n    │                      ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\n","passed":true},{"durationMs":22835,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 30 tests for test/Ochre.t.sol:OchreTest\n[PASS] testAll335SeatsInIdOrderAndMerkleExhaustion() (gas: 49642033)\n[PASS] testAll737EventuallyMintedExactlyOnce() (gas: 57915702)\n[PASS] testBuyAndQuoteTimeBoundaries() (gas: 691279)\n[PASS] testBuyEventAndDirectBurnPayment() (gas: 320903)\n[PASS] testClaimProofStartAndDuplicate() (gas: 315086)\n[PASS] testCoinReentrySeesCompletedSaleAndCannotDuplicatePiece() (gas: 751690)\n[PASS] testConstructorWithoutCoinCodeAndFixedDeployment() (gas: 174218)\n[PASS] testERC721TransfersApprovalsAndNoReceiverCallbacks() (gas: 811912)\n[PASS] testEveryPieceAndSaleCount() (gas: 9470948)\n[PASS] testEverySaleSlotBoughtInOrderAndAllSalesExhausted() (gas: 63856939)\n[PASS] testFalseAndRevertingCoinRollbackEntireBuy() (gas: 1275690)\n[PASS] testFreezeOnlyAdminOnceAndValidBase() (gas: 233830)\n[PASS] testFuzzHalvingPriceIsBoundedAndMonotone(uint256) (runs: 256, μ: 51757, ~: 51660)\nLogs:\n  Bound result 1095\n\n[PASS] testHalvingSegmentEndsAndInterior() (gas: 188850)\n[PASS] testInterfacesRoyaltyAndNonexistentURI() (gas: 83965)\n[PASS] testInvalidConfiguration() (gas: 5582)\n[PASS] testLadderAcrossCavesAndUnboughtRoundNotSnapshot() (gas: 635856)\n[PASS] testLadderDoublesLastLineSaleAndHalvesQuietRounds() (gas: 903635)\n[PASS] testLadderFloorBuysIgnoredAndStoredOpeningStable() (gas: 1013662)\n[PASS] testLastLineSaleReplacesEarlierSaleAndHalfOpeningMinimum() (gas: 1170907)\n[PASS] testLeftoverFailureRollsBackCursorAndReentryUsesNextPiece() (gas: 808452)\n[PASS] testMintToContractWithoutReceiver() (gas: 518998)\n[PASS] testMissingBoolOrMissingAllowanceRejectsBuy() (gas: 428452)\n[PASS] testQuietFirstBuyAtFloorDoesNotRaiseNextOpening() (gas: 271073)\n[PASS] testRehearsalFractionalSegments() (gas: 94065)\n[PASS] testReleaseTimingPermissionlessAndClaimStopsOnlyOnRelease() (gas: 543108)\n[PASS] testRuntimePassesProtectedOpcodeScanAndSizeLimit() (gas: 3630547)\n[PASS] testSweepBoundariesPartialBatchesAndEvents() (gas: 1936589)\n[PASS] testURIsIncludingEndpointsRoundsSlotsAndFrozenCaves() (gas: 12549467)\n[PASS] testWindowsAndInvalidIndices() (gas: 2286269)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 87.53ms (232.77ms CPU time)\n\nRan 13 tests for test/OchreProperties.t.sol:OchrePropertiesTest\n[PASS] testConstructorRejectsZeroAddressesAndOverflowingSchedule() (gas: 6480)\n[PASS] testEveryMintPathWorksWithAReceiverThatRejectsCallbacks() (gas: 1458200)\n[PASS] testFullWidthInterpolationDoesNotOverflow() (gas: 118395)\n[PASS] testFuzzEveryCaveRoundBoundary(uint8,uint8) (runs: 1000, μ: 504484, ~: 481636)\nLogs:\n  Bound result 4\n  Bound result 1\n\n[PASS] testFuzzFractionalCurveBoundsAndPayment(uint96,uint96,uint32,uint32) (runs: 1000, μ: 476424, ~: 473768)\nLogs:\n  Bound result 3371715337552666048770084806\n  Bound result 72484731839229719284001340392\n  Bound result 6555\n  Bound result 479\n\n[PASS] testFuzzHalvingKnotsAcrossConstructorPrices(uint96,uint8,uint32) (runs: 1000, μ: 334281, ~: 251561)\nLogs:\n  Bound result 1002515886209911305656\n  Bound result 1\n  Bound result 81629\n\n[PASS] testFuzzRoyaltyRoundingIdentity(uint256,uint256) (runs: 1000, μ: 12256, ~: 12256)\n[PASS] testInsufficientBalanceAndLeftoverAllowancePreserveInventory() (gas: 747747)\n[PASS] testLabelsRejectMalformedPaddingAndAcceptAll32Bytes() (gas: 6759)\n[PASS] testMaximumRehearsalLadderRemainsLiveThroughAll147Rounds() (gas: 34980862)\n[PASS] testMerkleProofCannotBeReusedByAnotherWalletOrAltered() (gas: 245138)\n[PASS] testNativeCurrencyIsRejectedByAllIssuancePaths() (gas: 183191)\n[PASS] testOneWeiFloorOddOpeningAndSubsecondSegments() (gas: 208301)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 87.67ms (375.96ms CPU time)\n\nRan 2 tests for test/OchreInvariant.t.sol:OchreInvariantTest\n[PASS] invariant_supplyPaymentAndPermanentTransitions() (runs: 256, calls: 32768, reverts: 0)\n\n╭-----------------------+-------------+-------+---------+----------╮\n| Contract              | Selector    | Calls | Reverts | Discards |\n+==================================================================+\n| OchreLifecycleHandler | advanceTime | 4067  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| OchreLifecycleHandler | buy         | 4135  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| OchreLifecycleHandler | buyLeftover | 4215  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| OchreLifecycleHandler | claim       | 4078  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| OchreLifecycleHandler | freeze      | 4051  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| OchreLifecycleHandler | release     | 4095  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| OchreLifecycleHandler | sweep       | 4073  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| OchreLifecycleHandler | transfer    | 4054  | 0       | 0        |\n╰-----------------------+-------------+-------+---------+----------╯\n\nLogs:\n  Bound result 6\n  Bound result 3\n  Bound result 1\n  Bound result 14\n  Bound result 2\n  Bound result 6\n  Bound result 220\n  Bound result 5\n  Bound result 11\n  Bound result 1\n  Bound result 3\n  Bound result 1\n  Bound result 26\n  Bound result 5\n  Bound result 6\n  Bound result 100\n  Bound result 3052\n  Bound result 1\n  Bound result 7\n  Bound result 3\n  Bound result 6\n  Bound result 3\n  Bound result 3\n  Bound result 16\n  Bound result 3615\n  Bound result 4\n  Bound result 18\n  Bound result 1\n  Bound result 19\n  Bound result 19\n  Bound result 4892\n  Bound result 334\n  Bound result 3\n  Bound result 2\n  Bound result 16\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 7\n  Bound result 5\n  Bound result 5\n  Bound result 471\n  Bound result 7\n  Bound result 2\n  Bound result 11\n  Bound result 7\n  Bound result 1273\n  Bound result 5\n  Bound result 6\n  Bound result 5\n  Bound result 4\n  Bound result 9\n  Bound result 3\n  Bound result 6\n  Bound result 75\n  Bound result 5\n  Bound result 7\n  Bound result 5\n  Bound result 1\n  Bound result 69\n  Bound result 335\n  Bound result 2\n  Bound result 63\n  Bound result 5\n  Bound result 60\n  Bound result 511\n  Bound result 4\n  Bound result 77\n  Bound result 5\n  Bound result 4\n  Bound result 7\n  Bound result 56\n  Bound result 2\n  Bound result 21\n  Bound result 5\n  Bound result 12\n  Bound result 6\n  Bound result 4\n  Bound result 3\n  Bound result 6\n  Bound result 18\n  Bound result 112\n  Bound result 32\n  Bound result 4\n  Bound result 7\n  Bound result 3134\n  Bound result 3837\n  Bound result 2\n  Bound result 7\n  Bound result 7\n  Bound result 7\n  Bound result 89\n  Bound result 5\n  Bound result 16\n  Bound result 1\n  Bound result 4\n  Bound result 63\n  Bound result 2\n  Bound result 45\n  Bound result 2\n  Bound result 5\n  Bound result 84\n  Bound result 3\n  Bound result 17\n  Bound result 2\n  Bound result 3\n  Bound result 3\n  Bound result 2\n  Bound result 12\n  Bound result 1\n  Bound result 5\n  Bound result 1\n  Bound result 2\n  Bound result 3\n  Bound result 4\n  Bound result 5\n  Bound result 6\n  Bound result 7\n  Bound result 1\n  Bound result 2\n  Bound result 3\n  Bound result 4\n  Bound result 5\n  Bound result 6\n  Bound result 7\n\n[PASS] testHandlerExercisesEveryTransition() (gas: 74748874)\nLogs:\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 3600\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 7200\n  Bound result 7200\n  Bound result 7200\n  Bound result 3600\n  Bound result 1\n  Bound result 2\n  Bound result 3\n  Bound result 4\n  Bound result 5\n  Bound result 6\n  Bound result 7\n  Bound result 1\n  Bound result 2\n  Bound result 3\n  Bound result 4\n  Bound result 5\n  Bound result 6\n  Bound result 7\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 22.68s (22.71s CPU time)\n\nRan 3 test suites in 22.68s (22.86s CPU time): 45 tests passed, 0 failed, 0 skipped (45 total tests)\n","passed":true},{"durationMs":51,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Ochre.approve(address,uint256)\",\"Ochre.buy(uint256,uint256)\",\"Ochre.buyLeftover()\",\"Ochre.claimSeat(bytes32[])\",\"Ochre.freeze(uint256,string)\",\"Ochre.releaseUnclaimed()\",\"Ochre.safeTransferFrom(address,address,uint256)\",\"Ochre.safeTransferFrom(address,address,uint256,bytes)\",\"Ochre.setApprovalForAll(address,bool)\",\"Ochre.sweep(uint256,uint256)\",\"Ochre.transferFrom(address,address,uint256)\"],\"files\":{\"README.md\":109,\"foundry.toml\":18,\"launch.json\":27,\"remappings.txt\":2,\"script/check_launch.py\":50,\"src/Ochre.sol\":357,\"test/Ochre.t.sol\":765,\"test/OchreInvariant.t.sol\":351,\"test/OchreProperties.t.sol\":298,\"test/README.md\":107,\"test/support/OchreSetup.sol\":123},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a688a64b608f6bc69cc1991df90e6a6fffc817862d666a661dca2bd32ad754a0","verifiedTreeHash":"5f7334be164c8df7b9c349baeb0fb58a18ba5baf","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":10428,"exitCode":0,"name":"build","output":"Compiling 25 files with Solc 0.8.26\nSolc 0.8.26 finished in 10.33s\nCompiler run successful!\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:120:38\n    │\n120 │             if (label == bytes32(0)) revert InvalidConfiguration();\n    │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:125:47\n    │\n125 │                 else if (padding || ch > 127) revert InvalidConfiguration();\n    │                                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:277:13\n    │\n277 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert WrongTime();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:277:40\n    │\n277 │         if (block.timestamp < opens || block.timestamp >= caveClose(c)) revert WrongTime();\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Ochre.sol:308:9\n    │\n308 │         emit Bought(id, msg.sender, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:313:13\n    │\n313 │         if (block.timestamp < caveClose(c)) revert WrongTime();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Ochre.sol:321:17\n    │\n321 │                 emit Swept(id);\n    │                 ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:195:31\n    │\n195 │         if (id >= MAX_SUPPLY) revert InvalidPiece();\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:435:30\n    │\n435 │         if (c == 0 || c > 7) revert InvalidCave();\n    │                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:440:31\n    │\n440 │         if (r == 0 || r > 21) revert InvalidRound();\n    │                               ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:374:60\n    │\n374 │         if (id >= MAX_SUPPLY || _owners[id] != address(0)) revert InvalidPiece();\n    │                                                            ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Ochre.sol:375:31\n    │\n375 │         if (to == address(0)) revert InvalidRecipient();\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:330:13\n    │\n330 │         if (block.timestamp < startTime) revert WrongTime();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Ochre.sol:344:9\n    │\n344 │         emit Claimed(id, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Ochre.sol:348:13\n    │\n348 │         if (block.timestamp < startTime + 8 * caveLength) revert WrongTime();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Ochre.sol:358:9\n    │\n358 │         emit Bought(id, msg.sender, floorPrice);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:391:79\n    │\n391 │         if (bytes(base).length == 0 || bytes(base)[bytes(base).length - 1] != bytes1(\"/\")) {\n    │                                                                               ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes1' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:406:80\n    │\n406 │             slot == 5 ? \"gathering/\" : string(abi.encodePacked(\"line-\", bytes1(uint8(48 + slot)), \"/\"));\n    │                                                                                ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:410:44\n    │\n410 │             string(abi.encodePacked(bytes1(uint8(48 + r / 10)), bytes1(uint8(48 + r % 10)))),\n    │                                            ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Ochre.sol:410:72\n    │\n410 │             string(abi.encodePacked(bytes1(uint8(48 + r / 10)), bytes1(uint8(48 + r % 10)))),\n    │                                                                        ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\n","passed":true},{"durationMs":109,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 24 tests for test/Ochre.t.sol:OchreTest\n[PASS] testAllSeatClaimsExhaustExactly335() (gas: 50204077)\n[PASS] testBuyOrderPaymentEventsAndNoReceiverCallback() (gas: 1576238)\n[PASS] testConstructorValidation() (gas: 3974252)\n[PASS] testDeploymentConfigurationAndEmptyEVM() (gas: 8179093)\n[PASS] testEveryPieceAndSaleCount() (gas: 17498532)\n[PASS] testFloorBuyIgnoredAndCachedOpeningStable() (gas: 479221)\n[PASS] testFullLifecycleExactly737AndNoMintPastSupply() (gas: 83592229)\n[PASS] testFuzzLineAgainstRationalModel(uint64,uint32,uint16) (runs: 256, μ: 2367129, ~: 2365269)\n[PASS] testHalvingLineSegmentEndsAndClamp() (gas: 2500496)\n[PASS] testHugeOpeningInterpolationDoesNotOverflowIntermediateProduct() (gas: 2391303)\n[PASS] testInputBoundsAndTimes() (gas: 1914228)\n[PASS] testInterfacesAndRoyalty() (gas: 69050)\n[PASS] testLadderHasNoEconomicCapAcrossAll147Rounds() (gas: 33842370)\n[PASS] testLadderLineSaleQuietRoundsAndWeekBoundary() (gas: 960156)\n[PASS] testLatestLineSaleAndHalfOpeningBound() (gas: 1113484)\n[PASS] testLeftoverReentryUsesDistinctSeats() (gas: 559120)\n[PASS] testPaymentFailuresRollbackAllEffects() (gas: 1979893)\n[PASS] testReentrantPurchaseUsesNextSlotAndPaysIndependently() (gas: 889469)\n[PASS] testReentryCannotReuseSoldPieceOrClaimForBuyer() (gas: 470572)\n[PASS] testReleaseTimingClaimRemainsUntilExplicitReleaseAndPaymentRollback() (gas: 759142)\n[PASS] testSeatProofTimingDuplicateAndEvent() (gas: 363916)\n[PASS] testSweepTimeOrderBatchesOnlyUnsoldSalePieces() (gas: 3658134)\n[PASS] testTransfersApprovalsAndNoCallbacks() (gas: 571630)\n[PASS] testURIAndFreeze() (gas: 1865683)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 35.69ms (134.81ms CPU time)\n\nRan 1 test suite in 36.58ms (35.69ms CPU time): 24 tests passed, 0 failed, 0 skipped (24 total tests)\n","passed":true},{"durationMs":39,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Ochre.approve(address,uint256)\",\"Ochre.buy(uint256,uint256)\",\"Ochre.buyLeftover()\",\"Ochre.claimSeat(bytes32[])\",\"Ochre.freeze(uint256,string)\",\"Ochre.releaseUnclaimed()\",\"Ochre.safeTransferFrom(address,address,uint256)\",\"Ochre.safeTransferFrom(address,address,uint256,bytes)\",\"Ochre.setApprovalForAll(address,bool)\",\"Ochre.sweep(uint256,uint256)\",\"Ochre.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":123,\"foundry.toml\":19,\"launch.json\":28,\"remappings.txt\":2,\"script/DeployOchre.s.sol\":29,\"src/Ochre.sol\":446,\"test/Ochre.t.sol\":743},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1523,"exitCode":0,"name":"slither","output":"[low/medium] timestamp at src/Ochre.sol:275: Ochre._elapsed(uint256,uint256) (src/Ochre.sol#275-279) uses timestamp for comparisons\n[low/medium] timestamp at src/Ochre.sol:282: Ochre._price(uint256,uint256) (src/Ochre.sol#282-294) uses timestamp for comparisons\n[low/medium] timestamp at src/Ochre.sol:296: Ochre.buy(uint256,uint256) (src/Ochre.sol#296-310) uses timestamp for comparisons\n[low/medium] timestamp at src/Ochre.sol:312: Ochre.sweep(uint256,uint256) (src/Ochre.sol#312-327) uses timestamp for comparisons\n[low/medium] timestamp at src/Ochre.sol:347: Ochre.releaseUnclaimed() (src/Ochre.sol#347-352) uses timestamp for comparisons\n[low/medium] timestamp at src/Ochre.sol:329: Ochre.claimSeat(bytes32[]) (src/Ochre.sol#329-345) uses timestamp for comparisons","passed":true},{"durationMs":377,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/Ochre.sol:406: `abi.encodePacked()` Hash Collision\n[low] costly-loop at src/Ochre.sol:317: Costly operations inside loop\n[low] literal-instead-of-constant at src/Ochre.sol:103: Literal Instead of Constant (37 places)\n[low] missing-inheritance at src/Ochre.sol:12: Missing Inheritance\n[low] require-revert-in-loop at src/Ochre.sol:317: Loop Contains `require`/`revert` (2 places)\n[low] state-change-without-event at src/Ochre.sol:166: State Change Without Event (3 places)\n[low] state-variable-could-be-immutable at src/Ochre.sol:60: State Variable Could Be Immutable\n[low] unchecked-return at src/Ochre.sol:148: Unchecked Return (5 places)\n[low] uninitialized-local-variable at src/Ochre.sol:118: Uninitialized Local Variable (3 places)\n[low] unused-public-function at src/Ochre.sol:270: Public Function Not Used Internally","passed":true}],"detail":"launch.json is not a valid launch manifest: contracts.0.constructorArgs: Too big: expected array to have <=16 items","evaluation":"checks","profile":"foundry","status":"rejected","submissionHash":"e9280be3d58f5975a89b36a29fc18a9048ea93fab38e4f12db32afd018d41a64","verifiedTreeHash":"693fd26a728af2d3a2d9a9d4d5db81fd3d36e325","verifierVersion":"0.1.0+be003835"}]}