{"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":"99e35c0e-0359-4f96-885e-0414013eaef5","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"50641eaac12b72f8df5c652d885d8317762ece6adf57cb4e29fc773cf5677fa7","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"a2cea02e8b33e91eeb784e0e5eaeb571cd62cd69e768d335d5834e24b3aa46e5","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"a2cea02e8b33e91eeb784e0e5eaeb571cd62cd69e768d335d5834e24b3aa46e5","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"e86f67a719054b656968d4d76b3412a731f7460a3514310eec59e60f21ea0206","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"4fd80628130ad43f1d1b63269a313ca73ce380bc5efee65ace9761ad151017f3","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"b1450f2b559a8e418ae58c0157999fc8627cb8d52445ef44b9e96fea4cb68a00","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"a2e278745bde897f04a486b514b007b5ff1ba63a071857fde08d67b93007450c","dependsOn":["adapt_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":"bcb5f09055980070a24ad778001fedfbdd460de85449866439b1091294d54174","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"8213a6f9e5dd4e727c00fc816f07d9ddf3d582c132dbef7fad72136b5d4fa8fd","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"e54c1bb72e8d158c077c63e760f919bfc7e6d4b2bae1569a9c19779bc6eec587","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"b78839171a74ec80eef03f8fcfd1f792428a508f79f87e7f3920782c31caff4d","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Deploy part 2 of 3 of the IMD6900 Frens on-chain art, exactly as it is in the repository: the data contracts FrenArtChunk3 and FrenArtChunk4 (src/FrenArtChunks.sol), in that order, no constructor arguments. Their code is generated art data (a STOP byte, then the bytes; FrenArtChunk4 framed with a PUSH32 byte before every 32 bytes so its code reads as PUSH data only, see README.md and test_ChunksPassTheAdmissionScan); do not change them, the renderer only accepts chunks with these exact code hashes (src/FrenArtIndex.sol). Part 1 is IMD launch #819; the renderer and the last chunks come in launch 3 (README.md).","parentJobId":null,"planHash":"52c91ea585b5f77a5a9f519b40cd187caa87773f618765f0046cc47fc54a397d","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"99e35c0e-0359-4f96-885e-0414013eaef5","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-838-frenartchunk3-frenartchunk4"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52015","feedbackHash":"4b527265d068f9065a879d4fa2739c6d733605ad6e188abc5a499b2c7dd9bd9f","nodeKey":"adapt_contract_project","submissionHash":"50641eaac12b72f8df5c652d885d8317762ece6adf57cb4e29fc773cf5677fa7","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51512","feedbackHash":"26279c1ca8589824f3b9ed5b11b68627dc724a3963d3836105e63914fc9f2e32","nodeKey":"audit_economics","submissionHash":"e86f67a719054b656968d4d76b3412a731f7460a3514310eec59e60f21ea0206","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51139","feedbackHash":"8fba791191428aabe218784c2c5405a73ff7af1ee67763a66826468bc207eed0","nodeKey":"audit_flow","submissionHash":"4fd80628130ad43f1d1b63269a313ca73ce380bc5efee65ace9761ad151017f3","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52160","feedbackHash":"4bc937ef3a622fd108a9ddc8aa91ae984ed9c7da4dfadf4b35f26eb36f448337","nodeKey":"audit_imported_code","submissionHash":"b1450f2b559a8e418ae58c0157999fc8627cb8d52445ef44b9e96fea4cb68a00","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51319","feedbackHash":"8ca6165b546e5198c1a1c71cf71657971e14be75acb242e0a167ab35da90f9c8","nodeKey":"audit_judge","submissionHash":"a2e278745bde897f04a486b514b007b5ff1ba63a071857fde08d67b93007450c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51251","feedbackHash":"f4fc5aca6b3f25b8fd3583c51e02002b0af38a513a6b0a9cd1e7d10eb0e63f1e","nodeKey":"audit_math","submissionHash":"bcb5f09055980070a24ad778001fedfbdd460de85449866439b1091294d54174","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51146","feedbackHash":"651acb4aeae756ad54c282b8ffc87b9fd535fb3a0f10aeeb28207a725a9ad94b","nodeKey":"audit_permissions","submissionHash":"8213a6f9e5dd4e727c00fc816f07d9ddf3d582c132dbef7fad72136b5d4fa8fd","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51198","feedbackHash":"c8d52d295516913822a6dffcbd69bac02dbba0dafd89d784232c56f4e24730a7","nodeKey":"manifest","submissionHash":"e54c1bb72e8d158c077c63e760f919bfc7e6d4b2bae1569a9c19779bc6eec587","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51358","feedbackHash":"0375496372dfc8144aa60005f31ba31040f2bda1290b488e83b05c5aebb367ba","nodeKey":"write_foundry_tests","submissionHash":"b78839171a74ec80eef03f8fcfd1f792428a508f79f87e7f3920782c31caff4d","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"8ef174880967688e6596f27d1e9e9872d6bfdaef7281eca5820a2c7a5c6db560","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"8d26cb1a4eaeb75a","findings":[{"citation":"resolved","description":"Not a code defect: the chunk is correct and passes the protected scan (.imd/reads/protected/evm_contracts/Contracts.protected.t.sol:44-48, which skips `op - 0x5f` bytes after every PUSH). It is a verification note for the admission step. FrenArtChunk4's runtime contains 234 bytes equal to 0xF2/0xF4/0xFF (CALLCODE/DELEGATECALL/SELFDESTRUCT), every one of them inside a PUSH32 frame. Every chunk deployed so far (FrenArtChunk1 and FrenArtChunk2 at 0xa92dAcfF6d6fcC218ADe20eD24857376BD8eBE81 / 0x9666A481e20F1dB59EEbD6c43D11Ae3505468c92, confirmed on mainnet to carry exactly CHUNK_HASHES[0..1]) and FrenArtChunk3 contain zero such bytes anywhere, so they pass any scan whether or not it skips PUSH data. Launch 819 therefore gives no evidence that the control-plane scan (apps/control-plane/src/launch/admission.ts, not in this repository) implements the same PUSH-skipping as the protected test. If that scan is a plain byte scan, or skips PUSH data differently, launch 2 is rejected at admission (no funds at risk; the launch simply does not happen). Evidence needed before submitting launch 2: confirm the production admission scan is byte-for-byte the protected test's loop (start at offset 0, STOP at byte 0 is not a PUSH, `j += op - 0x5f; continue`). Chunk 7 in launch 3 (23 such bytes, all framed) depends on the same property.","line":1162,"path":"src/FrenArtChunks.sol","reproduction":"forge test: deploy `new FrenArtChunk4()` and read `.code` (21,187 bytes). Count bytes in {0xf2,0xf4,0xff} without PUSH skipping: 234. Run the protected loop from Contracts.protected.t.sol:44-48: 0 hits. Repeat for FrenArtChunk1/2/3/5/6: 0 and 0 (no dependence on PUSH skipping). Expected for launch 2 to be admitted: the production scan reports 0 for chunk 4. Actual if the production scan does not skip PUSH data: 234 hits, launch 2 refused. The unframed art of chunk 4 (strip the STOP byte, then drop every 33rd byte starting at offset 1) scanned as a plain code blob also yields 234 hits, which is why the generator framed it.","severity":"info","snippet":"contract FrenArtChunk4 {","title":"FrenArtChunk4 is the first launched contract whose admission depends on the production scan skipping PUSH data; launch 819 never exercised that path"},{"citation":"resolved","description":"By design the constructor returns the art literal as the contract's code, so solc's `deployedBytecode` for FrenArtChunk3 and FrenArtChunk4 is the 16-byte revert stub `0x5f80fdfea164736f6c6343000825000a` (with solc 0.8.37, the version auto-detected here), while the deployed code is 23,479 and 21,187 bytes with hashes d73ecfd9…c9a8 and 54bd89d9…1a49b. The deployed code and its hash are compiler-independent (verified: the same hashes with the auto-detected 0.8.37 as FrenArtIndex records), but the creation bytecode is not: FrenArtChunk3's initcode is 27,878 bytes with solc 0.8.37 and 28,320 bytes with the compiler used in ADAPTATION.md, so the CREATE2 address prediction and the attestation's creation-bytecode hash are only reproducible with the exact solc the verifier used (foundry.toml has `auto_detect_solc = true` with `pragma ^0.8.26`). Consequences to plan for, none of which block deployment: (1) any service step that compares the artifact's runtime hash to on-chain code will report a mismatch for these two contracts; (2) standard explorer verification compares runtime bytecode and will not verify them; Sourcify reports `match: null` for the launch-819 chunk at 0xa92dAcfF6d6fcC218ADe20eD24857376BD8eBE81 today. Evidence/handling needed: verify by creation-bytecode match (Sourcify `creationMatch` with the factory's creation transaction, or Etherscan's creation-input verification) and pin the solc version used for the attested build. The protected floor itself is unaffected since it deploys the initcode and reads the real code.","line":1155,"path":"src/FrenArtChunks.sol","reproduction":"`forge build` then compare out/FrenArtChunks.sol/FrenArtChunk3.json `deployedBytecode.object` (0x5f80fdfea164736f6c6343000825000a, 16 bytes) with the code of a deployed FrenArtChunk3 (23,479 bytes, keccak256 d73ecfd95e853d3bf20224d02e30889477ac2627bc1970c5e6b0ca5ef202c9a8). Expected by a runtime-bytecode verifier: equal. Actual: different in length and content. `type(FrenArtChunk3).creationCode.length` is 27,878 under solc 0.8.37 versus 28,320 reported in ADAPTATION.md under another solc, while `keccak256(deployed.code)` is identical under both.","severity":"info","snippet":"            return(add(code, 32), mload(code))","title":"Compiled runtime artifact (16 bytes) never matches the deployed code of FrenArtChunk3/4; explorer and runtime-hash verification need creation-bytecode matching"}],"hash":"4fd80628130ad43f1d1b63269a313ca73ce380bc5efee65ace9761ad151017f3","nodeId":"2fe869d2-6004-4070-be77-29fcfd669d3f","outcome":"completed","summary":"The review is complete. The findings file holds two informational notes and no defects; the working tree is clean apart from it.\n\n**Result: no defect in the launch 2 deliverable.** FrenArtChunk3 and FrenArtChunk4 deploy exactly as the repository states, and nothing in their control flow can fail against the protected floor.\n\nWhat I verified, independently of the repository's own tests:\n\n- **Bytes and hashes.** Deployed through a CREATE2 probe identical to the protected harness, chunk 3 is 23,479 bytes and chunk 4 is 21,187 bytes, with keccak256 and `codehash` equal to entries 2 and 3 of `CHUNK_HASHES`. Both start with STOP, and chunk 4 has 642 complete PUSH32 frames plus six zero padding bytes.\n- **Art content.** All 36 index entries that point into chunks 3 and 4 match the art kit binaries byte for byte after unframing, and chunk 3's art is consumed to its last byte.\n- **Constructor control flow.** No arguments, nonpayable (a 1 wei CREATE2 reverts), initcode 27,878 and 25,852 bytes under the 49,152 limit, runtime under 24,576, first byte not 0xEF. Calling either contract with any data or value returns nothing. The compiled ABI confirms an argument-free constructor.\n- **Admission scan.** Both pass the protected opcode scan. Chunk 3 contains zero refused bytes at all; chunk 4 contains 234, all inside PUSH32 data.\n- **Gas.** The launch 2 model is about 10.08M gas against the 16.78M transaction cap, consistent with my own estimate of the code deposit, creation and calldata charges.\n- **Prior launch.** Both launch 819 addresses on mainnet carry exactly the hashes in the index, and the repository's fork test passes against a public RPC with chunks 3 to 7 deployed locally.\n\nThe two informational notes, both verification items for the service rather than code changes:\n\n1. **Chunk 4 is the first contract whose admission relies on PUSH skipping.** Every chunk launched so far has no refused byte anywhere, so launch 819 proves nothing about how the production scan handles PUSH data. If that scan differs from the protected test's loop, launch 2 is refused with no loss. Confirming the scan before submission removes the risk.\n2. **The compiler's runtime artifact never matches the deployed code.** The constructor returns the art, so the artifact runtime is a 16-byte stub and runtime-based explorer verification cannot succeed. Sourcify shows no match for the launch 819 chunk today. Creation-bytecode matching and pinning the solc version used for the attested build are the remedy, since initcode length varies by compiler while the deployed hash does not.\n\nCoverage rows:\n\n| Entry point | Status | Reason |\n| --- | --- | --- |\n| FrenArtChunk3 constructor | holds | Traced value check, memory return, size limits, exact runtime and hash |\n| FrenArtChunk4 constructor | holds | Same, plus frame structure and padding |\n| Chunk 3 and 4 runtime (any call) | holds | STOP at byte 0, returns empty, no state; sent ETH is unrecoverable but only by the sender's own action |\n| FrenRenderer constructor | holds | Code hash loop accepts these two chunks and rejects others or reordering |\n| FrenRenderer `_entry` framed path | holds | Offset and frame arithmetic checked for chunk 4; outputs match reference and launch renderer |\n| FrenRenderer view functions | holds | Outside my area; read-only, no state, covered by reference equality tests |\n\nNot reached: the control-plane admission and deployer code, which are not in this repository, and Slither or Mythril, which are not installed. The scratch tests were deleted after use.","treeHash":null,"usage":{"cachedInputTokens":964653,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":29629,"runtime":"claude","turns":32,"wallClockMs":444178}},{"artifacts":[],"attempt":1,"bundleHash":"d77bb62fc42472810c100591968e0c9615f5420ef0820a9dec32b2785e3a81d2","device":"19ed076a8c002c03","findings":[],"hash":"50641eaac12b72f8df5c652d885d8317762ece6adf57cb4e29fc773cf5677fa7","nodeId":"eaf0730d-1a48-43c7-935f-424e53552b86","outcome":"completed","summary":"Completed the adaptation. Art contracts remain unchanged; gas accounting is corrected, with new regression and CREATE2 deployment tests.\n\n`forge build` passed. Tests: 10 passed, 1 fork test skipped without RPC.\n\nChanges and audit results are documented in [ADAPTATION.md](/home/imd/.identitymd/work/99e35c0e-0359-4f96-885e-0414013eaef5/eaf0730d-1a48-43c7-935f-424e53552b86/ADAPTATION.md). No transactions were broadcast.","treeHash":"80bc3c9766c190f8d23506a6c00cb7c4375614c1","usage":{"cachedInputTokens":567168,"inputTokens":67381,"model":"gpt-6-astra","outputTokens":10314,"runtime":"codex","turns":4,"wallClockMs":370451}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"824e6de6196c686f","findings":[{"citation":"resolved","description":"Trust-gap note, not a code defect. FrenArtChunk4's 21,187-byte runtime contains 234 raw bytes equal to 0xF2 (CALLCODE), 0xF4 (DELEGATECALL) or 0xFF (SELFDESTRUCT). They are hidden from the admission scan only because every 32 art bytes are preceded by a 0x7F (PUSH32) byte and the scan skips PUSH immediates. The protected check (.imd/reads/protected/evm_contracts/Contracts.protected.t.sol, test_applicationRuntimeIsPresentBoundedAndHasNoEscapeOpcodes) and test_ChunksPassTheAdmissionScan both skip PUSH data, so chunk 4 passes them. However the four chunks launched or deployable without framing (1, 2, 3, 5, 6) contain zero raw forbidden bytes, so launch #819 passing admission is not evidence that the live control-plane scanner (apps/control-plane/src/launch/admission.ts, not in this tree) skips PUSH data; launch 2 is the first submission whose admission depends on that behaviour. FrenArtChunk3 (23,479 bytes) has zero raw forbidden bytes and passes either way. No funds are at risk: a mismatch would refuse the launch, and the renderer (launch 3) would then be unbuildable until the chunk is re-submitted. Verified independently: chunk 3 and 4 code hashes equal FrenArtIndex.CHUNK_HASHES entries 2 and 3, sizes equal CHUNK_SIZES, both start with STOP, chunk 4 has 642 complete PUSH32 frames with 6 zero padding bytes, and all 36 index entries pointing at chunks 3 and 4 read back byte-identical to script/art/data through the renderer's unframed and framed addressing.","line":1160,"path":"src/FrenArtChunks.sol","reproduction":"Deploy FrenArtChunk4 (no arguments, zero value). Count bytes of its runtime equal to 0xF2/0xF4/0xFF without skipping PUSH immediates: 234. Count them with the protected test's loop (op in 0x60..0x7F skips op-0x5F bytes): 0. Expected under the documented admission semantics (README.md line 12): accepted. Actual if the live scanner counted raw bytes: launch 2 refused with 'forbidden application opcode'. Evidence needed from the service: that the live scanner matches the protected test's PUSH-skipping loop.","severity":"info","snippet":"/// @notice The frens' art, part 4 of 7: this contract's code is a STOP byte, then 20538 bytes of art in frames: a PUSH32 byte before every 32 (FrenArtIndex.FRAMED)","title":"FrenArtChunk4 passes admission only under PUSH-data-skipping scan semantics; launch 2 is the first launch that depends on them"},{"citation":"resolved","description":"Access-control inventory note, by design. Each chunk's runtime begins with STOP, so every call, with any calldata and any msg.value, succeeds and returns nothing. There is no receive/fallback revert and no withdrawal path, so ETH sent to a chunk address is unrecoverable. Self-harm only: no third party can be made to lose anything, and the chunks hold no roles, storage or privileges. Documented here because it is the only runtime surface the launch 2 contracts expose; no change is required unless the author wants a stray transfer to revert, which would require a different (non-STOP-prefixed) runtime and new code hashes in FrenArtIndex.","line":1498,"path":"src/FrenArtChunks.sol","reproduction":"c3 = new FrenArtChunk3(). (bool ok,) = address(c3).call{value: 1 ether}(''); ok == true and address(c3).balance == 1 ether afterwards; the same for FrenArtChunk4. Expected for an inert data contract: either behaviour is acceptable; actual: value is kept permanently.","severity":"info","snippet":"            return(add(code, 32), mload(code))","title":"Chunk data contracts accept ETH sent to them and have no way to return it"},{"citation":"resolved","description":"Documentation inaccuracy with a provenance implication. With the toolchain in this tree (Forge 1.8.3, auto-detected solc, via_ir, 200 runs) type(FrenArtChunk3).creationCode.length is 27,878 bytes, not 28,320; FrenArtChunk4's 25,852 matches. The runtime bytes and code hashes are compiler-independent (the constructor returns the literal verbatim) and both figures are far below the 49,152-byte EIP-3860 limit, so deployment is unaffected. But the release attestation binds creation-bytecode hashes, and the gas budget in test_LaunchesFitTransactions prices initcode calldata by length, so the launch 2 figures in README.md/ADAPTATION.md (10,084,652 gas) are from a different build than the one in this tree (10,077,470 gas measured now). Whoever attests launch 2 should take the creation bytes from the attested build, not from these documents.","line":41,"path":"ADAPTATION.md","reproduction":"forge test --match-test test_Launch2ThroughCreate2 with a log of type(FrenArtChunk3).creationCode.length prints 27878 (FrenArtChunk4: 25852). Expected per ADAPTATION.md line 41: 28320. forge test --match-test test_LaunchesFitTransactions -vv prints 'launch 2 gas budget (with code deposit): 10077470' against the documented 10,084,652.","severity":"info","snippet":"no arguments; their initcode lengths are 28,320 and 25,852 bytes, below 49,152.","title":"ADAPTATION.md states a FrenArtChunk3 initcode length that this build does not produce"}],"hash":"8213a6f9e5dd4e727c00fc816f07d9ddf3d582c132dbef7fad72136b5d4fa8fd","nodeId":"f26d1c01-9b55-45f0-9c31-bcc3d44654e8","outcome":"completed","summary":"The findings file parses, the scratch tests are gone, and the only untracked items are the ignored findings file and build outputs. Nothing else is needed.\n\nReview of launch 2 (FrenArtChunk3 and FrenArtChunk4) is complete. No defect was found in the assigned area, and the findings file at `.imd-findings.json` holds three informational notes, each with a concrete reproduction.\n\n**What I checked, and the result**\n\n- **Access control.** Both contracts have exactly one entry point, the argument-free non-payable constructor, which returns the art literal as runtime and writes no storage. Creating either with any ETH fails. The runtime is a STOP byte followed by data, so there are no functions, roles, initializers, callbacks or selfdestruct paths. The whole permission model is empty, and nothing in launch 2 depends on who deploys it or in which order.\n- **Trust gap.** The renderer in launch 3 trusts the chunks by code hash, not by address or deployer. Both chunk hashes and sizes match the entries in `FrenArtIndex`, and every one of the 36 index entries pointing at chunks 3 and 4 reads back byte-identical to the art kit through the renderer's own addressing. Launch 819's on-chain chunks 1 and 2 also hash exactly to their index entries, so the static addresses launch 3 will cite are consistent with this tree.\n- **Asymmetry.** Chunk 3 is unframed and chunk 4 framed, which matches the framing bitmask. Chunk 4 has 642 complete PUSH32 frames with six zero padding bytes, and both bounds checks in the renderer's unframed and framed branches hold for every entry. The existing test suite passes, 10 of 10 with the fork test skipped.\n\n**The three informational notes**\n\n1. **Chunk 4's admission depends on PUSH-skipping scan semantics.** It carries 234 raw bytes that read as forbidden opcodes, hidden only because the scan skips PUSH immediates. The protected test skips them, so the launch passes the check this task is judged by. But no chunk launched so far had any raw forbidden bytes, so launch 819 is not evidence that the live control-plane scanner behaves the same. A mismatch refuses the launch and risks no funds.\n2. **The chunks accept and keep ETH sent to them.** A value call to either chunk succeeds and the ETH is unrecoverable. Self-harm only and inherent to a STOP-prefixed data contract, recorded because it is the only runtime surface.\n3. **ADAPTATION.md's initcode figure for chunk 3 does not match this build.** This tree produces 27,878 bytes rather than the documented 28,320, and the launch 2 gas budget measures slightly lower than documented. Runtime bytes and hashes are unaffected, but the attestation should take creation bytes from the attested build rather than from the documents.\n\n**Outside my area, for the judge.** The README gives a mainnet address for the frens contract, and that address currently holds no code. That is consistent with the README describing a future deployment, and it does not affect launch 2.","treeHash":null,"usage":{"cachedInputTokens":1130151,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":21170,"runtime":"claude","turns":24,"wallClockMs":371967}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"8eebc53449bafe7b","findings":[{"citation":"resolved","description":"Not a code defect; a verification gap for the admission step. FrenArtChunk4's 21,187-byte runtime holds 234 raw bytes equal to 0xF2 (CALLCODE), 0xF4 (DELEGATECALL) or 0xFF (SELFDESTRUCT). Every one sits inside a PUSH32 frame (STOP at byte 0, then 642 frames of 0x7F + 32 bytes, 6 zero padding bytes at the end), so the protected scan (.imd/reads/protected/evm_contracts/Contracts.protected.t.sol lines 44-48, which does `j += op - 0x5f` after any PUSH) and test_ChunksPassTheAdmissionScan both report 0 hits. All chunks admitted so far (launch #819: FrenArtChunk1 at 0xa92dAcfF6d6fcC218ADe20eD24857376BD8eBE81 and FrenArtChunk2 at 0x9666A481e20F1dB59EEbD6c43D11Ae3505468c92, whose on-chain code hashes equal CHUNK_HASHES[0] and [1]) and FrenArtChunk3 contain zero such bytes anywhere, so launch #819 is not evidence that the production scanner in apps/control-plane/src/launch/admission.ts (not in this tree) skips PUSH data the same way. If it counts raw bytes, launch 2 is refused at admission; no funds are at risk and the chunk cannot be changed (the renderer only accepts hash 54bd89d9…1a49b). Chunk 7 in launch 3 (23 framed forbidden bytes) depends on the same property. Evidence needed before submission: confirmation that the production scan equals the protected test's loop.","line":1162,"path":"src/FrenArtChunks.sol","reproduction":"Parse FrenArtChunk4's hex literal (src/FrenArtChunks.sol lines 1165-1496) or deploy `new FrenArtChunk4()` and read `.code`: length 21187, keccak256 0x54bd89d96a8e4b1a1530687bb8442321920166014b5b7a89a414bae379f1a49b = FrenArtIndex.CHUNK_HASHES[3]. Count bytes in {0xf2,0xf4,0xff} with a plain byte scan: 234. Run the protected loop (skip op-0x5f bytes after any 0x60..0x7f): 0. Same two counts for FrenArtChunk1/2/3/5/6: 0 and 0; FrenArtChunk7: 23 and 0. Expected for admission under README.md line 12-15 semantics: 0 hits, accepted. Actual under a raw byte scan: 234 hits, launch 2 refused.","severity":"info","snippet":"contract FrenArtChunk4 {","title":"FrenArtChunk4 is the first launched contract whose admission depends on the scanner skipping PUSH immediates (merged: audit_permissions + audit_flow)"},{"citation":"resolved","description":"By design and self-harm only. Each chunk's runtime is a STOP byte followed by art, so any CALL with any calldata and any msg.value succeeds and returns nothing. There is no receive/fallback revert, no owner, no SELFDESTRUCT (forbidden by admission), so ETH sent to FrenArtChunk3 or FrenArtChunk4 after deployment is unrecoverable. The constructors themselves are nonpayable (test_ConstructorsRejectOneWeiAndMaximumValue) and the launch sends zero ETH, so deployment is unaffected. No third party can be made to lose anything. Documented as the only runtime surface these contracts expose; changing it would require a non-STOP-prefixed runtime and new code hashes in FrenArtIndex, which the task forbids. README.md line 6 ('calling it does nothing') could add 'and keeps any ETH sent'.","line":1498,"path":"src/FrenArtChunks.sol","reproduction":"Foundry test on this tree: `address c3 = address(new FrenArtChunk3()); (bool ok,) = c3.call{value: 1 ether}(\"\");` gives ok == true and c3.balance == 1 ether; `address(new FrenArtChunk4()).call{value: 1 ether}(hex\"f2f4ff\")` likewise succeeds and the balance stays. Expected for an inert data contract: either revert or documented sink; actual: value is kept permanently with no code path that can move it.","severity":"info","snippet":"            return(add(code, 32), mload(code))","title":"Chunk data contracts accept ETH sent to them and have no way to return it (merged: audit_permissions + audit_economics)"},{"citation":"resolved","description":"By design the constructor returns the art literal as the contract's code, so the solc artifact's deployedBytecode for FrenArtChunk3 and FrenArtChunk4 is a 16-byte revert stub (0x5f80fdfea164736f6c634300081a000a with the solc 0.8.26 auto-detected in this tree), while the deployed code is 23,479 and 21,187 bytes with hashes d73ecfd9…c9a8 and 54bd89d9…1a49b. Any service or explorer step that compares the artifact's runtime bytecode to on-chain code will report a mismatch for these two contracts; the protected floor is unaffected since it deploys the initcode and reads the real code. The creation bytecode, which the release attestation binds, depends on the compiler that foundry.toml auto-detects: here solc 0.8.26 gives 28,320 and 25,852 bytes, matching ADAPTATION.md line 41 and the 10,084,652-gas launch 2 budget in README.md; a worker with a different solc installed produces different initcode bytes and a different CREATE2 address. The audit_permissions finding that ADAPTATION.md states a wrong initcode length did not reproduce in this tree (it was measured under another solc) and is dropped. Handling needed: pin or record the solc used for the attested build and verify by creation-bytecode match.","line":1155,"path":"src/FrenArtChunks.sol","reproduction":"`forge build` (solc 0.8.26 auto-detected here), then compare out/FrenArtChunks.sol/FrenArtChunk3.json deployedBytecode.object (0x5f80fdfea164736f6c634300081a000a, 16 bytes) with the code of a deployed FrenArtChunk3 (23,479 bytes, keccak256 0xd73ecfd95e853d3bf20224d02e30889477ac2627bc1970c5e6b0ca5ef202c9a8, verified with cast keccak over the parsed literal). Expected by a runtime-bytecode verifier: equal; actual: different in length and content. bytecode.object lengths: 28,320 (chunk 3) and 25,852 (chunk 4).","severity":"info","snippet":"            return(add(code, 32), mload(code))","title":"Compiled runtime artifact (16 bytes) never matches the deployed code of FrenArtChunk3/4; runtime-bytecode verification must use creation-bytecode matching"},{"citation":"resolved","description":"The README states the frens contract exists at this address and that its owner will point it at this renderer after launch 3. On Ethereum mainnet at block 26,135,430 the address has no code and nonce 0. This does not affect FrenArtChunk3/FrenArtChunk4 (they reference nothing) and may mean the frens have not launched yet or the address is a planned CREATE2 address, but the statement is not verifiable today and the hand-off described for launch 3 should not be taken as given. By contrast the launch #819 chunk addresses in test/OnChainChunks.fork.t.sol do have code whose keccak256 equals CHUNK_HASHES[0] and [1].","line":25,"path":"README.md","reproduction":"`cast code 0x69004fEd3d8a34FFA952d15A128f74D8340fa79d --rpc-url https://ethereum-rpc.publicnode.com` returns `0x` (expected: non-empty runtime); `cast nonce` returns 0; block number 26,135,430 at the time of the check. `cast code 0xa92dAcfF6d6fcC218ADe20eD24857376BD8eBE81 | cast keccak` returns 0xf86a2dec…2d4b = CHUNK_HASHES[0].","severity":"info","snippet":"The frens contract (`IMD6900Frens`, 0x69004fEd3d8a34FFA952d15A128f74D8340fa79d on Ethereum) draws through whatever","title":"README names an IMD6900Frens mainnet address that currently has no code"}],"hash":"a2e278745bde897f04a486b514b007b5ff1ba63a071857fde08d67b93007450c","nodeId":"e3aebf5c-4ae5-472c-95bd-5c88151a918d","outcome":"completed","summary":"The review is complete. The findings file holds four informational findings and no defects that would open a revision.\n\n**What I verified against the code**\n\n- Both chunks' parsed literals hash to the index entries. Chunk 3 is 23,479 bytes with hash d73ecfd9…c9a8 and chunk 4 is 21,187 bytes with hash 54bd89d9…1a49b, both starting with STOP. Chunk 4 has 642 complete PUSH32 frames.\n- The full suite passes, including the CREATE2 rehearsal, the admission scan, the nonpayable constructor checks and the renderer's unframed reads of every launch-2 layer.\n- The launch manifest lists FrenArtChunk3 then FrenArtChunk4 with no arguments, as the brief requires.\n\n**Specialist findings, settled**\n\n- Kept and merged into one: chunk 4 carries 234 raw CALLCODE/DELEGATECALL/SELFDESTRUCT bytes that only PUSH-skipping scans hide. All earlier admitted chunks have zero such bytes, so launch 819 proves nothing about the production scanner. This is a verification gap for the admission service, not a code defect.\n- Kept and merged into one: both chunks accept and permanently keep any ETH sent after deployment. Self-harm only, by design of a STOP-prefixed runtime.\n- Kept: the compiled runtime artifact is a 16-byte stub that never matches the deployed code, so explorer or runtime-hash verification needs creation-bytecode matching.\n- Kept: the frens address in the README has no code and nonce 0 on mainnet at block 26,135,430.\n- Dropped: the claim that ADAPTATION.md states a wrong initcode length. In this tree the auto-detected solc is 0.8.26, the initcode is 28,320 bytes and the launch-2 budget is 10,084,652 gas, both matching the documents. The specialist measured under a different solc, which I noted inside the artifact finding instead.\n\n**My own pass** found nothing further. The two contracts have no storage, roles, callbacks or executable code beyond STOP, the runtime and initcode sizes are within EIP-170 and EIP-3860, and the renderer's framed addressing recovers every chunk-4 layer byte-identically.\n\nThe scratch test I used for the ETH check was removed, so only the findings file differs from the tree.","treeHash":null,"usage":{"cachedInputTokens":665565,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":11501,"runtime":"claude","turns":11,"wallClockMs":274714}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"cd8076510aad8b8e","findings":[{"citation":"resolved","description":"The test measures each launch with gasleft() around an external call that performs the CREATEs. Under forge (1.8.3, with and without --isolate) that measurement does not include the 200 gas/byte code-deposit cost of the contracts created, nor realistic CREATE costs: the suite logs 1,000,622 / 957,524 / 1,295,967 gas for the three launches, while on Ethereum the code deposit alone for launch 2 (FrenArtChunk3 23,479 bytes + FrenArtChunk4 21,187 bytes) is 200 * 44,666 = 8,933,200 gas. A scratch test creating FrenArtChunk3 alone was metered at 2,994 gas by forge. The assertion `total < 2^24 * 95 / 100` therefore passes for any chunk set, including one that exceeds the cap, and the README's quoted 10.7M / 10.0M / 13.9M figures are not what this test measures. Recomputed by hand for launch 2: 21,000 base + 2 * 32,000 CREATE + about 3,400 initcode-word cost + 8,933,200 deposit + at most 16 * (28,320 + 25,852) = 866,752 calldata + factory overhead, about 9.9M gas, which still fits under the 16,777,216 cap, so the launch itself is not at risk; only the test's guarantee is. Suggested fix: compute the bound from the known cost model (200 * runtime size per contract + 32,000 per CREATE + 2 gas per initcode word + calldata) instead of gasleft(), or assert on numbers measured on a real client.","line":147,"path":"test/FrenRenderer.t.sol","reproduction":"Run `forge test --match-test test_LaunchesFitTransactions -vv`: it logs `launch 2 gas (with calldata): 957524` and passes. Compare with the deployed code sizes the same suite exposes (`chunks[2].code.length` = 23479, `chunks[3].code.length` = 21187): 200 * (23479 + 21187) = 8,933,200 gas of code deposit that a mainnet transaction must pay but the logged total does not contain. Expected: the test's total for launch 2 is roughly 9.9M. Actual: 957,524, under 1/9 of the real cost, so the `assertLt(total, TX_CAP * 95 / 100)` on line 149 cannot fail for any realistic input.","severity":"low","snippet":"            uint256 total = launchGas[i] + 21_000 + 16 * launchInitBytes[i];","title":"test_LaunchesFitTransactions asserts a Foundry-metered gas figure that omits the code-deposit cost, so the EIP-7825 check is vacuous"},{"citation":"resolved","description":"Contracts read in full: FrenArtChunk3 and FrenArtChunk4 (the launch-2 deliverable), FrenArtChunk1, 2, 5, 6, 7, FrenArtIndex and FrenRenderer (src/), the generator script/art/chunks.py, test/FrenRenderer.t.sol, test/OnChainChunks.fork.t.sol, and the protected floor .imd/reads/protected/evm_contracts/Contracts.protected.t.sol. Not reachable in this environment (no RPC, no network): the already-deployed FrenArtChunk1 (0xa92dAcfF6d6fcC218ADe20eD24857376BD8eBE81) and FrenArtChunk2 (0x9666A481e20F1dB59EEbD6c43D11Ae3505468c92) from IMD launch 819, the IMD6900Frens contract (0x69004fEd3d8a34FFA952d15A128f74D8340fa79d), and the control-plane admission code (apps/control-plane/src/launch/admission.ts) that the README describes; the fork test was skipped. Checks performed on the chunk bytes parsed independently from the Solidity hex literals (Python + `cast keccak`): (1) each chunk's runtime starts with a STOP byte (0x00); (2) runtime lengths 23,479 and 21,187 equal FrenArtIndex.CHUNK_SIZES and are under the EIP-170 limit of 24,576; initcode lengths 28,320 and 25,852 are under the EIP-3860 limit of 49,152 the protected probe enforces; (3) keccak256 of each chunk's runtime equals the corresponding 32 bytes of FrenArtIndex.CHUNK_HASHES, for all seven chunks, so FrenRenderer's constructor accepts these exact contracts; (4) the protected scan (PUSH data skipped, 0xf2/0xf4/0xff refused) reports zero hits on every chunk; chunks 1, 2 and 3 contain no raw 0xf2/0xf4/0xff byte at all, so they do not depend on PUSH alignment; chunk 4 is framed (FRAMED bit 3 set) with a 0x7f byte at every 33rd position after the STOP byte, 642 frames, last frame zero-padded by 6 bytes, and its unframed art contains 234 such bytes, which is why framing is needed; (5) all 70 FrenArtIndex entries (69 layers + palette) have non-zero length, lie inside their chunk's art, and the bytes they address in the (de-framed) chunks are identical to script/art/data/layers/*.bin and palette.bin; chunk 3 holds entries 25..36, chunk 4 entries 37..60; (6) FrenRenderer._entry's framed read (first = off/32, frames = (off+len-1)/32 - first + 1, bound 1 + (first+frames)*33 <= code.length) covers every chunk-4 entry including the last, whose end at 20,538 gives exactly the 21,187-byte runtime. The chunk constructors take no arguments, are nonpayable, hold no storage, have no owner, and the deployed runtime contains no executable code beyond STOP: no DELEGATECALL, CALLCODE, SELFDESTRUCT, proxy, initializer, mint, pause or seizure surface exists. The project suite (`forge test`) passes: 7 passed, 1 skipped (fork). The renderer's combo range checks, table indices (FACE_TABLE max index 38 of 39, TABLES max 28 of 29) and layer offsets (backgrounds at 59..68, items 44..58, hats 42..43, coats 39..41, palette 69) were traced and are in bounds for every accepted combo; tokenURI reads at about 10.3M gas (view only).","line":784,"path":"src/FrenArtChunks.sol","reproduction":"Not a defect. To reproduce the coverage claims: `forge test -vv` (7 passed, fork test skipped without MAINNET_RPC_URL); parse the hex literal of FrenArtChunk3 / FrenArtChunk4 from src/FrenArtChunks.sol, hash with `cast keccak`, and compare to bytes 64..95 and 96..127 of FrenArtIndex.CHUNK_HASHES (0xd73ecfd9...c9a8 and 0x54bd89d9...a49b); byte 0 of each is 0x00; for chunk 4 every byte at index 1 + 33*k is 0x7f for k in 0..641.","severity":"info","snippet":"contract FrenArtChunk3 {","title":"Coverage: FrenArtChunk3 and FrenArtChunk4 verified byte-for-byte against FrenArtIndex, the art kit and the admission scan; no defect found in the launch-2 contracts"}],"hash":"b1450f2b559a8e418ae58c0157999fc8627cb8d52445ef44b9e96fea4cb68a00","nodeId":"221808ab-a7cb-40ab-8d2f-caa9e8f18a93","outcome":"completed","summary":"The review is complete and the findings are in `.imd-findings.json`. The launch-2 contracts are clean. The only defect found is in the test suite.\n\n**What I read**\n\n- FrenArtChunk3 and FrenArtChunk4 in full, plus the other five chunks, FrenArtIndex, FrenRenderer, the generator script, both test files and the protected floor test.\n- Not reachable: the mainnet copies of chunks 1 and 2 from launch 819, the IMD6900Frens contract, and the control-plane admission code. There is no RPC or network here, and the fork test skipped.\n\n**What I verified on chunks 3 and 4**\n\n- Independently parsed the hex literals and hashed them with `cast keccak`. Both hashes match the entries in FrenArtIndex, so the renderer constructor accepts these exact contracts.\n- Each runtime starts with a STOP byte, sizes match the index constants, and both runtime and initcode sit under the EIP-170 and EIP-3860 limits the protected probe enforces.\n- The protected admission scan reports zero hits on every chunk. Chunk 3 contains no raw forbidden byte at all. Chunk 4 is correctly framed with a PUSH32 byte at every 33rd position across 642 frames, and its unframed art holds 234 forbidden bytes, which justifies the framing.\n- All 70 index entries address bytes identical to the art kit's layer and palette files. Chunk 3 holds entries 25 to 36 and chunk 4 entries 37 to 60. The renderer's framed read covers the last chunk-4 entry exactly.\n- No constructor arguments, no storage, no owner, no executable code beyond STOP. Nothing the launch forbids is present. The project suite passes with 7 tests and one skipped fork test.\n\n**Findings written**\n\n- **Low, test coverage.** The transaction-cap test in `test/FrenRenderer.t.sol` uses Foundry-metered gas that omits code-deposit cost. It logs about 957k gas for launch 2 while the code deposit alone is about 8.9M on Ethereum. Hand recomputation gives roughly 9.9M, still under the 2^24 cap, so the launch is safe but the test cannot fail. Reproduction and a suggested fix are in the file.\n- **Info.** A coverage entry recording which contracts were read, which were unreachable, and the exact checks that passed.\n\nNo critical or high findings, so no proof tests were attached. Scratch tests and the snapshots directory they produced were removed, leaving the tree unchanged apart from the findings file.","treeHash":null,"usage":{"cachedInputTokens":916528,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":21352,"runtime":"claude","turns":22,"wallClockMs":727609}},{"artifacts":[],"attempt":1,"bundleHash":"1f56d6a8cc039aa82ce1dc35bde92372709004bf09163d99b30aeadc2c778bb8","device":"0e53ef0bd01824cb","findings":[],"hash":"b78839171a74ec80eef03f8fcfd1f792428a508f79f87e7f3920782c31caff4d","nodeId":"281b492b-daff-4511-a1c1-aa3c6fdb769a","outcome":"completed","summary":"Added tests under `test/` covering exact art bytes, framing, deployment failures, corrupted-chunk rejection, and ETH/code invariants.\n\nValidation passed:\n- `forge build --offline`\n- `forge test --offline`: 27 passed, 0 failed; existing RPC-dependent test skipped.\n- Invariants: 16,384 randomized calls.\n\nNo defects found. Only `test/` changed.","treeHash":"21d52a31ded29f666ac08a58a3971e74e82b9d46","usage":{"cachedInputTokens":753920,"inputTokens":63717,"model":"gpt-6-astra","outputTokens":12579,"runtime":"codex","turns":6,"wallClockMs":458961}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"723b11f958c65250","findings":[],"hash":"bcb5f09055980070a24ad778001fedfbdd460de85449866439b1091294d54174","nodeId":"e5aa6db8-ef2e-4cda-9d83-0162e34b31a6","outcome":"completed","summary":"**Result: no defects found in the Math Precision, Boundary or Numerical Gap area for launch 2.** The findings file at `.imd-findings.json` holds `{\"findings\":[]}`. The scratch harness I used lives under `test/scratch/` and touches nothing else.\n\n**What I verified, with concrete numbers**\n\n- **Bytes and hashes.** Keccak of the hex literals in the source for FrenArtChunk3 and FrenArtChunk4 equals the index's third and fourth entries. On-chain code size after deployment is 23,479 and 21,187 bytes, matching the declared sizes and the EIP-170 cap of 24,576. Initcode is 28,320 and 25,852 bytes, under 49,152.\n- **Index arithmetic for the 36 entries in these two chunks.** Every offset and length is a 16-bit value, every entry ends inside its chunk, and chunk 3's last entry and chunk 4's last entry end exactly at their code length. Decoding each entry, through the renderer's own read path and independently in Python, reproduces the art kit binaries byte for byte.\n- **Framed read arithmetic for chunk 4.** The frame count formula gives 642 frames and 6 zero padding bytes, which is what the code contains. The flat buffer is always at least offset-within-frame plus length, so the final copy cannot over-read. The bound check is tight: truncating chunk 4's code by one byte makes the last entry revert with the Missing error, and the untouched code reads it cleanly.\n- **Admission scan.** Both chunks pass the protected scan with zero hits. Chunk 3 contains no 0xF2, 0xF4 or 0xFF byte at all, so it does not depend on PUSH skipping. Chunk 4's 234 refused bytes all sit inside PUSH32 data.\n- **Launch 2 gas boundary.** The budget of 10,084,652 gas, including the 8,933,200 code deposit, sits under 95 percent of the 2^24 transaction cap. Memory expansion and calldata floor costs do not change this.\n- **Renderer trait math that touches these chunks.** Face, coat, hat, item and background indices stay inside the 70-entry index and the 29-byte colour table for every combo the guards admit.\n\n**Coverage rows**\n\n| Entry point | Status | Reason |\n| --- | --- | --- |\n| FrenArtChunk3 constructor | holds | Argument-free, returns the literal; deployed bytes and hash verified |\n| FrenArtChunk4 constructor | holds | Same; framing complete, 642 frames, padding correct |\n| FrenArtChunk3 / 4 runtime call (any calldata) | holds | Leading STOP, returns nothing, tested with empty and ERC-20-shaped calldata |\n| FrenRenderer constructor hash check | holds | Rejects reordered or wrong chunks; codehash compare is exact |\n| Renderer `_entry` unframed and framed paths | holds | Every entry in chunks 3 and 4 round-trips; boundary tight at both chunk ends |\n| Test gas budget for launch 2 | holds | Deposit, creation, initcode-word and calldata terms correct; cap is 2^24 |\n| Deployed launch #819 chunks on mainnet | unreached | No RPC available; fork test skipped |\n\n**One trust note, not a defect.** The chunk runtime is a bare STOP, so ETH sent to a chunk address is accepted and unrecoverable. This is inherent to any data contract and has no code path to fix.","treeHash":null,"usage":{"cachedInputTokens":906270,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":17754,"runtime":"claude","turns":23,"wallClockMs":695984}},{"artifacts":[],"attempt":1,"bundleHash":"04ec66b5eda58aea7041e0d928a46b45db01f24040e376f82564c41d8c0cd7fe","device":"29ea8835baa3dfe1","findings":[],"hash":"e54c1bb72e8d158c077c63e760f919bfc7e6d4b2bae1569a9c19779bc6eec587","nodeId":"d57af077-3604-4e99-851d-31ba4cb00eed","outcome":"completed","summary":"Created [launch.json](/home/seat/.identitymd/work/99e35c0e-0359-4f96-885e-0414013eaef5/d57af077-3604-4e99-851d-31ba4cb00eed/launch.json) with `FrenArtChunk3`, then `FrenArtChunk4`, both with empty constructor arguments.\n\nManifest and compiled ABI checks passed. `forge build` succeeded; `forge test` reported 10 passed, 0 failed, and 1 fork test skipped because no RPC was configured.\n\nOnly `launch.json` changed.","treeHash":"4622046d879db113e0107889d985eec3f263c9bc","usage":{"cachedInputTokens":275840,"inputTokens":31876,"model":"gpt-6-astra","outputTokens":2479,"runtime":"codex","turns":3,"wallClockMs":98596}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"8c9c4986ca881107","findings":[{"citation":"resolved","description":"Each chunk's runtime code is a STOP byte followed by art, so a plain CALL with value succeeds (STOP, no revert) and the ETH is credited to the chunk. The contracts have no functions, no owner and no SELFDESTRUCT (forbidden by admission), so value sent there can never be moved again. The only loser is the sender (self-harm), the launch sends zero ETH, and the behaviour is identical to the SSTORE2-style pointers of the launch renderer (test/ref/FrenRendererRef.sol), so this is a documented trust property rather than a defect: README's 'Calling it does nothing' is accurate, but 'and keeps any ETH sent' would be more precise. No change to the generated art contracts is recommended; the renderer only accepts these exact code hashes. Area: Economic Security (value flows / sentinel-like addresses), Invariant (no withdrawal path for any balance).","line":784,"path":"src/FrenArtChunks.sol","reproduction":"Deploy FrenArtChunk3 (any way, e.g. `address a = address(new FrenArtChunk3());`). Then `(bool ok,) = a.call{value: 1 ether}(\"\");`. Expected for a pure data contract: either revert or a documented sink. Actual (measured in a Foundry scratch test on this tree): ok == true, a.balance == 1 ether, and there is no code path on the chunk that can send it anywhere. Same for FrenArtChunk4.","severity":"info","snippet":"contract FrenArtChunk3 {","title":"FrenArtChunk3 and FrenArtChunk4 accept and permanently strand any ETH sent to them"},{"citation":"resolved","description":"The README states that the frens contract exists on Ethereum at 0x69004fEd3d8a34FFA952d15A128f74D8340fa79d and that its owner will point it at this renderer after launch 3. On Ethereum mainnet at block ~26,135,373 (public RPC https://ethereum-rpc.publicnode.com) that address has no code, nonce 0 and zero balance. This does not affect FrenArtChunk3/FrenArtChunk4 (they carry no reference to it) and may simply mean the frens have not launched yet or the address is a planned CREATE2 address, but the statement as written is not verifiable today and the judge should not take the frens' existence as given when assessing launch 3's hand-off. Outside the assigned area; reported because the flow-gap guide asks for stated-purpose claims that the chain does not currently support.","line":25,"path":"README.md","reproduction":"`cast code 0x69004fEd3d8a34FFA952d15A128f74D8340fa79d --rpc-url https://ethereum-rpc.publicnode.com` -> `0x` (expected: non-empty runtime). `cast nonce` -> 0, `cast balance` -> 0. By contrast the launch 819 chunk addresses in test/OnChainChunks.fork.t.sol do have code whose keccak256 matches FrenArtIndex.CHUNK_HASHES[0..1] (0xf86a2dec... and 0x8579d215...).","severity":"info","snippet":"The frens contract (`IMD6900Frens`, 0x69004fEd3d8a34FFA952d15A128f74D8340fa79d on Ethereum) draws through whatever","title":"README names an IMD6900Frens mainnet address that currently has no code"}],"hash":"e86f67a719054b656968d4d76b3412a731f7460a3514310eec59e60f21ea0206","nodeId":"440f52c6-2541-487f-88d5-ddfd04299026","outcome":"completed","summary":"The review is complete. Findings are in `.imd-findings.json`, and nothing else in the tree was changed.\n\n**Outcome: no economic, invariant, or flow-gap defect in FrenArtChunk3 or FrenArtChunk4.** The two data contracts hold no value flows, no state, and no dependencies, and their bytes are exactly what the index and the art kit require. Two informational notes are recorded.\n\n**What I verified**\n\n- Every hex literal in `src/FrenArtChunks.sol` was parsed independently and hashed with `cast keccak`. All seven runtime hashes and sizes match the index. Each runtime starts with the STOP byte.\n- All 70 index entries were decoded and compared byte for byte against the art kit layer and palette binaries. They match, and they tile every chunk's art with no gaps. Chunk 3 holds faces 25 to 36. Chunk 4 holds faces 37 and 38, the coats, hats, items, and the first two backgrounds.\n- Chunk 4's framing is complete: 642 PUSH32 frames with six zero pad bytes. The renderer's framed bounds check equals the code length exactly at the last chunk 4 entry, so the boundary holds.\n- The admission scan was re-run over both the runtime and the creation code of chunks 3 and 4, with zero hits. Chunk 3 has no raw forbidden bytes at all. Chunk 4 has 234, all hidden inside frames, so its admission depends on the scanner skipping PUSH data as the protected test does.\n- On mainnet, the launch 819 addresses hold code whose hashes match the index for chunks 1 and 2. The fork test also passed against a public RPC.\n- A CREATE2 rehearsal metered the launch 2 pair at roughly 10M gas including code deposit, well under the transaction cap. Both constructors are nonpayable with no arguments.\n\n**Informational notes recorded**\n\n- The chunks accept and permanently strand any ETH sent to them, since a plain call hits STOP and succeeds. This is self-harm only and matches the launch renderer's own pointers, so it is a trust property to document, not a defect.\n- The README names a mainnet frens contract address that currently has no code, nonce, or balance. This does not touch the chunks but the judge should not assume the frens exist when weighing the launch 3 hand-off.\n\n**Not reached:** the production factory, control-plane scanner, and launch policy are outside the repository, so the protected test served as the reference for both. Chunks 1, 2, 5, 6, and 7 were hash and index verified only.","treeHash":null,"usage":{"cachedInputTokens":929182,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":25494,"runtime":"claude","turns":24,"wallClockMs":471162}}],"verification":[{"checks":[{"durationMs":60750,"exitCode":0,"name":"build","output":"Compiling 35 files with Solc 0.8.30\nSolc 0.8.30 finished in 60.50s\nCompiler run successful!\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/FrenRenderer.sol:62:41\n   │\n62 │             if (cs[k].codehash != want) revert BadArt();\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/FrenRenderer.sol:337:48\n    │\n337 │             if (p.code.length < 1 + off + len) revert Missing();\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/FrenRenderer.sol:346:56\n    │\n346 │         if (p.code.length < 1 + (first + frames) * 33) revert Missing();\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/FrenRenderer.sol:274:22\n    │\n274 │         if (hat > 2) revert Missing();\n    │                      ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:102:60\n    │\n102 │         _draw(back, _entry(faceLayers + 20 + PENDING_BG), -int256(seed % 37), -int256((seed >> 8) % 37), none, 0);\n    │                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:102:80\n    │\n102 │         _draw(back, _entry(faceLayers + 20 + PENDING_BG), -int256(seed % 37), -int256((seed >> 8) % 37), none, 0);\n    │                                                                                ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:109:23\n    │\n109 │             _fren(cv, uint24(combo));\n    │                       ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint24' 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/FrenRenderer.sol:171:54\n    │\n171 │                     bytes memory out = new bytes(j - start);\n    │                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/FrenRenderer.sol:170:21\n    │\n170 │                 if (k == i) {\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:227:35\n    │\n227 │                 bytes1 v = bytes1(uint8(l * 3 / 5));\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/FrenRenderer.sol:253:50\n    │\n253 │         _draw(cv, _entry(faceLayers + 20 + bg), -int256(seed % 37), -int256((seed >> 8) % 37), slot, 0);\n    │                                                  ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:253:70\n    │\n253 │         _draw(cv, _entry(faceLayers + 20 + bg), -int256(seed % 37), -int256((seed >> 8) % 37), slot, 0);\n    │                                                                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:271:79\n    │\n271 │         _draw(cv, _entry(uint8(FrenArtIndex.FACE_TABLE[ch * FACES + face])), -int256(CX), -int256(CY), slot, 0);\n    │                                                                               ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:271:92\n    │\n271 │         _draw(cv, _entry(uint8(FrenArtIndex.FACE_TABLE[ch * FACES + face])), -int256(CX), -int256(CY), slot, 0);\n    │                                                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:272:36\n    │\n272 │         _draw(cv, _entry(f + ch), -int256(CX), -int256(CY), slot, 0);\n    │                                    ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:272:49\n    │\n272 │         _draw(cv, _entry(f + ch), -int256(CX), -int256(CY), slot, 0);\n    │                                                 ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:275:55\n    │\n275 │         if (hat != 0) _draw(cv, _entry(f + 2 + hat), -int256(CX), -int256(CY), slot, 0);\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:275:68\n    │\n275 │         if (hat != 0) _draw(cv, _entry(f + 2 + hat), -int256(CX), -int256(CY), slot, 0);\n    │                                                                    ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:277:57\n    │\n277 │         if (item != 0) _draw(cv, _entry(f + 4 + item), -int256(CX), -int256(CY), slot, 0);\n    │                                                         ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:277:70\n    │\n277 │         if (item != 0) _draw(cv, _entry(f + 4 + item), -int256(CX), -int256(CY), slot, 0);\n    │                                                                      ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:288:25\n    │\n288 │             int256 yy = int256(y) + dy;\n    │                         ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:289:40\n    │\n289 │             bool row = yy >= 0 && yy < int256(N);\n    │                                        ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:297:32\n    │\n297 │                     int256 a = int256(x) + dx;\n    │                                ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:298:36\n    │\n298 │                     int256 b = a + int256(n);\n    │                                    ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:300:29\n    │\n300 │                     if (b > int256(N)) b = int256(N);\n    │                             ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:300:44\n    │\n300 │                     if (b > int256(N)) b = int256(N);\n    │                                            ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:301:36\n    │\n301 │                     uint256 base = uint256(yy) * N;\n    │                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:302:65\n    │\n302 │                     for (int256 xx = a; xx < b; ++xx) cv[base + uint256(xx)] = bytes1(uint8(c));\n    │                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:302:87\n    │\n302 │                     for (int256 xx = a; xx < b; ++xx) cv[base + uint256(xx)] = bytes1(uint8(c));\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/FrenRenderer.sol:317:56\n    │\n317 │         for (uint256 i; i < n; ++i) b[at + i] = bytes1(uint8(v >> (8 * i)));\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[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/FrenRenderer.sol:350:49\n    │\n350 │             extcodecopy(p, add(raw, 32), add(1, mul(first, 33)), mul(frames, 33))\n    │                                                 ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\n","passed":true},{"durationMs":3021,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/OnChainChunks.fork.t.sol:OnChainChunksForkTest\n[SKIP] test_swarmChunksDrawTheReference() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 1.63ms (1.42ms CPU time)\n\nRan 10 tests for test/FrenRenderer.t.sol:FrenRendererTest\n[PASS] test_ChunksPassTheAdmissionScan() (gas: 38663674)\n[PASS] test_GasBudgetRejectsOversizedBatch() (gas: 26330)\n[PASS] test_Launch2GasIncludesCodeDeposit() (gas: 17956)\n[PASS] test_Launch2ThroughCreate2() (gas: 10963543)\n[PASS] test_LaunchesFitTransactions() (gas: 34632)\nLogs:\n  launch 1 gas budget (with code deposit): 10814872\n  launch 2 gas budget (with code deposit): 10077470\n  launch 3 gas budget (with code deposit): 14055980\n\n[PASS] test_MatchesTheReference() (gas: 38337057)\n[PASS] test_RejectsCombosOutsideTheArt() (gas: 11168652)\n[PASS] test_SameAsTheLaunchRenderer() (gas: 1039160244)\n[PASS] test_TakesOnlyThisArt() (gas: 19351)\n[PASS] test_TokenURIIsCheapEnoughToRead() (gas: 10321599)\nLogs:\n  tokenURI gas: 10315624\n\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 2.83s (3.08s CPU time)\n\nRan 2 test suites in 2.83s (2.83s CPU time): 10 tests passed, 0 failed, 1 skipped (11 total tests)\n","passed":true},{"durationMs":173,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":59,\"README.md\":63,\"foundry.toml\":22,\"script/art/chunks.py\":120,\"script/art/data/expected.json\":32,\"script/art/data/facetable.bin\":2,\"script/art/data/layers/bg0.bin\":59,\"script/art/data/layers/bg1.bin\":44,\"script/art/data/layers/bg2.bin\":44,\"script/art/data/layers/bg3.bin\":4,\"script/art/data/layers/bg4.bin\":2,\"script/art/data/layers/bg5.bin\":1,\"script/art/data/layers/bg6.bin\":6,\"script/art/data/layers/bg7.bin\":13,\"script/art/data/layers/bg8.bin\":20,\"script/art/data/layers/bg9.bin\":4,\"script/art/data/layers/coat0.bin\":10,\"script/art/data/layers/coat1.bin\":10,\"script/art/data/layers/coat2.bin\":10,\"script/art/data/layers/face0.bin\":36,\"script/art/data/layers/face1.bin\":29,\"script/art/data/layers/face10.bin\":34,\"script/art/data/layers/face11.bin\":33,\"script/art/data/layers/face12.bin\":36,\"script/art/data/layers/face13.bin\":19,\"script/art/data/layers/face14.bin\":20,\"script/art/data/layers/face15.bin\":20,\"script/art/data/layers/face16.bin\":19,\"script/art/data/layers/face17.bin\":20,\"script/art/data/layers/face18.bin\":19,\"script/art/data/layers/face19.bin\":21,\"script/art/data/layers/face2.bin\":34,\"script/art/data/layers/face20.bin\":20,\"script/art/data/layers/face21.bin\":19,\"script/art/data/layers/face22.bin\":19,\"script/art/data/layers/face23.bin\":20,\"script/art/data/layers/face24.bin\":20,\"script/art/data/layers/face25.bin\":19,\"script/art/data/layers/face26.bin\":23,\"script/art/data/layers/face27.bin\":23,\"script/art/data/layers/face28.bin\":23,\"script/art/data/layers/face29.bin\":23,\"script/art/data/layers/face3.bin\":31,\"script/art/data/layers/face30.bin\":23,\"script/art/data/layers/face31.bin\":23,\"script/art/data/layers/face32.bin\":26,\"script/art/data/layers/face33.bin\":24,\"script/art/data/layers/face34.bin\":23,\"script/art/data/layers/face35.bin\":22,\"script/art/data/layers/face36.bin\":22,\"script/art/data/layers/face37.bin\":24,\"script/art/data/layers/face38.bin\":22,\"script/art/data/layers/face4.bin\":31,\"script/art/data/layers/face5.bin\":29,\"script/art/data/layers/face6.bin\":29,\"script/art/data/layers/face7.bin\":28,\"script/art/data/layers/face8.bin\":29,\"script/art/data/layers/face9.bin\":30,\"script/art/data/layers/hat0.bin\":3,\"script/art/data/layers/hat1.bin\":5,\"script/art/data/layers/item0.bin\":2,\"script/art/data/layers/item1.bin\":1,\"script/art/data/layers/item10.bin\":1,\"script/art/data/layers/item11.bin\":1,\"script/art/data/layers/item12.bin\":1,\"script/art/data/layers/item13.bin\":1,\"script/art/data/layers/item14.bin\":3,\"script/art/data/layers/item2.bin\":3,\"script/art/data/layers/item3.bin\":1,\"script/art/data/layers/item4.bin\":1,\"script/art/data/layers/item5.bin\":2,\"script/art/data/layers/item6.bin\":3,\"script/art/data/layers/item7.bin\":1,\"script/art/data/layers/item8.bin\":1,\"script/art/data/layers/item9.bin\":1,\"script/art/data/manifest.json\":329,\"script/art/data/palette.bin\":7,\"script/art/data/tables.bin\":2,\"script/art/derive_renderer.py\":117,\"src/FrenArtChunks.sol\":2313,\"src/FrenArtIndex.sol\":34,\"src/FrenRenderer.sol\":357,\"test/FrenRenderer.t.sol\":278,\"test/OnChainChunks.fork.t.sol\":37,\"test/ref/FrenRendererRef.sol\":369},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"50641eaac12b72f8df5c652d885d8317762ece6adf57cb4e29fc773cf5677fa7","verifiedTreeHash":"80bc3c9766c190f8d23506a6c00cb7c4375614c1","verifierVersion":"0.1.0+94826a22"},{"checks":[{"durationMs":141037,"exitCode":0,"name":"build","output":"Compiling 37 files with Solc 0.8.30\nSolc 0.8.30 finished in 140.80s\nCompiler run successful!\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/FrenRenderer.sol:62:41\n   │\n62 │             if (cs[k].codehash != want) revert BadArt();\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/FrenRenderer.sol:337:48\n    │\n337 │             if (p.code.length < 1 + off + len) revert Missing();\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/FrenRenderer.sol:346:56\n    │\n346 │         if (p.code.length < 1 + (first + frames) * 33) revert Missing();\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/FrenRenderer.sol:274:22\n    │\n274 │         if (hat > 2) revert Missing();\n    │                      ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:102:60\n    │\n102 │         _draw(back, _entry(faceLayers + 20 + PENDING_BG), -int256(seed % 37), -int256((seed >> 8) % 37), none, 0);\n    │                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:102:80\n    │\n102 │         _draw(back, _entry(faceLayers + 20 + PENDING_BG), -int256(seed % 37), -int256((seed >> 8) % 37), none, 0);\n    │                                                                                ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:109:23\n    │\n109 │             _fren(cv, uint24(combo));\n    │                       ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint24' 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/FrenRenderer.sol:171:54\n    │\n171 │                     bytes memory out = new bytes(j - start);\n    │                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/FrenRenderer.sol:170:21\n    │\n170 │                 if (k == i) {\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:227:35\n    │\n227 │                 bytes1 v = bytes1(uint8(l * 3 / 5));\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/FrenRenderer.sol:253:50\n    │\n253 │         _draw(cv, _entry(faceLayers + 20 + bg), -int256(seed % 37), -int256((seed >> 8) % 37), slot, 0);\n    │                                                  ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:253:70\n    │\n253 │         _draw(cv, _entry(faceLayers + 20 + bg), -int256(seed % 37), -int256((seed >> 8) % 37), slot, 0);\n    │                                                                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:271:79\n    │\n271 │         _draw(cv, _entry(uint8(FrenArtIndex.FACE_TABLE[ch * FACES + face])), -int256(CX), -int256(CY), slot, 0);\n    │                                                                               ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:271:92\n    │\n271 │         _draw(cv, _entry(uint8(FrenArtIndex.FACE_TABLE[ch * FACES + face])), -int256(CX), -int256(CY), slot, 0);\n    │                                                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:272:36\n    │\n272 │         _draw(cv, _entry(f + ch), -int256(CX), -int256(CY), slot, 0);\n    │                                    ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:272:49\n    │\n272 │         _draw(cv, _entry(f + ch), -int256(CX), -int256(CY), slot, 0);\n    │                                                 ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:275:55\n    │\n275 │         if (hat != 0) _draw(cv, _entry(f + 2 + hat), -int256(CX), -int256(CY), slot, 0);\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:275:68\n    │\n275 │         if (hat != 0) _draw(cv, _entry(f + 2 + hat), -int256(CX), -int256(CY), slot, 0);\n    │                                                                    ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:277:57\n    │\n277 │         if (item != 0) _draw(cv, _entry(f + 4 + item), -int256(CX), -int256(CY), slot, 0);\n    │                                                         ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:277:70\n    │\n277 │         if (item != 0) _draw(cv, _entry(f + 4 + item), -int256(CX), -int256(CY), slot, 0);\n    │                                                                      ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:288:25\n    │\n288 │             int256 yy = int256(y) + dy;\n    │                         ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:289:40\n    │\n289 │             bool row = yy >= 0 && yy < int256(N);\n    │                                        ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:297:32\n    │\n297 │                     int256 a = int256(x) + dx;\n    │                                ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:298:36\n    │\n298 │                     int256 b = a + int256(n);\n    │                                    ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:300:29\n    │\n300 │                     if (b > int256(N)) b = int256(N);\n    │                             ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:300:44\n    │\n300 │                     if (b > int256(N)) b = int256(N);\n    │                                            ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:301:36\n    │\n301 │                     uint256 base = uint256(yy) * N;\n    │                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:302:65\n    │\n302 │                     for (int256 xx = a; xx < b; ++xx) cv[base + uint256(xx)] = bytes1(uint8(c));\n    │                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:302:87\n    │\n302 │                     for (int256 xx = a; xx < b; ++xx) cv[base + uint256(xx)] = bytes1(uint8(c));\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/FrenRenderer.sol:317:56\n    │\n317 │         for (uint256 i; i < n; ++i) b[at + i] = bytes1(uint8(v >> (8 * i)));\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[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/FrenRenderer.sol:350:49\n    │\n350 │             extcodecopy(p, add(raw, 32), add(1, mul(first, 33)), mul(frames, 33))\n    │                                                 ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\n","passed":true},{"durationMs":3354,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/OnChainChunks.fork.t.sol:OnChainChunksForkTest\n[SKIP] test_swarmChunksDrawTheReference() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 422.88µs (185.37µs CPU time)\n\nRan 7 tests for test/FrenArtLaunch2.t.sol:FrenArtLaunch2RendererTest\n[PASS] testFuzz_RendererRejectsSameLengthSingleByteCorruption(bool,uint256,uint8) (runs: 128, μ: 349594, ~: 349366)\nLogs:\n  Bound result 1097\n  Bound result 117\n\n[PASS] test_ProductionReaderRecoversEveryLaunch2Layer() (gas: 786227)\n[PASS] test_RendererRejectsChangedStopFrameMarkerAndFinalPadding() (gas: 998206)\n[PASS] test_RendererRejectsMissingOrStopOnlyLaunch2Chunks() (gas: 1868097)\n[PASS] test_RendererRejectsSwappedAndDuplicatedLaunch2Chunks() (gas: 945757)\n[PASS] test_RendererRejectsTruncatedOrExtendedChunks() (gas: 1349085)\n[PASS] test_RendererRejectsUnframedChunk4EvenWithCorrectArt() (gas: 672319)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 20.50ms (26.44ms CPU time)\n\nRan 8 tests for test/FrenArtLaunch2.t.sol:FrenArtLaunch2Test\n[PASS] testFuzz_ArbitraryCalldataAndCallerCannotExecuteArt(bool,address,bytes) (runs: 128, μ: 24460, ~: 24247)\n[PASS] testFuzz_ConstructorsRejectNonzeroValue(bool,uint256) (runs: 128, μ: 5643908, ~: 5880118)\nLogs:\n  Bound result 190526185604104507330753620843992878993057\n\n[PASS] testFuzz_Create2IdentityAndCollisionLeaveBothChunksIntact(bytes32) (runs: 128, μ: 10152269, ~: 10152455)\n[PASS] test_Chunk3ContainsEverySourceByteWithoutFrames() (gas: 321820)\n[PASS] test_Chunk4FramesPreserveEverySourceByteAndZeroPadOnlyTheTail() (gas: 10119183)\n[PASS] test_ConstructorsRejectOneWeiAndMaximumValue() (gas: 22461285)\n[PASS] test_EmptyAndOpcodeLikeCalldataStopWithoutEffects() (gas: 155537)\n[PASS] test_ExactSizesHashesAndDeploymentLimits() (gas: 65124)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 86.30ms (172.70ms CPU time)\n\nRan 10 tests for test/FrenRenderer.t.sol:FrenRendererTest\n[PASS] test_ChunksPassTheAdmissionScan() (gas: 38663674)\n[PASS] test_GasBudgetRejectsOversizedBatch() (gas: 26330)\n[PASS] test_Launch2GasIncludesCodeDeposit() (gas: 17956)\n[PASS] test_Launch2ThroughCreate2() (gas: 10963543)\n[PASS] test_LaunchesFitTransactions() (gas: 34632)\nLogs:\n  launch 1 gas budget (with code deposit): 10814872\n  launch 2 gas budget (with code deposit): 10077470\n  launch 3 gas budget (with code deposit): 14055980\n\n[PASS] test_MatchesTheReference() (gas: 38337057)\n[PASS] test_RejectsCombosOutsideTheArt() (gas: 11168652)\n[PASS] test_SameAsTheLaunchRenderer() (gas: 1039160244)\n[PASS] test_TakesOnlyThisArt() (gas: 19351)\n[PASS] test_TokenURIIsCheapEnoughToRead() (gas: 10321599)\nLogs:\n  tokenURI gas: 10315624\n\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 2.79s (3.11s CPU time)\n\nRan 2 tests for test/FrenArtLaunch2.invariant.t.sol:FrenArtLaunch2InvariantTest\n[PASS]\nFrenArtLaunch2InvariantTest invariants:\n[PASS] invariant_ArtCodeCannotChange\n[PASS] invariant_EthEqualsSuccessfulTransfersAndCallersFundEveryWei\n FrenArtLaunch2InvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------------+--------------------------+-------+---------+----------╮\n| Contract           | Selector                 | Calls | Reverts | Discards |\n+============================================================================+\n| Launch2CallHandler | callWithData             | 4106  | 0       | 0        |\n|--------------------+--------------------------+-------+---------+----------|\n| Launch2CallHandler | callWithoutEnoughBalance | 4058  | 0       | 0        |\n|--------------------+--------------------------+-------+---------+----------|\n| Launch2CallHandler | readWithStaticCall       | 4084  | 0       | 0        |\n|--------------------+--------------------------+-------+---------+----------|\n| Launch2CallHandler | sendWithStipend          | 4136  | 0       | 0        |\n╰--------------------+--------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 442384056986787829\n  Bound result 0\n  Bound result 0\n  Bound result 77\n  Bound result 0\n  Bound result 0\n  Bound result 953\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 25287\n  Bound result 1\n  Bound result 0\n  Bound result 12580326\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 686936019559696181\n  Bound result 0\n  Bound result 0\n  Bound result 999999999999999998\n  Bound result 1\n  Bound result 0\n  Bound result 854269729980695952\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 34\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 48\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 40\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 768\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1179\n  Bound result 1\n  Bound result 2\n  Bound result 10\n  Bound result 1\n  Bound result 0\n  Bound result 659918\n  Bound result 0\n  Bound result 2\n  Bound result 5120\n  Bound result 0\n  Bound result 2\n  Bound result 6571\n  Bound result 0\n  Bound result 0\n  Bound result 12\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 484359320923432499\n  Bound result 0\n  Bound result 2\n  Bound result 327471931335887681\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 532406030649314864\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 491520\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 342615883178207357\n  Bound result 0\n  Bound result 2\n  Bound result 609127564076549774\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 96\n  Bound result 0\n  Bound result 1\n  Bound result 39\n  Bound result 0\n  Bound result 2\n  Bound result 116385085860405209\n  Bound result 1\n  Bound result 1\n  Bound result 880412555686252388\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 987556352121185843\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 542511354261649650\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 775580\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 983625458813993268\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 32557095206538039\n\n[PASS] test_HandlerSequencePinsZeroOneWeiAndMaximumPerCall() (gas: 584308)\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 1000000000000000000\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 2\n  Bound result 0\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.17s (3.17s CPU time)\n\nRan 5 test suites in 3.18s (6.07s CPU time): 27 tests passed, 0 failed, 1 skipped (28 total tests)\n","passed":true},{"durationMs":120,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":59,\"README.md\":63,\"foundry.toml\":22,\"script/art/chunks.py\":120,\"script/art/data/expected.json\":32,\"script/art/data/facetable.bin\":2,\"script/art/data/layers/bg0.bin\":59,\"script/art/data/layers/bg1.bin\":44,\"script/art/data/layers/bg2.bin\":44,\"script/art/data/layers/bg3.bin\":4,\"script/art/data/layers/bg4.bin\":2,\"script/art/data/layers/bg5.bin\":1,\"script/art/data/layers/bg6.bin\":6,\"script/art/data/layers/bg7.bin\":13,\"script/art/data/layers/bg8.bin\":20,\"script/art/data/layers/bg9.bin\":4,\"script/art/data/layers/coat0.bin\":10,\"script/art/data/layers/coat1.bin\":10,\"script/art/data/layers/coat2.bin\":10,\"script/art/data/layers/face0.bin\":36,\"script/art/data/layers/face1.bin\":29,\"script/art/data/layers/face10.bin\":34,\"script/art/data/layers/face11.bin\":33,\"script/art/data/layers/face12.bin\":36,\"script/art/data/layers/face13.bin\":19,\"script/art/data/layers/face14.bin\":20,\"script/art/data/layers/face15.bin\":20,\"script/art/data/layers/face16.bin\":19,\"script/art/data/layers/face17.bin\":20,\"script/art/data/layers/face18.bin\":19,\"script/art/data/layers/face19.bin\":21,\"script/art/data/layers/face2.bin\":34,\"script/art/data/layers/face20.bin\":20,\"script/art/data/layers/face21.bin\":19,\"script/art/data/layers/face22.bin\":19,\"script/art/data/layers/face23.bin\":20,\"script/art/data/layers/face24.bin\":20,\"script/art/data/layers/face25.bin\":19,\"script/art/data/layers/face26.bin\":23,\"script/art/data/layers/face27.bin\":23,\"script/art/data/layers/face28.bin\":23,\"script/art/data/layers/face29.bin\":23,\"script/art/data/layers/face3.bin\":31,\"script/art/data/layers/face30.bin\":23,\"script/art/data/layers/face31.bin\":23,\"script/art/data/layers/face32.bin\":26,\"script/art/data/layers/face33.bin\":24,\"script/art/data/layers/face34.bin\":23,\"script/art/data/layers/face35.bin\":22,\"script/art/data/layers/face36.bin\":22,\"script/art/data/layers/face37.bin\":24,\"script/art/data/layers/face38.bin\":22,\"script/art/data/layers/face4.bin\":31,\"script/art/data/layers/face5.bin\":29,\"script/art/data/layers/face6.bin\":29,\"script/art/data/layers/face7.bin\":28,\"script/art/data/layers/face8.bin\":29,\"script/art/data/layers/face9.bin\":30,\"script/art/data/layers/hat0.bin\":3,\"script/art/data/layers/hat1.bin\":5,\"script/art/data/layers/item0.bin\":2,\"script/art/data/layers/item1.bin\":1,\"script/art/data/layers/item10.bin\":1,\"script/art/data/layers/item11.bin\":1,\"script/art/data/layers/item12.bin\":1,\"script/art/data/layers/item13.bin\":1,\"script/art/data/layers/item14.bin\":3,\"script/art/data/layers/item2.bin\":3,\"script/art/data/layers/item3.bin\":1,\"script/art/data/layers/item4.bin\":1,\"script/art/data/layers/item5.bin\":2,\"script/art/data/layers/item6.bin\":3,\"script/art/data/layers/item7.bin\":1,\"script/art/data/layers/item8.bin\":1,\"script/art/data/layers/item9.bin\":1,\"script/art/data/manifest.json\":329,\"script/art/data/palette.bin\":7,\"script/art/data/tables.bin\":2,\"script/art/derive_renderer.py\":117,\"src/FrenArtChunks.sol\":2313,\"src/FrenArtIndex.sol\":34,\"src/FrenRenderer.sol\":357,\"test/FrenArtLaunch2.invariant.t.sol\":127,\"test/FrenArtLaunch2.t.sol\":291,\"test/FrenRenderer.t.sol\":278,\"test/OnChainChunks.fork.t.sol\":37,\"test/ref/FrenRendererRef.sol\":369},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"b78839171a74ec80eef03f8fcfd1f792428a508f79f87e7f3920782c31caff4d","verifiedTreeHash":"21d52a31ded29f666ac08a58a3971e74e82b9d46","verifierVersion":"0.1.0+94826a22"},{"checks":[{"durationMs":50777,"exitCode":0,"name":"build","output":"Compiling 35 files with Solc 0.8.30\nSolc 0.8.30 finished in 50.60s\nCompiler run successful!\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/FrenRenderer.sol:62:41\n   │\n62 │             if (cs[k].codehash != want) revert BadArt();\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/FrenRenderer.sol:337:48\n    │\n337 │             if (p.code.length < 1 + off + len) revert Missing();\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/FrenRenderer.sol:346:56\n    │\n346 │         if (p.code.length < 1 + (first + frames) * 33) revert Missing();\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/FrenRenderer.sol:274:22\n    │\n274 │         if (hat > 2) revert Missing();\n    │                      ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:102:60\n    │\n102 │         _draw(back, _entry(faceLayers + 20 + PENDING_BG), -int256(seed % 37), -int256((seed >> 8) % 37), none, 0);\n    │                                                            ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:102:80\n    │\n102 │         _draw(back, _entry(faceLayers + 20 + PENDING_BG), -int256(seed % 37), -int256((seed >> 8) % 37), none, 0);\n    │                                                                                ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:109:23\n    │\n109 │             _fren(cv, uint24(combo));\n    │                       ━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint24' 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/FrenRenderer.sol:171:54\n    │\n171 │                     bytes memory out = new bytes(j - start);\n    │                                                      ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/FrenRenderer.sol:170:21\n    │\n170 │                 if (k == i) {\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:227:35\n    │\n227 │                 bytes1 v = bytes1(uint8(l * 3 / 5));\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/FrenRenderer.sol:253:50\n    │\n253 │         _draw(cv, _entry(faceLayers + 20 + bg), -int256(seed % 37), -int256((seed >> 8) % 37), slot, 0);\n    │                                                  ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:253:70\n    │\n253 │         _draw(cv, _entry(faceLayers + 20 + bg), -int256(seed % 37), -int256((seed >> 8) % 37), slot, 0);\n    │                                                                      ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:271:79\n    │\n271 │         _draw(cv, _entry(uint8(FrenArtIndex.FACE_TABLE[ch * FACES + face])), -int256(CX), -int256(CY), slot, 0);\n    │                                                                               ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:271:92\n    │\n271 │         _draw(cv, _entry(uint8(FrenArtIndex.FACE_TABLE[ch * FACES + face])), -int256(CX), -int256(CY), slot, 0);\n    │                                                                                            ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:272:36\n    │\n272 │         _draw(cv, _entry(f + ch), -int256(CX), -int256(CY), slot, 0);\n    │                                    ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:272:49\n    │\n272 │         _draw(cv, _entry(f + ch), -int256(CX), -int256(CY), slot, 0);\n    │                                                 ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:275:55\n    │\n275 │         if (hat != 0) _draw(cv, _entry(f + 2 + hat), -int256(CX), -int256(CY), slot, 0);\n    │                                                       ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:275:68\n    │\n275 │         if (hat != 0) _draw(cv, _entry(f + 2 + hat), -int256(CX), -int256(CY), slot, 0);\n    │                                                                    ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:277:57\n    │\n277 │         if (item != 0) _draw(cv, _entry(f + 4 + item), -int256(CX), -int256(CY), slot, 0);\n    │                                                         ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:277:70\n    │\n277 │         if (item != 0) _draw(cv, _entry(f + 4 + item), -int256(CX), -int256(CY), slot, 0);\n    │                                                                      ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:288:25\n    │\n288 │             int256 yy = int256(y) + dy;\n    │                         ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:289:40\n    │\n289 │             bool row = yy >= 0 && yy < int256(N);\n    │                                        ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:297:32\n    │\n297 │                     int256 a = int256(x) + dx;\n    │                                ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:298:36\n    │\n298 │                     int256 b = a + int256(n);\n    │                                    ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:300:29\n    │\n300 │                     if (b > int256(N)) b = int256(N);\n    │                             ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:300:44\n    │\n300 │                     if (b > int256(N)) b = int256(N);\n    │                                            ━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:301:36\n    │\n301 │                     uint256 base = uint256(yy) * N;\n    │                                    ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:302:65\n    │\n302 │                     for (int256 xx = a; xx < b; ++xx) cv[base + uint256(xx)] = bytes1(uint8(c));\n    │                                                                 ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/FrenRenderer.sol:302:87\n    │\n302 │                     for (int256 xx = a; xx < b; ++xx) cv[base + uint256(xx)] = bytes1(uint8(c));\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/FrenRenderer.sol:317:56\n    │\n317 │         for (uint256 i; i < n; ++i) b[at + i] = bytes1(uint8(v >> (8 * i)));\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[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/FrenRenderer.sol:350:49\n    │\n350 │             extcodecopy(p, add(raw, 32), add(1, mul(first, 33)), mul(frames, 33))\n    │                                                 ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\n","passed":true},{"durationMs":2492,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/OnChainChunks.fork.t.sol:OnChainChunksForkTest\n[SKIP] test_swarmChunksDrawTheReference() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 424.24µs (138.88µs CPU time)\n\nRan 10 tests for test/FrenRenderer.t.sol:FrenRendererTest\n[PASS] test_ChunksPassTheAdmissionScan() (gas: 38663674)\n[PASS] test_GasBudgetRejectsOversizedBatch() (gas: 26330)\n[PASS] test_Launch2GasIncludesCodeDeposit() (gas: 17956)\n[PASS] test_Launch2ThroughCreate2() (gas: 10963543)\n[PASS] test_LaunchesFitTransactions() (gas: 34632)\nLogs:\n  launch 1 gas budget (with code deposit): 10814872\n  launch 2 gas budget (with code deposit): 10077470\n  launch 3 gas budget (with code deposit): 14055980\n\n[PASS] test_MatchesTheReference() (gas: 38337057)\n[PASS] test_RejectsCombosOutsideTheArt() (gas: 11168652)\n[PASS] test_SameAsTheLaunchRenderer() (gas: 1039160244)\n[PASS] test_TakesOnlyThisArt() (gas: 19351)\n[PASS] test_TokenURIIsCheapEnoughToRead() (gas: 10321599)\nLogs:\n  tokenURI gas: 10315624\n\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 2.36s (2.56s CPU time)\n\nRan 2 test suites in 2.36s (2.36s CPU time): 10 tests passed, 0 failed, 1 skipped (11 total tests)\n","passed":true},{"durationMs":93,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":59,\"README.md\":63,\"foundry.toml\":22,\"launch.json\":14,\"script/art/chunks.py\":120,\"script/art/data/expected.json\":32,\"script/art/data/facetable.bin\":2,\"script/art/data/layers/bg0.bin\":59,\"script/art/data/layers/bg1.bin\":44,\"script/art/data/layers/bg2.bin\":44,\"script/art/data/layers/bg3.bin\":4,\"script/art/data/layers/bg4.bin\":2,\"script/art/data/layers/bg5.bin\":1,\"script/art/data/layers/bg6.bin\":6,\"script/art/data/layers/bg7.bin\":13,\"script/art/data/layers/bg8.bin\":20,\"script/art/data/layers/bg9.bin\":4,\"script/art/data/layers/coat0.bin\":10,\"script/art/data/layers/coat1.bin\":10,\"script/art/data/layers/coat2.bin\":10,\"script/art/data/layers/face0.bin\":36,\"script/art/data/layers/face1.bin\":29,\"script/art/data/layers/face10.bin\":34,\"script/art/data/layers/face11.bin\":33,\"script/art/data/layers/face12.bin\":36,\"script/art/data/layers/face13.bin\":19,\"script/art/data/layers/face14.bin\":20,\"script/art/data/layers/face15.bin\":20,\"script/art/data/layers/face16.bin\":19,\"script/art/data/layers/face17.bin\":20,\"script/art/data/layers/face18.bin\":19,\"script/art/data/layers/face19.bin\":21,\"script/art/data/layers/face2.bin\":34,\"script/art/data/layers/face20.bin\":20,\"script/art/data/layers/face21.bin\":19,\"script/art/data/layers/face22.bin\":19,\"script/art/data/layers/face23.bin\":20,\"script/art/data/layers/face24.bin\":20,\"script/art/data/layers/face25.bin\":19,\"script/art/data/layers/face26.bin\":23,\"script/art/data/layers/face27.bin\":23,\"script/art/data/layers/face28.bin\":23,\"script/art/data/layers/face29.bin\":23,\"script/art/data/layers/face3.bin\":31,\"script/art/data/layers/face30.bin\":23,\"script/art/data/layers/face31.bin\":23,\"script/art/data/layers/face32.bin\":26,\"script/art/data/layers/face33.bin\":24,\"script/art/data/layers/face34.bin\":23,\"script/art/data/layers/face35.bin\":22,\"script/art/data/layers/face36.bin\":22,\"script/art/data/layers/face37.bin\":24,\"script/art/data/layers/face38.bin\":22,\"script/art/data/layers/face4.bin\":31,\"script/art/data/layers/face5.bin\":29,\"script/art/data/layers/face6.bin\":29,\"script/art/data/layers/face7.bin\":28,\"script/art/data/layers/face8.bin\":29,\"script/art/data/layers/face9.bin\":30,\"script/art/data/layers/hat0.bin\":3,\"script/art/data/layers/hat1.bin\":5,\"script/art/data/layers/item0.bin\":2,\"script/art/data/layers/item1.bin\":1,\"script/art/data/layers/item10.bin\":1,\"script/art/data/layers/item11.bin\":1,\"script/art/data/layers/item12.bin\":1,\"script/art/data/layers/item13.bin\":1,\"script/art/data/layers/item14.bin\":3,\"script/art/data/layers/item2.bin\":3,\"script/art/data/layers/item3.bin\":1,\"script/art/data/layers/item4.bin\":1,\"script/art/data/layers/item5.bin\":2,\"script/art/data/layers/item6.bin\":3,\"script/art/data/layers/item7.bin\":1,\"script/art/data/layers/item8.bin\":1,\"script/art/data/layers/item9.bin\":1,\"script/art/data/manifest.json\":329,\"script/art/data/palette.bin\":7,\"script/art/data/tables.bin\":2,\"script/art/derive_renderer.py\":117,\"src/FrenArtChunks.sol\":2313,\"src/FrenArtIndex.sol\":34,\"src/FrenRenderer.sol\":357,\"test/FrenRenderer.t.sol\":278,\"test/OnChainChunks.fork.t.sol\":37,\"test/ref/FrenRendererRef.sol\":369},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"e54c1bb72e8d158c077c63e760f919bfc7e6d4b2bae1569a9c19779bc6eec587","verifiedTreeHash":"4622046d879db113e0107889d985eec3f263c9bc","verifierVersion":"0.1.0+94826a22"}]}