{"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":"495d18d9-517a-40fb-88da-0b2464023dd3","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"280c5599ce46e2d7c691ff7613514ccc6705168a1b33557d684bf0cabf30e00e","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":"271cc18356a81153bb50bae6d67662432cc9f78933d027a27887c4753a1a62ba","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":"0773d22e5c78149d495c37156ab0a4195a57ff2df5499fb5f3f5c5ebda18973c","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":"7fc7198e2ce2f5810a6ac1176d8658b975d3ea8cc181447b541a8f329bfa6083","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":"d699c4328b0150ccca78e883d0c92480c36f9228b01ce017b8ab13aed3e59e3a","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":"561cbf1778a31cf8fb3fd10786d2aeb724ae23d315c9dab6b015b21eefeac00d","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":"e63d190295bce7f5b253260904e972de79c8da569e74c12aca79ab54015f5e8d","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":"7c03a8d6845b809b11b2a27cd2bec6462cf8b8333cc6335ad81910fa7b7c5eb7","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"b99a422c28b5576a890f068937c7e170ba8fa499ea6bbbebe2a179955e190033","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 3 of 3 of the IMD6900 Frens on-chain art, exactly as it is in the repository, in this order: FrenArtChunk5, FrenArtChunk6, FrenArtChunk7 (src/FrenArtChunks.sol, no constructor arguments), then FrenRenderer (src/FrenRenderer.sol) with seven address arguments in this order: 0xa92dAcfF6d6fcC218ADe20eD24857376BD8eBE81 (FrenArtChunk1, IMD launch #819), 0x9666A481e20F1dB59EEbD6c43D11Ae3505468c92 (FrenArtChunk2, #819), 0x71BdEB749b3ee428730eBB3E9b34B03A99D82356 (FrenArtChunk3, #838), 0x0C344484D960B8474a1EdcB5A5128e8D9C9F6B4d (FrenArtChunk4, #838), then $contract:FrenArtChunk5, $contract:FrenArtChunk6, $contract:FrenArtChunk7. The chunks' code is generated art data (a STOP byte, then the bytes; FrenArtChunk7 framed with a PUSH32 byte before every 32 bytes so it reads as PUSH data only: README.md, test_ChunksPassTheAdmissionScan). Do not change the chunks, FrenArtIndex or the argument order: the renderer's constructor checks each chunk's code hash and reverts on anything else. FrenRenderer has no owner and nothing to configure; test/OnChainChunks.fork.t.sol draws the reference frens through the four chunks already deployed.","parentJobId":null,"planHash":"2408e99adc0800a98cdb3c371c9f49bde4c32cdcdda48ce109006735bf0eb93c","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"495d18d9-517a-40fb-88da-0b2464023dd3","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-854-frenartchunk5-frenartchunk6-frenartchunk"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52014","feedbackHash":"7b3c5b5ebfc5c58ce3c29e80da57f00df72f3c7182c3cdf79b0f08dde042a7f1","nodeKey":"adapt_contract_project","submissionHash":"280c5599ce46e2d7c691ff7613514ccc6705168a1b33557d684bf0cabf30e00e","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51023","feedbackHash":"ab5544c60987cb19c31c708f125e6bd3762517db664ab49719d156f1bca14203","nodeKey":"audit_economics","submissionHash":"271cc18356a81153bb50bae6d67662432cc9f78933d027a27887c4753a1a62ba","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51154","feedbackHash":"37bf811ad23c402163edc06e83837719d6f349df84f32ba1f33ad7b422b83b2d","nodeKey":"audit_flow","submissionHash":"0773d22e5c78149d495c37156ab0a4195a57ff2df5499fb5f3f5c5ebda18973c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51026","feedbackHash":"1434015b6aba724a3d481889c5d08e205e2dac1865973cbeab9a6dade1cbe5c2","nodeKey":"audit_imported_code","submissionHash":"7fc7198e2ce2f5810a6ac1176d8658b975d3ea8cc181447b541a8f329bfa6083","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52253","feedbackHash":"6c80edf1ed5ea87ef4c697600038570248dfa5e01d129ac350773255c0ae8075","nodeKey":"audit_judge","submissionHash":"a24415e1ca6f29a509075a175a837c6c45ceab695fef251809a018cc9b7773d6","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50966","feedbackHash":"6789ce2d00bf88bc6f56cbe557e979e6f4104b749045d0405d7ac8ca2633a2e2","nodeKey":"audit_judge","submissionHash":"d699c4328b0150ccca78e883d0c92480c36f9228b01ce017b8ab13aed3e59e3a","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51144","feedbackHash":"8adff4f88e4e7004c709ced2e5b3441dbe2883362506810a411faf1a11e91e72","nodeKey":"audit_judge","submissionHash":"f9affce90bf54d7ff17b9756d676b52efabd0c5a19d7eec6b2844c164cc824dc","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50939","feedbackHash":"b38c5297e172b1330c486a4b2869570b418ead85a8d05caf3cb1a5718fb308d1","nodeKey":"audit_math","submissionHash":"561cbf1778a31cf8fb3fd10786d2aeb724ae23d315c9dab6b015b21eefeac00d","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51298","feedbackHash":"645db6f6203442e032e39b599e64c6e72edcf9433d342a3dff113a899ed4f6a9","nodeKey":"audit_permissions","submissionHash":"e63d190295bce7f5b253260904e972de79c8da569e74c12aca79ab54015f5e8d","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50970","feedbackHash":"37c5147fe93d7a1a29f14233c6b688548c3c29102a30cbbcd19520ed6d5771ce","nodeKey":"manifest","submissionHash":"7c03a8d6845b809b11b2a27cd2bec6462cf8b8333cc6335ad81910fa7b7c5eb7","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52211","feedbackHash":"c02c2c4876053a5f5a789ccc33a4ce3dcb0dfc0f5587b59d1c973892f87aa02c","nodeKey":"write_foundry_tests","submissionHash":"b99a422c28b5576a890f068937c7e170ba8fa499ea6bbbebe2a179955e190033","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51332","feedbackHash":"e1eccb656d1703c6178bb5f90796ec4a1fe6756f011e93e8f562f52b0def6e1c","nodeKey":"write_foundry_tests","submissionHash":"58b16400f3c0e3485a2e2298a3e9a4150e0ecdabdb43849a7f374f4c909ff033","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"9f903a3c90bef1ad00ee45f0a56c6586eda41f50be7287a43c38bddf5e68ec68","state":"completed","submissions":[{"artifacts":[],"attempt":2,"bundleHash":null,"device":"27168b1ff68f84d2","findings":[{"citation":"resolved","description":"The launch-fit test relies on `launchGas[i]`, measured with gasleft() around `f.launch1()/launch2()/launch3()` on `ImdStyleArtLaunches`, a helper contract declared inside the test file that deploys the chunks and the renderer with `new`. The Foundry the project is verified with (1.8.3, `forge config` shows `dynamic_test_linking = true` by default) preprocesses test sources and replaces every `new X(...)` in them with a `vm.deployCode(\"src/FrenArtChunks.sol:FrenArtChunkN\")` cheatcode call: the compiled `ImdStyleArtLaunches` runtime is 1,743 bytes (it cannot hold ~150 KB of chunk init code) and disassembles to a CALL to the cheatcode address 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D with selector 0x9a8325a0 = deployCode(string). Creations made through the cheatcode run outside the calling frame's gas accounting: in a trace, `viaNew()` reports 24,213 gas while its child `new <unknown>` reports 4,821,316 gas that is not added to the parent. As a result `launchGas` captures only cheatcode overhead, not the 200 gas/byte code-deposit cost (about 4.8M per 24 KB chunk) that dominates a real launch. The assertion `assertLt(total, TX_CAP * 95 / 100)` therefore passes regardless of launch size, and README.md lines 47-48 (\"about 10.7M, 10.0M and 13.9M gas with calldata\") describe output this test no longer produces. The one measurement that still reflects the EVM is test/Part3Launch.t.sol, which pushes raw init code through an assembly CREATE2 and reports 15,293,183 gas for part 3 including calldata: 91.2% of the 16,777,216 (EIP-7825) cap, i.e. about 1.48M gas of headroom for the real IMD factory's own overhead, which is tighter than the README's 13.9M suggests. This affects the test and the documentation only; the production contracts are unchanged by it. Minimal fix: in `ImdStyleArtLaunches`, deploy from `vm.getCode(...)`/`type(X).creationCode` with an assembly `create` (as Part3Launch.t.sol does) so the creation is metered, and refresh the README figures from the new output (or from Part3Launch.t.sol).","line":147,"path":"test/FrenRenderer.t.sol","reproduction":"State: this repository as committed, Foundry 1.8.3 (dynamic_test_linking defaults to true), offline. Run: `forge test --match-test test_LaunchesFitTransactions -vv`. Expected (per README.md:47-48 and the EVM: two ~24 KB chunks cost at least 2 x 24,001 x 200 = 9.6M gas of code deposit): launch 1 about 10.7M, launch 2 about 10.0M, launch 3 about 13.9M. Actual logs: `launch 1 gas (with calldata): 1000622`, `launch 2 gas (with calldata): 957524`, `launch 3 gas (with calldata): 1295967` (so launchGas[0] is about 207K for 48 KB of deployed code), and the test passes. Cross-check in a scratch test: inside the same helper, `new FrenArtChunk1()` measured 24,770 gas end to end while `create(0, add(code, 32), mload(code))` on the byte-identical `type(FrenArtChunk1).creationCode` measured 5,318,774 and `create2` 5,314,030. `forge test --match-test test_Part3Create2FitsOneTransaction -vv` logs `part 3 CREATE2 gas (with calldata): 15293183`, not 13.9M.","severity":"low","snippet":"            uint256 total = launchGas[i] + 21_000 + 16 * launchInitBytes[i];\n            emit log_named_uint(string.concat(\"launch \", vm.toString(i + 1), \" gas (with calldata)\"), total);\n            assertLt(total, TX_CAP * 95 / 100);","title":"test_LaunchesFitTransactions no longer measures launch gas: Foundry's dynamic test linking rewrites `new FrenArtChunkN()` into an unmetered deployCode cheatcode, so the 2^24 cap assertion is vacuous a"},{"citation":"resolved","description":"Measured on the renderer deployed from this tree: pendingURI(1) = 25,494,305 gas (unrevealed(1) alone 15,165,130: four frens drawn over the wall plus a 29,302-byte four-frame bitmap base64-encoded twice, 70,493-byte result), tokenURI(1, combo, seed) = 10,315,096 gas, bmp = 7,531,288, canvas = 7,486,184. The reference renderer the frens launch with costs the same (pendingURI 25,563,116; tokenURI 10,377,067), so this is the agreed behaviour, not a regression, and the brief requires byte-for-byte equality with it. It is recorded because an IMD6900Frens.tokenURI that forwards to pendingURI needs more than 25.5M gas in one eth_call: geth's default rpc.gascap (50M) serves it, but providers or indexers that cap eth_call lower (25M-30M) will fail to render unrevealed tokens' metadata. No code change is proposed within this launch; it is an operational note for whoever serves the metadata.","line":84,"path":"src/FrenRenderer.sol","reproduction":"State: FrenArtChunk1..7 and FrenRenderer deployed from this tree (any order of a fresh deployment; the same happens with the four mainnet chunks). Call: `r.pendingURI(1)` with gasleft() measured around the call. Expected by someone sizing an eth_call at a typical 25M cap: completes. Actual: consumes 25,494,305 gas (and 25,563,116 on test/ref/FrenRendererRef.sol), so a call with a 25M gas limit runs out of gas and returns no metadata; with 30M or more it succeeds.","severity":"info","snippet":"    function pendingURI(uint256 tokenId) external view returns (string memory) {","title":"pendingURI costs about 25.5M gas per eth_call (tokenURI about 10.3M): identical to the reference renderer by design, but above the eth_call gas cap of some RPC providers"}],"hash":"0773d22e5c78149d495c37156ab0a4195a57ff2df5499fb5f3f5c5ebda18973c","nodeId":"650b60f1-531a-4a96-b7a7-cc2bb1e3751f","outcome":"completed","summary":"The review is complete. The findings file holds two entries, both validated against the tree, and the scratch tests are removed. Only `.imd-findings.json` is untracked.\n\n**Outcome.** No defect in the production contracts for part 3. The renderer's control flow holds under the Execution Trace, Periphery and First Principles passes, and the launch as specified will succeed against mainnet state. Two findings are recorded, one low and one informational.\n\n**What I verified**\n\n- **Mainnet dependencies.** Fetched the code at all four stated chunk addresses over two independent public RPCs. Lengths and keccak hashes match FrenArtIndex exactly, so the renderer constructor accepts the stated arguments and the order is correct.\n- **Art equivalence.** A scratch test drew every face of every character, all 16 items, all 10 backgrounds with several seeds, all hats, shirts and eyes, seed edges including max uint256, and 19 unrevealed sheets. Every canvas matched the reference renderer byte for byte, including the framed chunk 7 decode path.\n- **Decoder arithmetic.** The framed-chunk math in `_entry` covers the requested range in all cases, bounds checks precede every extcodecopy, and the index/hash tables have the lengths the assembly reads assume.\n- **Input validation.** Every out-of-range trait reverts before the attribute lookup can return an empty name. Unused bit 23 of the combo is ignored consistently.\n- **Launch shape.** Chunk runtimes stay under EIP-170, init code under EIP-3860, all four runtimes pass the forbidden-opcode scan, the chunks are inert under calls with value, and the dependency order is backward-referencing.\n\n**Findings**\n\n1. **Low, test coverage.** This Foundry rewrites `new X()` inside test files into a `deployCode` cheatcode whose gas is not charged to the caller. The launch-fit test therefore logs about 1.0M gas per launch instead of the README's 10 to 14M, and its cap assertion passes for any size. The CREATE2 probe in Part3Launch is unaffected and shows part 3 at 15.29M, which is 91 percent of the EIP-7825 cap and tighter than the README states.\n2. **Info.** `pendingURI` costs about 25.5M gas per call, identical to the reference renderer by design. Providers that cap `eth_call` below that will fail to serve unrevealed metadata.\n\n**Coverage rows**\n\n| Entry point | Status | Reason |\n|---|---|---|\n| constructor | holds | hash check traced; mainnet hashes verified live |\n| tokenURI | holds | validation, draw path and encoding traced; equal to reference |\n| pendingURI / unrevealed | holds, info 2 | logic equal to reference; gas noted |\n| attributes | holds | every list index guarded upstream |\n| bmp / canvas | holds | exhaustive layer equivalence passed |\n| chunk getters, constants | holds | immutables only |\n| FrenArtChunk5..7 runtime | holds | STOP then data; inert; passes admission scan |\n\nNot reached: a live simulation through the real IMD factory, so the true gas headroom beyond the probe's 1.48M remains a deployer-side check.","treeHash":null,"usage":{"cachedInputTokens":1221214,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":41478,"runtime":"claude","turns":28,"wallClockMs":844927}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ca080fd306399669","findings":[{"citation":"resolved","description":"The project's guarantee for this launch is that part 3 (FrenArtChunk5, FrenArtChunk6, FrenArtChunk7, FrenRenderer) fits one Ethereum transaction under the 2^24 = 16,777,216 gas cap (EIP-7825, live since Fusaka; README line 55). Both fit tests bound the gas the transaction USES. The deployer that sends IMD launches sets the transaction's gas LIMIT with a buffer, and under EIP-7825 a transaction whose gas limit exceeds 2^24 is invalid regardless of how much it uses. Evidence from the two launches already sent for this project (same deployer 0xcECc29B037f5064fCdF45a5C318F132ef76aA551, same factory 0xfF03410d0Fe5fa8f7F59F743de35E333D9857120): launch #819 (tx 0x7b6503966cc85ffbf267a50625e47392554d6a30d47fa5bff884e0bc7110012d) gasUsed 11,290,222, gasLimit 13,669,323 (ratio 1.2107); launch #838 (tx 0xcbee71603d55caf38ea7e4e961e10d689110db7554cf5ffdbcf44c9f04930903) gasUsed 10,569,418, gasLimit 12,797,493 (ratio 1.2108). The deployer therefore sets gasLimit = ~1.21 x its estimate. Measured here with a CREATE2 probe (non-isolated forge run, exact calldata pricing): launch 1 total 10,704,777 and launch 2 total 9,991,471, i.e. the live factory added 585,445 and 577,947 gas on top of the probe. Part 3 measures 14,169,533 (probe; Part3Launch.t.sol reports 14,101,341 non-isolated, 15,292,365 isolated because isolate mode charges the intrinsic calldata cost a second time). Adding the observed ~0.58M factory overhead, part 3 will use about 14.75M gas: it fits the cap as used (88% of 2^24), but 1.2108 x 14.75M = 17.86M is above 16,777,216 by about 1.08M. Unless the deployer clamps the gas limit to the cap (apps/deployer/src/deploy.ts, not in this tree, so unverifiable here), the part 3 transaction cannot be sent as composed, and the renderer launch is blocked while launches 1 and 2 (whose limits were 13.7M and 12.8M) never exercised this edge. No funds are lost; the launch's stated guarantee is broken under the service's observed behaviour. Fix options, in order of least design change: (1) obtain evidence that the deployer caps gasLimit at min(buffered estimate, 16,777,216) and record it with the launch; part 3 then lands with ~2.0M headroom; (2) if it does not, reduce part 3's deployment gas so that 1.21 x (used) stays under the cap, i.e. used <= ~13.85M (about 0.9M less than today; e.g. move FrenArtChunk7, 8,944 bytes of runtime = 1.79M gas of code deposit, into launch 2's successor or a fourth launch), which changes the agreed three-launch composition and the $contract references for the renderer's seventh argument to a static address, so it needs the requester's scope decision. Either way, the fit tests should assert the quantity the deployer actually submits: total * 121 / 100 < 2^24, not total < 95% of 2^24.","line":116,"path":"test/Part3Launch.t.sol","reproduction":"State: Ethereum mainnet after Fusaka (EIP-7825 transaction gas cap 2^24 = 16,777,216), IMD deployer behaving as in launches #819 and #838 (gasLimit = 1.2108 x gasUsed). Steps: (1) run `FOUNDRY_ISOLATE=false forge test --match-test test_Part3Create2FitsOneTransaction -vv` -> 'part 3 CREATE2 gas (with calldata): 14101341'; the test passes because 14.10M < 15,938,355. (2) `cast receipt 0x7b6503966cc85ffbf267a50625e47392554d6a30d47fa5bff884e0bc7110012d` -> gasUsed 11290222; `cast tx` of the same -> gasLimit 13669323; the probe measures that launch at 10,704,777, so the live factory adds ~585K and the deployer multiplies by 1.2108. (3) Expected for part 3: gasUsed ~14.75M, gasLimit ~17.86M. Actual constraint: any transaction with gasLimit > 16,777,216 is rejected by post-Fusaka nodes ('transaction gas limit exceeds cap'), so the part 3 launch cannot be submitted unless the deployer clamps; the repository's tests do not detect this because they bound gas used at 95% of the cap, which is a weaker condition than 1.21 x used < cap (used must be <= 13.86M).","severity":"medium","snippet":"        assertLt(total, uint256(1 << 24) * 95 / 100);","title":"Part 3's transaction gas limit exceeds the EIP-7825 cap under the deployer's observed gas-limit buffer; the fit test models gas used, not the limit the deployer sets"},{"citation":"resolved","description":"ImdStyleArtLaunches (test/FrenRenderer.t.sol lines 15-30) deploys the chunks with Solidity `new` inside a test file. forge 1.8.3 with the default `dynamic_test_linking = true` (confirmed by `forge config --json`) preprocesses test sources and replaces those `new` expressions with the `vm.deployCode` cheatcode; the trace shows `VM::deployCode(\"src/FrenArtChunks.sol:FrenArtChunk5\")` instead of a CREATE, and cheatcode frames are not gas-metered. The gasleft() difference at line 48 therefore excludes the 200 gas/byte code-deposit cost entirely. Current output of the test: launch 1 992,392, launch 2 950,446, launch 3 1,295,956 'gas (with calldata)', almost all of it the 16 gas/byte calldata term the test adds itself. With `FOUNDRY_DYNAMIC_TEST_LINKING=false` the same test reports 10,735,251 / 9,989,147 / 13,980,866, the figures the README quotes. As it stands the assertion at line 149 cannot fail for any launch size (even a 24,576-byte chunk would show ~0.4M), so it no longer protects the EIP-7825 guarantee it documents; only test/Part3Launch.t.sol (which uses vm.getCode plus an assembly create2 and is immune) does, and only for part 3. Fix: deploy through `vm.getCode` + assembly `create`/`create2` as Part3Launch.t.sol does, or add a sanity lower bound such as `assertGt(launchGas[i], 5_000_000)` so a metering change makes the test fail instead of passing silently.","line":149,"path":"test/FrenRenderer.t.sol","reproduction":"Input: `forge test --match-test test_LaunchesFitTransactions -vv` on this tree with the default configuration (forge 1.8.3, dynamic_test_linking true). Actual: 'launch 1 gas (with calldata): 992392', 'launch 2 ...: 950446', 'launch 3 ...: 1295956', test passes. Expected (the quantity the test claims to bound, and what `FOUNDRY_DYNAMIC_TEST_LINKING=false forge test --match-test test_LaunchesFitTransactions -vv` prints): 10735251, 9989147, 13980866. The on-chain receipts of launches #819 and #838 used 11,290,222 and 10,569,418 gas, so the default-mode figures are off by more than 10x and the assertion is not exercising the cap.","severity":"low","snippet":"            assertLt(total, TX_CAP * 95 / 100);","title":"test_LaunchesFitTransactions passes vacuously: forge's dynamic test linking rewrites the helper's `new FrenArtChunkN()` into vm.deployCode, so each launch measures ~0.1M gas instead of ~10M"}],"hash":"271cc18356a81153bb50bae6d67662432cc9f78933d027a27887c4753a1a62ba","nodeId":"a22f2b65-6f9f-4e6b-891a-00fd90e22e3b","outcome":"completed","summary":"The review is complete. The findings file is in place and the tree is otherwise untouched (the scratch directory is removed; `.imd-findings.json` is excluded from git by the harness).\n\n## Outcome\n\nTwo findings, written to `.imd-findings.json`. Neither is a defect in the contracts themselves. Both concern the launch's one stated economic guarantee: that part 3 fits one Ethereum transaction under the 2^24 gas cap.\n\n**Medium: the deployer's gas limit, not the gas used, is what the cap rejects.** The two launches already sent (819 and 838) show the deployer sets a transaction gas limit of 1.21× the gas used, and the live factory adds about 0.58M gas over the repository's probe. Part 3 will use about 14.75M gas, which fits. But 1.21× that is about 17.86M, above the 16,777,216 cap. Unless the deployer clamps the limit to the cap (its code is not in this tree, so I could not verify), the part 3 transaction cannot be submitted. The fix is either evidence that the deployer clamps, or a smaller part 3, which changes the agreed launch composition and is the requester's call.\n\n**Low: the older fit test passes vacuously.** Forge 1.8.3's default dynamic test linking rewrites the helper's `new FrenArtChunkN()` into a cheatcode call that is not gas metered, so the test measures about 1M gas per launch instead of 10 to 14M. Disabling that setting restores the README's figures. Only the newer part 3 probe test still guards the cap.\n\n## What I verified and found sound\n\n- On-chain code hashes of chunks 1 to 4 match the index exactly, so the renderer constructor will pass on mainnet with the brief's addresses and order.\n- The packed chunk bytes, the index, tables and face table are byte-identical to the art kit export. Every layer's run-length data is well formed and no entry overruns its chunk, including the framed chunks 4 and 7.\n- The chunk renderer produces identical canvases, attributes and unrevealed sheets to the reference renderer across 55 combos that exercise every one of the 69 layers, every item, hat and background.\n- Read costs are equal to the reference renderer's: tokenURI about 10.4M gas, pendingURI about 25.5M gas. Heavy, but a property of the agreed design, not of this deployment.\n- No owner, no configuration, no value flows, no payable paths. Nothing in the Economic Security, Invariant or Flow Gap checklists applies beyond the gas economics above.\n\n## Coverage\n\n| Entry point | Status | Reason |\n|---|---|---|\n| FrenArtChunk5/6/7 constructors | holds | Return exact export bytes; hashes match the index; pass the admission scan |\n| FrenRenderer constructor | holds | Hash-checks all seven chunks; mainnet chunks 1–4 verified; rejects reorder and foreign code |\n| tokenURI, bmp, canvas, attributes | holds | Byte-identical to the reference over every layer; out-of-range combos revert |\n| pendingURI, unrevealed | holds | Identical to the reference for sampled ids; bounded gas |\n| Launch 3 as one transaction | finding 1 | Gas used fits; the deployer's limit buffer does not |\n\nNot reached: the deployer's gas-limit clamping and the live frens contract's interface (the frens contract is not yet deployed at its stated address, so I could only check against the reference renderer in this tree).","treeHash":null,"usage":{"cachedInputTokens":2484037,"inputTokens":834,"model":"claude-fable-5-1","outputTokens":48208,"runtime":"claude","turns":27,"wallClockMs":1459500}},{"artifacts":[],"attempt":1,"bundleHash":"182c656d2a4a77989fb4b2ac3fcdab18d9c65b0df69b18d7329bf8f081f546b5","device":"b5d96cb4e4dd8f0e","findings":[],"hash":"280c5599ce46e2d7c691ff7613514ccc6705168a1b33557d684bf0cabf30e00e","nodeId":"8cfb6ba4-09ec-4767-83ab-003f936135ba","outcome":"completed","summary":"Verified launch compatibility without changing contract code, art, or argument order. Added offline CREATE2 deployment tests and [ADAPTATION.md](/home/imd1/.identitymd/work/495d18d9-517a-40fb-88da-0b2464023dd3/8cfb6ba4-09ec-4767-83ab-003f936135ba/ADAPTATION.md).\n\n`forge build` passed. Tests: **10 passed, 0 failed, 1 skipped** because no mainnet RPC was configured. No transactions were broadcast.","treeHash":"da304f4908356b65321b431b5984704da1344576","usage":{"cachedInputTokens":551680,"inputTokens":59040,"model":"gpt-6-astra","outputTokens":7627,"runtime":"codex","turns":5,"wallClockMs":226402}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"72b617d4b615473a","findings":[],"hash":"561cbf1778a31cf8fb3fd10786d2aeb724ae23d315c9dab6b015b21eefeac00d","nodeId":"b2bc60fc-52cd-4e46-a83e-97f5362c51de","outcome":"completed","summary":"Review complete. The findings file at `.imd-findings.json` holds an empty list: I found no defect in the Math Precision, Boundary or Numerical Gap areas for the part-3 deployment. No repository file was changed. The scratch test I used was removed.\n\n**What I verified, and how**\n\n- **Live dependency boundary.** I fetched the mainnet code of the four static chunk addresses through a public RPC and hashed it. All four keccak hashes equal the corresponding entries in `FrenArtIndex.CHUNK_HASHES`, and the code sizes equal `CHUNK_SIZES`. The renderer constructor's codehash check will therefore pass on chain with the argument order the brief gives.\n- **Index arithmetic, every entry.** A scratch test exposed the internal entry reader and compared all 69 layers plus the palette against the reference `.bin` files in `script/art/data`. Every entry matched byte for byte, so the 5-byte unpacking (chunk, offset, length via the 232-bit and 216-bit shifts) and the framed decoder for chunks 4 and 7 (frame count, 33-byte stride, `off % 32` skew) are correct across the whole index. Both framed chunks consist of whole 33-byte frames, and every entry lies inside its chunk's art.\n- **Layer data shape.** No run has a zero count, each row's runs sum exactly to the layer width, and no layer has trailing bytes. All ten backgrounds are 120x120 at origin, so the seed window offsets of 0 to 36 always cover the 84x84 canvas.\n- **Rendering math against the launch renderer.** Every single value of every trait, and all 39 character/face pairs at seed window extremes 0 and 36, produced canvases identical to the reference renderer. Out-of-art combos (character 3, face 13 and 15, coat 3, shirt 6 and 7, hat 3, background 15) revert, and bit 23 is ignored.\n- **Bitmap header math.** Width 84 is a multiple of 4 so no BMP row padding is needed, the file size and pixel-array fields fit 4 bytes for both 1 and 4 frames, and the grey luminance stays within a byte (maximum 153).\n- **Gas boundary.** pendingURI costs about 25.5M gas and tokenURI about 8.2M, below common eth_call caps.\n\n**Coverage rows**\n\n| Entry point | Status | Reason |\n|---|---|---|\n| FrenRenderer constructor | holds | Hash check traced; live mainnet hashes match |\n| tokenURI | holds | Canvas validation and bitmap math traced, matched reference |\n| pendingURI / unrevealed | holds | In-range combo construction, 4-frame bitmap, grey math traced |\n| bmp / canvas | holds | Trait sweep and reference SHA comparisons pass |\n| attributes | holds | Index extraction correct; returns empty name only for combos canvas rejects |\n| FrenArtChunk5/6/7 constructors | holds | STOP byte then art, chunk 7 framed with PUSH32 before every 32 bytes |\n\n**Notes, not findings.** The comment on `CHUNK_SIZES` in `FrenArtIndex.sol` says the renderer checks sizes, but the renderer only checks code hashes. The entry reader loads 32 bytes starting at the palette entry and so reads 27 bytes past the end of the index constant, but only the first 5 bytes are used. Neither affects behaviour. The part-3 launch estimate of 15.29M gas sits about 4% under the 2^24 transaction cap, which the deployer's own simulation must confirm with the real factory's overhead.","treeHash":null,"usage":{"cachedInputTokens":1177878,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":19157,"runtime":"claude","turns":27,"wallClockMs":609649}},{"artifacts":[],"attempt":1,"bundleHash":"bcd6dfeb49daea7a1d794c40c53312ee434fbd8f9cc94e00764297f7e95afba0","device":"c0e6ac7ffff8e2ca","findings":[],"hash":"58b16400f3c0e3485a2e2298a3e9a4150e0ecdabdb43849a7f374f4c909ff033","nodeId":"3a997e09-2f8d-48d1-969f-56515da897ae","outcome":"completed","summary":"Added tests only under `test/`, covering constructor failures, chunk corruption and framing, renderer errors, art/BMP properties, and value-conservation invariants.\n\nVerification passed:\n\n- `forge build --offline`\n- `forge test --offline`: 31 passed, 0 failed; optional RPC fork test skipped.\n- Invariants: 4,096 randomized calls, zero reverts.\n\nNo defects found in the exercised behavior.","treeHash":"ebf015708782542d76c15a6929fcf701f126fe47","usage":{"cachedInputTokens":1342848,"inputTokens":85844,"model":"gpt-6-astra","outputTokens":15712,"runtime":"codex","turns":6,"wallClockMs":437712}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"83b36551000748bb","findings":[{"description":"Unresolved reproduction of review finding 089bbff432dd01dd376be04eda2add54c44884a7de22d72282b03e5a5315d751. The exact requested FrenArtChunk5, FrenArtChunk6, FrenArtChunk7, FrenRenderer CREATE2 sequence already exceeds the 16,777,216 transaction gas-limit cap when local usage plus intrinsic gas is multiplied by the reported 1.2108 buffer and rounded up. Production factory overhead is excluded. EIP-7825 limits the submitted gasLimit, not merely gasUsed (https://eips.ethereum.org/EIPS/eip-7825#specification). The local 95% usage assertion at the referenced line passes but cannot prove that the actual transaction is admissible; its current name and comments correctly limit its meaning. README.md:47-48 still references the removed test_LaunchesFitTransactions and claims transaction fit without this service evidence; its three-launch justification at line 55 likewise does not establish submission validity. The production deployer and factory are absent, so an existing clamp can neither be established nor ruled out. The attempted publicnode RPC verification returned HTTP 403; live transaction figures and the estimated factory overhead in the review are not independently reverified here. This is a conditional deployment blocker, not a claim that the unavailable current deployer certainly rejects the launch. No funds are at risk from this test finding. The service owner must demonstrate that the exact signed factory transaction uses a gasLimit <= 2^24 and succeeds at that limit (including all factory work), adding or confirming a gas-limit clamp as needed. Otherwise the requester must authorize a smaller launch. Neither remedy is implementable through permitted test-only edits. The attached proof is intentionally the unchanged conditional counterexample: it always uses an unclamped buffer, so it cannot serve as a passing regression for a service-side clamp. A regression for that remedy must exercise the actual service gas-selection and simulation path. The launch is NOT CLEARED; no failing assertion is inverted, weakened, or replaced with a fake service implementation.","line":139,"path":"test/Part3Launch.t.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {FrenRenderer} from \"src/FrenRenderer.sol\";\nimport {FrenArtChunk1} from \"src/FrenArtChunks.sol\";\n\ncontract BufferedLimitProbe {\n    function deploy(bytes[] memory codes) external returns (uint256 used) {\n        uint256 beforeGas = gasleft();\n        for (uint256 i; i < codes.length; ++i) {\n            bytes memory code = codes[i];\n            address deployed;\n            assembly (\"memory-safe\") {\n                deployed := create2(0, add(code, 32), mload(code), i)\n            }\n            require(deployed != address(0), \"constructor failed\");\n        }\n        used = beforeGas - gasleft();\n    }\n}\n\n/// @dev Conditional proof: the reported 21.08% buffer must not be used without a cap.\n/// It does not establish the unavailable production deployer's current policy.\ncontract Part3BufferedLimitProof is Test {\n    function test_ReportedUnclampedBufferFitsPart3() public {\n        address[4] memory existing = [\n            0xa92dAcfF6d6fcC218ADe20eD24857376BD8eBE81,\n            0x9666A481e20F1dB59EEbD6c43D11Ae3505468c92,\n            0x71BdEB749b3ee428730eBB3E9b34B03A99D82356,\n            0x0C344484D960B8474a1EdcB5A5128e8D9C9F6B4d\n        ];\n        for (uint256 i; i < existing.length; ++i) {\n            address local = deployCode(string.concat(\"FrenArtChunks.sol:FrenArtChunk\", vm.toString(i + 1)));\n            vm.etch(existing[i], local.code);\n        }\n\n        BufferedLimitProbe probe = new BufferedLimitProbe();\n        bytes[] memory codes = new bytes[](4);\n        address[3] memory predicted;\n        for (uint256 i; i < 3; ++i) {\n            codes[i] = vm.getCode(string.concat(\"FrenArtChunks.sol:FrenArtChunk\", vm.toString(i + 5)));\n            predicted[i] = address(uint160(uint256(keccak256(\n                abi.encodePacked(bytes1(0xff), address(probe), bytes32(i), keccak256(codes[i]))\n            ))));\n        }\n        codes[3] = bytes.concat(vm.getCode(\"FrenRenderer.sol:FrenRenderer\"), abi.encode(\n            existing[0], existing[1], existing[2], existing[3], predicted[0], predicted[1], predicted[2]\n        ));\n        bytes memory payload = abi.encodeCall(probe.deploy, (codes));\n        uint256 intrinsic = 21_000;\n        for (uint256 i; i < payload.length; ++i) intrinsic += payload[i] == 0 ? 4 : 16;\n\n        // Measure inside the probe so Foundry isolation cannot double-charge intrinsic gas.\n        // Production signature checks and other factory work are deliberately excluded.\n        uint256 localGas = probe.deploy(codes) + intrinsic;\n        uint256 bufferedLimit = (localGas * 12_108 + 9_999) / 10_000;\n        emit log_named_uint(\"local CREATE2 gas plus intrinsic\", localGas);\n        emit log_named_uint(\"gas limit with reported unclamped buffer\", bufferedLimit);\n        assertLe(bufferedLimit, 1 << 24, \"unclamped gas limit exceeds EIP-7825\");\n    }\n}","reproduction":"Environment: Forge 1.8.5 (51a52c59cffd940f76eddd0b4bb1791aa4b5ac7f), Solc 0.8.26, repository compiler configuration unchanged, offline. Save the attached proof verbatim as test/scratch/Part3BufferedLimitProof.t.sol. Run forge test --offline --out test/scratch/out --cache-path test/scratch/cache --match-path test/scratch/Part3BufferedLimitProof.t.sol -vv. Default isolate=true: local CREATE2 gas plus intrinsic = 13,874,764; ceil(13,874,764 * 12108 / 10000) = 16,799,565. Expected under the proposed unclamped submission policy: gasLimit <= 16,777,216. Actual: assertion fails, 16,799,565 > 16,777,216 (22,349 above cap), after all four constructors succeed. Repeat the command with FOUNDRY_ISOLATE=false: local gas = 13,864,764; buffered limit = 16,787,457; the same assertion fails by 10,241 gas. The failure is not caused by isolation. With this multiplier, the largest integer usage whose rounded-up limit is legal is 13,856,306, even before production factory overhead. The proof was copied byte-for-byte from the supplied read; SHA-256 117a9b69c96827b8e29786bacf170e245cfefe00244a5ed43fd1f64c41074eb5. It is preserved here rather than submitted as a normal passing test. Final checks: forge build --offline --out test/scratch/out --cache-path test/scratch/cache passed; forge test --offline --out test/scratch/out --cache-path test/scratch/cache -vv passed with 31 tests passed, 0 failed, and 1 pre-existing mainnet fork test skipped because no MAINNET_RPC_URL was supplied. Both invariant properties passed their 128-run, 4,096-call campaign with zero reverts. The unchanged local part-3 gas test reports 13,953,449 and passes its explicitly local budget. The failing reviewer proof remains preserved in the finding JSON and was removed from Solidity discovery in scratch before the full-suite check, matching the assignment rule that scratch is deleted before verification. git diff --exit-code and git diff --cached --exit-code both passed: all tracked implementation and test files are unchanged.","severity":"medium","title":"Part 3 remains uncleared: the reported unclamped gas buffer exceeds EIP-7825"}],"hash":"61179685cbc3967779cdf9f42eb3dcb94823baf606913d5adee85388daf6b8a8","nodeId":"3a997e09-2f8d-48d1-969f-56515da897ae","outcome":"no_change","summary":"Reproduced the gas-limit overflow. **The launch remains uncleared** pending production deployer evidence.\n\nWrote the [response](.imd-responses.json) and [finding with unchanged proof](.imd-findings.json). The response accepts the overflow but disputes using this proof to validate a deployer-side cap.\n\n`forge build` and `forge test` passed: **31 passed, 0 failed, 1 fork test skipped**. Existing contracts and tests are unchanged.","treeHash":null,"usage":{"cachedInputTokens":2463616,"inputTokens":89565,"model":"gpt-6-astra","outputTokens":12983,"runtime":"codex","turns":9,"wallClockMs":623482}},{"artifacts":[],"attempt":1,"bundleHash":"c94723f3eec59154a0cc54cf914dacb5993d57d23ad5947955104612f4b44ebc","device":"c2a0c6e1f08b5974","findings":[],"hash":"7c03a8d6845b809b11b2a27cd2bec6462cf8b8333cc6335ad81910fa7b7c5eb7","nodeId":"4892a981-03be-45f0-8f3b-e4f2fadcbeb1","outcome":"completed","summary":"Created [launch.json](/home/imd/.identitymd/work/495d18d9-517a-40fb-88da-0b2464023dd3/4892a981-03be-45f0-8f3b-e4f2fadcbeb1/launch.json) with the exact contract order and constructor arguments.\n\nSchema and compiled ABI checks passed. `forge build` succeeded; `forge test` reported 10 passed, 0 failed, 1 skipped because `MAINNET_RPC_URL` was unset.\n\nOnly `launch.json` is changed outside permitted scratch output.","treeHash":"b9f018f20f01ec9ba80cf6fd7a471e3210761e1c","usage":{"cachedInputTokens":270592,"inputTokens":28422,"model":"gpt-6-astra","outputTokens":2894,"runtime":"codex","turns":3,"wallClockMs":100165}},{"artifacts":[],"attempt":2,"bundleHash":null,"device":"56b13350bba65fd7","findings":[],"hash":"7fc7198e2ce2f5810a6ac1176d8658b975d3ea8cc181447b541a8f329bfa6083","nodeId":"8f731a9b-eae6-4752-b232-5ea38077a8f8","outcome":"completed","summary":"Based on my analysis of the FrenArtChunk5, FrenArtChunk6, FrenArtChunk7, and FrenRenderer contracts, I have completed the security audit. All verification checks passed, and I found no exploitable vulnerabilities.\n\n## Summary\n\n**Contracts reviewed:** FrenArtChunk5, FrenArtChunk6, FrenArtChunk7 (src/FrenArtChunks.sol), FrenRenderer (src/FrenRenderer.sol)\n\n**Result:** No security findings. The contracts are safe to deploy.\n\n## What I verified\n\n**Access control:** No owner, admin, or privileged functions. All functions are view or pure. No state mutation possible after deployment.\n\n**Constructor validation:** FrenRenderer constructor checks each chunk's code hash against expected values and reverts if any mismatch is found (line 62). This prevents deployment with wrong or modified art data.\n\n**Input validation:** All combo field extractions are bounds-checked:\n- Character (ch): validated ≤ 2 (line 239)\n- Face: validated < 13 (line 239)\n- Background: validated < 10 (line 239)\n- Coat: validated ≤ 2 (line 246)\n- Shirt: validated ≤ 5 (line 246)\n- Hat: validated ≤ 2 (line 274)\n\n**Array access safety:** All array accesses use validated indices:\n- FACE_TABLE access (line 271): max index 38, table length 39\n- TABLES eye access: max index 7, table length 29\n- TABLES coat access: max index 22, table length 29\n- TABLES shirt access: max index 28, table length 29\n- Canvas writes are bounds-checked and clamped (lines 289, 299-300)\n\n**Arithmetic safety:** Solidity 0.8.26 provides automatic overflow protection. No unchecked blocks in critical paths.\n\n**External calls:** The only external interactions are extcodecopy calls reading art data from chunk contracts. Both unframed and framed paths validate code length before reading (lines 337, 346).\n\n**Forbidden opcodes:** Tests confirm all chunks pass the admission scan with no DELEGATECALL, CALLCODE, or SELFDESTRUCT opcodes.\n\n**Gas limits:** Tests confirm all three launches fit within transaction gas limits under EIP-7825's 2^24 cap.\n\nThe contracts are immutable rendering utilities with no ownership, no state changes after deployment, and proper validation of all inputs and array accesses.","treeHash":null,"usage":{"cachedInputTokens":1687171,"inputTokens":1560,"model":"claude-fable-5-1","outputTokens":22079,"runtime":"claude","turns":52,"wallClockMs":417462}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7591760a616c6429","findings":[{"citation":"resolved","description":"The launch's stated guarantee (README.md:47-48, 55) is that each part fits one Ethereum transaction under the EIP-7825 per-transaction gas cap of 2^24 = 16,777,216 gas (live on mainnet since Fusaka). Both fit tests bound the gas the transaction USES (test/Part3Launch.t.sol:114-116, test/FrenRenderer.t.sol:147-149). Under EIP-7825 a transaction is rejected by the node when its gas LIMIT exceeds 2^24, whatever it uses. The deployer that sent this project's two earlier launches sets the limit with a ~21% buffer, verified on chain during this review via a public RPC: launch #819 (tx 0x7b6503966cc85ffbf267a50625e47392554d6a30d47fa5bff884e0bc7110012d, from 0xcECc29B037f5064fCdF45a5C318F132ef76aA551 to the factory 0xfF03410d0Fe5fa8f7F59F743de35E333D9857120) gasUsed 11,290,222, gas limit 13,669,323 (ratio 1.2107); launch #838 (tx 0xcbee71603d55caf38ea7e4e961e10d689110db7554cf5ffdbcf44c9f04930903) gasUsed 10,569,418, gas limit 12,797,493 (ratio 1.2108). A CREATE2 probe in this review (non-isolated run, exact 16/4 calldata pricing, test/scratch) measures launch 1 at 10,707,682 and launch 2 at 9,957,993 including 21,000 base and calldata, so the live factory adds about 582K-611K gas on top of the raw creations. The same probe measures part 3 (FrenArtChunk5, 6, 7 and FrenRenderer with the four mainnet addresses plus three predicted ones) at 14,075,939; test/Part3Launch.t.sol itself prints 14,102,171 with FOUNDRY_ISOLATE=false and 15,293,183 in the default isolated run (isolate mode charges the intrinsic calldata cost once itself and the test adds it a second time). With the factory overhead part 3 will use about 14.68M gas: 87.5% of the cap, which is why both tests pass against their 95% bound. The limit the deployer would set, 1.2108 x 14.68M = 17.77M, is above 16,777,216 by about 1.0M. For a 21% buffer to fit, gas used must stay under 13.86M; part 3 is 0.8M over that. The deployer's code (apps/deployer/src/deploy.ts) is not in this tree, so whether it clamps the limit to min(buffered estimate, 2^24) could not be verified here; the factory call cannot be simulated with the real factory either, since its calldata carries a verifier signature (decoded from launch #819: launch number, bytes[] init codes, bytes32[] names, address[] predicted addresses, kind string, verifier address and signed hashes). Launches #819 and #838 never exercised this edge: their limits were 13.7M and 12.8M. No funds are at risk; the contracts themselves are correct. The gap is service evidence: either (1) a record that the deployer caps gasLimit at 2^24 (part 3 then lands with ~2.1M of headroom as used), or (2) if it does not, part 3 must shrink so that 1.21 x used stays under the cap (used <= ~13.85M), e.g. by moving FrenArtChunk7 (8,944 bytes of runtime, ~1.8M gas of code deposit plus ~0.15M calldata) out of this launch, which changes the agreed three-launch composition and turns the renderer's seventh argument into a static address, a scope decision for the requester. In both cases the fit tests should assert the quantity the deployer actually submits (total * 121 / 100 < 2^24, or total < 2^24 / 1.21) rather than total < 95% of the cap, and README.md:47-48 should state the real part-3 figure (~14.1M before factory overhead, not 13.9M). This keeps the audit_economics medium finding; its on-chain figures and probe measurements were re-derived independently here.","line":116,"path":"test/Part3Launch.t.sol","reproduction":"State: Ethereum mainnet after Fusaka (EIP-7825: a transaction with gasLimit > 16,777,216 is invalid), IMD deployer behaving as in launches #819 and #838 (gas limit ~1.2108 x gas used). Steps: (1) `cast tx 0x7b6503966cc85ffbf267a50625e47392554d6a30d47fa5bff884e0bc7110012d --rpc-url <mainnet>` -> gas 13669323; `cast receipt` of it -> gasUsed 11290222 (ratio 1.2107). Same for 0xcbee71603d55caf38ea7e4e961e10d689110db7554cf5ffdbcf44c9f04930903 -> gas 12797493, gasUsed 10569418 (ratio 1.2108). (2) `FOUNDRY_ISOLATE=false forge test --match-test test_Part3Create2FitsOneTransaction -vv` -> 'part 3 CREATE2 gas (with calldata): 14102171', PASS because 14.10M < 15,938,355. The same probe applied to launches 1 and 2 gives 10,707,682 and 9,957,993, i.e. the live factory added 582,540 and 611,425 gas on top of the probe figures. (3) Expected part-3 transaction: gasUsed ~14.68M (14.10M + ~0.6M factory overhead), gasLimit 1.2108 x 14.68M ~ 17.77M. Actual constraint: gasLimit > 16,777,216 -> node rejects the transaction ('transaction gas limit exceeds cap'), so the part-3 launch cannot be submitted unless the deployer clamps its limit. The repository's tests cannot detect this: they bound gas used at 95% of the cap, whereas the deployer's observed buffer requires used <= 16,777,216 / 1.2108 = 13,856,000; replacing line 116 with `assertLt(total * 12108 / 10000, 1 << 24)` fails on this tree: 'assertion failed: 17074908 >= 16777216' with FOUNDRY_ISOLATE=false and '18516985 >= 16777216' in the default isolated run.","severity":"medium","snippet":"        assertLt(total, uint256(1 << 24) * 95 / 100);","title":"Part 3 fits the EIP-7825 cap as gas used, but not as the gas limit the IMD deployer has set so far: 1.21 x ~14.7M = ~17.8M > 2^24, so the launch transaction is invalid unless the deployer clamps its l"},{"citation":"resolved","description":"ImdStyleArtLaunches (test/FrenRenderer.t.sol:13-30) deploys the chunks and the renderer with Solidity `new` inside a test file, and setUp measures each launch with gasleft() around f.launch1()/launch2()/launch3() (lines 46-55). Foundry 1.8.3, which verifies this project, has dynamic_test_linking = true by default (`forge config --json` on this tree) and preprocesses test sources so that every `new X(...)` becomes a `vm.deployCode(\"src/FrenArtChunks.sol:FrenArtChunkN\")` cheatcode call; creations made through the cheatcode run outside the calling frame's gas accounting, so launchGas excludes the 200 gas/byte code-deposit cost (about 4.8M per 24 KB chunk) that dominates a real launch. In the default run the test logs 1,000,622 / 957,524 / 1,295,967 for launches 1-3 (almost all of it the 16 gas/byte calldata term the test adds itself) and passes; with FOUNDRY_DYNAMIC_TEST_LINKING=false it logs 10,739,138 / 9,992,078 / 13,981,156, the figures README.md:47-48 quotes. The on-chain receipts of launches #819 and #838 used 11,290,222 and 10,569,418 gas, so the default-mode numbers are off by more than 10x and the assertion at line 149 would pass for any launch size (even a 24,576-byte chunk would show ~0.4M). The EIP-7825 guarantee the test documents is therefore protected only by test/Part3Launch.t.sol (vm.getCode plus assembly create2, immune to the rewrite), and only for part 3; README.md:47-48 describes output the default test run no longer produces. Production contracts are unaffected. Minimal fix: in ImdStyleArtLaunches deploy from type(X).creationCode (or vm.getCode) with an assembly create/create2 as Part3Launch.t.sol does, and add a lower bound such as assertGt(launchGas[i], 5_000_000) so a metering change fails the test instead of passing silently; then refresh the README figures. Merged from the audit_economics low (line 149) and audit_flow low (line 147): same root cause, same fix.","line":149,"path":"test/FrenRenderer.t.sol","reproduction":"Input: `forge test --match-test test_LaunchesFitTransactions -vv` on this tree with the default configuration (forge 1.8.3, dynamic_test_linking true). Actual: 'launch 1 gas (with calldata): 1000622', 'launch 2 gas (with calldata): 957524', 'launch 3 gas (with calldata): 1295967', PASS. Expected (the quantity the test claims to bound; what `FOUNDRY_DYNAMIC_TEST_LINKING=false forge test --match-test test_LaunchesFitTransactions -vv` prints): 10739138 / 9992078 / 13981156, matching the 11,290,222 and 10,569,418 gasUsed of the mainnet receipts for launches #819 and #838 within the factory's overhead. Cross-check: a CREATE2 probe over vm.getCode bytes (non-isolated) measures 10,707,682 / 9,957,993 / 14,075,939 for the three launches. Adding `assertGt(launchGas[i], 5_000_000, \"launch gas not metered\")` inside the loop fails on the default run with 'launch gas not metered: 69750 <= 5000000' (launchGas[0] is 69,750 for 48 KB of deployed code) and passes with FOUNDRY_DYNAMIC_TEST_LINKING=false.","severity":"low","snippet":"            uint256 total = launchGas[i] + 21_000 + 16 * launchInitBytes[i];\n            emit log_named_uint(string.concat(\"launch \", vm.toString(i + 1), \" gas (with calldata)\"), total);\n            assertLt(total, TX_CAP * 95 / 100);","title":"test_LaunchesFitTransactions passes vacuously: forge's default dynamic test linking rewrites the helper's `new FrenArtChunkN()` into an unmetered vm.deployCode, so each launch measures ~1M gas instead"},{"citation":"resolved","description":"Measured on the renderer deployed from this tree (non-isolated run, gasleft() around the call): pendingURI(1) = 25,474,264 gas, unrevealed(1) alone = 15,143,700 (four frens drawn over the machine wall into a 4 x 84 x 84 sheet, then a 29,302-byte bitmap base64-encoded twice into a 70,493-byte URI), tokenURI(1, 0xbd59c, 42) = 9,034,529, bmp = 6,225,680. test/FrenRenderer.t.sol:133-140 and the byte-for-byte comparison with test/ref/FrenRendererRef.sol show this is the agreed behaviour (the brief requires equality with the renderer the frens launch with), not a regression, so no code change is proposed within this launch. It is recorded for whoever serves the metadata: an IMD6900Frens.tokenURI that forwards to pendingURI needs more than 25.5M gas in one eth_call. geth's default rpc.gascap (50M) serves it; providers or indexers that cap eth_call at 25M-30M fail to render unrevealed tokens' metadata and return no data for them until reveal. Reproduces the audit_flow info finding.","line":84,"path":"src/FrenRenderer.sol","reproduction":"State: FrenArtChunk1..7 and FrenRenderer deployed from this tree (FOUNDRY_ISOLATE=false; the same holds with the four mainnet chunks). Call `r.pendingURI(1)` with gasleft() measured around it. Expected by an operator sizing an eth_call at a typical 25M cap: completes. Actual: consumes 25,474,264 gas (unrevealed(1) 15,143,700; tokenURI(1, 0xbd59c, 42) 9,034,529), so an eth_call with a 25M gas limit runs out of gas and returns no metadata; with 30M or more it succeeds and returns a 70,493-byte data URI.","severity":"info","snippet":"    function pendingURI(uint256 tokenId) external view returns (string memory) {","title":"pendingURI costs about 25.5M gas per eth_call (unrevealed about 15.1M, tokenURI about 9-10M): identical to the launch renderer by design, but above the eth_call gas cap of some RPC providers"}],"hash":"a24415e1ca6f29a509075a175a837c6c45ceab695fef251809a018cc9b7773d6","nodeId":"926624a5-def2-47f3-8c23-0548a71cc81c","outcome":"completed","summary":"The review is complete. The findings file holds three findings, all reproduced on this tree, and no tracked file was changed.\n\n**Outcome of the specialist findings**\n\n- **Kept at medium (economics):** part 3 fits the EIP-7825 cap as gas used but not as the gas limit the IMD deployer has set so far. I re-derived the on-chain facts from a public RPC: launches #819 and #838 had gas limits of 1.2107x and 1.2108x their gas used. A CREATE2 probe measures part 3 at about 14.1M gas with calldata. The live factory added roughly 0.6M to the probe figure for launches 1 and 2, so part 3 will use about 14.7M. A 21% buffer on that gives about 17.8M, above the 16,777,216 cap. Replacing the test's bound with the buffered quantity fails on this tree. The deployer code is not in the repository and the real factory cannot be simulated because its calldata carries a verifier signature, so the finding names the needed evidence: either a record that the deployer clamps the limit at 2^24, or a smaller part 3, which is a scope decision.\n- **Merged into one low (economics + flow):** the launch-fit test in test/FrenRenderer.t.sol is vacuous under forge's default dynamic test linking. The default run logs about 1.0M per launch against 10.7M with linking off. A lower bound added to the loop fails with 69,750 gas metered for 48 KB of code.\n- **Kept at info (flow):** pendingURI costs about 25.5M gas per call, by design and byte-equal to the launch renderer. Recorded as an operational note for whoever serves the metadata.\n\n**My own pass found nothing further.** I checked the constructor's code-hash gate, every index and table read in the renderer against the layer counts, the framed decoder's bounds, the BMP assembly, the unrevealed combo construction, and the deployment-phase checklist from the x-ray reference. The four mainnet chunk addresses have exactly the code hashes FrenArtIndex names, verified live. The full suite passes with 31 tests.","treeHash":null,"usage":{"cachedInputTokens":2098949,"inputTokens":674,"model":"claude-fable-5-1","outputTokens":32731,"runtime":"claude","turns":49,"wallClockMs":1062225}},{"artifacts":[],"attempt":1,"bundleHash":"914e06c30175993e953ef4d51c7c52fe7ea36eee7274ffe8185a400e3e62515b","device":"26d42bb29b53b9d8","findings":[{"description":"The local deployment rehearsal consumes less than the EIP-7825 cap, but this does not establish that the gasLimit submitted by the production service is valid. EIP-7825 rejects limits above 16,777,216 regardless of actual usage (https://eips.ethereum.org/EIPS/eip-7825). Applying the reviewer-reported 21.08% buffer without a clamp exceeds the cap even on a conservative local lower bound before production factory overhead. The service source apps/deployer/src/deploy.ts and signed factory calldata are absent. A clamp may already exist; an actual production rejection is therefore conditional, not independently established. The tests now meter actual creations and identify their assertions as local usage budgets, but cannot certify this service policy. README.md lines 47-48 also retain an unconditional fit claim outside the allowed test-only changes. Resolve by verifying gasLimit <= 2^24 on the fully signed, simulated production call; if the service does not clamp, fix it or obtain approval for a different launch composition. Do not change generated art or constructor order to silence this test.","line":126,"path":"test/Part3Launch.t.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {FrenRenderer} from \"src/FrenRenderer.sol\";\nimport {FrenArtChunk1} from \"src/FrenArtChunks.sol\";\n\ncontract BufferedLimitProbe {\n    function deploy(bytes[] memory codes) external returns (uint256 used) {\n        uint256 beforeGas = gasleft();\n        for (uint256 i; i < codes.length; ++i) {\n            bytes memory code = codes[i];\n            address deployed;\n            assembly (\"memory-safe\") {\n                deployed := create2(0, add(code, 32), mload(code), i)\n            }\n            require(deployed != address(0), \"constructor failed\");\n        }\n        used = beforeGas - gasleft();\n    }\n}\n\n/// @dev Conditional proof: the reported 21.08% buffer must not be used without a cap.\n/// It does not establish the unavailable production deployer's current policy.\ncontract Part3BufferedLimitProof is Test {\n    function test_ReportedUnclampedBufferFitsPart3() public {\n        address[4] memory existing = [\n            0xa92dAcfF6d6fcC218ADe20eD24857376BD8eBE81,\n            0x9666A481e20F1dB59EEbD6c43D11Ae3505468c92,\n            0x71BdEB749b3ee428730eBB3E9b34B03A99D82356,\n            0x0C344484D960B8474a1EdcB5A5128e8D9C9F6B4d\n        ];\n        for (uint256 i; i < existing.length; ++i) {\n            address local = deployCode(string.concat(\"FrenArtChunks.sol:FrenArtChunk\", vm.toString(i + 1)));\n            vm.etch(existing[i], local.code);\n        }\n\n        BufferedLimitProbe probe = new BufferedLimitProbe();\n        bytes[] memory codes = new bytes[](4);\n        address[3] memory predicted;\n        for (uint256 i; i < 3; ++i) {\n            codes[i] = vm.getCode(string.concat(\"FrenArtChunks.sol:FrenArtChunk\", vm.toString(i + 5)));\n            predicted[i] = address(uint160(uint256(keccak256(\n                abi.encodePacked(bytes1(0xff), address(probe), bytes32(i), keccak256(codes[i]))\n            ))));\n        }\n        codes[3] = bytes.concat(vm.getCode(\"FrenRenderer.sol:FrenRenderer\"), abi.encode(\n            existing[0], existing[1], existing[2], existing[3], predicted[0], predicted[1], predicted[2]\n        ));\n        bytes memory payload = abi.encodeCall(probe.deploy, (codes));\n        uint256 intrinsic = 21_000;\n        for (uint256 i; i < payload.length; ++i) intrinsic += payload[i] == 0 ? 4 : 16;\n\n        // Measure inside the probe so Foundry isolation cannot double-charge intrinsic gas.\n        // Production signature checks and other factory work are deliberately excluded.\n        uint256 localGas = probe.deploy(codes) + intrinsic;\n        uint256 bufferedLimit = (localGas * 12_108 + 9_999) / 10_000;\n        emit log_named_uint(\"local CREATE2 gas plus intrinsic\", localGas);\n        emit log_named_uint(\"gas limit with reported unclamped buffer\", bufferedLimit);\n        assertLe(bufferedLimit, 1 << 24, \"unclamped gas limit exceeds EIP-7825\");\n    }\n}","reproduction":"Before changes: forge test --match-test test_Part3Create2FitsOneTransaction -vv passed and logged 15,293,183; FOUNDRY_ISOLATE=false produced 14,102,171 and also passed. Save the attached proof as test/scratch/Part3BufferedLimitProof.t.sol and run FOUNDRY_ISOLATE=false forge test --match-path test/scratch/Part3BufferedLimitProof.t.sol -vv. Executed locally with Foundry 1.8.5/Solc 0.8.26: local CREATE2 body plus exact intrinsic gas = 13,864,764; rounded-up buffered limit = 16,787,457; assertion fails: 16,787,457 > 16,777,216. Expected for the reported unclamped policy: limit <= cap. Actual: the lower bound alone violates it. The proof omits ABI dispatch/encoding around the probe and production factory work, making the bound conservative. It proves the unclamped-buffer incompatibility; it does not simulate a node rejection or inspect the current service clamp. It is preserved here rather than submitted as a failing test or inverted into an assertion blessing the invalid limit.","severity":"medium","title":"Part 3 still needs evidence of a capped deployer gas limit before submission"}],"hash":"b99a422c28b5576a890f068937c7e170ba8fa499ea6bbbebe2a179955e190033","nodeId":"3a997e09-2f8d-48d1-969f-56515da897ae","outcome":"completed","summary":"Fixed gas metering and intrinsic-gas double counting; added code-deposit regression checks.\n\nOffline build and tests pass: **31 passed, 1 optional fork skipped**. Checks also pass without dynamic linking.\n\nSaved both [responses](.imd-responses.json) and the [unresolved gas-limit finding with proof](.imd-findings.json). The actual deployer’s gas-limit cap remains unverified.","treeHash":"5aa9fc04695ff4367115b5acb03e8d435380686d","usage":{"cachedInputTokens":3905024,"inputTokens":169094,"model":"gpt-6-astra","outputTokens":31431,"runtime":"codex","turns":13,"wallClockMs":1289832}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"759c614fdc84ff66","findings":[{"citation":"resolved","description":"Settlement of the round-2 medium finding (id 089bbff4...), merged with the economics medium (a49e1eff...) and the write_foundry_tests medium (64a72793...). Nothing in the tree changed this round, and the author's dispute holds. The attached proof (Proof_089bbff432dd / Proof_64a72793faf2, which are identical) hardcodes an unclamped 1.2108 gas-limit buffer inside the test and never runs the production gas-limit selection. So it fails on this code, and it would still fail after the remedy the finding itself accepted (the deployer clamps gasLimit to min(estimate x 1.21, 2^24)). That makes it an invalid regression criterion for anything the author can change. The defect is not in the Solidity, the constructor arguments or launch.json. The brief fixes the chunks, the argument order and the three-launch composition. Measured as gas used, part 3 fits the cap with about 2.8M to spare locally, and about 2.2M once the ~0.6M factory overhead seen in launches #819 and #838 is added. Under the severity rubric the worst case is not a loss of funds or permanent breakage. If the deployer submitted an unclamped limit, the node would reject the transaction at submission, so no gas is spent and nothing is deployed, and the launch can be retried once the service clamps its limit. That is a service configuration item for the deployer's operator (apps/deployer/src/deploy.ts, not in this tree), not a defect the author can fix, so it is recorded here as information and does not block. What the operator should confirm before sending part 3: the gas limit actually submitted is <= 16,777,216, and the signed factory call simulates successfully at that limit. A residual documentation inaccuracy is kept in the same note. README.md lines 47-48 name test_LaunchesFitTransactions, which no longer exists: it is now test_LaunchCreationGasIsMeteredAndWithinLocalBudget (test/FrenRenderer.t.sol:174), and it prints 10,780,000 / 10,030,026 / 14,057,311 rather than 10.7M / 10.0M / 13.9M. The specialists' two low findings about that old test passing vacuously under dynamic test linking (551272959e..., ecebb7cbb6...) are fixed: the replacement test meters real CREATEs and asserts a 200 gas per runtime byte lower bound, and now reports ~10-14M per launch instead of ~1M.","line":47,"path":"README.md","reproduction":"Run on this tree with Foundry 1.8.3, offline. (1) `forge test --offline -vv`: 31 passed, 1 skipped (fork test, no MAINNET_RPC_URL). test_Part3Create2GasIsMeteredAndWithinLocalBudget logs 'part 3 local CREATE2 gas (with intrinsic): 13953449' (< 16,777,216, passes). test_LaunchCreationGasIsMeteredAndWithinLocalBudget logs 10780000 / 10030026 / 14057311, so it is metered and no longer vacuous. (2) Copy .imd/reads/proofs/Proof_089bbff432dd.t.sol to test/scratch/ and run it. It fails with 'unclamped gas limit exceeds EIP-7825: 16799565 > 16777216' from 'local CREATE2 gas plus intrinsic: 13874764'. That is gas used of ~82.7% of the cap; only the hardcoded 1.2108 multiplier crosses it, and no change inside this repository can make that assertion pass without changing the brief's fixed composition. The proof is therefore dropped as a regression criterion. (3) README.md:47 names `test_LaunchesFitTransactions`. `grep -n test_LaunchesFitTransactions test/*.sol` finds nothing. Expected: the README names the existing test and its current figures. Actual: a stale name and stale figures.","severity":"info","snippet":"- `test_LaunchesFitTransactions`: each of the three launches below fits one transaction under EIP-7825's cap","title":"Settled (no longer blocking): part 3 uses ~13.95M gas locally, within EIP-7825's 2^24 cap. Its submitted gas limit is valid only if the IMD deployer clamps its ~1.21x buffer, which is a service item o"},{"citation":"resolved","description":"Carried over unchanged (ids 5b0017d7..., 1e60bbca...), and merged with audit_flow's info finding 72463c09... (same mechanism). test/FrenRenderer.t.sol requires the renderer to be byte-for-byte the same as test/ref/FrenRendererRef.sol, and the brief requires the renderer the frens launch with, so this is agreed behaviour, not a regression. Operational note only, for whoever serves the metadata: an IMD6900Frens.tokenURI that forwards to pendingURI needs more than 25.5M gas in one eth_call. geth's default rpc.gascap (50M) serves it. Providers or indexers that cap eth_call at about 25M cannot render unrevealed tokens until reveal. No code change is proposed.","line":84,"path":"src/FrenRenderer.sol","reproduction":"State: FrenArtChunk1..4 etched at the four mainnet addresses, and FrenArtChunk5..7 plus FrenRenderer deployed from this tree. Call r.pendingURI(1) and measure gasleft() around the call. It consumes 25,611,804 gas in the default configuration (25,494,305 measured by audit_flow) and returns a 70,493-byte data URI. Expected by an operator sizing eth_call at a 25M cap: it completes. Actual: out of gas below about 25.6M; it succeeds at 30M. In this round's run, tokenURI logs 10,315,627 gas (test_TokenURIIsCheapEnoughToRead).","severity":"info","snippet":"    function pendingURI(uint256 tokenId) external view returns (string memory) {","title":"pendingURI costs about 25.6M gas per eth_call (tokenURI about 10.3M). It is identical to the launch renderer by design, but above the eth_call gas cap of some RPC providers"}],"hash":"d699c4328b0150ccca78e883d0c92480c36f9228b01ce017b8ab13aed3e59e3a","nodeId":"926624a5-def2-47f3-8c23-0548a71cc81c","outcome":"completed","summary":"I've settled last round's medium finding: it is no longer blocking and is now an informational note. Nothing is left that blocks this launch. `.imd-findings.json` holds two informational findings and no tracked file changed.\n\n**What I ran.** Nothing in `src/`, the tests or `launch.json` changed this round; the author changed no files. The full suite (Forge 1.8.3, offline) gave 31 passed and 1 skipped. The skipped one is the mainnet fork test, which needs an RPC URL that wasn't supplied. I also ran the attached proof from a scratch copy, then deleted the scratch folder.\n\n**Last round's medium (the transaction gas limit), now informational.** The author's dispute holds:\n- **The numbers still match.** Part 3 uses 13,953,449 gas locally, under the 16,777,216 per-transaction cap. The proof fails only because it multiplies its usage figure (13,874,764) by the deployer's ~1.21 buffer, giving 16,799,565.\n- **The proof can't serve as the fix test.** The 1.21 buffer is written into the test, so it would still fail after the remedy I accepted last round: the deployer capping the gas limit it submits at 2^24. The author cannot make it pass without changing the three-launch split, which the brief fixes.\n- **It is not a defect in this code.** Source, constructor arguments, chunks and `launch.json` are correct. If the deployer sent a limit over the cap, the node would refuse the transaction before it ran. That costs nothing and can be retried once the deployer is fixed, so it is not a loss of funds or permanent breakage.\n- **Open item for the deployer's operator:** before part 3 is sent, confirm the gas limit actually submitted is at most 16,777,216 and that the signed factory call succeeds at that limit. The deployer code (`apps/deployer/src/deploy.ts`) is not in this tree, so this can't be checked here.\n\n**README still out of date.** `README.md:47` names `test_LaunchesFitTransactions`, which no longer exists. It is now `test_LaunchCreationGasIsMeteredAndWithinLocalBudget` (`test/FrenRenderer.t.sol:174`), and it prints 10,780,000 / 10,030,026 / 14,057,311 rather than the README's 10.7M / 10.0M / 13.9M.\n\n**`pendingURI` gas, carried over as informational.** `src/FrenRenderer.sol:84` takes about 25.6M gas per call, and `tokenURI` about 10.3M. That matches the reference renderer, as the brief requires. RPC providers that cap read calls near 25M won't serve unrevealed tokens' metadata. audit_flow reported the same thing, so I merged it.\n\n**Specialists' findings this round:**\n- **Merged:** audit_economics' medium and write_foundry_tests' medium have the same root cause as my gas-limit finding.\n- **Dropped as fixed:** the two low findings saying the old launch-fit test measured almost nothing. Its replacement measures real deployments, refuses to pass if code storage isn't charged (200 gas per byte), and now reports about 10–14M gas per launch.\n- **No findings:** audit_permissions and audit_math.","treeHash":null,"usage":{"cachedInputTokens":322542,"inputTokens":14,"model":"claude-opus-5-5","outputTokens":7574,"runtime":"claude","turns":7,"wallClockMs":289734}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2d027bc56749d95c","findings":[],"hash":"e63d190295bce7f5b253260904e972de79c8da569e74c12aca79ab54015f5e8d","nodeId":"74b67861-e915-452a-8648-2413da3e8e68","outcome":"completed","summary":"The review is complete. The findings file holds an empty list: within the Access Control, Trust Gap and Asymmetry guides I found no defect with a concrete failing input, and nothing severe outside them.\n\n**What I verified**\n\n- **Permission model.** The renderer has no owner, no roles, no state-changing function, no receive or fallback, and no use of the factory as caller. Calls with value or an unknown selector revert. Chunks 5, 6 and 7 are a STOP byte and data, so any call succeeds and does nothing.\n- **Constructor and trust boundary.** The constructor refuses a zero-code address, a misordered chunk, and a chunk with one byte changed, and it accepts the same code at another address. So the argument order and the four static addresses are the only trust input.\n- **Live dependencies.** Over a public mainnet RPC, the code hashes and sizes at all four static addresses match the index entry for their position, and the repository's fork test passes against the live chain.\n- **Encode and decode symmetry.** A scratch test drew every face for every character, every hat, item, coat, shirt, eye and background, seed window extremes, the palette, and the pending path at ids 0, 2222 and the maximum, on this renderer and the launch reference. All identical, including layers in the framed chunks 4 and 7.\n- **Existing suite.** All ten offline tests pass, and the fork test passes with an RPC.\n\n**Coverage rows**\n\n| Entry point | Verdict | Reason |\n|---|---|---|\n| FrenArtChunk5/6/7 constructors | holds | No arguments, return STOP plus data, no caller dependence |\n| FrenArtChunk runtime (any call) | holds | STOP only, no state |\n| FrenRenderer constructor | holds | Code hash per position, immutables only, no roles |\n| tokenURI, bmp, canvas | holds | View, validated combo, same bytes as reference |\n| pendingURI, unrevealed | holds | View, generated combos in range, same bytes as reference |\n| attributes | holds | Pure, no state |\n| Getters (chunk1..7, faceLayers, shadow) | holds | Immutables and constants |\n\n**Notes that do not qualify as findings**\n\n- Sending ETH to a chunk succeeds and strands it. That is self-harm intrinsic to STOP-prefixed data contracts, and the task forbids changing the chunks.\n- The comment on CHUNK_SIZES in src/FrenArtIndex.sol says the renderer checks sizes, but nothing reads that constant. The hash check is strictly stronger, so there is no failing input.\n- The frens contract address the README names has no code on mainnet today, so I could not confirm which renderer selectors it will call. The signatures match the launch reference exactly.\n- Read cost is about 25.5M gas for pendingURI and 8.2M for tokenURI, identical to the reference and under common RPC call caps.\n\nThe scratch tests were removed; only .imd-findings.json was added.","treeHash":null,"usage":{"cachedInputTokens":984243,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":22886,"runtime":"claude","turns":31,"wallClockMs":530402}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"91067b3439961e55","findings":[{"citation":"resolved","description":"Settlement of the earlier medium finding (id 09603caf...). The author answered 'disputed' only as to an unconditional claim that the production deployer rejects the launch; they reproduced the measurement gap, left the launch 'NOT cleared', and changed tests only. What they changed holds: the part-3 probe now meters inside a nested call so the isolated run no longer double-counts intrinsic gas (13,953,173 by default vs 13,940,673 with FOUNDRY_ISOLATE=false, against 15,293,183 vs 14,102,171 before), both gas tests carry a 200 gas per runtime byte lower bound, and they are renamed to say they bound local usage rather than transaction validity. None of that resolves the defect, which was never in the Solidity: it is that the transaction this launch produces is invalid under EIP-7825 unless the deployer caps the gas LIMIT it submits. Re-verified on chain during this round over a public RPC (ethereum-rpc.publicnode.com): launch #819 tx 0x7b6503966cc85ffbf267a50625e47392554d6a30d47fa5bff884e0bc7110012d (from 0xcECc29B037f5064fCdF45a5C318F132ef76aA551 to factory 0xfF03410d0Fe5fa8f7F59F743de35E333D9857120, block 26134918) gas limit 13,669,323 for gasUsed 11,290,222 (ratio 1.21072); launch #838 tx 0xcbee71603d55caf38ea7e4e961e10d689110db7554cf5ffdbcf44c9f04930903 (block 26135458) gas limit 12,797,493 for gasUsed 10,569,418 (ratio 1.21080). The author's RPC attempts returned 403; these figures are therefore now independently confirmed twice. The specialist proof attached this round (write_foundry_tests, Proof_64a72793faf2.t.sol) was run on this tree: it measures 13,874,488 gas for the bare part-3 CREATE2 sequence plus exact intrinsic gas (13,864,488 non-isolated) and fails with 'unclamped gas limit exceeds EIP-7825: 16799231 > 16777216' (16,787,123 non-isolated). That bound excludes the production factory's own work, which the two live receipts show adds roughly 0.58M to 0.61M gas on top of the raw creations, so the real part-3 transaction will use about 14.5M and a 1.2108 buffer puts its limit near 17.5M, about 0.75M over the cap, even though usage itself is only about 86% of it. The deployer code (apps/deployer/src/deploy.ts) is not in this tree, so a clamp to min(estimate x 1.21, 2^24) can be neither confirmed nor excluded here; launches #819 and #838 never exercised it (limits 13.7M and 12.8M). This is the one unresolved item blocking admission and it is a service-evidence or scope decision, not a code defect: (1) record evidence that the deployer caps gasLimit at 2^24 and simulates the signed factory call successfully at that limit (part 3 then has about 2.2M of headroom as used), or (2) if it does not, shrink part 3 so that 1.21 x used stays under the cap (used <= ~13.85M including factory overhead, i.e. about 1.2M less than today), for example by moving FrenArtChunk7 (8,944 runtime bytes, ~1.8M gas of code deposit plus calldata) to a separate launch and turning the renderer's seventh argument into a static address, which changes the agreed three-launch composition and needs the requester's decision. Whichever is chosen, the fit assertion should encode the quantity actually submitted (e.g. total * 12108 / 10000 < 1 << 24, which fails on this tree) rather than 95% of the cap. Residual documentation gap, outside the author's test-only scope and still present: README.md lines 47-48 name test_LaunchesFitTransactions, a test that no longer exists (it is now test_LaunchCreationGasIsMeteredAndWithinLocalBudget), and state that each launch 'fits one transaction under EIP-7825's cap' at 13.9M for part 3, while line 55 repeats the fit claim; the current default run prints 10,775,568 / 10,026,712 / 14,057,012 and the fit as a transaction is exactly what is unproven. Merged with the write_foundry_tests medium (same root cause, same numbers, proof kept on this finding). Source, constructor arguments, launch.json and the chunks are correct and unchanged; no funds are at risk.","line":139,"path":"test/Part3Launch.t.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {FrenRenderer} from \"src/FrenRenderer.sol\";\nimport {FrenArtChunk1} from \"src/FrenArtChunks.sol\";\n\ncontract BufferedLimitProbe {\n    function deploy(bytes[] memory codes) external returns (uint256 used) {\n        uint256 beforeGas = gasleft();\n        for (uint256 i; i < codes.length; ++i) {\n            bytes memory code = codes[i];\n            address deployed;\n            assembly (\"memory-safe\") {\n                deployed := create2(0, add(code, 32), mload(code), i)\n            }\n            require(deployed != address(0), \"constructor failed\");\n        }\n        used = beforeGas - gasleft();\n    }\n}\n\n/// @dev Conditional proof: the reported 21.08% buffer must not be used without a cap.\n/// It does not establish the unavailable production deployer's current policy.\ncontract Part3BufferedLimitProof is Test {\n    function test_ReportedUnclampedBufferFitsPart3() public {\n        address[4] memory existing = [\n            0xa92dAcfF6d6fcC218ADe20eD24857376BD8eBE81,\n            0x9666A481e20F1dB59EEbD6c43D11Ae3505468c92,\n            0x71BdEB749b3ee428730eBB3E9b34B03A99D82356,\n            0x0C344484D960B8474a1EdcB5A5128e8D9C9F6B4d\n        ];\n        for (uint256 i; i < existing.length; ++i) {\n            address local = deployCode(string.concat(\"FrenArtChunks.sol:FrenArtChunk\", vm.toString(i + 1)));\n            vm.etch(existing[i], local.code);\n        }\n\n        BufferedLimitProbe probe = new BufferedLimitProbe();\n        bytes[] memory codes = new bytes[](4);\n        address[3] memory predicted;\n        for (uint256 i; i < 3; ++i) {\n            codes[i] = vm.getCode(string.concat(\"FrenArtChunks.sol:FrenArtChunk\", vm.toString(i + 5)));\n            predicted[i] = address(uint160(uint256(keccak256(\n                abi.encodePacked(bytes1(0xff), address(probe), bytes32(i), keccak256(codes[i]))\n            ))));\n        }\n        codes[3] = bytes.concat(vm.getCode(\"FrenRenderer.sol:FrenRenderer\"), abi.encode(\n            existing[0], existing[1], existing[2], existing[3], predicted[0], predicted[1], predicted[2]\n        ));\n        bytes memory payload = abi.encodeCall(probe.deploy, (codes));\n        uint256 intrinsic = 21_000;\n        for (uint256 i; i < payload.length; ++i) intrinsic += payload[i] == 0 ? 4 : 16;\n\n        // Measure inside the probe so Foundry isolation cannot double-charge intrinsic gas.\n        // Production signature checks and other factory work are deliberately excluded.\n        uint256 localGas = probe.deploy(codes) + intrinsic;\n        uint256 bufferedLimit = (localGas * 12_108 + 9_999) / 10_000;\n        emit log_named_uint(\"local CREATE2 gas plus intrinsic\", localGas);\n        emit log_named_uint(\"gas limit with reported unclamped buffer\", bufferedLimit);\n        assertLe(bufferedLimit, 1 << 24, \"unclamped gas limit exceeds EIP-7825\");\n    }\n}","reproduction":"State: this tree, Foundry 1.8.3, offline, Ethereum mainnet after Fusaka (EIP-7825: a transaction whose gas limit exceeds 16,777,216 is rejected by the node), IMD deployer behaving as in launches #819 and #838. Steps: (1) `cast tx 0x7b6503966cc85ffbf267a50625e47392554d6a30d47fa5bff884e0bc7110012d gas --rpc-url https://ethereum-rpc.publicnode.com` -> 13669323; `cast receipt ... gasUsed` -> 11290222 (ratio 1.2107). Same for 0xcbee71603d55caf38ea7e4e961e10d689110db7554cf5ffdbcf44c9f04930903 -> 12797493 / 10569418 (ratio 1.2108). (2) `forge test --offline --match-test test_Part3Create2GasIsMeteredAndWithinLocalBudget -vv` -> 'part 3 local CREATE2 gas (with intrinsic): 13953173', PASS (13.95M < 15,938,355); with FOUNDRY_ISOLATE=false -> 13940673, PASS. (3) Save the proof below as test/scratch/Part3BufferedLimitProof.t.sol and run `forge test --offline --match-path test/scratch/Part3BufferedLimitProof.t.sol -vv`. Expected if the launch were submittable with the observed unclamped buffer: PASS. Actual: 'local CREATE2 gas plus intrinsic: 13874488', 'gas limit with reported unclamped buffer: 16799231', FAIL 'unclamped gas limit exceeds EIP-7825: 16799231 > 16777216' (non-isolated: 13864488 -> 16787123 > 16777216). (4) The same holds against the repository test: replacing line 139 with `assertLt(total * 12108 / 10000, 1 << 24)` fails with 16894500 >= 16777216 on the default run. (5) Expected live figures: gasUsed ~13.95M + ~0.6M factory overhead = ~14.5M, gasLimit 1.2108 x 14.5M = ~17.5M > 2^24, so the node rejects the transaction unless the deployer clamps its limit; no artefact in this tree shows that it does.","severity":"medium","snippet":"assertLt(total, uint256(1 << 24) * 95 / 100, \"local creation gas budget\");","title":"Still open: part 3 fits the EIP-7825 cap as gas used but not as the gas limit the IMD deployer has set so far (1.2108 x ~13.9M local, ~14.5M live > 2^24); the revised tests bound local usage only and "},{"citation":"resolved","description":"Carried over unchanged from the first round (id 1e60bbca...): the author gave no answer and no change was expected, since test/FrenRenderer.t.sol:144-146 requires byte-for-byte equality with test/ref/FrenRendererRef.sol and the brief requires the renderer the frens launch with. Re-measured on this tree: pendingURI(1) consumes 25,611,804 gas (25,599,304 with FOUNDRY_ISOLATE=false) and returns a 70,493-byte data URI; tokenURI(1, 0xbd59c, 42) consumes 9,082,421. Operational note only, for whoever serves the metadata: an IMD6900Frens.tokenURI that forwards to pendingURI needs more than 25.6M gas in one eth_call. geth's default rpc.gascap (50M) serves it; providers or indexers that cap eth_call at 25M fail to render unrevealed tokens' metadata until reveal. Not blocking; no code change proposed within this launch.","line":84,"path":"src/FrenRenderer.sol","reproduction":"State: FrenArtChunk1..4 etched at the four mainnet addresses from this tree's bytecode, FrenArtChunk5..7 and FrenRenderer deployed from this tree. Call `r.pendingURI(1)` with gasleft() measured around the call. Expected by an operator sizing an eth_call at a 25M cap: completes. Actual: 25,611,804 gas consumed (log 'pendingURI(1) gas: 25611804' in a scratch forge test, default configuration), so an eth_call with a 25M gas limit runs out of gas and returns no metadata; with 30M or more it succeeds and returns 70,493 bytes.","severity":"info","snippet":"function pendingURI(uint256 tokenId) external view returns (string memory) {","title":"pendingURI costs about 25.6M gas per eth_call (tokenURI about 9.1M): identical to the launch renderer by design, but above the eth_call gas cap of some RPC providers"}],"hash":"f9affce90bf54d7ff17b9756d676b52efabd0c5a19d7eec6b2844c164cc824dc","nodeId":"926624a5-def2-47f3-8c23-0548a71cc81c","outcome":"completed","summary":"Review settled. The findings file is written, parses, and the working tree is clean apart from the ignored `.imd-findings.json`.\n\n**Outcome of the three earlier findings**\n\n- **Medium, deployer gas limit: still open, kept at medium.** The author's test changes are sound and were accepted. The part-3 probe no longer double-counts intrinsic gas in isolated runs, both gas tests carry a code-deposit lower bound, and both are renamed to claim only a local usage budget. None of that touches the defect, which was never in the Solidity. The attached specialist proof fails on this tree for exactly the stated reason, and I re-verified both mainnet receipts over a public RPC this round, so the author's 403 gap is closed. The write_foundry_tests medium was the same root cause and is merged into this one, with its proof kept on it.\n- **Low, vacuous gas metering: fixed and dropped.** The launch helper now deploys with assembly CREATE, so the default run meters real creation gas, and a scratch check confirmed the new lower bound trips on a `new`-based helper.\n- **Info, pendingURI gas: still true, kept as info.** Re-measured at about 25.6M gas. It is identical to the launch renderer by design and is an operational note for whoever serves the metadata, not a blocker.\n\nKey figures behind the open finding:\n\n| Quantity | Value |\n| --- | --- |\n| Launch #819 gas limit / used | 13,669,323 / 11,290,222 (ratio 1.2107) |\n| Launch #838 gas limit / used | 12,797,493 / 10,569,418 (ratio 1.2108) |\n| Part 3 local CREATE2 gas, repository test | 13,953,173 |\n| Part 3 proof lower bound x 1.2108 | 16,799,231, cap is 16,777,216 |\n\n**What is next** is a service or scope decision, not a code fix. Either the deployer records that it clamps the submitted gas limit to the EIP-7825 cap and simulates the signed call at that limit, or part 3 is recomposed so that the buffered limit fits, which changes the agreed three-launch plan. The README also still names a test that no longer exists and repeats the unproven fit claim at lines 47 to 48 and 55. That is noted inside the medium finding because it was outside the author's test-only scope.\n\nNothing new was reported. Source, constructor arguments, launch.json and the chunks are correct and unchanged.","treeHash":null,"usage":{"cachedInputTokens":910516,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":17340,"runtime":"claude","turns":23,"wallClockMs":525680}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"03f15d1296244279","findings":[],"hash":"fee662a6cef905788269e0fe9845dd7fc7deef46baa095d2264592d1eaf60ebd","nodeId":"650b60f1-531a-4a96-b7a7-cc2bb1e3751f","outcome":"failed","summary":"wall-clock budget exhausted","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":"claude-fable-5-1","outputTokens":0,"runtime":"claude","turns":0,"wallClockMs":7980672}}],"verification":[{"checks":[{"durationMs":28074,"exitCode":0,"name":"build","output":"Compiling 36 files with Solc 0.8.30\nSolc 0.8.30 finished in 27.95s\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:170:21\n    │\n170 │                 if (k == i) {\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:171:54\n    │\n171 │                     bytes memory out = new bytes(j - start);\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":1539,"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 268.34µs (117.87µs CPU time)\n\nRan 3 tests for test/Part3Launch.t.sol:Part3LaunchTest\n[PASS] test_AllPart3RuntimesPassAdmission() (gas: 64613365)\n[PASS] test_Create2DeploysPart3WithTheRequestedArguments() (gas: 38412207)\n[PASS] test_Part3Create2FitsOneTransaction() (gas: 9719)\nLogs:\n  part 3 CREATE2 gas (with calldata): 15292365\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 75.92ms (134.55ms CPU time)\n\nRan 7 tests for test/FrenRenderer.t.sol:FrenRendererTest\n[PASS] test_ChunksPassTheAdmissionScan() (gas: 35283045)\n[PASS] test_LaunchesFitTransactions() (gas: 27191)\nLogs:\n  launch 1 gas (with calldata): 992392\n  launch 2 gas (with calldata): 950446\n  launch 3 gas (with calldata): 1295956\n\n[PASS] test_MatchesTheReference() (gas: 38337406)\n[PASS] test_RejectsCombosOutsideTheArt() (gas: 11168803)\n[PASS] test_SameAsTheLaunchRenderer() (gas: 1039150660)\n[PASS] test_TakesOnlyThisArt() (gas: 19364)\n[PASS] test_TokenURIIsCheapEnoughToRead() (gas: 10321612)\nLogs:\n  tokenURI gas: 10315627\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.45s (1.59s CPU time)\n\nRan 3 test suites in 1.45s (1.52s CPU time): 10 tests passed, 0 failed, 1 skipped (11 total tests)\n","passed":true},{"durationMs":43,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":72,\"README.md\":66,\"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\":176,\"test/OnChainChunks.fork.t.sol\":36,\"test/Part3Launch.t.sol\":118,\"test/ref/FrenRendererRef.sol\":369},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"280c5599ce46e2d7c691ff7613514ccc6705168a1b33557d684bf0cabf30e00e","verifiedTreeHash":"da304f4908356b65321b431b5984704da1344576","verifierVersion":"0.1.0+7471272e"},{"checks":[{"durationMs":44638,"exitCode":0,"name":"build","output":"Compiling 40 files with Solc 0.8.30\nSolc 0.8.30 finished in 44.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":13470,"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 4.00ms (3.84ms CPU time)\n\nRan 3 tests for test/Part3Launch.t.sol:Part3LaunchTest\n[PASS] test_AllPart3RuntimesPassAdmission() (gas: 64613365)\n[PASS] test_Create2DeploysPart3WithTheRequestedArguments() (gas: 38412207)\n[PASS] test_Part3Create2FitsOneTransaction() (gas: 9719)\nLogs:\n  part 3 CREATE2 gas (with calldata): 15292365\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 125.31ms (202.68ms CPU time)\n\nRan 11 tests for test/Part3Adversarial.t.sol:Part3AdversarialTest\n[PASS] testFuzz_AnySingleByteCorruptionIsRejected(uint8,uint256,uint8) (runs: 256, μ: 60183, ~: 62583)\nLogs:\n  Bound result 3\n  Bound result 6742\n  Bound result 4\n\n[PASS] testFuzz_InvalidTraitInOtherwiseValidComboReverts(uint256,uint8,uint8,uint256,uint256) (runs: 64, μ: 1845409, ~: 72995)\nLogs:\n  Bound result 4\n  Bound result 2\n  Bound result 3\n  Bound result 3\n  Bound result 2\n  Bound result 2\n  Bound result 2\n  Bound result 0\n  Bound result 8\n  Bound result 3\n\n[PASS] test_AllInvalidTraitEncodingsUseMissingAcrossRenderingEntrypoints() (gas: 18130413)\n[PASS] test_EveryChunkRejectsChangedStopMiddleAndLastByte() (gas: 47765)\n[PASS] test_EveryChunkRejectsTruncationAndAppendedData() (gas: 5495506)\n[PASS] test_EveryConstructorSlotRejectsZeroEmptyAccountAndWrongCode() (gas: 22931)\n[PASS] test_EveryPairOfSwappedChunksIsRejected() (gas: 20445)\n[PASS] test_EverySlotRejectsADuplicateChunk() (gas: 20070)\n[PASS] test_IdenticalRuntimeAtAnotherAddressIsAccepted() (gas: 11874798)\n[PASS] test_Part3ConstructorsRejectOneWei() (gas: 1621518)\n[PASS] test_RendererHasNoConfigurationOrFallbackEntrypoints() (gas: 124799)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 212.66ms (295.64ms CPU time)\n\nRan 7 tests for test/FrenRenderer.t.sol:FrenRendererTest\n[PASS] test_ChunksPassTheAdmissionScan() (gas: 35283045)\n[PASS] test_LaunchesFitTransactions() (gas: 27191)\nLogs:\n  launch 1 gas (with calldata): 992392\n  launch 2 gas (with calldata): 950446\n  launch 3 gas (with calldata): 1295956\n\n[PASS] test_MatchesTheReference() (gas: 38337406)\n[PASS] test_RejectsCombosOutsideTheArt() (gas: 11168803)\n[PASS] test_SameAsTheLaunchRenderer() (gas: 1039150660)\n[PASS] test_TakesOnlyThisArt() (gas: 19364)\n[PASS] test_TokenURIIsCheapEnoughToRead() (gas: 10321612)\nLogs:\n  tokenURI gas: 10315627\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.85s (2.03s CPU time)\n\nRan 8 tests for test/Part3ArtProperties.t.sol:Part3ArtPropertiesTest\n[PASS] testFuzz_MetadataAndUnrevealedFramesMatchReference(uint256,uint256,uint256) (runs: 16, μ: 100428901, ~: 100955691)\nLogs:\n  Bound result 1\n  Bound result 6\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n\n[PASS] testFuzz_ValidCombosMatchReferenceAndRoundTripBMP(uint256,uint256) (runs: 64, μ: 29957264, ~: 29672995)\nLogs:\n  Bound result 2\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 4\n  Bound result 2\n  Bound result 8\n  Bound result 1\n\n[PASS] test_AllLayersAndPaletteDecodeExactlyToTheArtKit() (gas: 2005993)\n[PASS] test_Chunk7FramesContainExactArtAndOnlyZeroPadding() (gas: 12410544)\n[PASS] test_ChunkSizesHashesAndStopPrefixMatchTheIndex() (gas: 124998)\n[PASS] test_PendingMetadataAtTokenIdBoundaries() (gas: 208607318)\n[PASS] test_ReaderRejectsShortPlainAndFramedRuntimes() (gas: 32849888)\n[PASS] test_ValidTraitAndSeedBoundaries() (gas: 184300866)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 3.37s (7.05s CPU time)\n\nRan 2 tests for test/Part3Invariant.t.sol:Part3InvariantTest\n[PASS]\nPart3InvariantTest invariants:\n[PASS] invariant_CodeAndDependenciesNeverChange\n[PASS] invariant_ConservesValueAcrossActorsAndDataContracts\n Part3InvariantTest invariants (runs: 128, calls: 4096, reverts: 0)\n\n╭------------------+---------------------+-------+---------+----------╮\n| Contract         | Selector            | Calls | Reverts | Discards |\n+=====================================================================+\n| Part3CallHandler | callChunk           | 1034  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| Part3CallHandler | probeChunk          | 990   | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| Part3CallHandler | rejectRendererValue | 1029  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| Part3CallHandler | renderAfterCalls    | 1043  | 0       | 0        |\n╰------------------+---------------------+-------+---------+----------╯\n\nLogs:\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 1\n  Bound result 0\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 3\n  Bound result 3\n  Bound result 1\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 6\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 1174\n  Bound result 0\n  Bound result 1\n  Bound result 1000000000000000000\n  Bound result 32\n  Bound result 6\n  Bound result 3\n  Bound result 2\n  Bound result 0\n  Bound result 8862\n  Bound result 6\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 3524\n  Bound result 0\n  Bound result 731\n  Bound result 0\n  Bound result 279627573446836923\n  Bound result 1\n  Bound result 6237\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 0\n  Bound result 5\n  Bound result 2\n  Bound result 2\n  Bound result 2\n  Bound result 5\n  Bound result 2\n  Bound result 3364511340\n  Bound result 32\n  Bound result 1\n  Bound result 2\n  Bound result 1000000000000000000\n  Bound result 32\n  Bound result 5\n  Bound result 2\n  Bound result 506657161581604801\n  Bound result 21\n  Bound result 2\n  Bound result 1000000000000000000\n  Bound result 2\n  Bound result 0\n  Bound result 760178063045034383\n  Bound result 0\n  Bound result 5\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 2\n  Bound result 3\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 1000000000000000000\n  Bound result 0\n  Bound result 6189\n  Bound result 0\n  Bound result 61770\n  Bound result 3\n  Bound result 0\n  Bound result 489147550858320419\n  Bound result 15\n  Bound result 3\n  Bound result 5492034844754682\n  Bound result 2\n  Bound result 3\n  Bound result 742631138957335186\n\n[PASS] test_ZeroOneWeiAndWholeActorBalanceSequence() (gas: 12031204)\nLogs:\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 1\n  Bound result 0\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 3\n  Bound result 3\n  Bound result 1\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 6\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 6\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 13.36s (13.37s CPU time)\n\nRan 6 test suites in 13.36s (18.93s CPU time): 31 tests passed, 0 failed, 1 skipped (32 total tests)\n","passed":true},{"durationMs":73,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":72,\"README.md\":66,\"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\":176,\"test/OnChainChunks.fork.t.sol\":36,\"test/Part3Adversarial.t.sol\":164,\"test/Part3ArtProperties.t.sol\":181,\"test/Part3Invariant.t.sol\":147,\"test/Part3Launch.t.sol\":118,\"test/helpers/Part3Fixture.sol\":40,\"test/ref/FrenRendererRef.sol\":369},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"58b16400f3c0e3485a2e2298a3e9a4150e0ecdabdb43849a7f374f4c909ff033","verifiedTreeHash":"ebf015708782542d76c15a6929fcf701f126fe47","verifierVersion":"0.1.0+7471272e"},{"checks":[{"durationMs":32736,"exitCode":0,"name":"build","output":"Compiling 36 files with Solc 0.8.30\nSolc 0.8.30 finished in 32.62s\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:170:21\n    │\n170 │                 if (k == i) {\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:171:54\n    │\n171 │                     bytes memory out = new bytes(j - start);\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":1599,"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 256.68µs (105.43µs CPU time)\n\nRan 3 tests for test/Part3Launch.t.sol:Part3LaunchTest\n[PASS] test_AllPart3RuntimesPassAdmission() (gas: 64613365)\n[PASS] test_Create2DeploysPart3WithTheRequestedArguments() (gas: 38412207)\n[PASS] test_Part3Create2FitsOneTransaction() (gas: 9719)\nLogs:\n  part 3 CREATE2 gas (with calldata): 15292365\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 83.64ms (138.05ms CPU time)\n\nRan 7 tests for test/FrenRenderer.t.sol:FrenRendererTest\n[PASS] test_ChunksPassTheAdmissionScan() (gas: 35283045)\n[PASS] test_LaunchesFitTransactions() (gas: 27191)\nLogs:\n  launch 1 gas (with calldata): 992392\n  launch 2 gas (with calldata): 950446\n  launch 3 gas (with calldata): 1295956\n\n[PASS] test_MatchesTheReference() (gas: 38337406)\n[PASS] test_RejectsCombosOutsideTheArt() (gas: 11168803)\n[PASS] test_SameAsTheLaunchRenderer() (gas: 1039150660)\n[PASS] test_TakesOnlyThisArt() (gas: 19364)\n[PASS] test_TokenURIIsCheapEnoughToRead() (gas: 10321612)\nLogs:\n  tokenURI gas: 10315627\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.52s (1.71s CPU time)\n\nRan 3 test suites in 1.52s (1.60s CPU time): 10 tests passed, 0 failed, 1 skipped (11 total tests)\n","passed":true},{"durationMs":48,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":72,\"README.md\":66,\"foundry.toml\":22,\"launch.json\":30,\"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\":176,\"test/OnChainChunks.fork.t.sol\":36,\"test/Part3Launch.t.sol\":118,\"test/ref/FrenRendererRef.sol\":369},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"7c03a8d6845b809b11b2a27cd2bec6462cf8b8333cc6335ad81910fa7b7c5eb7","verifiedTreeHash":"b9f018f20f01ec9ba80cf6fd7a471e3210761e1c","verifierVersion":"0.1.0+7471272e"},{"checks":[{"durationMs":44714,"exitCode":0,"name":"build","output":"Compiling 40 files with Solc 0.8.30\nSolc 0.8.30 finished in 44.59s\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:170:21\n    │\n170 │                 if (k == i) {\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:171:54\n    │\n171 │                     bytes memory out = new bytes(j - start);\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":14092,"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 263.37µs (107.02µs CPU time)\n\nRan 3 tests for test/Part3Launch.t.sol:Part3LaunchTest\n[PASS] test_AllPart3RuntimesPassAdmission() (gas: 67319703)\n[PASS] test_Create2DeploysPart3WithTheRequestedArguments() (gas: 38412207)\n[PASS] test_Part3Create2GasIsMeteredAndWithinLocalBudget() (gas: 33134)\nLogs:\n  part 3 local CREATE2 gas (with intrinsic): 13953173\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 149.79ms (172.52ms CPU time)\n\nRan 11 tests for test/Part3Adversarial.t.sol:Part3AdversarialTest\n[PASS] testFuzz_AnySingleByteCorruptionIsRejected(uint8,uint256,uint8) (runs: 256, μ: 59698, ~: 62382)\nLogs:\n  Bound result 0\n  Bound result 22934\n  Bound result 1\n\n[PASS] testFuzz_InvalidTraitInOtherwiseValidComboReverts(uint256,uint8,uint8,uint256,uint256) (runs: 64, μ: 2373030, ~: 72949)\nLogs:\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 3\n\n[PASS] test_AllInvalidTraitEncodingsUseMissingAcrossRenderingEntrypoints() (gas: 18130413)\n[PASS] test_EveryChunkRejectsChangedStopMiddleAndLastByte() (gas: 47765)\n[PASS] test_EveryChunkRejectsTruncationAndAppendedData() (gas: 5495506)\n[PASS] test_EveryConstructorSlotRejectsZeroEmptyAccountAndWrongCode() (gas: 22931)\n[PASS] test_EveryPairOfSwappedChunksIsRejected() (gas: 20445)\n[PASS] test_EverySlotRejectsADuplicateChunk() (gas: 20070)\n[PASS] test_IdenticalRuntimeAtAnotherAddressIsAccepted() (gas: 11874798)\n[PASS] test_Part3ConstructorsRejectOneWei() (gas: 1621518)\n[PASS] test_RendererHasNoConfigurationOrFallbackEntrypoints() (gas: 124799)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 267.95ms (363.51ms CPU time)\n\nRan 7 tests for test/FrenRenderer.t.sol:FrenRendererTest\n[PASS] test_ChunksPassTheAdmissionScan() (gas: 35283045)\n[PASS] test_LaunchCreationGasIsMeteredAndWithinLocalBudget() (gas: 71223)\nLogs:\n  launch 1 local CREATE gas (with initcode allowance): 10775568\n  launch 2 local CREATE gas (with initcode allowance): 10026712\n  launch 3 local CREATE gas (with initcode allowance): 14057012\n\n[PASS] test_MatchesTheReference() (gas: 38337406)\n[PASS] test_RejectsCombosOutsideTheArt() (gas: 11168803)\n[PASS] test_SameAsTheLaunchRenderer() (gas: 1039150660)\n[PASS] test_TakesOnlyThisArt() (gas: 19364)\n[PASS] test_TokenURIIsCheapEnoughToRead() (gas: 10321612)\nLogs:\n  tokenURI gas: 10315627\n\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.93s (2.13s CPU time)\n\nRan 8 tests for test/Part3ArtProperties.t.sol:Part3ArtPropertiesTest\n[PASS] testFuzz_MetadataAndUnrevealedFramesMatchReference(uint256,uint256,uint256) (runs: 16, μ: 101302536, ~: 101216439)\nLogs:\n  Bound result 0\n  Bound result 11\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n\n[PASS] testFuzz_ValidCombosMatchReferenceAndRoundTripBMP(uint256,uint256) (runs: 64, μ: 30144097, ~: 29431351)\nLogs:\n  Bound result 0\n  Bound result 3\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 3\n  Bound result 1\n\n[PASS] test_AllLayersAndPaletteDecodeExactlyToTheArtKit() (gas: 2005993)\n[PASS] test_Chunk7FramesContainExactArtAndOnlyZeroPadding() (gas: 12410544)\n[PASS] test_ChunkSizesHashesAndStopPrefixMatchTheIndex() (gas: 124998)\n[PASS] test_PendingMetadataAtTokenIdBoundaries() (gas: 208607318)\n[PASS] test_ReaderRejectsShortPlainAndFramedRuntimes() (gas: 32849888)\n[PASS] test_ValidTraitAndSeedBoundaries() (gas: 184300866)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 3.33s (7.03s CPU time)\n\nRan 2 tests for test/Part3Invariant.t.sol:Part3InvariantTest\n[PASS]\nPart3InvariantTest invariants:\n[PASS] invariant_CodeAndDependenciesNeverChange\n[PASS] invariant_ConservesValueAcrossActorsAndDataContracts\n Part3InvariantTest invariants (runs: 128, calls: 4096, reverts: 0)\n\n╭------------------+---------------------+-------+---------+----------╮\n| Contract         | Selector            | Calls | Reverts | Discards |\n+=====================================================================+\n| Part3CallHandler | callChunk           | 1009  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| Part3CallHandler | probeChunk          | 992   | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| Part3CallHandler | rejectRendererValue | 1028  | 0       | 0        |\n|------------------+---------------------+-------+---------+----------|\n| Part3CallHandler | renderAfterCalls    | 1067  | 0       | 0        |\n╰------------------+---------------------+-------+---------+----------╯\n\nLogs:\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 1\n  Bound result 0\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 3\n  Bound result 3\n  Bound result 1\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 6\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 260463820495\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 5830\n  Bound result 32\n  Bound result 5\n  Bound result 0\n  Bound result 2\n  Bound result 2\n  Bound result 6\n  Bound result 3\n  Bound result 3\n  Bound result 2\n  Bound result 2\n  Bound result 968350427121585586\n  Bound result 32\n  Bound result 1\n  Bound result 95032863283353265\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 879852465899191074\n  Bound result 35\n  Bound result 3\n  Bound result 0\n  Bound result 749608906019765832\n  Bound result 32\n  Bound result 5\n  Bound result 0\n  Bound result 1\n  Bound result 2\n  Bound result 6\n  Bound result 0\n  Bound result 2624\n  Bound result 26\n  Bound result 0\n  Bound result 3\n  Bound result 0\n  Bound result 1\n  Bound result 553039243580080561\n  Bound result 3\n  Bound result 1\n  Bound result 2589\n  Bound result 29\n  Bound result 0\n  Bound result 3\n  Bound result 1000000000000000000\n  Bound result 0\n  Bound result 2\n  Bound result 1000000000000000000\n  Bound result 0\n  Bound result 3\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 4\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 32\n  Bound result 3\n  Bound result 70866631447451984\n  Bound result 6\n  Bound result 2\n  Bound result 8787171777210\n  Bound result 14\n  Bound result 2\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 3\n  Bound result 3\n  Bound result 1\n\n[PASS] test_ZeroOneWeiAndWholeActorBalanceSequence() (gas: 12031204)\nLogs:\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 1\n  Bound result 0\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 3\n  Bound result 3\n  Bound result 1\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 6\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 3\n  Bound result 6\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 6\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 13.99s (13.98s CPU time)\n\nRan 6 test suites in 13.99s (19.67s CPU time): 31 tests passed, 0 failed, 1 skipped (32 total tests)\n","passed":true},{"durationMs":69,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":72,\"README.md\":66,\"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\":214,\"test/OnChainChunks.fork.t.sol\":36,\"test/Part3Adversarial.t.sol\":164,\"test/Part3ArtProperties.t.sol\":181,\"test/Part3Invariant.t.sol\":147,\"test/Part3Launch.t.sol\":141,\"test/helpers/Part3Fixture.sol\":40,\"test/ref/FrenRendererRef.sol\":369},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"b99a422c28b5576a890f068937c7e170ba8fa499ea6bbbebe2a179955e190033","verifiedTreeHash":"5aa9fc04695ff4367115b5acb03e8d435380686d","verifierVersion":"0.1.0+7471272e"}]}