{"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":"834c0e87-f40c-4a5d-9935-03d865b034ec","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"working"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"working"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"working"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"working"},{"acceptedSubmissionHash":"beefa6ad9c630ef2842e11a8411d55a4ef0b30fc7db631ace446fd6c5adb444f","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"587567a5ef71546b5973ceaf6ef1dbbd590f49503b5ac9a6973ed86b89584857","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"587567a5ef71546b5973ceaf6ef1dbbd590f49503b5ac9a6973ed86b89584857","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"failed"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"working"}],"objective":"imd/place (x.com/imdplace): a pixel war on a Uniswap v4 hook, where your pixels earn: buying the token gives paint, painting pixels on a shared on-chain canvas earns a share of every trade, and each weekly canvas is auctioned as a 1/1 NFT with the proceeds paid to its artists. Launch kind univ4_hook on Robinhood Chain (4663), paired with IMD: the launch's standard token and pool with our hook, plus our canvas and season-NFT contracts. Deploy in the launch, then host a site on the live addresses. No owner, admin, upgrade or pause in our contracts.\n\nToken name: imd/place. Symbol: i/p (if the launch refuses the slash, use IP).\n\nPAINT\n- The hook credits paint on every buy (afterSwap): 1 drop per 0.05 IMD spent. The buyer is the address passed in hookData by our router; without hookData, tx.origin. Paint is not transferable and never expires.\n- Sells give no paint and take none away.\n\nCANVAS\n- 64x64 pixels, 16-colour palette (bright, classic pixel-art colours), stored in the contract. Per pixel, one packed slot: owner, colour, paints in the current 24 h window, window start.\n- paint(pixels[], colours[]): up to 50 pixels per call. An empty pixel costs 1 drop. Repainting costs 2^k drops, k = times that pixel was painted in its current 24 h window (cap 2^10). Spent paint is consumed.\n\nPIXELS EARN\n- Hook fee 2% on every buy and sell, taken in IMD (on top of the launch's pool fee). Split: 67% to pixel owners, 25% to the season pot, 8% to 0xA7e99BB7155D7477E0C838E201b16E62B9c0b5Ac.\n- The 67% is shared pro rata by pixels currently owned: a global accumulator per pixel, settled on every ownership change, so a pixel earns while it is yours and earnings already accrued stay claimable after it is painted over. claim() anytime. Fees with no painted pixels go to the season pot.\n- First 30 minutes after launch: the hook fee decays linearly from 35% to 2%; the extra goes to the season pot.\n\nSEASONS\n- A season lasts 7 days. After it, anyone calls endSeason(): the final canvas is frozen and minted as a 1/1 ERC-721 to the season contract (tokenURI: on-chain SVG of the canvas, crisp pixels, name \"imd/place season N\", external_url https://x.com/imdplace, attributes: season, painters, paints), and the canvas resets for the next season immediately.\n- The NFT is sold in a 24 h English auction in IMD (5% minimum raise, bids in the last 10 min extend by 10 min, outbid refunded at once). Winning bid + the season pot go to the final canvas's pixel owners, pro rata by pixels held at the freeze. No bids: the NFT goes to the top painter and the pot carries to the next season.\n\nSITE\nLive canvas (zoom, pan, palette, pixel info: owner, times painted, current repaint price), batch painting, buy paint (swap via our router with hookData), my pixels and my IMD earnings with claim, leaderboard, season timer, auction with bidding, gallery of past season NFTs, totals paid to painters. Header and footer link to x.com/imdplace and to every contract on the explorer. Look: dark background, the canvas's 16-colour palette, chunky pixel type, the i/p logo. Phones work.\n\nTESTS\nPaint credited only on buys and to the right address; repaint cost doubles inside 24 h and resets after; batch limit; fee split exactly 67/25/8 and the launch decay; owner earnings match accumulator math across many repaints (fuzz); claims never exceed fees received; endSeason only after 7 days, freezes the right canvas, resets; auction rules, refunds, extensions; payout sums equal pot + bid; no function moves IMD, NFTs or paint anywhere else. Robinhood fork: buy and sell through the real PoolManager with the hook. Independent review.","parentJobId":null,"planHash":"3ff43247dc4b122834911d91fb6504067fa32f6ead33edf9a84b008a77186179","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"834c0e87-f40c-4a5d-9935-03d865b034ec","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1019-imd-place-symbol-i-p-if-the-launch-refus"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51175","feedbackHash":"51b33795f860f4846865717a329c90f72bb6aeb7d10ea0778e787a5ebbb4cd0c","nodeKey":"build_contract_project","submissionHash":"e623a6c8c5468859b307062ed217a7ed7c254d09cd0670f6d4b664ab8da65f48","tag1":"verification:checks","tag2":"acceptance-v2","value":0},{"agentId":"51037","feedbackHash":"a8e430159f2140440c402e48f5109d1fdd4d806ec633ed1ca53b305358e374c2","nodeKey":"build_contract_project","submissionHash":"beefa6ad9c630ef2842e11a8411d55a4ef0b30fc7db631ace446fd6c5adb444f","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"80c379affdab0a04fafb55cbdcfbf76010265f102070acb9a3253dbcc109f360","state":"blocked","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"0b129ef2f81deead","findings":[],"hash":"50ee94388216877636b51060df35a900e6731e7a2ec7ee88c72d39e4b9e8cfbe","nodeId":"2168b2f4-6b59-4037-876d-043db8910037","outcome":"failed","summary":"needs input: The production pool.initialPrice (decimal sqrtPriceX96) and pool.tickSpacing are missing. The accepted deployment recipe delegates these values to the launch factory's standard pool configuration, but that configuration was not supplied. The values 79228162514264337593543950336 and 60 occur only in test fixtures; they do not establish the launch settings. The manifest schema requires concrete numeric values and provides no placeholder for either field. — What production pool.initialPrice (as a decimal sqrtPriceX96 integer) and pool.tickSpacing should launch.json use for the imd/place–IMD pool on Robinhood Chain (4663)?","treeHash":null,"usage":{"cachedInputTokens":754432,"inputTokens":62878,"model":"gpt-6-astra","outputTokens":3617,"runtime":"codex","turns":4,"wallClockMs":221829}},{"artifacts":[],"attempt":2,"bundleHash":"624e4be3dda1c33c6258619a53a63170bebcefca7c0890da5dcd5fa2a34cfac0","device":"a8f78934be011e4c","findings":[],"hash":"beefa6ad9c630ef2842e11a8411d55a4ef0b30fc7db631ace446fd6c5adb444f","nodeId":"ba3895aa-6ee4-4f16-a97e-6bb0642ce3ec","outcome":"completed","summary":"Implemented contracts, responsive site, deployment tooling, and independent review.\n\n- Build, formatting, and 35 tests pass.\n- Robinhood fork passes.\n- Slither reports no high/medium findings.\n\nLive deployment and hosting remain pending launch-operator access. Instructions are in [README.md](/home/identitymd/.identitymd/work/834c0e87-f40c-4a5d-9935-03d865b034ec/ba3895aa-6ee4-4f16-a97e-6bb0642ce3ec/README.md).","treeHash":"d53117dedd9461d6a4a13dd9d1a05134ec85ebd5","usage":{"cachedInputTokens":7649280,"inputTokens":180237,"model":"gpt-6-astra","outputTokens":71820,"runtime":"codex","turns":11,"wallClockMs":2961953}},{"artifacts":[],"attempt":1,"bundleHash":"56f94f0d3dbe7a9f05a2f3347a76ffa75db375c7b17c957aa924bd209ade1376","device":"1fe90fcdee1e5d05","findings":[],"hash":"e623a6c8c5468859b307062ed217a7ed7c254d09cd0670f6d4b664ab8da65f48","nodeId":"ba3895aa-6ee4-4f16-a97e-6bb0642ce3ec","outcome":"completed","summary":"Implemented contracts, site, vendored dependencies and independent review.\n\nChecks passed: `forge build`, 44 local tests, `forge fmt --check`, Robinhood fork swaps and full browser flow.\n\nProduction deployment and hosting remain pending. Handoff: [README.md](/home/levi/imd/p6/work/834c0e87-f40c-4a5d-9935-03d865b034ec/ba3895aa-6ee4-4f16-a97e-6bb0642ce3ec/README.md).","treeHash":"7edca7fa3be3d3dda5656af475ce8ab975c7079a","usage":{"cachedInputTokens":7928448,"inputTokens":181015,"model":"gpt-6-astra","outputTokens":62875,"runtime":"codex","turns":13,"wallClockMs":2657709}}],"verification":[{"checks":[{"durationMs":37350,"exitCode":0,"name":"build","output":"Compiling 100 files with Solc 0.8.26\nSolc 0.8.26 finished in 37.21s\nCompiler run successful!\nwarning[missing-events-access-control]: `callbackHash` is changed without an event but is used for access control\n   ╭▸ src/PlaceRouter.sol:82:16\n   │\n82 │         delete callbackHash;\n   │                ━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `paymentHash` is changed without an event but is used for access control\n    ╭▸ src/PlaceHook.sol:182:9\n    │\n182 │         paymentHash = keccak256(data);\n    │         ━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/PlaceHook.sol:46:44\n   │\n46 │     constructor(IPoolManager poolManager_, address token_, address factory_) {\n   │                                            ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n   ╭▸ src/PlaceRouter.sol:71:40\n   │\n71 │         (spent, received) = abi.decode(manager.unlock(data), (uint256, uint256));\n   │                                        ━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/PlaceRouter.sol:50:13\n   │\n50 │             block.timestamp > deadline || amount == 0 || limit == 0\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/PlaceRouter.sol:74:9\n   │\n74 │         emit Swapped(msg.sender, buy, spent, received);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/PlaceRouter.sol:51:29\n   │\n51 │                 || amount > uint256(uint128(type(int128).max))\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/PlaceRouter.sol:51:37\n   │\n51 │                 || amount > uint256(uint128(type(int128).max))\n   │                                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' 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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlaceHook.sol:103:16\n    │\n103 │         return elapsed >= 30 minutes ? 200 : 200 + 3300 * (30 minutes - elapsed) / 30 minutes;\n    │                ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlaceHook.sol:111:25\n    │\n111 │         if (buy) return uint256(-specified) * bps / 10_000;\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/PlaceHook.sol:113:17\n    │\n113 │         return (uint256(specified) * bps + (10_000 - bps) - 1) / (10_000 - bps);\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/PlaceRouter.sol:87:41\n   │\n87 │         int256 amount = r.exactInput ? -int256(r.amount) : int256(r.amount);\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/PlaceRouter.sol:87:60\n   │\n87 │         int256 amount = r.exactInput ? -int256(r.amount) : int256(r.amount);\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/PlaceRouter.sol:93:25\n   │\n93 │         uint256 spent = uint256(-int256(inputDelta));\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/PlaceRouter.sol:94:28\n   │\n94 │         uint256 received = uint256(uint128(outputDelta));\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/PlaceRouter.sol:94:36\n   │\n94 │         uint256 received = uint256(uint128(outputDelta));\n   │                                    ━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' 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[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlaceHook.sol:172:9\n    │\n172 │         emit SwapFee(buy, buyer, gross, fee, paintDrops);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlaceHook.sol:143:33\n    │\n143 │         uint256 poolIMD = buy ? uint256(-int256(pairDelta)) : uint256(uint128(pairDelta));\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/PlaceHook.sol:143:63\n    │\n143 │         uint256 poolIMD = buy ? uint256(-int256(pairDelta)) : uint256(uint128(pairDelta));\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/PlaceHook.sol:143:71\n    │\n143 │         uint256 poolIMD = buy ? uint256(-int256(pairDelta)) : uint256(uint128(pairDelta));\n    │                                                                       ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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/PlaceHook.sol:150:23\n    │\n150 │                 buy ? uint256(-params.amountSpecified) - fee : uint256(params.amountSpecified) + fee;\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/PlaceHook.sol:150:64\n    │\n150 │                 buy ? uint256(-params.amountSpecified) - fee : uint256(params.amountSpecified) + fee;\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-oz-erc721-mint]: `ERC721._mint` does not check that the recipient can receive the token; use `_safeMint`\n   ╭▸ src/Seasons.sol:77:9\n   │\n77 │         _mint(address(this), id);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-oz-erc721-mint\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/Seasons.sol:65:18\n   │\n65 │             end: uint64(block.timestamp + 1 days),\n   │                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint64' 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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/Seasons.sol:84:42\n   │\n84 │         if (a.end == 0 || a.finalized || block.timestamp >= a.end || a.occupied == 0) revert AuctionClosed();\n   │                                          ━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Seasons.sol:103:13\n    │\n103 │         if (block.timestamp >= uint256(a.end) - 10 minutes) a.end += 10 minutes;\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/Seasons.sol:121:32\n    │\n121 │             uint256 released = canvas.releasePot(id);\n    │                                ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/Seasons.sol:128:13\n    │\n128 │             canvas.rollPot(id);\n    │             ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Seasons.sol:113:42\n    │\n113 │         if (a.end == 0 || a.finalized || block.timestamp < a.end) revert NotReady();\n    │                                          ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Seasons.sol:143:53\n    │\n143 │             if (claimedBitmap[id][word] & bit != 0) revert AlreadyClaimed();\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/Seasons.sol:249:9\n    │\n249 │         require(pos + part.length <= dest.length, \"SVG buffer\");\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/Canvas.sol:115:20\n    │\n115 │     function start(address imd_) external onlyHook {\n    │                    ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/Seasons.sol:256:29\n    │\n256 │           bytes memory json = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n257 │ ┃             '{\"name\":\"imd/place season ',\n258 │ ┃             id.toString(),\n259 │ ┃             '\",\"external_url\":\"https://x.com/imdplace\",\"image\":\"data:image/svg+xml;base64,',\n    ‡ ┃\n267 │ ┃             \"}]}\"\n268 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Canvas.sol:148:9\n    │\n148 │         emit FeeRecorded(artists, pot, treasury);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Canvas.sol:154:38\n    │\n154 │         if (p.owner == address(0) || block.timestamp >= uint256(p.windowStart) + 1 days) return 1;\n    │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Canvas.sol:173:13\n    │\n173 │         if (block.timestamp >= seasonStart + DURATION) revert SeasonNotReady();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Canvas.sol:198:43\n    │\n198 │             if (previous == address(0) || block.timestamp >= uint256(p.windowStart) + 1 days) {\n    │                                           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Canvas.sol:178:53\n    │\n178 │             if (ids[i] >= 4096 || colours[i] >= 16) revert InvalidPixel();\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/Canvas.sol:181:39\n    │\n181 │                 if (ids[j] == ids[i]) revert InvalidBatch();\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/Canvas.sol:152:25\n    │\n152 │         if (id >= 4096) revert InvalidPixel();\n    │                         ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Canvas.sol:199:33\n    │\n199 │                 p.windowStart = uint40(block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint40' 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/Canvas.sol:212:45\n    │\n212 │         uint64 newPaints = previousPaints + uint64(ids.length);\n    │                                             ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' 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/Canvas.sol:214:21\n    │\n214 │         s.paints += uint64(ids.length);\n    │                     ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' 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[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/Canvas.sol:248:25\n    │\n248 │         if (amount > 0) IPlaceHook(hook).pay(msg.sender, amount);\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/Canvas.sol:256:25\n    │\n256 │         if (amount > 0) IPlaceHook(hook).pay(TREASURY, amount);\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/Canvas.sol:272:9\n    │\n272 │         seasons.open(id, pot, s.occupied, s.painters, s.paints, s.topPainter);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Canvas.sol:260:35\n    │\n260 │         if (currentSeason == 0 || block.timestamp < seasonStart + DURATION) revert SeasonNotReady();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/Canvas.sol:279:25\n    │\n279 │         if (amount > 0) IPlaceHook(hook).pay(address(seasons), amount);\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/Canvas.sol:275:58\n    │\n275 │     function releasePot(uint256 id) external onlySeasons nonReentrant returns (uint256 amount) {\n    │                                                          ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/Canvas.sol:282:55\n    │\n282 │     function rollPot(uint256 id) external onlySeasons nonReentrant {\n    │                                                       ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Canvas.sol:297:33\n    │\n297 │             if (ids[i] >= 4096) revert InvalidPixel();\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/Canvas.sol:299:60\n    │\n299 │             if (p.owner != artist || artist == address(0)) revert Unauthorized();\n    │                                                            ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/helpers/PoolFixture.sol:170:73\n    │\n170 │         return router.swap(buy, exactInput, amount, limit, _limit(buy), block.timestamp);\n    │                                                                         ━━━━━━━━━━━━━━━\n    │\n    ⸬  test/Hook.t.sol:64:9\n    │\n 64 │         vm.warp(hook.launchTime() + 15 minutes);\n    │         ─────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Hook.t.sol:73:17\n   │\n73 │         vm.warp(block.timestamp + 30 minutes);\n   │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Hook.t.sol:93:17\n   │\n93 │         vm.warp(block.timestamp + 30 minutes);\n   │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/Hook.t.sol:163:17\n    │\n163 │         vm.warp(block.timestamp + 30 minutes);\n    │         ────────━━━━━━━━━━━━━━━────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":712,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/fork/Robinhood.t.sol:RobinhoodForkTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 402.78µs (0.00ns CPU time)\n\nRan 2 tests for test/Adversarial.t.sol:AuctionReentrancyTest\n[PASS] testBidCallbackCannotReenterAuction() (gas: 710433)\n[PASS] testRefundFailureRollsBackNewBidAndEscrow() (gas: 699167)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.16ms (487.84µs CPU time)\n\nRan 1 test for test/Hook.t.sol:FreshManagerTest\n[PASS] testFirstBuyTokenOnlyLiquidity() (gas: 24083617)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 14.58ms (14.23ms CPU time)\n\nRan 2 tests for test/review/IndependentSwapModes.t.sol:IndependentSwapModesTest\n[PASS] test_ReviewAllModesWhenIMDIsCurrencyOne() (gas: 25716295)\n[PASS] test_ReviewAllModesWhenIMDIsCurrencyZero() (gas: 26633246)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 18.78ms (33.70ms CPU time)\n\nRan 1 test for test/Adversarial.t.sol:RouterReentrancyTest\n[PASS] testTransferCallbackCannotReplaceSwapPayerOrSpendAgain() (gas: 24452880)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 19.38ms (18.97ms CPU time)\n\nRan 10 tests for test/Hook.t.sol:HookTest\n[PASS] testBaseSplitWithOwnedPixelAndClaims() (gas: 1160749)\n[PASS] testCannotInitializeAnotherPool() (gas: 46088)\n[PASS] testDeadlineSlippageAndPartialFillRollBack() (gas: 606727)\n[PASS] testFlagsAndCallbackAuthorization() (gas: 169954)\n[PASS] testFourSwapModesCreditOnlyBuysAndSettle() (gas: 1075828)\n[PASS] testFuzzBuySellConservation(uint96,bool) (runs: 256, μ: 615089, ~: 616608)\nLogs:\n  Bound result 99950000000006834530\n\n[PASS] testLaunchDecayAndNoPixelFeeSplit() (gas: 423123)\n[PASS] testOriginFallbackAndSpoofedDataRefused() (gas: 1096335)\n[PASS] testRouterNeverSpendsVictimAllowance() (gas: 419723)\n[PASS] testTokenSupplyAndTransfers() (gas: 90596)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 52.08ms (44.42ms CPU time)\n\nRan 2 tests for test/review/Metadata.t.sol:MetadataPerformanceReviewTest\n[PASS] test_ReviewDenseMetadataWithin32MillionGas() (gas: 30502251)\nLogs:\n  dense tokenURI gas: 30394991\n  dense tokenURI bytes: 99877\n\n[PASS] test_ReviewPackedColourExtractionAcrossWholeCanvas() (gas: 12384941)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 155.55ms (44.11ms CPU time)\n\nRan 11 tests for test/Canvas.t.sol:CanvasTest\n[PASS] testAuctionRefundRaiseExtensionAndExactPayout() (gas: 1862794)\n[PASS] testBatchValidationAndAtomicBudget() (gas: 3664127)\n[PASS] testBlankSeasonCarriesPotAndCannotAcceptBids() (gas: 432331)\n[PASS] testFrozenSVGAndMetadata() (gas: 38267145)\n[PASS] testFuzzAccumulatorAcrossManyRepaints(uint256) (runs: 256, μ: 12361219, ~: 12358354)\n[PASS] testFuzzRoundingCannotOverclaim(uint128,uint8) (runs: 256, μ: 3501214, ~: 3260520)\nLogs:\n  Bound result 2996\n  Bound result 8\n\n[PASS] testNoBidTopPainterAndPotCarryCannotBeDelayedToThirdSeason() (gas: 1146014)\n[PASS] testNoUnauthorizedMoneyPaintOrNFTMovement() (gas: 553929)\n[PASS] testOverwritePreservesEarnedBalance() (gas: 1114210)\n[PASS] testPackedPixelWindowDoublingAndCap() (gas: 1372550)\n[PASS] testSeasonDeadlineFreezeAndReset() (gas: 39545545)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 376.30ms (557.53ms CPU time)\n\nRan 5 tests for test/review/IndependentAccounting.t.sol:IndependentAccountingTest\n[PASS] testFuzz_ReviewPerPixelReferenceAccountingAcrossSeasons(uint256) (runs: 256, μ: 21900379, ~: 21911461)\n[PASS] test_ReviewConcurrentAuctionEscrowsRemainIndependent() (gas: 1969550)\n[PASS] test_ReviewDelayedRolloverCannotChooseLaterSeason() (gas: 1282896)\n[PASS] test_ReviewFrozenOwnersAndExactRemainderPayout() (gas: 1867096)\n[PASS] test_ReviewOldAccrualSurvivesSkippedSeasons() (gas: 2010681)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 565.44ms (567.83ms CPU time)\n\nRan 1 test for test/Invariant.t.sol:PlaceInvariantTest\n[PASS]\nPlaceInvariantTest invariants:\n[PASS] invariantClaimsNeverExceedArtistAllocation\n[PASS] invariantExactFeeBacking\n PlaceInvariantTest invariants (runs: 64, calls: 4096, reverts: 527)\n\n╭--------------+----------+-------+---------+----------╮\n| Contract     | Selector | Calls | Reverts | Discards |\n+======================================================+\n| PlaceHandler | claim    | 1063  | 0       | 0        |\n|--------------+----------+-------+---------+----------|\n| PlaceHandler | paint    | 1015  | 527     | 0        |\n|--------------+----------+-------+---------+----------|\n| PlaceHandler | trade    | 994   | 0       | 0        |\n|--------------+----------+-------+---------+----------|\n| PlaceHandler | treasury | 1024  | 0       | 0        |\n╰--------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 619.95ms (605.15ms CPU time)\n\nRan 10 test suites in 621.45ms (1.82s CPU time): 35 tests passed, 0 failed, 1 skipped (36 total tests)\n","passed":true},{"durationMs":49,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Canvas.claim()\",\"Canvas.claimTreasury()\",\"Canvas.credit(address,uint256)\",\"Canvas.endSeason()\",\"Canvas.paint(uint16[],uint8[])\",\"Canvas.paintWithLimit(uint16[],uint8[],uint256)\",\"Canvas.recordFee(uint256,uint256)\",\"Canvas.releasePot(uint256)\",\"Canvas.rollPot(uint256)\",\"Canvas.start(address)\",\"PlaceHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"PlaceHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"PlaceHook.pay(address,uint256)\",\"PlaceHook.unlockCallback(bytes)\",\"PlaceRouter.swap(bool,bool,uint256,uint256,uint160,uint256)\",\"PlaceRouter.unlockCallback(bytes)\",\"PlaceToken.approve(address,uint256)\",\"PlaceToken.transfer(address,uint256)\",\"PlaceToken.transferFrom(address,address,uint256)\",\"Seasons.approve(address,uint256)\",\"Seasons.bid(uint256,uint256)\",\"Seasons.claim(uint256,uint16[])\",\"Seasons.finalize(uint256)\",\"Seasons.open(uint256,uint256,uint16,uint32,uint64,address)\",\"Seasons.safeTransferFrom(address,address,uint256)\",\"Seasons.safeTransferFrom(address,address,uint256,bytes)\",\"Seasons.setApprovalForAll(address,bool)\",\"Seasons.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":5,\"LICENSE\":23,\"README.md\":105,\"dependencies.json\":22,\"deployment/launch-recipe.json\":11,\"docs/INDEPENDENT_REVIEW.md\":59,\"docs/VERIFICATION.md\":46,\"docs/static-analysis.json\":18,\"foundry.toml\":21,\"remappings.txt\":4,\"site/abi.json\":1,\"site/app.js\":247,\"site/index.html\":29,\"site/logo.svg\":1,\"site/style.css\":1,\"site/vendor/ETHERS_LICENSE.md\":21,\"site/vendor/FONT_LICENSE.txt\":93,\"site/vendor/PixelifySans.ttf\":328,\"site/vendor/ethers.min.js\":1,\"site/vendor/provenance.json\":22,\"src/Canvas.sol\":334,\"src/HookFlags.sol\":30,\"src/PlaceHook.sol\":195,\"src/PlaceRouter.sol\":107,\"src/PlaceToken.sol\":10,\"src/Seasons.sol\":271,\"src/interfaces/IPlace.sol\":22,\"test/Adversarial.t.sol\":136,\"test/Canvas.t.sol\":337,\"test/Hook.t.sol\":185,\"test/Invariant.t.sol\":74,\"test/fork/Robinhood.t.sol\":65,\"test/helpers/PoolFixture.sol\":181,\"test/helpers/TestDeployer.sol\":10,\"test/mocks/MockERC20.sol\":13,\"test/review/IndependentAccounting.t.sol\":198,\"test/review/IndependentSwapModes.t.sol\":80,\"test/review/Metadata.t.sol\":58,\"tools/configure-site.mjs\":27,\"tools/export-abi.py\":10,\"tools/mine-hook.mjs\":18},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":8361,"exitCode":0,"name":"slither","output":"[low/medium] reentrancy-benign at src/PlaceRouter.sol:41: Reentrancy in PlaceRouter.swap(bool,bool,uint256,uint256,uint160,uint256) (src/PlaceRouter.sol#41-76):\n[low/medium] reentrancy-benign at src/PlaceRouter.sol:41: Reentrancy in PlaceRouter.swap(bool,bool,uint256,uint256,uint160,uint256) (src/PlaceRouter.sol#41-76):\n[low/medium] reentrancy-events at src/PlaceHook.sol:130: Reentrancy in PlaceHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PlaceHook.sol#130-174):\n[low/medium] timestamp at src/PlaceRouter.sol:41: PlaceRouter.swap(bool,bool,uint256,uint256,uint160,uint256) (src/PlaceRouter.sol#41-76) uses timestamp for comparisons\n[low/medium] timestamp at src/Seasons.sol:111: Seasons.finalize(uint256) (src/Seasons.sol#111-130) uses timestamp for comparisons\n[low/medium] timestamp at src/Seasons.sol:95: Seasons.bid(uint256,uint256) (src/Seasons.sol#95-109) uses timestamp for comparisons\n[low/medium] timestamp at src/Canvas.sol:259: Canvas.endSeason() (src/Canvas.sol#259-273) uses timestamp for comparisons\n[low/medium] timestamp at src/PlaceHook.sol:130: PlaceHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PlaceHook.sol#130-174) uses timestamp for comparisons\n[low/medium] timestamp at src/Seasons.sol:82: Seasons.minimumBid(uint256) (src/Seasons.sol#82-87) uses timestamp for comparisons\n[low/medium] timestamp at src/Canvas.sol:151: Canvas.price(uint16) (src/Canvas.sol#151-156) uses timestamp for comparisons\n[low/medium] timestamp at src/PlaceHook.sol:100: PlaceHook.feeBps() (src/PlaceHook.sol#100-104) uses timestamp for comparisons\n[low/medium] timestamp at src/Canvas.sol:170: Canvas._paint(uint16[],uint8[],uint256) (src/Canvas.sol#170-219) uses timestamp for comparisons","passed":true},{"durationMs":542,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/Seasons.sol:205: `abi.encodePacked()` Hash Collision (2 places)\n[high] eth-send-unchecked-address at src/Seasons.sol:95: ETH transferred without address checks (2 places)\n[high] reentrancy-state-change at src/Canvas.sol:262: Reentrancy: State change after external call (7 places)\n[low] costly-loop at src/Canvas.sol:177: Costly operations inside loop (2 places)\n[low] internal-function-used-once at src/HookFlags.sol:23: Internal Function Used Only Once\n[low] large-numeric-literal at src/PlaceHook.sol:111: Large Numeric Literal (8 places)\n[low] literal-instead-of-constant at src/Canvas.sol:132: Literal Instead of Constant (51 places)\n[low] non-reentrant-not-first at src/Canvas.sol:275: `nonReentrant` is Not the First Modifier (2 places)\n[low] require-revert-in-loop at src/Canvas.sol:177: Loop Contains `require`/`revert` (5 places)\n[low] state-change-without-event at src/PlaceHook.sol:177: State Change Without Event (3 places)\n[low] state-variable-could-be-constant at src/Canvas.sol:59: State Variable Could Be Constant\n[low] unchecked-return at src/Seasons.sol:157: Unchecked Return\n[low] uninitialized-local-variable at src/Seasons.sol:160: Uninitialized Local Variable\n[low] unsafe-oz-erc721-mint at src/Seasons.sol:77: Unsafe `ERC721::_mint()`","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"beefa6ad9c630ef2842e11a8411d55a4ef0b30fc7db631ace446fd6c5adb444f","verifiedTreeHash":"d53117dedd9461d6a4a13dd9d1a05134ec85ebd5","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":36566,"exitCode":0,"name":"build","output":"Compiling 105 files with Solc 0.8.26\nSolc 0.8.26 finished in 36.43s\nCompiler run successful!\nwarning[missing-events-arithmetic]: `launchedAt` is changed without an event but is used in arithmetic\n   ╭▸ src/PlaceHook.sol:85:9\n   │\n85 │         launchedAt = uint40(block.timestamp);\n   │         ━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/PlaceRouter.sol:47:13\n   │\n47 │             block.timestamp > deadline || amount == 0 || amount > uint256(uint128(type(int128).max))\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-events-arithmetic]: `seasonStart` is changed without an event but is used in arithmetic\n   ╭▸ src/Canvas.sol:73:9\n   │\n73 │         seasonStart = uint40(block.timestamp);\n   │         ━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/PlaceRouter.sol:47:67\n   │\n47 │             block.timestamp > deadline || amount == 0 || amount > uint256(uint128(type(int128).max))\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/PlaceRouter.sol:47:75\n   │\n47 │             block.timestamp > deadline || amount == 0 || amount > uint256(uint128(type(int128).max))\n   │                                                                           ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' 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[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/PlaceHook.sol:39:40\n   │\n39 │     constructor(IPoolManager manager_, address token_, address factory_) {\n   │                                        ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[arbitrary-send-erc20]: `transferFrom` uses an arbitrary `from`; require it to equal `msg.sender` or `address(this)`\n   ╭▸ src/PlaceRouter.sol:79:9\n   │\n79 │         IERC20(Currency.unwrap(pay)).safeTransferFrom(r.payer, address(manager), spent);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-erc20\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/PlaceRouter.sol:63:52\n   │\n63 │             SwapParams(zeroForOne, r.exactInput ? -int256(r.amount) : int256(r.amount), r.price),\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/PlaceRouter.sol:63:71\n   │\n63 │             SwapParams(zeroForOne, r.exactInput ? -int256(r.amount) : int256(r.amount), r.price),\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/PlaceRouter.sol:69:25\n   │\n69 │         uint256 spent = uint256(-int256(input));\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/PlaceRouter.sol:70:28\n   │\n70 │         uint256 received = uint256(int256(output));\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/PlaceHook.sol:85:22\n   │\n85 │         launchedAt = uint40(block.timestamp);\n   │                      ━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint40' 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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/PlaceHook.sol:94:16\n   │\n94 │         return elapsed >= 30 minutes ? 200 : 200 + 3300 * (30 minutes - elapsed) / 30 minutes;\n   │                ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlaceHook.sol:120:77\n    │\n120 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(fee)), 0), 0);\n    │                                                                             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlaceHook.sol:115:30\n    │\n115 │             uint256 amount = uint256(exactInput ? -params.amountSpecified : params.amountSpecified);\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/PlaceHook.sol:117:23\n    │\n117 │             if (fee > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/PlaceHook.sol:117:31\n    │\n117 │             if (fee > uint256(uint128(type(int128).max))) revert InvalidSwap();\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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/PlaceHook.sol:120:63\n    │\n120 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(fee)), 0), 0);\n    │                                                               ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' 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/PlaceHook.sol:120:70\n    │\n120 │         return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(fee)), 0), 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-oz-erc721-mint]: `ERC721._mint` does not check that the recipient can receive the token; use `_safeMint`\n   ╭▸ src/Seasons.sol:49:9\n   │\n49 │         _mint(address(this), id);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-oz-erc721-mint\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlaceHook.sol:163:44\n    │\n163 │         return (IHooks.afterSwap.selector, returned);\n    │                                            ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/Seasons.sol:47:38\n   │\n47 │             pot, 0, address(0), top, uint40(block.timestamp + 1 days), owned, painters, paints, false\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint40' 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/PlaceHook.sol:135:29\n    │\n135 │         uint256 principal = uint256(buy ? -int256(pairDelta) : int256(pairDelta));\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/PlaceHook.sol:140:30\n    │\n140 │             uint256 amount = uint256(exactInput ? -params.amountSpecified : params.amountSpecified);\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/PlaceHook.sol:149:23\n    │\n149 │             if (fee > uint256(uint128(type(int128).max))) revert InvalidSwap();\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/PlaceHook.sol:149:31\n    │\n149 │             if (fee > uint256(uint128(type(int128).max))) revert InvalidSwap();\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' 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/PlaceHook.sol:150:24\n    │\n150 │             returned = int128(int256(fee));\n    │                        ━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int128' 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/PlaceHook.sol:150:31\n    │\n150 │             returned = int128(int256(fee));\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[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/PlaceHook.sol:169:68\n    │\n169 │         if (poolManager.balanceOf(address(this), imd.toId()) != 0) poolManager.unlock(\"\");\n    │                                                                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/Seasons.sol:60:42\n   │\n60 │         if (a.end == 0 || a.finalized || block.timestamp >= a.end || a.owned == 0 || amount < minimumBid(id)) revert InvalidAction();\n   │                                          ━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/Seasons.sol:69:13\n   │\n69 │         if (a.end - block.timestamp < 10 minutes) a.end += 10 minutes;\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlaceHook.sol:169:13\n    │\n169 │         if (poolManager.balanceOf(address(this), imd.toId()) != 0) poolManager.unlock(\"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n   ╭▸ src/Seasons.sol:64:13\n   │\n64 │         if (token.balanceOf(address(this)) != balance + amount) revert InvalidAction();\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/PlaceHook.sol:169:68\n    │\n169 │         if (poolManager.balanceOf(address(this), imd.toId()) != 0) poolManager.unlock(\"\");\n    │                                                                    ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n   ╭▸ src/Seasons.sol:84:13\n   │\n84 │             canvas.carryPot(pot);\n   │             ━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/Seasons.sol:76:42\n   │\n76 │         if (a.end == 0 || a.finalized || block.timestamp < a.end) revert InvalidAction();\n   │                                          ━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/Seasons.sol:89:9\n   │\n89 │         emit Finalized(id, winner, a.bid == 0 ? 0 : a.pot + a.bid);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/Canvas.sol:73:23\n   │\n73 │         seasonStart = uint40(block.timestamp);\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint40' 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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/Seasons.sol:94:57\n   │\n94 │         if (a.end != 0 && !a.finalized && a.bid == 0 && block.timestamp >= a.end) finalize(id);\n   │                                                         ━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/Seasons.sol:107:47\n    │\n107 │             (address owner,,,, uint16 rank) = canvas.pixels(id, pixel);\n    │                                               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Seasons.sol:106:32\n    │\n106 │             if (pixel >= 4096) revert InvalidAction();\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/Seasons.sol:110:77\n    │\n110 │             if (owner != msg.sender || claimedBitmap[id][word] & mask != 0) revert InvalidAction();\n    │                                                                             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/Seasons.sol:107:47\n    │\n107 │             (address owner,,,, uint16 rank) = canvas.pixels(id, pixel);\n    │                                               ━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/Seasons.sol:125:17\n    │\n125 │ ┏                 abi.encodePacked(\n126 │ ┃                     '{\"name\":\"imd/place season ',\n127 │ ┃                     id.toString(),\n128 │ ┃                     '\",\"external_url\":\"https://x.com/imdplace\",\"image\":\"data:image/svg+xml;base64,',\n    ‡ ┃\n136 │ ┃                     \"}]}\"\n137 │ ┃                 )\n    │ ┗━━━━━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/Seasons.sol:178:66\n    │\n178 │             bytes memory rgb = bytes(Strings.toHexString(uint256(canvas.palette(colour)), 3));\n    │                                                                  ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Seasons.sol:197:48\n    │\n197 │         if (n >= 10) output[cursor++] = bytes1(uint8(48 + n / 10));\n    │                                                ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Seasons.sol:198:35\n    │\n198 │         output[cursor++] = bytes1(uint8(48 + n % 10));\n    │                                   ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Seasons.sol:203:25\n    │\n203 │         for (uint256 i; i < part.length; i += 32) {\n    │                         ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/Canvas.sol:91:28\n   │\n91 │             accPerPixel += artists * SCALE / painted;\n   │                            ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Canvas.sol:102:21\n    │\n102 │         uint256 k = block.timestamp >= uint256(p.windowStart) + 1 days ? 0 : p.paints;\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/Canvas.sol:127:13\n    │\n127 │             spent += cost;\n    │             ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Canvas.sol:119:28\n    │\n119 │             season == 0 || block.timestamp >= uint256(seasonStart) + 7 days || ids.length == 0\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Canvas.sol:141:17\n    │\n141 │             if (block.timestamp >= uint256(p.windowStart) + 1 days || p.paints == 0) {\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/Canvas.sol:125:53\n    │\n125 │             if (ids[i] >= 4096 || colours[i] >= 16) revert InvalidAction();\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/Canvas.sol:100:25\n    │\n100 │         if (id >= 4096) revert InvalidAction();\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/Canvas.sol:128:63\n    │\n128 │             if (spent > maxDrops || cost > drops[msg.sender]) revert InsufficientPaint();\n    │                                                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Canvas.sol:142:33\n    │\n142 │                 p.windowStart = uint40(block.timestamp);\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint40' 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/Canvas.sol:151:19\n    │\n151 │         paints += uint64(ids.length);\n    │                   ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' 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[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/Canvas.sol:178:9\n    │\n178 │         IPlaceHook(hook).collectFees();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Canvas.sol:180:9\n    │\n180 │         emit Claimed(msg.sender, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/Canvas.sol:186:9\n    │\n186 │         IPlaceHook(hook).collectFees();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `season` is updated\n    ╭▸ src/Canvas.sol:194:21\n    │\n194 │         if (id > 1) seasons.rollUnbid(id - 1);\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `season` is updated\n    ╭▸ src/Canvas.sol:197:9\n    │\n197 │         seasons.open(id, amount, painted, painters, paints, topPainter);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/Canvas.sol:208:9\n    │\n208 │         IPlaceHook(hook).collectFees();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/Canvas.sol:191:28\n    │\n191 │         if (season == 0 || block.timestamp < uint256(seasonStart) + 7 days) revert InvalidAction();\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/Canvas.sol:198:9\n    │\n198 │         emit SeasonEnded(id, amount, painted);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/Canvas.sol:200:23\n    │\n200 │         seasonStart = uint40(block.timestamp);\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint40' 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[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/Hook.t.sol:70:13\n    │\n 70 │             block.timestamp + 1\n    │             ━━━━━━━━━━━━━━━\n    ‡\n151 │         vm.warp(hook.launchedAt() + 15 minutes);\n    │         ─────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":810,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/RobinhoodFork.t.sol:RobinhoodForkTest\n[SKIP] test_realRobinhoodManagerBuySell() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 413.50µs (47.92µs CPU time)\n\nRan 3 tests for test/Adversarial.t.sol:AdversarialTest\n[PASS] test_duplicatePixelAuctionClaimIsAtomic() (gas: 773386)\n[PASS] test_failedClaimRestoresCreditAndReentrancyBlocked() (gas: 498147)\n[PASS] test_failedImmediateRefundRollsBackBidAndFunds() (gas: 1019333)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.52ms (1.11ms CPU time)\n\nRan 1 test for test/Deployment.t.sol:DeploymentTest\n[PASS] test_realCreate2DeploymentAndFactoryInitialization() (gas: 12437859)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.43ms (4.06ms CPU time)\n\nRan 9 tests for test/Hook.t.sol:ReverseCurrencyHookTest\n[PASS] testFuzz_buyFeeCredit(uint96,bool) (runs: 256, μ: 339305, ~: 341679)\nLogs:\n  Bound result 996995496653462481985\n\n[PASS] test_allFourSwapModesAndFeeBacking() (gas: 1185144)\n[PASS] test_buyCreditSmartWalletAndSellsUnchanged() (gas: 720025)\n[PASS] test_callbacksAndPoolBinding() (gas: 190184)\n[PASS] test_decayAndSplit() (gas: 975251)\n[PASS] test_freshManagerSeededWithLaunchTokensOnly() (gas: 10448164)\n[PASS] test_noDataUsesOriginAndRejectsForgedIdentity() (gas: 453762)\n[PASS] test_slippageDeadlineAndPartialFillRevert() (gas: 468559)\n[PASS] test_tokenSupplyAndTransfer() (gas: 130094)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 26.41ms (29.73ms CPU time)\n\nRan 9 tests for test/Hook.t.sol:HookTest\n[PASS] testFuzz_buyFeeCredit(uint96,bool) (runs: 256, μ: 334201, ~: 337035)\nLogs:\n  Bound result 999999999000000014375\n\n[PASS] test_allFourSwapModesAndFeeBacking() (gas: 1184330)\n[PASS] test_buyCreditSmartWalletAndSellsUnchanged() (gas: 713933)\n[PASS] test_callbacksAndPoolBinding() (gas: 190184)\n[PASS] test_decayAndSplit() (gas: 969297)\n[PASS] test_freshManagerSeededWithLaunchTokensOnly() (gas: 10413479)\n[PASS] test_noDataUsesOriginAndRejectsForgedIdentity() (gas: 447125)\n[PASS] test_slippageDeadlineAndPartialFillRevert() (gas: 457380)\n[PASS] test_tokenSupplyAndTransfer() (gas: 130094)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 380.03ms (29.27ms CPU time)\n\nRan 9 tests for test/Canvas.t.sol:CanvasTest\n[PASS] testFuzz_accumulatorAcrossRepaints(bytes32) (runs: 256, μ: 14981997, ~: 14982808)\n[PASS] test_auctionRaiseRefundExtensionAndExactPayout() (gas: 1853392)\n[PASS] test_batchLimitsAndValidationAtomic() (gas: 847264)\n[PASS] test_feeSplitAndNoPixels() (gas: 852977)\n[PASS] test_freezeTimeSnapshotAndReset() (gas: 23423526)\n[PASS] test_noBidTopPainterAndCarryIntoCurrentSeason() (gas: 1342131)\n[PASS] test_privilegedEntrypointsRefuseOthers() (gas: 134000)\n[PASS] test_repaintWindowAndCap() (gas: 1464538)\n[PASS] test_rewardsSurviveRepaintAndManySeasons() (gas: 2150162)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 402.34ms (433.65ms CPU time)\n\nRan 13 tests for test/IndependentReview.t.sol:IndependentReviewTest\n[PASS] testFuzz_accumulatorAcrossRepaints(bytes32) (runs: 256, μ: 14981979, ~: 14983042)\n[PASS] testFuzz_reviewAccountingAcrossSeasons(bytes32) (runs: 256, μ: 24647862, ~: 24643151)\n[PASS] test_auctionRaiseRefundExtensionAndExactPayout() (gas: 1853546)\n[PASS] test_batchLimitsAndValidationAtomic() (gas: 847308)\n[PASS] test_feeSplitAndNoPixels() (gas: 853194)\n[PASS] test_freezeTimeSnapshotAndReset() (gas: 23423661)\n[PASS] test_noBidTopPainterAndCarryIntoCurrentSeason() (gas: 1342329)\n[PASS] test_privilegedEntrypointsRefuseOthers() (gas: 134044)\n[PASS] test_repaintWindowAndCap() (gas: 1464626)\n[PASS] test_reviewFullCanvasMetadataGas() (gas: 63649159)\nLogs:\n  SVG bytes: 56636\n  SVG gas: 19066907\n  tokenURI bytes: 101021\n  tokenURI gas: 30308401\n\n[PASS] test_reviewLateCarryTargetsNextSeason() (gas: 875643)\n[PASS] test_reviewSVGCoordinatesAndFrozenColours() (gas: 22372454)\n[PASS] test_rewardsSurviveRepaintAndManySeasons() (gas: 2150580)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 694.15ms (1.60s CPU time)\n\nRan 7 test suites in 695.68ms (1.51s CPU time): 44 tests passed, 0 failed, 1 skipped (45 total tests)\n","passed":true},{"durationMs":48,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Canvas.carryPot(uint256)\",\"Canvas.claim()\",\"Canvas.credit(address,uint256)\",\"Canvas.endSeason()\",\"Canvas.paint(uint16[],uint8[])\",\"Canvas.paintWithLimit(uint16[],uint8[],uint256)\",\"Canvas.payRecipient()\",\"Canvas.recordFee(uint256,uint256)\",\"Canvas.start(address)\",\"PlaceHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"PlaceHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"PlaceHook.beforeSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),bytes)\",\"PlaceHook.collectFees()\",\"PlaceHook.unlockCallback(bytes)\",\"PlaceRouter.swap(bool,bool,uint256,uint256,uint160,uint256)\",\"PlaceRouter.unlockCallback(bytes)\",\"PlaceToken.approve(address,uint256)\",\"PlaceToken.transfer(address,uint256)\",\"PlaceToken.transferFrom(address,address,uint256)\",\"Seasons.approve(address,uint256)\",\"Seasons.bid(uint256,uint256)\",\"Seasons.claim(uint256,uint16[])\",\"Seasons.finalize(uint256)\",\"Seasons.open(uint256,uint256,uint16,uint32,uint64,address)\",\"Seasons.rollUnbid(uint256)\",\"Seasons.safeTransferFrom(address,address,uint256)\",\"Seasons.safeTransferFrom(address,address,uint256,bytes)\",\"Seasons.setApprovalForAll(address,bool)\",\"Seasons.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":124,\"REVIEW.md\":27,\"foundry.toml\":19,\"script/MineHook.s.sol\":32,\"script/configure-site.mjs\":20,\"script/export-abi.mjs\":5,\"src/Canvas.sol\":259,\"src/HookFlags.sol\":30,\"src/Interfaces.sol\":17,\"src/PlaceHook.sol\":178,\"src/PlaceRouter.sol\":84,\"src/PlaceToken.sol\":10,\"src/Seasons.sol\":210,\"test/Adversarial.t.sol\":124,\"test/Canvas.t.sol\":302,\"test/Deployment.t.sol\":40,\"test/Hook.t.sol\":252,\"test/IndependentReview.t.sol\":134,\"test/RobinhoodFork.t.sol\":34,\"test/mocks/MockERC20.sol\":13,\"test/mocks/PoolDriver.sol\":59,\"web/abi.json\":1,\"web/app.js\":161,\"web/deployment.json\":1,\"web/index.html\":32,\"web/style.css\":1,\"web/vendor/LICENSE.md\":21,\"web/vendor/PROVENANCE\":3,\"web/vendor/ethers.min.js\":1,\"web/vendor/package.json\":1},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":7542,"exitCode":0,"name":"slither","output":"[high/high] arbitrary-send-erc20 at src/PlaceRouter.sol:56: PlaceRouter.unlockCallback(bytes) (src/PlaceRouter.sol#56-83) uses arbitrary from in transferFrom: IERC20(Currency.unwrap(pay)).safeTransferFrom(r.payer,address(manager),spent) (src/PlaceRouter.sol#79)\n[medium/medium] divide-before-multiply at src/Canvas.sol:82: Canvas.recordFee(uint256,uint256) (src/Canvas.sol#82-97) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/Seasons.sol:53: Seasons.minimumBid(uint256) (src/Seasons.sol#53-56) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/Canvas.sol:190: Reentrancy in Canvas.endSeason() (src/Canvas.sol#190-210):\n[medium/medium] uninitialized-local at src/Canvas.sol:122: Canvas._paint(uint16[],uint8[],uint256).spent (src/Canvas.sol#122) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PlaceHook.sol:138: PlaceHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes).returned (src/PlaceHook.sol#138) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PlaceHook.sol:113: PlaceHook.beforeSwap(address,PoolKey,SwapParams,bytes).fee (src/PlaceHook.sol#113) is a local variable never initialized\n[medium/medium] unused-return at src/Seasons.sol:98: Seasons.claim(uint256,uint16[]) (src/Seasons.sol#98-117) ignores return value by (owner,None,None,None,rank) = canvas.pixels(id,pixel) (src/Seasons.sol#107)\n[medium/medium] unused-return at src/PlaceHook.sol:167: PlaceHook.collectFees() (src/PlaceHook.sol#167-170) ignores return value by poolManager.unlock() (src/PlaceHook.sol#169)\n[low/medium] events-maths at src/Canvas.sol:212: Canvas.carryPot(uint256) (src/Canvas.sol#212-215) should emit an event for: \n[low/medium] calls-loop at src/Seasons.sol:98: Seasons.claim(uint256,uint16[]) (src/Seasons.sol#98-117) has external calls inside a loop: (owner,None,None,None,rank) = canvas.pixels(id,pixel) (src/Seasons.sol#107)\n[low/medium] calls-loop at src/Seasons.sol:142: Seasons.svg(uint256) (src/Seasons.sol#142-194) has external calls inside a loop: rgb = bytes(Strings.toHexString(uint256(canvas.palette(colour_scope_3)),3)) (src/Seasons.sol#178)\n[low/medium] calls-loop at src/Seasons.sol:142: Seasons.svg(uint256) (src/Seasons.sol#142-194) has external calls inside a loop: rgb = bytes(Strings.toHexString(uint256(canvas.palette(colour_scope_3)),3)) (src/Seasons.sol#178)\n[low/medium] reentrancy-benign at src/Canvas.sol:190: Reentrancy in Canvas.endSeason() (src/Canvas.sol#190-210):\n[low/medium] reentrancy-benign at src/Canvas.sol:190: Reentrancy in Canvas.endSeason() (src/Canvas.sol#190-210):\n[low/medium] timestamp at src/PlaceHook.sol:91: PlaceHook.feeBps() (src/PlaceHook.sol#91-95) uses timestamp for comparisons\n[low/medium] timestamp at src/PlaceHook.sol:105: PlaceHook.beforeSwap(address,PoolKey,SwapParams,bytes) (src/PlaceHook.sol#105-121) uses timestamp for comparisons\n[low/medium] timestamp at src/Seasons.sol:58: Seasons.bid(uint256,uint256) (src/Seasons.sol#58-72) uses timestamp for comparisons\n[low/medium] timestamp at src/Canvas.sol:117: Canvas._paint(uint16[],uint8[],uint256) (src/Canvas.sol#117-156) uses timestamp for comparisons\n[low/medium] timestamp at src/PlaceHook.sol:123: PlaceHook.afterSwap(address,PoolKey,SwapParams,BalanceDelta,bytes) (src/PlaceHook.sol#123-164) uses timestamp for comparisons\n[low/medium] timestamp at src/Seasons.sol:74: Seasons.finalize(uint256) (src/Seasons.sol#74-90) uses timestamp for comparisons\n[low/medium] timestamp at src/Canvas.sol:99: Canvas.price(uint16) (src/Canvas.sol#99-104) uses timestamp for comparisons\n[low/medium] timestamp at src/Seasons.sol:42: Seasons.open(uint256,uint256,uint16,uint32,uint64,address) (src/Seasons.sol#42-51) uses timestamp for comparisons\n[low/medium] timestamp at src/PlaceRouter.sol:41: PlaceRouter.swap(bool,bool,uint256,uint256,uint160,uint256) (src/PlaceRouter.sol#41-54) uses timestamp for comparisons\n[low/medium] timestamp at src/Seasons.sol:92: Seasons.rollUnbid(uint256) (src/Seasons.sol#92-95) uses timestamp for comparisons\n[low/medium] timestamp at src/Seasons.sol:53: Seasons.minimumBid(uint256) (src/Seasons.sol#53-56) uses timestamp for comparisons\n[low/medium] timestamp at src/Canvas.sol:190: Canvas.endSeason() (src/Canvas.sol#190-210) uses timestamp for comparisons","passed":false}],"detail":"static analysis found arbitrary-send-erc20 at src/PlaceRouter.sol:56: PlaceRouter.unlockCallback(bytes) (src/PlaceRouter.sol#56-83) uses arbitrary from in transferFrom: IERC20(Currency.unwrap(pay)).safeTransferFrom(r.payer,address(manager),spent) (src/PlaceRouter.sol#79)","evaluation":"checks","profile":"foundry","status":"rejected","submissionHash":"e623a6c8c5468859b307062ed217a7ed7c254d09cd0670f6d4b664ab8da65f48","verifiedTreeHash":"7edca7fa3be3d3dda5656af475ce8ab975c7079a","verifierVersion":"0.1.0+ad90ce4c"}]}