{"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":"bc00d056-b211-47bb-8d1c-62d76785dc51","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"f259fb56bc552b6be9867040d7630f23a2b2166f50107d8032565590df14b589","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":"2f18a5b461b9960903669a9f16e90b97ef53fd86f43ab819381c639f9d4e658c","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":"94b4ac16a397712bd24ea9111ed0de6262942a44206e6fdf384beb3b51a2b243","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":"127671c3cf97d8c82cadc540bbc5b3d126659c17b3163f3ad5c73558d9d3734e","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":"6aabbd060a3ffb52b204414794f577d31b8db1349a50b77391cd77b753514da1","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":"45a0dafc001ba67ad6a451db3bc5c7b822c1df41a1b473ab14bfb01306fbab37","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"587567a5ef71546b5973ceaf6ef1dbbd590f49503b5ac9a6973ed86b89584857","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"587567a5ef71546b5973ceaf6ef1dbbd590f49503b5ac9a6973ed86b89584857","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"3951437b45831c231c399836c2519cc2a8fa969e946f0336f885b43e7a67b27d","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"ad9828c0d0a07a4f785f3b80c1efe0e83e72623553280358ffc07096bfd31f0e","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":"Pepeolithic: one ERC-721 contract that sells and gives away 737 pieces of a cave wall painted live by the IMD swarm, paid in ZTO that is sent to the dead address. Deploy on Ethereum mainnet (chain id 1). 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; ZTO has 18 decimals, a constant): zto 0xd782bdea4ef02a0bd391eb9089470c8080f0a68e ; dead 0x000000000000000000000000000000000000dEaD; admin 0x433c8a73bec1273561e4e2201649de12f20b7d58; adam 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7; seatRoot 0xbe96ac9140fa07013148f2dd158576ae6cbe2b4a0ce4be64782b37acc9ad0e1b (Merkle root of keccak256(abi.encodePacked(address)) leaves, sorted pairs); startTime 1791810000 (Unix; Oct 12 2026, 9:00 AM New York time); caveLength 86400 and roundLength 3600 (seconds); firstPrice 1000000000000000000000000 and floorPrice 10000000000000000000000 (1,000,000 and 10,000 ZTO); labels: seven bytes32, one per cave, in cave order: pepeolithic-base-naij, -moss-naij, -water-naij, -ice-naij, -lava-naij, -crystal-naij, -roots-naij. 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, when the next cave opens (cave 7 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 (mainnet: 1 day and 1 hour; 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 and lineSales; openingPrice(c, r) walks back over earlier rounds until one with a stored opening or a line sale, halving per quiet round, and a round's first buy stores its opening. firstPrice and floorPrice are CONSTRUCTOR ARGUMENTS (not code constants) in ZTO base units: firstPrice 1,000,000 ZTO = 1000000000000000000000000; floorPrice 10,000 ZTO = 10000000000000000000000. 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 ZTO.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 ZTO first; the contract never holds it. TEETH: no buys after caveClose(c); 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 \"Pepeolithic\", symbol \"PEPEO\"; royaltyInfo(id, salePrice) returns (admin, salePrice / 100): a 1% creator fee to admin, fixed at deploy, no setter. No function may move ZTO anywhere but the dead address. Tests against a mock ZTO: the id arithmetic for every cave/round/slot, sale counts per cave (400), 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) and deployed code under 9,000 bytes (the new gas schedule charges ~1,540 gas per byte and caps a transaction at 16,777,216 gas): custom errors only, no ReentrancyGuard (the coin call is the last thing buy does). Slither: string.concat, not encodePacked with 2+ dynamic args; multiply before dividing. REFERENCE: match swarm launch 928 src/Ochre.sol (commit b0923044) exactly; only name, symbol and constructor values differ.","parentJobId":null,"planHash":"cde8d9dfc8e9601e0746a5c133fae9f8c6c7ac3e2c5efbf3bf052c7858a4c80b","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"bc00d056-b211-47bb-8d1c-62d76785dc51","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1073-pepeolithic-one-erc-721-contract"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51886","feedbackHash":"39700f5f68a1ec2aab911a6762dddd98001be72910c89f85582b3e98cd755d70","nodeKey":"audit_economics","submissionHash":"f259fb56bc552b6be9867040d7630f23a2b2166f50107d8032565590df14b589","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52262","feedbackHash":"bdff3de4386902dce81cea1b750d8a8c48b92aea7ea85cb76e992e70dfe6f368","nodeKey":"audit_flow","submissionHash":"2f18a5b461b9960903669a9f16e90b97ef53fd86f43ab819381c639f9d4e658c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52271","feedbackHash":"a09d7f9a7d7d85304d308b60a35855751cf144b5da716b7c3726f6e92514f892","nodeKey":"audit_judge","submissionHash":"94b4ac16a397712bd24ea9111ed0de6262942a44206e6fdf384beb3b51a2b243","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52420","feedbackHash":"e4aca04e362bb13f2c25ca92184dfebb78a2c8a5297f78722463934caaa3db26","nodeKey":"audit_math","submissionHash":"127671c3cf97d8c82cadc540bbc5b3d126659c17b3163f3ad5c73558d9d3734e","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52253","feedbackHash":"df85404567c9ae6abfde48ba0f29cc02f4bb75a75c23f49c10a0fff4863a3e63","nodeKey":"audit_permissions","submissionHash":"6aabbd060a3ffb52b204414794f577d31b8db1349a50b77391cd77b753514da1","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51088","feedbackHash":"ad656c3e968dedfc31decd9c29c5cbb8494b680e885b86dabbc629f807537e2e","nodeKey":"build_contract_project","submissionHash":"45a0dafc001ba67ad6a451db3bc5c7b822c1df41a1b473ab14bfb01306fbab37","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51726","feedbackHash":"793a7b79e2dfdd0e32f617cb157bb04f545201ea6bf80d195e28b4352564779c","nodeKey":"manifest","submissionHash":"3951437b45831c231c399836c2519cc2a8fa969e946f0336f885b43e7a67b27d","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51560","feedbackHash":"7a413130e85c232655988a9023fbb81ee513de8ab5d6e7e08f1491ff219173ec","nodeKey":"write_foundry_tests","submissionHash":"ad9828c0d0a07a4f785f3b80c1efe0e83e72623553280358ffc07096bfd31f0e","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"1b3f919a2a6f2a967d8b7e76d8bab44073505847c39cf79130691e41b197fdad","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"c9668a6c89d33b13","findings":[],"hash":"0a804aa77917879e14a15c51624ebfdc7544628f13d87260d0b964194330a314","nodeId":"e0697b73-30bc-47df-b664-80cbc46f4d7b","outcome":"failed","summary":"This content was flagged for possible cybersecurity risk. If this seems wrong, try rephrasing your request. If you’re doing authorized security work that requires more cyber permissive safeguards, apply for Daybreak access via https://platform.openai.com/settings/organization/status-and-access before retrying.","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":"gpt-6-astra","outputTokens":0,"runtime":"codex","turns":1,"wallClockMs":41117}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"1559912e747bbcd4","findings":[{"citation":"resolved","description":"openingPrice has no cap by design, and the constructor only bounds floorPrice (<= max/2) and firstPrice (>= 2*floor). It does not bound firstPrice from above. If every round is bought at its opening, each opening doubles, so round k opens at firstPrice * 2^(k-1) and lastLineSale equals that opening. When lastLineSale reaches 2^255, the checked multiplication `2 * previous.lastLineSale` panics (0x11), which makes openingPrice, priceNow and buy revert for that round and every later round of the sale. Those pieces can then only be swept to admin. With the mainnet arguments (firstPrice 1e24, 146 doublings max) the largest reachable opening is ~8.9e67 < 2^256, so this is NOT reachable on the launch configuration; the README states the same. It is reported as a configuration-hardening note for the constructor (e.g. require firstPrice_ <= type(uint256).max >> 147), not as a launch defect.","line":285,"path":"src/Pepeolithic.sol","reproduction":"Deploy with firstPrice_ = 1 << 120, floorPrice_ = 1, caveLength 86400, roundLength 3600 (constructor accepts this). For k = 1..136 (cave 1 round 1 through cave 7 round 10): warp to roundOpen(c, r) and buy(c, r) once at the opening price, so lastLineSale(c, r) = firstPrice * 2^(k-1). Then openingPrice(7, 11) and buy(7, 11) revert with an arithmetic panic because 2 * lastLineSale(7, 10) = 2^256 overflows. Expected per the brief: round 11 opens at twice the last line sale (uncapped) or the sale continues; actual: cave 7 rounds 11..21 (44 sale pieces) cannot be bought and are swept to admin. Verified with a scratch Foundry test; mainnet parameters were also verified to complete all 147 rounds at maximum doubling without overflow (final opening 89202980794122492566142873090593446023921664000000000000000000000000).","severity":"info","snippet":"                if (previous.lastLineSale != 0) next = Math.max(next, 2 * previous.lastLineSale);","title":"Uncapped ladder can overflow 2 * lastLineSale for extreme (non-mainnet) firstPrice, bricking later rounds"}],"hash":"127671c3cf97d8c82cadc540bbc5b3d126659c17b3163f3ad5c73558d9d3734e","nodeId":"ff8e356b-09e0-476e-bdb8-9b0aa384f103","outcome":"completed","summary":"The review is complete. `.imd-findings.json` holds one informational finding and a coverage record for all 11 entry points plus three invariant rows. No source files were changed, and the scratch tests were removed.\n\n**Outcome: the math holds on the launch configuration.** I checked the Pashov Math Precision, Boundary and Numerical Gap guides against every arithmetic path and found no defect reachable with the mainnet constructor values.\n\nWhat I verified, with differential scratch tests against independently written references:\n\n- **Halving line.** Price matched a from-spec rational formula for every second of a mainnet round and under fuzzed opening, floor and round length. Segment ends equal `opening >> k` exactly on a divisible fixture, the curve is monotone, rounds up by under 1 wei, and the mainnet first round hits the floor at 3456 seconds as the README states.\n- **Ladder.** The walk-back with a single final clamp is algebraically identical to the per-round recursion in the brief, including integer halving. A fuzz over all 147 rounds with random line and floor buys agreed with the per-round reference at every round. An open round's opening is immutable, since every earlier round is already at floor when it opens.\n- **Ids and counts.** All 735 ids round-trip through cave, round and slot. Sales total 400 and seats 335 with the per-cave split from the brief. The buy id formula yields slot order 5, 4, 3, 2, 1.\n- **Boundaries.** Buy close is exclusive and sweep close is inclusive, so they are complementary. Constructor overflow guards are ordered correctly. Sweep never touches ids 0 or 736. The release timestamp cannot overflow.\n- **External boundary.** Via public RPC, the live ZTO contract has 18 decimals, symbol ZTO, and returns `true` from `transfer` and `transferFrom`, with OpenZeppelin-style custom-error reverts. Both outcomes roll back a buy.\n- **Provenance.** `src/Pepeolithic.sol` is byte-identical to the pinned Ochre.sol after the name and symbol rename. The manifest start time decodes to October 12, 2026, 09:00 New York time, and the label check script passes.\n\n**One informational finding.** The ladder has no cap, and the constructor does not bound `firstPrice` from above. With `firstPrice = 2^120` and `floorPrice = 1`, buying every round at its opening makes `2 * lastLineSale` overflow at cave 7 round 11, bricking the remaining 44 sale pieces into sweeps. The mainnet values complete all 147 rounds at maximum doubling without overflow, so this is a hardening note only.\n\nNot covered: live `transferFrom` from a funded ZTO holder could not be simulated without an allowance, so the dead-address transfer path is confirmed only for zero-value calls and by bytecode behavior.","treeHash":null,"usage":{"cachedInputTokens":969358,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":33569,"runtime":"claude","turns":24,"wallClockMs":623087}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"28e346843ec15530","findings":[{"citation":"resolved","description":"Both safeTransferFrom overloads (the 3-arg OZ version forwards to this 4-arg override) revert with ContractRecipient() whenever `to` has code, instead of calling onERC721Received and accepting the magic value as ERC-721 requires. supportsInterface(0x80ac58cd) still returns true. Any holder trying to move a piece into a contract that correctly implements the receiver (a Safe multisig, an escrow, a lending or rental vault, a bridge) through the standard safe path is rejected; wallet UIs and marketplaces that default to safeTransferFrom will show the transfer as failing, and only the unchecked transferFrom works. This is a deliberate consequence of the brief's 'no receiver callbacks anywhere' and it matches the pinned Ochre.sol reference byte-for-byte, so it is a design decision to confirm rather than a logic bug; it is reported because it is a concrete ERC-721 compliance deviation that integrators will hit, and because the ERC-165 declaration overstates compliance. Minimal options: (a) keep the restriction but document it in contractURI/collection metadata and the README (already partly done), or (b) if the brief's restriction is meant only for mints, restore OZ's _checkOnERC721Received path for transfers.","line":272,"path":"src/Pepeolithic.sol","reproduction":"Deploy Pepeolithic with any valid constructor arguments (adam holds id 0). Deploy a contract C whose onERC721Received returns IERC721Receiver.onERC721Received.selector. As adam call safeTransferFrom(adam, C, 0) or safeTransferFrom(adam, C, 0, \"\"): expected per ERC-721 (and per supportsInterface(0x80ac58cd)==true) the transfer succeeds and ownerOf(0)==C; actual both calls revert with ContractRecipient(). transferFrom(adam, C, 0) then succeeds. Verified with test/scratch/SafeTransferReceiver.t.sol (passes on current code, i.e. the revert is confirmed).","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);","title":"safeTransferFrom rejects every contract recipient, including compliant IERC721Receiver implementations, while supportsInterface claims full ERC-721"}],"hash":"2f18a5b461b9960903669a9f16e90b97ef53fd86f43ab819381c639f9d4e658c","nodeId":"c952dd1d-d0d0-4263-a7f9-598e4cb9c838","outcome":"completed","summary":"The review is complete. The findings file is written and validated, and the working tree shows no tracked changes.\n\n**Outcome.** The contract behaves as the brief specifies on every control-flow path I traced. I found one low-severity deviation and nothing higher.\n\n**What I verified in the assigned area.**\n- Execution trace: every state-changing entry point was traced through its guards, writes and failure paths. The sale id formula, slot order, the stored-opening rule, the line-sale rule, the shared seat cursor and the per-cave sweep cursor all match the brief. Minting and all writes precede the only external call.\n- Periphery: the live ZTO token at the fixed mainnet address is a plain 1,287-byte ERC-20 with no proxy slot and no hooks. Its `transferFrom` returns a bool, and it has 18 decimals. The vendored OpenZeppelin files differ from upstream v5.0.2 only by line wrapping. The source is byte-identical to the pinned Ochre reference after renaming.\n- First principles: I proved that once a round opens, no predecessor can still be on its line, so an opened round's ladder opening is immutable and a quote is an upper bound on the charge. This is stronger than the README's cautious wording, not a bug.\n- Deployment facts: start epoch resolves to October 12 2026, 09:00 New York time. Runtime is 8,285 bytes. The manifest check passes. All three existing suites pass, including the 256-run invariant suite.\n\n**The one finding (low).** Both `safeTransferFrom` overloads revert for any contract recipient, even one that correctly implements the ERC-721 receiver interface, while the contract still advertises full ERC-721 support. A Safe multisig or escrow can only receive a piece through the unchecked `transferFrom`. This is a deliberate consequence of the brief's \"no receiver callbacks anywhere\" and matches the reference exactly, so it is flagged for the author to confirm as intended rather than as a logic error. The reproduction is in a scratch test that passes on the current code, confirming the revert.\n\n**Not verifiable offline.** Whether the production seat root was generated with the single-hash sorted-pair leaf format the brief specifies. If it was built with a double-hashed standard tree instead, no seat proof would verify. This is an operational check for the seat-list operator, not a code defect.","treeHash":null,"usage":{"cachedInputTokens":1780862,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":42285,"runtime":"claude","turns":30,"wallClockMs":629269}},{"artifacts":[],"attempt":1,"bundleHash":"b2756cf23794fc12edf8b8595cabbea3dcd01537741ebfed28195643e88569d5","device":"2b4e97bb63195f54","findings":[],"hash":"3951437b45831c231c399836c2519cc2a8fa969e946f0336f885b43e7a67b27d","nodeId":"d98ea7ec-0759-4566-9394-56c1bed54a65","outcome":"completed","summary":"Updated [launch.json](/home/imd/.identitymd-2/work/bc00d056-b211-47bb-8d1c-62d76785dc51/d98ea7ec-0759-4566-9394-56c1bed54a65/launch.json) with clarified deployment notes; all 16 constructor arguments match the accepted ABI and brief.\n\nValidation passed: schema checks, `forge build`, and all 46 tests, including protected deployment. Runtime: 8,285 bytes.\n\nOnly `launch.json` changed outside permitted scratch files.","treeHash":"d8b697c71591fe1e5fc0c215ec873f27f9b6c3d2","usage":{"cachedInputTokens":268160,"inputTokens":41527,"model":"gpt-6-astra","outputTokens":3845,"runtime":"codex","turns":4,"wallClockMs":186514}},{"artifacts":[],"attempt":1,"bundleHash":"b7fd715d30e944f5d7fe406e514bc8f7331a3d2c3f8cf5442d978e87fe2a20fc","device":"f801e761d7a1ec94","findings":[],"hash":"45a0dafc001ba67ad6a451db3bc5c7b822c1df41a1b473ab14bfb01306fbab37","nodeId":"d0ef46a8-4c2f-432a-81d8-52ab2d0e14af","outcome":"completed","summary":"Implemented Pepeolithic, mainnet deployment parameters, vendored dependencies, tests, and documentation.\n\nValidation passed:\n\n- `forge build`\n- `forge test`: 45 tests passed\n- `forge fmt --check`\n- Offline manifest and reference-source checks\n\nRuntime: **8,285 bytes**, below 9,000.\n\nDeployment handoff is ready; no transaction was broadcast.","treeHash":"28f7eeef82780abff343a86abe9ee8c83251d3fb","usage":{"cachedInputTokens":839040,"inputTokens":95822,"model":"gpt-6-astra","outputTokens":10114,"runtime":"codex","turns":5,"wallClockMs":358571}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7591760a616c6429","findings":[{"citation":"resolved","description":"Asymmetry between the two transfer paths (transferFrom vs. both safeTransferFrom overloads, src/Pepeolithic.sol:271-274, routed via OZ v5.0.2 ERC721.safeTransferFrom(address,address,uint256) -> virtual 4-arg override). The override replaces the ERC-721 receiver check with a blanket `to.code.length != 0` rejection. On Ethereum mainnet since Pectra (EIP-7702, May 2025) an EOA that has set a delegation keeps a 23-byte designator (0xef0100 || implementation) as its account code, and EXTCODESIZE returns 23 for it. Such accounts are ordinary user wallets (MetaMask Smart Accounts, Ambire, Uniswap wallet, etc.), not contracts, and they can hold ERC-721s like any EOA. Every safeTransferFrom to them reverts with ContractRecipient(), so marketplace and wallet flows that deliver ERC-721s through safeTransferFrom (most wallet 'send NFT' UIs, several exchange delegates) fail for those users; only a raw transferFrom works. README.md documents the restriction for contract wallets as intentional but does not cover delegated EOAs, and the brief only required no receiver callbacks (which a designator-aware check would still satisfy). No funds are lost and transferFrom remains available, hence low. Trade-off: the brief asks that the source match launch-928 Ochre.sol exactly, so any fix changes the reference and needs that scope decision. Minimal fix preserving 'no callbacks': treat a 23-byte code starting with 0xef0100 as a non-contract recipient (e.g. `bytes memory code = to.code; if (code.length != 0 && !(code.length == 23 && code[0] == 0xef && code[1] == 0x01 && code[2] == 0x00)) revert ContractRecipient();`), and document the remaining contract-recipient restriction.","line":272,"path":"src/Pepeolithic.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Pepeolithic} from \"src/Pepeolithic.sol\";\n\n/// @dev Minimal bool-returning coin standing in for ZTO at the pinned address.\ncontract ScratchCoin {\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        allowance[from][msg.sender] -= amount;\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n}\n\n/// @notice An EOA that has set an EIP-7702 delegation keeps its 23-byte delegation\n/// designator as its account code (EXTCODESIZE == 23 on mainnet since Pectra).\n/// Pepeolithic.safeTransferFrom rejects every recipient with code, so such a wallet\n/// can never receive a piece through the standard safe-transfer path.\ncontract Delegated7702TransferTest is Test {\n    address internal constant COIN = 0xd782Bdea4EF02a0Bd391eb9089470c8080f0A68e;\n    address internal constant ADMIN = 0x433c8A73Bec1273561E4E2201649de12f20B7D58;\n    address internal constant ADAM = 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7;\n    uint256 internal constant START = 1791810000;\n\n    Pepeolithic internal pepeolithic;\n    ScratchCoin internal coin;\n    address internal seller = address(0xA11CE);\n    address internal delegatedWallet = address(0xB0B);\n\n    function setUp() public {\n        ScratchCoin implementation = new ScratchCoin();\n        vm.etch(COIN, address(implementation).code);\n        coin = ScratchCoin(COIN);\n        pepeolithic = new Pepeolithic(\n            COIN,\n            ADMIN,\n            ADAM,\n            bytes32(uint256(1)),\n            START,\n            86400,\n            3600,\n            1e24,\n            1e22,\n            bytes32(\"pepeolithic-base-naij\"),\n            bytes32(\"pepeolithic-moss-naij\"),\n            bytes32(\"pepeolithic-water-naij\"),\n            bytes32(\"pepeolithic-ice-naij\"),\n            bytes32(\"pepeolithic-lava-naij\"),\n            bytes32(\"pepeolithic-crystal-naij\"),\n            bytes32(\"pepeolithic-roots-naij\")\n        );\n        // Seller buys cave 1 round 1 slot 5 (id 5) at the floor.\n        coin.mint(seller, 1e24);\n        vm.prank(seller);\n        coin.approve(address(pepeolithic), 1e24);\n        vm.warp(START + 3600);\n        vm.prank(seller);\n        uint256 id = pepeolithic.buy(1, 1);\n        assertEq(id, 5);\n        // The recipient is an ordinary user whose EOA carries an EIP-7702 delegation\n        // designator: 0xef0100 followed by the delegate implementation address.\n        vm.etch(delegatedWallet, abi.encodePacked(hex\"ef0100\", address(0xDE1E6A7E)));\n        assertEq(delegatedWallet.code.length, 23);\n    }\n\n    function testDelegatedEoaCanReceiveViaSafeTransferFrom() public {\n        vm.prank(seller);\n        pepeolithic.safeTransferFrom(seller, delegatedWallet, 5);\n        assertEq(pepeolithic.ownerOf(5), delegatedWallet);\n    }\n\n    function testDelegatedEoaCanReceiveViaSafeTransferFromWithData() public {\n        vm.prank(seller);\n        pepeolithic.safeTransferFrom(seller, delegatedWallet, 5, \"\");\n        assertEq(pepeolithic.ownerOf(5), delegatedWallet);\n    }\n}","reproduction":"State: Pepeolithic deployed with mainnet-shaped arguments and a bool-returning mock at the ZTO address; seller buys cave 1 round 1 (id 5) at START+3600; recipient 0xB0B has account code 0xef0100<20-byte address> (23 bytes, exactly what an EIP-7702 delegated EOA has on mainnet; vm.etch in the test). Call: vm.prank(seller); pepeolithic.safeTransferFrom(seller, 0xB0B, 5) (and the 4-arg overload with empty data). Expected: ownerOf(5) == 0xB0B, as for any EOA recipient. Actual: both calls revert with ContractRecipient(); the piece can only reach that wallet via transferFrom. Run: forge test --match-path test/scratch/Delegated7702Transfer.t.sol (both tests fail on the current code).","severity":"low","snippet":"        if (to.code.length != 0) revert ContractRecipient();","title":"safeTransferFrom rejects EIP-7702 delegated EOAs: ordinary wallets with a delegation designator cannot receive pieces by safe transfer"}],"hash":"6aabbd060a3ffb52b204414794f577d31b8db1349a50b77391cd77b753514da1","nodeId":"24718f5f-46c9-4a7e-a7b2-abc94b597964","outcome":"completed","summary":"Review complete. The findings record is at `.imd-findings.json` with one low finding and 15 coverage rows. No source files were changed. The only files written are the findings JSON and two scratch tests under `test/scratch/`.\n\n**What I verified**\n\n- The source is byte-identical to the pinned launch-928 `Ochre.sol` at commit b0923044 after the two renames, so the reference requirement holds. Runtime is 8,285 bytes with no forbidden opcodes, and `launch.json` matches the brief's arguments.\n- ZTO on mainnet is a plain ERC-20 with no owner or pause functions and no CALL opcodes, so it cannot reenter. Its `transferFrom` to the dead address returns true.\n- The existing 45 tests pass. My scratch tests confirmed that a round's opening never changes once it opens, that sweep never touches seat pieces or sold pieces, that release cuts off claims and leftovers pay the floor to dead, and that freeze is admin only and once per cave.\n- Access control reduces to one privileged entry point, `freeze`, which affects metadata only. Admin and adam are mainnet EOAs. Sweep is permissionless but can only mint to the fixed admin. No storage variable has writers with differing guards.\n\n**The one finding (low)**\n\nBoth `safeTransferFrom` overloads reject any recipient with code. On mainnet since Pectra, an EOA with an EIP-7702 delegation has a 23-byte designator as its code, so ordinary users with delegated wallets cannot receive pieces by safe transfer. Only `transferFrom` works for them. The README documents the restriction for contract wallets but not for delegated EOAs. A proof test under `test/scratch/Delegated7702Transfer.t.sol` fails on the current code. Fixing it would diverge from the pinned reference, which is a scope decision for the author.\n\n**Trust assumptions noted in coverage, not reported as defects**\n\n- The production seat root cannot be verified offline. A wrong root would silently turn all 335 seats into floor-price leftovers, with no setter to recover.\n- A pending seat claim can be sandwiched by `releaseUnclaimed` plus `buyLeftover` at the release instant. This matches the specified behaviour.\n- Admin may freeze a cave's metadata before it opens. This is admin-only with no unprivileged amplifier.","treeHash":null,"usage":{"cachedInputTokens":1105910,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":37203,"runtime":"claude","turns":34,"wallClockMs":518915}},{"artifacts":[],"attempt":2,"bundleHash":null,"device":"b414b10f97bca557","findings":[{"citation":"resolved","description":"Merged from audit_permissions (EIP-7702 wallets), audit_flow and audit_economics (compliant receivers): one root cause. Both safeTransferFrom overloads reach this 4-arg override (OZ v5.0.2's 3-arg version forwards to the virtual 4-arg one), which replaces the ERC-721 onERC721Received check with a blanket revert for any `to` whose EXTCODESIZE is nonzero. Two populations are hit: (a) contracts that correctly implement IERC721Receiver (Safe multisigs, escrows, marketplace delegates such as Blur's ExecutionDelegate, which transfer via safeTransferFrom); (b) ordinary EOAs that have set an EIP-7702 delegation on mainnet since Pectra, whose account code is the 23-byte designator 0xef0100||impl, so to.code.length == 23 (MetaMask Smart Accounts, Ambire, Uniswap wallet users). supportsInterface(0x80ac58cd) still returns true, overstating compliance. No funds are lost and transferFrom works, so low. This matches the pinned Ochre.sol byte-for-byte and the README documents it as the chosen reading of 'no receiver callbacks anywhere'; changing it is a scope decision against the 'match Ochre.sol exactly' requirement. If the author decides to keep callbacks out, the minimal fix that preserves that is to exempt the 23-byte 0xef0100 designator (bytes memory code = to.code; if (code.length != 0 && !(code.length == 23 && code[0] == 0xef && code[1] == 0x01 && code[2] == 0x00)) revert ContractRecipient();) and document the remaining contract restriction in collection metadata; if receiver compliance is wanted, restore OZ's _checkOnERC721Received for transfers only.","line":272,"path":"src/Pepeolithic.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Pepeolithic} from \"src/Pepeolithic.sol\";\n\n/// @dev Minimal bool-returning coin standing in for ZTO at the pinned address.\ncontract ScratchCoin {\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        allowance[from][msg.sender] -= amount;\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        return true;\n    }\n}\n\n/// @notice An EOA that has set an EIP-7702 delegation keeps its 23-byte delegation\n/// designator as its account code (EXTCODESIZE == 23 on mainnet since Pectra).\n/// Pepeolithic.safeTransferFrom rejects every recipient with code, so such a wallet\n/// can never receive a piece through the standard safe-transfer path.\ncontract Delegated7702TransferTest is Test {\n    address internal constant COIN = 0xd782Bdea4EF02a0Bd391eb9089470c8080f0A68e;\n    address internal constant ADMIN = 0x433c8A73Bec1273561E4E2201649de12f20B7D58;\n    address internal constant ADAM = 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7;\n    uint256 internal constant START = 1791810000;\n\n    Pepeolithic internal pepeolithic;\n    ScratchCoin internal coin;\n    address internal seller = address(0xA11CE);\n    address internal delegatedWallet = address(0xB0B);\n\n    function setUp() public {\n        ScratchCoin implementation = new ScratchCoin();\n        vm.etch(COIN, address(implementation).code);\n        coin = ScratchCoin(COIN);\n        pepeolithic = new Pepeolithic(\n            COIN,\n            ADMIN,\n            ADAM,\n            bytes32(uint256(1)),\n            START,\n            86400,\n            3600,\n            1e24,\n            1e22,\n            bytes32(\"pepeolithic-base-naij\"),\n            bytes32(\"pepeolithic-moss-naij\"),\n            bytes32(\"pepeolithic-water-naij\"),\n            bytes32(\"pepeolithic-ice-naij\"),\n            bytes32(\"pepeolithic-lava-naij\"),\n            bytes32(\"pepeolithic-crystal-naij\"),\n            bytes32(\"pepeolithic-roots-naij\")\n        );\n        // Seller buys cave 1 round 1 slot 5 (id 5) at the floor.\n        coin.mint(seller, 1e24);\n        vm.prank(seller);\n        coin.approve(address(pepeolithic), 1e24);\n        vm.warp(START + 3600);\n        vm.prank(seller);\n        uint256 id = pepeolithic.buy(1, 1);\n        assertEq(id, 5);\n        // The recipient is an ordinary user whose EOA carries an EIP-7702 delegation\n        // designator: 0xef0100 followed by the delegate implementation address.\n        vm.etch(delegatedWallet, abi.encodePacked(hex\"ef0100\", address(0xDE1E6A7E)));\n        assertEq(delegatedWallet.code.length, 23);\n    }\n\n    function testDelegatedEoaCanReceiveViaSafeTransferFrom() public {\n        vm.prank(seller);\n        pepeolithic.safeTransferFrom(seller, delegatedWallet, 5);\n        assertEq(pepeolithic.ownerOf(5), delegatedWallet);\n    }\n\n    function testDelegatedEoaCanReceiveViaSafeTransferFromWithData() public {\n        vm.prank(seller);\n        pepeolithic.safeTransferFrom(seller, delegatedWallet, 5, \"\");\n        assertEq(pepeolithic.ownerOf(5), delegatedWallet);\n    }\n}","reproduction":"Deploy with the mainnet arguments and a bool-returning mock etched at the ZTO address. (a) Deploy GoodReceiver whose onERC721Received returns IERC721Receiver.onERC721Received.selector. As adam: safeTransferFrom(adam, GoodReceiver, 0) and safeTransferFrom(adam, GoodReceiver, 0, \"\"). Expected per ERC-721 (and supportsInterface(0x80ac58cd)==true): ownerOf(0)==GoodReceiver and onERC721Received called once. Actual: both revert ContractRecipient(); transferFrom(adam, GoodReceiver, 0) then succeeds with zero receiver calls. (b) vm.etch(0xB0B, hex\"ef0100\" ++ 20-byte address) so 0xB0B.code.length == 23 exactly as a delegated EOA on mainnet; warp START+3600, seller buys (1,1) -> id 5; seller calls safeTransferFrom(seller, 0xB0B, 5) and the 4-arg form. Expected: ownerOf(5)==0xB0B as for any EOA. Actual: both revert ContractRecipient(). Verified: the attached proof (specialist's Proof_08f3e1e8bd71.t.sol) fails on this tree with ContractRecipient() in both tests; my scratch tests testSafeTransferCompliantReceiverReverts / testSafeTransferDelegatedEoaReverts confirm the same.","severity":"low","snippet":"        if (to.code.length != 0) revert ContractRecipient();","title":"safeTransferFrom rejects every recipient with code: compliant IERC721Receiver contracts and EIP-7702 delegated EOAs cannot receive pieces through the standard safe path while supportsInterface claims "},{"citation":"resolved","description":"From audit_economics; reproduced. The charge is price(c, r, now) with no maxPrice argument. Inside an open round the price is deterministic and non-increasing (I also verified that out-of-order floor buys in earlier quiet rounds leave the open round's derived opening unchanged: round 1 line sale at 93,750 ZTO, rounds 2 and 3 quiet, round 4 open at 125,000 ZTO; floor buys of rounds 2 and 3 after round 4 opened leave openingPrice(1,4) and priceNow(1,4) identical). The exposure is only at the round boundary: openingPrice(c, r) for a not-yet-open round is derived, and a line sale in round r-1, whose line runs until the instant r opens, raises it to max(2*lastLineSale, opening(r-1)/2). A buyer who reads openingPrice before the open, signs with an unlimited approval and lands at the open pays the lifted value. Nobody profits from the lift (the predecessor buyer pays real ZTO for a real piece), so this is a bounded user-protection gap, not an exploit. The README already states that a quote is not a reservation and recommends an exact allowance. Adding a maxPrice parameter would change the reference ABI, so this is a scope decision; otherwise the mitigation is wallet-side (approve exactly the quoted amount).","line":175,"path":"src/Pepeolithic.sol","reproduction":"Mainnet parameters (first 1e24, floor 1e22, 3600 s rounds), nothing bought in cave 1 rounds 1..5 so the ladder halves to 20,000 ZTO by round 7. (a) At roundOpen(1,7)-600 Alice reads openingPrice(1,7) = 20000000000000000000000 and holds an unlimited allowance. Bob calls buy(1,6) at that time and pays priceNow(1,6) = 10416666666666666666667 (a line sale). At roundOpen(1,7) Alice's buy(1,7) is charged 20833333333333333333334 (coin balance delta), +4.2% over the quote. (b) Same, but Bob buys (1,6) at roundOpen(1,7)-1799 for 15620659722222222222223: Alice's quote 20000000000000000000000, charge at open 31241319444444444444446 (+56%). Expected by a quoting user: pay <= quote or revert; actual: pays the lifted opening. Verified with scratch tests testQuoteVsCharge / testQuoteVsChargeMax (logged values above).","severity":"low","snippet":"        uint256 price = _price(opening, block.timestamp - opens);","title":"buy()/buyLeftover() accept no caller price bound; a line sale in the preceding round lifts a pre-open quote by up to 2x and an unlimited ZTO allowance pays the lifted opening"},{"citation":"resolved","description":"From audit_math; reproduced. The constructor bounds floorPrice (<= max/2) and firstPrice from below (>= 2*floor) but not from above. If every round is bought at its opening the opening doubles each round, so round k opens at firstPrice*2^(k-1) and lastLineSale equals it; once lastLineSale reaches 2^255 the checked multiplication panics (0x11) and openingPrice, priceNow and buy revert for that round and every later one, leaving those pieces only sweepable to admin. With the mainnet arguments (firstPrice 1e24) the maximum reachable opening after 146 doublings is 89202980794122492566142873090593446023921664000000000000000000000000 (~8.9e67 < 2^256), so this cannot happen on the launch configuration; verified by buying all 147 rounds at their openings. Configuration-hardening note only (e.g. require firstPrice_ <= type(uint256).max >> 147); the brief requires matching Ochre.sol, so no change is expected for this launch.","line":285,"path":"src/Pepeolithic.sol","reproduction":"Deploy with firstPrice_ = 1 << 120, floorPrice_ = 1, caveLength 86400, roundLength 3600 (accepted by the constructor). For k = 1..136 (cave 1 round 1 through cave 7 round 10): warp to roundOpen(c, r) and buy(c, r) once; lastLineSale(c, r) == (1<<120) << (k-1) each time. Then at roundOpen(7,11): openingPrice(7,11) and buy(7,11) both revert with an arithmetic panic because 2 * lastLineSale(7,10) = 2^256. Expected per the brief: the round opens at twice the last line sale (no cap) or the sale continues; actual: cave 7 rounds 11..21 (44 pieces) are unbuyable. Verified with scratch test testLadderOverflowExtreme; testMainnetMaxDoublingNoOverflow confirms the mainnet arguments complete all 147 rounds.","severity":"info","snippet":"                if (previous.lastLineSale != 0) next = Math.max(next, 2 * previous.lastLineSale);","title":"Uncapped ladder: 2 * lastLineSale can overflow for extreme (non-mainnet) firstPrice, bricking the remaining rounds; unreachable with the launch arguments"},{"citation":"resolved","description":"From audit_economics; reproduced. The curve is anchored to the fixed constructor value startTime = 1791810000, not to deployment time, and there is no startTime_ > block.timestamp check (the brief fixes startTime and requires matching Ochre.sol, so this is an operational item for the deployer, not a code change). If the deployment transaction lands after startTime, the 1,000,000 ZTO opening and the upper part of the ladder are never purchasable and claimSeat is live immediately. Lower-than-designed price discovery for cave 1; no loss of funds. Today is 2026-10-08; the launch must be mined before 2026-10-12 13:00 UTC, and the deployer should abort and re-plan if it cannot be.","line":98,"path":"src/Pepeolithic.sol","reproduction":"Deploy with the mainnet arguments at block.timestamp = startTime + 1800: priceNow(1,1) immediately returns 93750000000000000000000; the 1,000,000 ZTO opening was never buyable. Deploy at startTime + 3600: priceNow(1,1) = 10000000000000000000000 (floor) and openingPrice(1,2) = 500000000000000000000000, derived from a round nobody could buy on its line. Expected for the designed sale: round 1 opens at 1,000,000 ZTO for buyers. Verified with scratch test testLateDeployment (logged values above).","severity":"info","snippet":"        startTime = startTime_;","title":"Constructor accepts a startTime already in the past; a launch mined after 2026-10-12 13:00 UTC silently truncates round 1's line and lowers the ladder anchor"}],"hash":"94b4ac16a397712bd24ea9111ed0de6262942a44206e6fdf384beb3b51a2b243","nodeId":"e0697b73-30bc-47df-b664-80cbc46f4d7b","outcome":"completed","summary":"The review is complete. `.imd-findings.json` holds four reproduced findings and a 14-row coverage record; the working tree is otherwise unchanged (scratch tests removed, `git status` clean apart from the findings file).\n\n**Outcome**\n\nNo critical, high or medium defect. The contract matches the pinned Ochre.sol reference except for the name and symbol line, which I confirmed by fetching the pinned commit and diffing. The build is 8,285 runtime bytes, all 56 project tests pass, and the launch check script passes.\n\n**Findings kept (all reproduced locally)**\n\n- **Low, merged from three specialists:** `safeTransferFrom` rejects every recipient with code. That blocks compliant `IERC721Receiver` contracts and, on mainnet since Pectra, ordinary EOAs carrying a 23-byte EIP-7702 delegation designator, while `supportsInterface` still advertises ERC-721. The specialist's proof fails on this tree with `ContractRecipient()` in both tests, so it stays attached. Changing it conflicts with the \"match Ochre.sol exactly\" rule, so I framed it as a scope decision with a callback-free minimal fix.\n- **Low:** no caller price bound in `buy`. A line sale in round r-1 lifts a pre-open quote for round r. I confirmed the exact numbers: a 20,000 ZTO quote charged 20,833 or 31,241 ZTO depending on when the predecessor sale lands. Within an open round the price is stable, which I also verified against out-of-order floor buys.\n- **Info:** ladder overflow of `2 * lastLineSale` only with extreme constructor values. Reproduced with firstPrice 2^120; the mainnet arguments complete all 147 rounds at maximum doubling without overflow.\n- **Info:** the constructor accepts a past startTime. Deploying 30 minutes late makes round 1 open at 93,750 ZTO instead of 1,000,000. Operational item for the deployer, launch must be mined before 2026-10-12 13:00 UTC.\n\n**Coverage:** all 11 ABI entry points answered (8 hold, 3 point to findings 1 and 2), plus rows for reference match, pricing/ladder invariants, and supply/size/build. Static-analysis leads (uninitialized locals, timestamp use, unsafe `_mint`) were traced and are by design, not reported.","treeHash":null,"usage":{"cachedInputTokens":1070235,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":30372,"runtime":"claude","turns":24,"wallClockMs":744087}},{"artifacts":[],"attempt":1,"bundleHash":"8ac2c0722bdc40147d24dc582dfc37e21b4e47276131bc0177c29d55fde3f75d","device":"282a1c2062280fd9","findings":[],"hash":"ad9828c0d0a07a4f785f3b80c1efe0e83e72623553280358ffc07096bfd31f0e","nodeId":"e2283bcb-3ae4-4609-9cee-4dd02c6847cb","outcome":"completed","summary":"Added independent pricing invariants, adversarial payment and reentrancy rollback tests, and README coverage details. All changes are under `test/`.\n\n`forge build` and `forge test` pass: **56 tests, 0 failures**, including 45,056 invariant calls.\n\nNo defects requiring a report were reproduced.","treeHash":"b8622f82f20b471aa6cd8f0de49a2e84e07c3e66","usage":{"cachedInputTokens":1865472,"inputTokens":118168,"model":"gpt-6-astra","outputTokens":18225,"runtime":"codex","turns":6,"wallClockMs":686887}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"dd3018ab6b18e7bc","findings":[{"citation":"resolved","description":"supportsInterface returns true for ERC-721 (0x80ac58cd), yet both safeTransferFrom overloads revert for any `to` that has code, including a recipient that correctly implements IERC721Receiver.onERC721Received. ERC-721 requires safeTransferFrom to succeed for such receivers; only recipients that do not return the magic value may be rejected. Economic effect: any contract-held wallet (Safe multisig, custody contract, escrow or marketplace path that uses safeTransferFrom such as Blur's ExecutionDelegate.transferERC721) cannot receive a piece through the safe path and the trade reverts; holders must fall back to plain transferFrom, which many integrations do not call. This is the behaviour of the pinned Ochre reference and the README documents it as an intentional reading of 'no receiver callbacks anywhere', so this is reported as a bounded compliance/interoperability defect, not a loss of funds. Fixing it (calling onERC721Received on code recipients) would diverge from the reference and the brief's callback prohibition; that is a scope decision for the author.","line":272,"path":"src/Pepeolithic.sol","reproduction":"Deploy Pepeolithic with the mainnet arguments and a mock coin. Deploy `GoodReceiver` implementing onERC721Received returning IERC721Receiver.onERC721Received.selector. warp to startTime; buyer calls buy(1,1) and receives id 5. buyer calls safeTransferFrom(buyer, address(GoodReceiver), 5). Expected (ERC-721): transfer succeeds and onERC721Received is called. Actual: revert ContractRecipient(). Control: transferFrom(buyer, address(GoodReceiver), 5) succeeds and ownerOf(5) == GoodReceiver. Verified with a scratch Foundry test (testSafeTransferToCompliantReceiverReverts) on this tree.","severity":"low","snippet":"        if (to.code.length != 0) revert ContractRecipient();","title":"safeTransferFrom rejects every contract recipient, so the advertised ERC-721 interface (0x80ac58cd) is not honoured for compliant receivers"},{"citation":"resolved","description":"The charge is whatever the curve says at inclusion time; the buyer cannot pass a maximum price. Within an already-open round this is safe (price is monotonically non-increasing and the opening is fixed once the round opens; verified by a 256-run randomized probe). The gap is at the round boundary: openingPrice(c, r) for a not-yet-open round is a derived value that any line sale in round r-1 (which is still on its line until the instant r opens) lifts to max(2*lastLineSale, opening(r-1)/2). A buyer who quotes before the open and signs with an unlimited allowance (the common wallet default) is charged the lifted opening. No attacker profits: the predecessor buyer pays real ZTO for a real piece, so this is a bounded user-protection gap rather than an exploit. The README's mitigation (approve exactly the quoted amount) works but relies on wallet UX. Adding a maxPrice argument would change the reference ABI, so this is a scope decision.","line":175,"path":"src/Pepeolithic.sol","reproduction":"Mainnet parameters (first 1,000,000 ZTO, floor 10,000, 1 h rounds), nothing bought in cave 1 so the ladder halves to 20,000 by round 7. (a) At roundOpen(1,7) - 600 s Alice reads openingPrice(1,7) = 20,000 ZTO and approves type(uint256).max. Bob calls buy(1,6) at that moment and pays priceNow(1,6) = 10,416.67 ZTO (a line sale). At roundOpen(1,7) Alice's buy(1,7) is mined: charged 20,833.33 ZTO instead of the 20,000 quoted (+4.2%). (b) Same setup but Bob buys (1,6) at roundOpen(1,7) - 1799 s for 15,620.66 ZTO: Alice's quote 20,000, charge at open 31,241.32 ZTO (+56%). Expected by a quoting user: pay <= quote or revert; actual: pays the lifted opening. Verified with scratch tests testQuoteVsCharge / testQuoteVsChargeMax on this tree.","severity":"low","snippet":"        uint256 price = _price(opening, block.timestamp - opens);","title":"buy()/buyLeftover() take no caller price bound; a round's opening can rise above a pre-open quote via a predecessor line sale, and an unlimited ZTO approval pays the higher amount"},{"citation":"resolved","description":"The price curve is anchored to the constant startTime (1791810000), not to deployment. There is no check that startTime_ > block.timestamp, and the brief forbids deviating from the reference, so this is an operational item for the deployer rather than a code change: if the launch transaction lands after startTime, the 1,000,000 ZTO opening (and with it the upper part of the ladder) is never purchasable, and claimSeat is live immediately. Economic effect is a lower-than-designed price discovery for cave 1, not a loss of funds.","line":98,"path":"src/Pepeolithic.sol","reproduction":"Deploy with the mainnet arguments at block.timestamp = startTime + 1800: priceNow(1,1) immediately returns 93,750 ZTO; the 1,000,000 opening was never buyable. Deploy at startTime + 3600: priceNow(1,1) = 10,000 (floor) and openingPrice(1,2) = 500,000 derived from a round nobody could buy on its line. Expected for the designed sale: round 1 opens at 1,000,000 ZTO for buyers. Verified with scratch test testLateDeployment on this tree. Today is 2026-10-08; the launch must be mined before 2026-10-12 13:00 UTC.","severity":"info","snippet":"        startTime = startTime_;","title":"Constructor accepts a startTime already in the past; deploying after Oct 12 2026 13:00 UTC silently truncates round 1's line and lowers the ladder anchor"}],"hash":"f259fb56bc552b6be9867040d7630f23a2b2166f50107d8032565590df14b589","nodeId":"5e0c56ef-6aff-431d-980f-f27df954ecd7","outcome":"completed","summary":"The review is complete and the findings file is written. Here is the recap.\n\n**Outcome.** The economics of Pepeolithic hold. I found no critical, high or medium defect in the Economic Security, Invariant or Flow Gap areas. Three bounded observations are recorded in `.imd-findings.json`, with 16 coverage rows answering all 11 entry points plus five invariants.\n\n**What I verified**\n- **Source identity.** The contract is byte-identical to the pinned Ochre reference at commit b0923044 after the name and symbol substitution.\n- **Live dependency.** The real ZTO at the configured mainnet address is an immutable nine-selector ERC-20 with 18 decimals and no owner or pause. A fork simulation of a full buy moved exactly the quoted price to the dead address and returned a 32-byte true.\n- **Ladder.** A randomized test over all 147 rounds matched the spec formula exactly, including quiet-round halving across stored and unstored predecessors and across cave boundaries. A second 256-run probe confirmed a round's opening never moves once it opens and every buyer pays exactly the quoted price.\n- **Halving line.** The mainnet curve reaches 93,750 ZTO at 1,800 seconds and the floor from 3,456 seconds, is monotone, and floor-clamped buys never record a line sale.\n- **Supply and issuance.** Slot-order id arithmetic, the 400/335 split, seat skipping, sweep exclusivity at the close instant, and the single shared cursor between claims and leftovers all behave as specified. The existing 45-test suite passes.\n\n**Findings reported**\n1. **Low.** `safeTransferFrom` rejects every contract recipient, including a compliant `IERC721Receiver`, while `supportsInterface` advertises ERC-721. Reference behaviour and documented, but it blocks contract wallets and marketplace paths that use the safe transfer.\n2. **Low.** `buy` has no caller price bound. A pre-open quote can be lifted by a predecessor's line sale, and an unlimited approval pays the higher opening. Measured 20,000 quoted versus 20,833 charged with a 10-minute-old quote, and up to 31,241 with a 30-minute-old one. No attacker profits.\n3. **Info.** The constructor accepts a past start time. Deploying 30 minutes after Oct 12 2026 13:00 UTC makes the first purchasable price 93,750 ZTO instead of 1,000,000.\n\nStatic-analysis leads were all dismissed as intentional. No files in the tree were changed besides the findings file, and the scratch tests were removed.","treeHash":null,"usage":{"cachedInputTokens":1016248,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":48139,"runtime":"claude","turns":31,"wallClockMs":829130}}],"verification":[{"checks":[{"durationMs":15525,"exitCode":0,"name":"build","output":"Compiling 35 files with Solc 0.8.26\nSolc 0.8.26 finished in 15.38s\nCompiler run successful!\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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":22173,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 30 tests for test/Pepeolithic.t.sol:PepeolithicTest\n[PASS] testAll335SeatsInIdOrderAndMerkleExhaustion() (gas: 49641985)\n[PASS] testAll737EventuallyMintedExactlyOnce() (gas: 57915654)\n[PASS] testBuyAndQuoteTimeBoundaries() (gas: 691301)\n[PASS] testBuyEventAndDirectBurnPayment() (gas: 320925)\n[PASS] testClaimProofStartAndDuplicate() (gas: 315016)\n[PASS] testCoinReentrySeesCompletedSaleAndCannotDuplicatePiece() (gas: 751712)\n[PASS] testConstructorWithoutCoinCodeAndFixedDeployment() (gas: 174020)\n[PASS] testERC721TransfersApprovalsAndNoReceiverCallbacks() (gas: 811934)\n[PASS] testEveryPieceAndSaleCount() (gas: 9470970)\n[PASS] testEverySaleSlotBoughtInOrderAndAllSalesExhausted() (gas: 63856939)\n[PASS] testFalseAndRevertingCoinRollbackEntireBuy() (gas: 1275690)\n[PASS] testFractionalSegmentsWithShortFixture() (gas: 93647)\n[PASS] testFreezeOnlyAdminOnceAndValidBase() (gas: 233852)\n[PASS] testFuzzHalvingPriceIsBoundedAndMonotone(uint256) (runs: 256, μ: 51765, ~: 51660)\nLogs:\n  Bound result 1972\n\n[PASS] testHalvingSegmentEndsAndInterior() (gas: 188780)\n[PASS] testInterfacesRoyaltyAndNonexistentURI() (gas: 83965)\n[PASS] testInvalidConfiguration() (gas: 5512)\n[PASS] testLadderAcrossCavesAndUnboughtRoundNotSnapshot() (gas: 635878)\n[PASS] testLadderDoublesLastLineSaleAndHalvesQuietRounds() (gas: 903635)\n[PASS] testLadderFloorBuysIgnoredAndStoredOpeningStable() (gas: 1013662)\n[PASS] testLastLineSaleReplacesEarlierSaleAndHalfOpeningMinimum() (gas: 1170907)\n[PASS] testLeftoverFailureRollsBackCursorAndReentryUsesNextPiece() (gas: 808452)\n[PASS] testMintToContractWithoutReceiver() (gas: 519020)\n[PASS] testMissingBoolOrMissingAllowanceRejectsBuy() (gas: 428474)\n[PASS] testQuietFirstBuyAtFloorDoesNotRaiseNextOpening() (gas: 271073)\n[PASS] testReleaseTimingPermissionlessAndClaimStopsOnlyOnRelease() (gas: 543060)\n[PASS] testRuntimePassesProtectedOpcodeScanAndSizeLimit() (gas: 3630569)\n[PASS] testSweepBoundariesPartialBatchesAndEvents() (gas: 1936589)\n[PASS] testURIsIncludingEndpointsRoundsSlotsAndFrozenCaves() (gas: 12576093)\n[PASS] testWindowsAndInvalidIndices() (gas: 2286291)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 63.50ms (212.09ms CPU time)\n\nRan 13 tests for test/PepeolithicProperties.t.sol:PepeolithicPropertiesTest\n[PASS] testConstructorRejectsZeroAddressesAndOverflowingSchedule() (gas: 6477)\n[PASS] testEveryMintPathWorksWithAReceiverThatRejectsCallbacks() (gas: 1458518)\n[PASS] testFullWidthInterpolationDoesNotOverflow() (gas: 118392)\n[PASS] testFuzzEveryCaveRoundBoundary(uint8,uint8) (runs: 1000, μ: 499487, ~: 479125)\nLogs:\n  Bound result 6\n  Bound result 17\n\n[PASS] testFuzzFractionalCurveBoundsAndPayment(uint96,uint96,uint32,uint32) (runs: 1000, μ: 476296, ~: 474171)\nLogs:\n  Bound result 253\n  Bound result 39614081257132168796771975167\n  Bound result 736\n  Bound result 648\n\n[PASS] testFuzzHalvingKnotsAcrossConstructorPrices(uint96,uint8,uint32) (runs: 1000, μ: 341892, ~: 251996)\nLogs:\n  Bound result 19148558270767\n  Bound result 1\n  Bound result 270\n\n[PASS] testFuzzRoyaltyRoundingIdentity(uint256,uint256) (runs: 1000, μ: 12278, ~: 12278)\n[PASS] testInsufficientBalanceAndLeftoverAllowancePreserveInventory() (gas: 748236)\n[PASS] testLabelsRejectMalformedPaddingAndAcceptAll32Bytes() (gas: 6756)\n[PASS] testMaximumMainnetLadderRemainsLiveThroughAll147Rounds() (gas: 35075126)\n[PASS] testMerkleProofCannotBeReusedByAnotherWalletOrAltered() (gas: 245135)\n[PASS] testNativeCurrencyIsRejectedByAllIssuancePaths() (gas: 183191)\n[PASS] testOneWeiFloorOddOpeningAndSubsecondSegments() (gas: 208292)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 63.61ms (281.21ms CPU time)\n\nRan 2 tests for test/PepeolithicInvariant.t.sol:PepeolithicInvariantTest\n[PASS] invariant_supplyPaymentAndPermanentTransitions() (runs: 256, calls: 32768, reverts: 0)\n\n╭-----------------------------+-------------+-------+---------+----------╮\n| Contract                    | Selector    | Calls | Reverts | Discards |\n+========================================================================+\n| PepeolithicLifecycleHandler | advanceTime | 4176  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | buy         | 4212  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | buyLeftover | 4061  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | claim       | 4128  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | freeze      | 4068  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | release     | 3941  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | sweep       | 4102  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | transfer    | 4080  | 0       | 0        |\n╰-----------------------------+-------------+-------+---------+----------╯\n\nLogs:\n  Bound result 4\n  Bound result 7\n  Bound result 41\n  Bound result 6\n  Bound result 12\n  Bound result 6\n  Bound result 59\n  Bound result 7\n  Bound result 3\n  Bound result 4\n  Bound result 5\n  Bound result 3\n  Bound result 3\n  Bound result 17\n  Bound result 5\n  Bound result 1\n  Bound result 18\n  Bound result 3\n  Bound result 6\n  Bound result 2\n  Bound result 4\n  Bound result 86397\n  Bound result 665\n  Bound result 1527\n  Bound result 5\n  Bound result 7\n  Bound result 1\n  Bound result 4\n  Bound result 12\n  Bound result 1\n  Bound result 6\n  Bound result 22\n  Bound result 2\n  Bound result 1\n  Bound result 3500\n  Bound result 3\n  Bound result 4\n  Bound result 9\n  Bound result 1\n  Bound result 21\n  Bound result 1\n  Bound result 6\n  Bound result 3057\n  Bound result 2\n  Bound result 29\n  Bound result 1\n  Bound result 4\n  Bound result 59\n  Bound result 84\n  Bound result 4\n  Bound result 5\n  Bound result 6\n  Bound result 4\n  Bound result 1\n  Bound result 512\n  Bound result 1\n  Bound result 95\n  Bound result 4\n  Bound result 2\n  Bound result 7\n  Bound result 3\n  Bound result 17\n  Bound result 18669\n  Bound result 5019\n  Bound result 1565\n  Bound result 3\n  Bound result 3\n  Bound result 8\n  Bound result 25962\n  Bound result 2\n  Bound result 5\n  Bound result 5\n  Bound result 1\n  Bound result 86400\n  Bound result 5\n  Bound result 1245\n  Bound result 1\n  Bound result 74\n  Bound result 144957\n  Bound result 4\n  Bound result 42\n  Bound result 4\n  Bound result 99\n  Bound result 6\n  Bound result 6\n  Bound result 42\n  Bound result 7\n  Bound result 16\n  Bound result 2\n  Bound result 5\n  Bound result 8\n  Bound result 4\n  Bound result 5362\n  Bound result 167677\n  Bound result 30\n  Bound result 3\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: 74785151)\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 86400\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 172800\n  Bound result 172800\n  Bound result 172800\n  Bound result 86400\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.08s (22.13s CPU time)\n\nRan 3 test suites in 22.08s (22.21s CPU time): 45 tests passed, 0 failed, 0 skipped (45 total tests)\n","passed":true},{"durationMs":53,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Pepeolithic.approve(address,uint256)\",\"Pepeolithic.buy(uint256,uint256)\",\"Pepeolithic.buyLeftover()\",\"Pepeolithic.claimSeat(bytes32[])\",\"Pepeolithic.freeze(uint256,string)\",\"Pepeolithic.releaseUnclaimed()\",\"Pepeolithic.safeTransferFrom(address,address,uint256)\",\"Pepeolithic.safeTransferFrom(address,address,uint256,bytes)\",\"Pepeolithic.setApprovalForAll(address,bool)\",\"Pepeolithic.sweep(uint256,uint256)\",\"Pepeolithic.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":5,\"README.md\":123,\"THIRD_PARTY.md\":25,\"foundry.toml\":18,\"launch.json\":27,\"remappings.txt\":2,\"script/check_launch.py\":57,\"src/Pepeolithic.sol\":357,\"test/Pepeolithic.t.sol\":767,\"test/PepeolithicInvariant.t.sol\":352,\"test/PepeolithicProperties.t.sol\":298,\"test/README.md\":37,\"test/support/PepeolithicSetup.sol\":124},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"3951437b45831c231c399836c2519cc2a8fa969e946f0336f885b43e7a67b27d","verifiedTreeHash":"d8b697c71591fe1e5fc0c215ec873f27f9b6c3d2","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":13127,"exitCode":0,"name":"build","output":"Compiling 35 files with Solc 0.8.26\nSolc 0.8.26 finished in 13.01s\nCompiler run successful!\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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":18721,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 30 tests for test/Pepeolithic.t.sol:PepeolithicTest\n[PASS] testAll335SeatsInIdOrderAndMerkleExhaustion() (gas: 49641985)\n[PASS] testAll737EventuallyMintedExactlyOnce() (gas: 57915654)\n[PASS] testBuyAndQuoteTimeBoundaries() (gas: 691301)\n[PASS] testBuyEventAndDirectBurnPayment() (gas: 320925)\n[PASS] testClaimProofStartAndDuplicate() (gas: 315016)\n[PASS] testCoinReentrySeesCompletedSaleAndCannotDuplicatePiece() (gas: 751712)\n[PASS] testConstructorWithoutCoinCodeAndFixedDeployment() (gas: 174020)\n[PASS] testERC721TransfersApprovalsAndNoReceiverCallbacks() (gas: 811934)\n[PASS] testEveryPieceAndSaleCount() (gas: 9470970)\n[PASS] testEverySaleSlotBoughtInOrderAndAllSalesExhausted() (gas: 63856939)\n[PASS] testFalseAndRevertingCoinRollbackEntireBuy() (gas: 1275690)\n[PASS] testFractionalSegmentsWithShortFixture() (gas: 93647)\n[PASS] testFreezeOnlyAdminOnceAndValidBase() (gas: 233852)\n[PASS] testFuzzHalvingPriceIsBoundedAndMonotone(uint256) (runs: 256, μ: 51845, ~: 51660)\nLogs:\n  Bound result 224\n\n[PASS] testHalvingSegmentEndsAndInterior() (gas: 188780)\n[PASS] testInterfacesRoyaltyAndNonexistentURI() (gas: 83965)\n[PASS] testInvalidConfiguration() (gas: 5512)\n[PASS] testLadderAcrossCavesAndUnboughtRoundNotSnapshot() (gas: 635878)\n[PASS] testLadderDoublesLastLineSaleAndHalvesQuietRounds() (gas: 903635)\n[PASS] testLadderFloorBuysIgnoredAndStoredOpeningStable() (gas: 1013662)\n[PASS] testLastLineSaleReplacesEarlierSaleAndHalfOpeningMinimum() (gas: 1170907)\n[PASS] testLeftoverFailureRollsBackCursorAndReentryUsesNextPiece() (gas: 808452)\n[PASS] testMintToContractWithoutReceiver() (gas: 519020)\n[PASS] testMissingBoolOrMissingAllowanceRejectsBuy() (gas: 428474)\n[PASS] testQuietFirstBuyAtFloorDoesNotRaiseNextOpening() (gas: 271073)\n[PASS] testReleaseTimingPermissionlessAndClaimStopsOnlyOnRelease() (gas: 543060)\n[PASS] testRuntimePassesProtectedOpcodeScanAndSizeLimit() (gas: 3630569)\n[PASS] testSweepBoundariesPartialBatchesAndEvents() (gas: 1936589)\n[PASS] testURIsIncludingEndpointsRoundsSlotsAndFrozenCaves() (gas: 12576093)\n[PASS] testWindowsAndInvalidIndices() (gas: 2286291)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 73.29ms (213.00ms CPU time)\n\nRan 13 tests for test/PepeolithicProperties.t.sol:PepeolithicPropertiesTest\n[PASS] testConstructorRejectsZeroAddressesAndOverflowingSchedule() (gas: 6477)\n[PASS] testEveryMintPathWorksWithAReceiverThatRejectsCallbacks() (gas: 1458518)\n[PASS] testFullWidthInterpolationDoesNotOverflow() (gas: 118392)\n[PASS] testFuzzEveryCaveRoundBoundary(uint8,uint8) (runs: 1000, μ: 508488, ~: 487804)\nLogs:\n  Bound result 4\n  Bound result 1\n\n[PASS] testFuzzFractionalCurveBoundsAndPayment(uint96,uint96,uint32,uint32) (runs: 1000, μ: 476093, ~: 473093)\nLogs:\n  Bound result 13026\n  Bound result 79228162514264337593543928244\n  Bound result 42\n  Bound result 11\n\n[PASS] testFuzzHalvingKnotsAcrossConstructorPrices(uint96,uint8,uint32) (runs: 1000, μ: 364326, ~: 297594)\nLogs:\n  Bound result 10310344\n  Bound result 2\n  Bound result 51043\n\n[PASS] testFuzzRoyaltyRoundingIdentity(uint256,uint256) (runs: 1000, μ: 12278, ~: 12278)\n[PASS] testInsufficientBalanceAndLeftoverAllowancePreserveInventory() (gas: 748236)\n[PASS] testLabelsRejectMalformedPaddingAndAcceptAll32Bytes() (gas: 6756)\n[PASS] testMaximumMainnetLadderRemainsLiveThroughAll147Rounds() (gas: 35075126)\n[PASS] testMerkleProofCannotBeReusedByAnotherWalletOrAltered() (gas: 245135)\n[PASS] testNativeCurrencyIsRejectedByAllIssuancePaths() (gas: 183191)\n[PASS] testOneWeiFloorOddOpeningAndSubsecondSegments() (gas: 208292)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 73.37ms (305.21ms CPU time)\n\nRan 2 tests for test/PepeolithicInvariant.t.sol:PepeolithicInvariantTest\n[PASS] invariant_supplyPaymentAndPermanentTransitions() (runs: 256, calls: 32768, reverts: 0)\n\n╭-----------------------------+-------------+-------+---------+----------╮\n| Contract                    | Selector    | Calls | Reverts | Discards |\n+========================================================================+\n| PepeolithicLifecycleHandler | advanceTime | 4028  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | buy         | 4057  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | buyLeftover | 4043  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | claim       | 4197  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | freeze      | 4095  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | release     | 4141  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | sweep       | 4109  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | transfer    | 4098  | 0       | 0        |\n╰-----------------------------+-------------+-------+---------+----------╯\n\nLogs:\n  Bound result 7\n  Bound result 38\n  Bound result 3\n  Bound result 6\n  Bound result 15\n  Bound result 7\n  Bound result 7\n  Bound result 110\n  Bound result 2\n  Bound result 33\n  Bound result 3\n  Bound result 2\n  Bound result 7\n  Bound result 2\n  Bound result 5\n  Bound result 67\n  Bound result 4\n  Bound result 21\n  Bound result 1\n  Bound result 3\n  Bound result 6\n  Bound result 77\n  Bound result 21420\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 106\n  Bound result 5\n  Bound result 3\n  Bound result 12\n  Bound result 6\n  Bound result 6\n  Bound result 5\n  Bound result 85\n  Bound result 2\n  Bound result 4\n  Bound result 77\n  Bound result 2\n  Bound result 20\n  Bound result 5\n  Bound result 4\n  Bound result 16\n  Bound result 7\n  Bound result 4\n  Bound result 6\n  Bound result 52\n  Bound result 3\n  Bound result 73\n  Bound result 54586\n  Bound result 18001\n  Bound result 63\n  Bound result 6\n  Bound result 96\n  Bound result 5\n  Bound result 98888\n  Bound result 12300\n  Bound result 214\n  Bound result 7\n  Bound result 6\n  Bound result 5897\n  Bound result 5\n  Bound result 8\n  Bound result 1\n  Bound result 3\n  Bound result 11\n  Bound result 4\n  Bound result 13\n  Bound result 9\n  Bound result 6\n  Bound result 2\n  Bound result 63\n  Bound result 5\n  Bound result 2\n  Bound result 2\n  Bound result 100\n  Bound result 3\n  Bound result 105\n  Bound result 6\n  Bound result 6\n  Bound result 108\n  Bound result 172800\n  Bound result 3\n  Bound result 7\n  Bound result 6\n  Bound result 1\n  Bound result 66\n  Bound result 7\n  Bound result 3\n  Bound result 20\n  Bound result 9\n  Bound result 5\n  Bound result 3\n  Bound result 23\n  Bound result 1\n  Bound result 29\n  Bound result 3\n  Bound result 3064\n  Bound result 7\n  Bound result 3\n  Bound result 17\n  Bound result 2\n  Bound result 4\n  Bound result 16\n  Bound result 1\n  Bound result 1\n  Bound result 50\n  Bound result 3\n  Bound result 42\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: 74785151)\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 86400\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 172800\n  Bound result 172800\n  Bound result 172800\n  Bound result 86400\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 18.64s (18.70s CPU time)\n\nRan 3 test suites in 18.64s (18.79s CPU time): 45 tests passed, 0 failed, 0 skipped (45 total tests)\n","passed":true},{"durationMs":37,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Pepeolithic.approve(address,uint256)\",\"Pepeolithic.buy(uint256,uint256)\",\"Pepeolithic.buyLeftover()\",\"Pepeolithic.claimSeat(bytes32[])\",\"Pepeolithic.freeze(uint256,string)\",\"Pepeolithic.releaseUnclaimed()\",\"Pepeolithic.safeTransferFrom(address,address,uint256)\",\"Pepeolithic.safeTransferFrom(address,address,uint256,bytes)\",\"Pepeolithic.setApprovalForAll(address,bool)\",\"Pepeolithic.sweep(uint256,uint256)\",\"Pepeolithic.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":5,\"README.md\":123,\"THIRD_PARTY.md\":25,\"foundry.toml\":18,\"launch.json\":27,\"remappings.txt\":2,\"script/check_launch.py\":57,\"src/Pepeolithic.sol\":357,\"test/Pepeolithic.t.sol\":767,\"test/PepeolithicInvariant.t.sol\":352,\"test/PepeolithicProperties.t.sol\":298,\"test/README.md\":37,\"test/support/PepeolithicSetup.sol\":124},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1588,"exitCode":0,"name":"slither","output":"[medium/medium] uninitialized-local at src/Pepeolithic.sol:296: Pepeolithic._price(uint256,uint256).segments (src/Pepeolithic.sol#296) is a local variable never initialized\n[medium/medium] uninitialized-local at src/Pepeolithic.sol:340: Pepeolithic._checkLabel(bytes32).padding (src/Pepeolithic.sol#340) is a local variable never initialized\n[low/medium] timestamp at src/Pepeolithic.sol:217: Pepeolithic.sweep(uint256,uint256) (src/Pepeolithic.sol#217-233) uses timestamp for comparisons\n[low/medium] timestamp at src/Pepeolithic.sol:294: Pepeolithic._price(uint256,uint256) (src/Pepeolithic.sol#294-308) uses timestamp for comparisons\n[low/medium] timestamp at src/Pepeolithic.sol:185: Pepeolithic.claimSeat(bytes32[]) (src/Pepeolithic.sol#185-199) uses timestamp for comparisons\n[low/medium] timestamp at src/Pepeolithic.sol:168: Pepeolithic.buy(uint256,uint256) (src/Pepeolithic.sol#168-183) uses timestamp for comparisons\n[low/medium] timestamp at src/Pepeolithic.sol:162: Pepeolithic.priceNow(uint256,uint256) (src/Pepeolithic.sol#162-166) uses timestamp for comparisons\n[low/medium] timestamp at src/Pepeolithic.sol:201: Pepeolithic.releaseUnclaimed() (src/Pepeolithic.sol#201-206) uses timestamp for comparisons","passed":true},{"durationMs":315,"exitCode":0,"name":"aderyn","output":"[low] costly-loop at src/Pepeolithic.sol:223: Costly operations inside loop\n[low] literal-instead-of-constant at src/Pepeolithic.sol:90: Literal Instead of Constant (37 places)\n[low] require-revert-in-loop at src/Pepeolithic.sol:223: Loop Contains `require`/`revert` (2 places)\n[low] state-variable-could-be-immutable at src/Pepeolithic.sol:42: State Variable Could Be Immutable (9 places)\n[low] unchecked-return at src/Pepeolithic.sol:123: Unchecked Return (3 places)\n[low] uninitialized-local-variable at src/Pepeolithic.sol:190: Uninitialized Local Variable (5 places)\n[low] unsafe-oz-erc721-mint at src/Pepeolithic.sol:323: Unsafe `ERC721::_mint()`\n[low] unused-public-function at src/Pepeolithic.sol:158: Public Function Not Used Internally (2 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"45a0dafc001ba67ad6a451db3bc5c7b822c1df41a1b473ab14bfb01306fbab37","verifiedTreeHash":"28f7eeef82780abff343a86abe9ee8c83251d3fb","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":19319,"exitCode":0,"name":"build","output":"Compiling 37 files with Solc 0.8.26\nSolc 0.8.26 finished in 19.15s\nCompiler run successful!\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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/Pepeolithic.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":22242,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 7 tests for test/PepeolithicSettlement.t.sol:PepeolithicSettlementTest\n[PASS] testCaughtNestedSoldOutDoesNotUndoPaidOuterPurchase() (gas: 559285)\n[PASS] testFuzzFailedOuterPaymentRollsBackSuccessfulNestedPurchase(uint8,bool) (runs: 128, μ: 1436459, ~: 1622156)\nLogs:\n  Bound result 1\n\n[PASS] testNestedSeatClaimRollsBackWithRejectedSaleAndCanBeRetried() (gas: 1265760)\n[PASS] testNestedSweepRollsBackWithRejectedSaleIncludingSweepCursor() (gas: 848685)\n[PASS] testPaymentCallbackCanTransferAlreadyMintedPieceWithoutChangingIssuance() (gas: 610197)\n[PASS] testReentryAtLastFreePieceCannotMintPastSeatInventory() (gas: 52000051)\n[PASS] testRejectedPaymentRollsBackNestedTransferAndPreservesOperatorApproval() (gas: 670401)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 70.14ms (92.84ms CPU time)\n\nRan 30 tests for test/Pepeolithic.t.sol:PepeolithicTest\n[PASS] testAll335SeatsInIdOrderAndMerkleExhaustion() (gas: 49641985)\n[PASS] testAll737EventuallyMintedExactlyOnce() (gas: 57915654)\n[PASS] testBuyAndQuoteTimeBoundaries() (gas: 691301)\n[PASS] testBuyEventAndDirectBurnPayment() (gas: 320925)\n[PASS] testClaimProofStartAndDuplicate() (gas: 315016)\n[PASS] testCoinReentrySeesCompletedSaleAndCannotDuplicatePiece() (gas: 751712)\n[PASS] testConstructorWithoutCoinCodeAndFixedDeployment() (gas: 174020)\n[PASS] testERC721TransfersApprovalsAndNoReceiverCallbacks() (gas: 811934)\n[PASS] testEveryPieceAndSaleCount() (gas: 9470970)\n[PASS] testEverySaleSlotBoughtInOrderAndAllSalesExhausted() (gas: 63856939)\n[PASS] testFalseAndRevertingCoinRollbackEntireBuy() (gas: 1275690)\n[PASS] testFractionalSegmentsWithShortFixture() (gas: 93647)\n[PASS] testFreezeOnlyAdminOnceAndValidBase() (gas: 233852)\n[PASS] testFuzzHalvingPriceIsBoundedAndMonotone(uint256) (runs: 256, μ: 51832, ~: 51660)\nLogs:\n  Bound result 255\n\n[PASS] testHalvingSegmentEndsAndInterior() (gas: 188780)\n[PASS] testInterfacesRoyaltyAndNonexistentURI() (gas: 83965)\n[PASS] testInvalidConfiguration() (gas: 5512)\n[PASS] testLadderAcrossCavesAndUnboughtRoundNotSnapshot() (gas: 635878)\n[PASS] testLadderDoublesLastLineSaleAndHalvesQuietRounds() (gas: 903635)\n[PASS] testLadderFloorBuysIgnoredAndStoredOpeningStable() (gas: 1013662)\n[PASS] testLastLineSaleReplacesEarlierSaleAndHalfOpeningMinimum() (gas: 1170907)\n[PASS] testLeftoverFailureRollsBackCursorAndReentryUsesNextPiece() (gas: 808452)\n[PASS] testMintToContractWithoutReceiver() (gas: 519020)\n[PASS] testMissingBoolOrMissingAllowanceRejectsBuy() (gas: 428474)\n[PASS] testQuietFirstBuyAtFloorDoesNotRaiseNextOpening() (gas: 271073)\n[PASS] testReleaseTimingPermissionlessAndClaimStopsOnlyOnRelease() (gas: 543060)\n[PASS] testRuntimePassesProtectedOpcodeScanAndSizeLimit() (gas: 3630569)\n[PASS] testSweepBoundariesPartialBatchesAndEvents() (gas: 1936589)\n[PASS] testURIsIncludingEndpointsRoundsSlotsAndFrozenCaves() (gas: 12576093)\n[PASS] testWindowsAndInvalidIndices() (gas: 2286291)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 85.46ms (219.17ms CPU time)\n\nRan 13 tests for test/PepeolithicProperties.t.sol:PepeolithicPropertiesTest\n[PASS] testConstructorRejectsZeroAddressesAndOverflowingSchedule() (gas: 6477)\n[PASS] testEveryMintPathWorksWithAReceiverThatRejectsCallbacks() (gas: 1458518)\n[PASS] testFullWidthInterpolationDoesNotOverflow() (gas: 118392)\n[PASS] testFuzzEveryCaveRoundBoundary(uint8,uint8) (runs: 1000, μ: 507644, ~: 478906)\nLogs:\n  Bound result 5\n  Bound result 10\n\n[PASS] testFuzzFractionalCurveBoundsAndPayment(uint96,uint96,uint32,uint32) (runs: 1000, μ: 476484, ~: 473913)\nLogs:\n  Bound result 12117156794296\n  Bound result 29355737920525120795717114071\n  Bound result 7\n  Bound result 2\n\n[PASS] testFuzzHalvingKnotsAcrossConstructorPrices(uint96,uint8,uint32) (runs: 1000, μ: 346056, ~: 274031)\nLogs:\n  Bound result 79228162514264337593543950335\n  Bound result 10\n  Bound result 12929\n\n[PASS] testFuzzRoyaltyRoundingIdentity(uint256,uint256) (runs: 1000, μ: 12278, ~: 12278)\n[PASS] testInsufficientBalanceAndLeftoverAllowancePreserveInventory() (gas: 748236)\n[PASS] testLabelsRejectMalformedPaddingAndAcceptAll32Bytes() (gas: 6756)\n[PASS] testMaximumMainnetLadderRemainsLiveThroughAll147Rounds() (gas: 35075126)\n[PASS] testMerkleProofCannotBeReusedByAnotherWalletOrAltered() (gas: 245135)\n[PASS] testNativeCurrencyIsRejectedByAllIssuancePaths() (gas: 183191)\n[PASS] testOneWeiFloorOddOpeningAndSubsecondSegments() (gas: 208292)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 87.75ms (370.95ms CPU time)\n\nRan 4 tests for test/PepeolithicPricingInvariant.t.sol:PepeolithicPricingInvariantTest\n[PASS] invariant_ladderAndBurnsMatchIndependentModel() (runs: 128, calls: 12288, reverts: 0)\n\n╭---------------------------+------------+-------+---------+----------╮\n| Contract                  | Selector   | Calls | Reverts | Discards |\n+=====================================================================+\n| PepeolithicPricingHandler | advance    | 3028  | 0       | 0        |\n|---------------------------+------------+-------+---------+----------|\n| PepeolithicPricingHandler | buyCurrent | 3084  | 0       | 0        |\n|---------------------------+------------+-------+---------+----------|\n| PepeolithicPricingHandler | buyOlder   | 3149  | 0       | 0        |\n|---------------------------+------------+-------+---------+----------|\n| PepeolithicPricingHandler | probe      | 3027  | 0       | 0        |\n╰---------------------------+------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1\n  Bound result 126\n  Bound result 3027\n  Bound result 60\n  Bound result 21\n  Bound result 1\n  Bound result 1\n  Bound result 36\n  Bound result 34\n  Bound result 3\n  Bound result 511\n  Bound result 3530\n  Bound result 45\n  Bound result 1\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 26\n  Bound result 33\n  Bound result 103\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 103\n  Bound result 1\n  Bound result 128\n  Bound result 78\n  Bound result 1\n  Bound result 60\n  Bound result 101\n  Bound result 1\n  Bound result 4345\n  Bound result 43\n  Bound result 101\n  Bound result 2\n  Bound result 2\n  Bound result 19\n  Bound result 120\n  Bound result 1\n  Bound result 3\n  Bound result 3\n  Bound result 68\n  Bound result 4\n  Bound result 1024\n  Bound result 15\n  Bound result 8\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 30\n  Bound result 1\n  Bound result 1\n  Bound result 4012\n  Bound result 6498\n  Bound result 1\n  Bound result 1\n  Bound result 122\n  Bound result 86\n  Bound result 7081\n  Bound result 145\n  Bound result 4\n  Bound result 2\n  Bound result 3\n  Bound result 5\n\n[PASS] testFuzzCurveMatchesWeightedKnotOracle(uint96,uint96,uint32,uint32) (runs: 1000, μ: 55701, ~: 53024)\nLogs:\n  Bound result 1\n  Bound result 39614081257132168796771975167\n  Bound result 1\n  Bound result 0\n\n[PASS] testMainnetFloorStartsBeforeRoundEndsAndDoesNotRecordALineSale() (gas: 333869)\n[PASS] testPricingHandlerExercisesSuccessfulAndRejectedLineAndFloorBuys() (gas: 74099161)\nLogs:\n  Bound result 1800\n  Bound result 2\n  Bound result 146\n\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 10.66s (10.77s CPU time)\n\nRan 2 tests for test/PepeolithicInvariant.t.sol:PepeolithicInvariantTest\n[PASS] invariant_supplyPaymentAndPermanentTransitions() (runs: 256, calls: 32768, reverts: 0)\n\n╭-----------------------------+-------------+-------+---------+----------╮\n| Contract                    | Selector    | Calls | Reverts | Discards |\n+========================================================================+\n| PepeolithicLifecycleHandler | advanceTime | 4086  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | buy         | 4132  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | buyLeftover | 4031  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | claim       | 4145  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | freeze      | 4141  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | release     | 4030  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | sweep       | 4059  | 0       | 0        |\n|-----------------------------+-------------+-------+---------+----------|\n| PepeolithicLifecycleHandler | transfer    | 4144  | 0       | 0        |\n╰-----------------------------+-------------+-------+---------+----------╯\n\nLogs:\n  Bound result 6\n  Bound result 7\n  Bound result 7\n  Bound result 20\n  Bound result 172800\n  Bound result 7750\n  Bound result 4\n  Bound result 4\n  Bound result 1\n  Bound result 140\n  Bound result 6\n  Bound result 6\n  Bound result 104\n  Bound result 41\n  Bound result 145880\n  Bound result 3\n  Bound result 4\n  Bound result 7\n  Bound result 6\n  Bound result 141515\n  Bound result 4\n  Bound result 40\n  Bound result 7\n  Bound result 2\n  Bound result 22\n  Bound result 5\n  Bound result 2\n  Bound result 6\n  Bound result 105\n  Bound result 6\n  Bound result 5\n  Bound result 90\n  Bound result 6\n  Bound result 107\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 8\n  Bound result 6\n  Bound result 95\n  Bound result 1\n  Bound result 3\n  Bound result 4\n  Bound result 3\n  Bound result 73\n  Bound result 2\n  Bound result 2\n  Bound result 5\n  Bound result 84\n  Bound result 6\n  Bound result 2\n  Bound result 5\n  Bound result 97138\n  Bound result 402\n  Bound result 7\n  Bound result 38\n  Bound result 4\n  Bound result 4\n  Bound result 6\n  Bound result 21\n  Bound result 14\n  Bound result 3\n  Bound result 42\n  Bound result 2\n  Bound result 50\n  Bound result 4\n  Bound result 84\n  Bound result 7\n  Bound result 3\n  Bound result 18\n  Bound result 4\n  Bound result 6\n  Bound result 108\n  Bound result 7\n  Bound result 21\n  Bound result 3\n  Bound result 7\n  Bound result 4\n  Bound result 5\n  Bound result 7\n  Bound result 4\n  Bound result 3\n  Bound result 4\n  Bound result 6\n  Bound result 98870\n  Bound result 1\n  Bound result 3\n  Bound result 11\n  Bound result 2\n  Bound result 22\n  Bound result 1\n  Bound result 9\n  Bound result 4\n  Bound result 23\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: 74785151)\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 86400\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 172800\n  Bound result 172800\n  Bound result 172800\n  Bound result 86400\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.15s (22.21s CPU time)\n\nRan 5 test suites in 22.15s (33.05s CPU time): 56 tests passed, 0 failed, 0 skipped (56 total tests)\n","passed":true},{"durationMs":53,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Pepeolithic.approve(address,uint256)\",\"Pepeolithic.buy(uint256,uint256)\",\"Pepeolithic.buyLeftover()\",\"Pepeolithic.claimSeat(bytes32[])\",\"Pepeolithic.freeze(uint256,string)\",\"Pepeolithic.releaseUnclaimed()\",\"Pepeolithic.safeTransferFrom(address,address,uint256)\",\"Pepeolithic.safeTransferFrom(address,address,uint256,bytes)\",\"Pepeolithic.setApprovalForAll(address,bool)\",\"Pepeolithic.sweep(uint256,uint256)\",\"Pepeolithic.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":5,\"README.md\":123,\"THIRD_PARTY.md\":25,\"foundry.toml\":18,\"launch.json\":27,\"remappings.txt\":2,\"script/check_launch.py\":57,\"src/Pepeolithic.sol\":357,\"test/Pepeolithic.t.sol\":767,\"test/PepeolithicInvariant.t.sol\":352,\"test/PepeolithicPricingInvariant.t.sol\":267,\"test/PepeolithicProperties.t.sol\":298,\"test/PepeolithicSettlement.t.sol\":313,\"test/README.md\":75,\"test/support/PepeolithicSetup.sol\":124},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"ad9828c0d0a07a4f785f3b80c1efe0e83e72623553280358ffc07096bfd31f0e","verifiedTreeHash":"b8622f82f20b471aa6cd8f0de49a2e84e07c3e66","verifierVersion":"0.1.0+ad90ce4c"}]}