{"assessments":[],"deployments":[{"attestationHash":"e2fa9e1fb77e042067e99b5b6c5791b5b8270bca6fa52da607e2a8fbe6e2b604","chainId":1,"contracts":[{"address":"0x58a5268fe97e1b4be0138bcd2527432a5ae30718","blockNumber":26209093,"name":"PlaygroundLauncher","role":"other","txHash":"0x1242bf9c95c47350bb35e8d9e323b6729fcfda8735cc70b5fe09f9d50aac594f"}],"id":"53ca1a1a-eae1-4bdb-87c7-5e6ef7485178","manifestHash":"2f8f00a238ad231cb7acb5105fa4eff576dcd105f001c7a2ad5b8ed9eff6fd53","status":"live"}],"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":"8e3d8881-e131-4adf-9956-563aea8af28f","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"8daceebdeff404fae9b35077d98d4419108abd8a007768cdffe64a2320b36c90","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"6a03e1e4369c4bd688be7cb8902d40c494b83632e64d59f47eb9d87d4af897f5","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"395a979ead3563ca07ecb339010c38550979614970d0312069d427aab325fb18","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"07aabce4ce368bae46b64279e4dd2a3eaabe183a58cc65bf926f8127ce99a6f7","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"f39837a3dd9d89d0ce8200c6df1cd66a8f546fdf7a051f58168f053d2c5b9d6e","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"418624f0a6c6624dd8b5421954f70ca392942cc459e971b9ee6d6fd5c6a8a5a1","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"ab78062754b834a6da05dc7e0df81610defd09d349c70359136145d68f8383ae","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"5f923c9376438cab036820998aacdda3470c748730e853b099d7481359c51a03","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Hook: 0xed9a04fa6693e754661a22502524df9b1857e544\nFactory: 0x801411c6acec4fa80c75c5d3c0eae13c84f8a173\nERC20T implementation: 0x2df7dcf4d19a7924e00ae96629cc1d1261670eee\n\ncreate a contract that uses the 0x801411c6acec4fa80c75c5d3c0eae13c84f8a173 factory to create a token called PLAYGROUND with the symbol PG\n\nsupply 1 billion\npair with IMD\n5% of supply goes to 0xcB58AdA9F7338Bfbe06Ec647f27DE8D0664dddaC\n\nthe rest of supply goes to the LP\n\ntax should be 2.5% that goes to 0xcB58AdA9F7338Bfbe06Ec647f27DE8D0664dddaC the 0.15% protocol tax will come out of the 2.5% so 0xcB58AdA9F7338Bfbe06Ec647f27DE8D0664dddaC will receive 2.35%. there will be no launch decay fee\n\nstarting valuation will be $20,000\n\nTotal supply: 1,000,000,000","parentJobId":null,"planHash":"f87df6f85a5652b5711e233d11972deef373d44ae673a70b6d9c5f88d2986733","previousHash":"8938f13898f843624131e5e0def850153dcc8c36a1074dd4e64c5cef4440dfbb","projectId":"8e3d8881-e131-4adf-9956-563aea8af28f","publication":{"commit":"bc59e7ee0cbf01a2b5fa93138cf481c53eab5893","deliveredAt":"2026-10-17T01:48:50.723Z","repoUrl":"https://github.com/identity-md-launches/launch-2039-hook-0xed9a04fa6693e754661a22502524df9b1"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"1b5f660f67cfc1aac4176b07f413045bbb5993d43f1fd32583b53c3541599f27","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"629987aaf6c7aa88","findings":[{"citation":"resolved","description":"Boundary x precision seam. quotePrice() only rejects 0 and values above 2e31, so setImdUsdPrice accepts any IMD/USD price from $1e-18 to $2e13 per IMD, and the factory happily launches at every value in that range (verified: P = 1, 1e3, 1e6 ... 1e12 and 1e24 ... 2e31 all launch against the real factory/hook bytecode). launch() is one-way: the PG/IMD position is minted to 0xdEaD and PG cannot be re-created, so a decimals or scale mistake in the single owner-typed number fixes the opening valuation forever. The $20,000 FDV the brief requires is enforced only by the formula, not by any plausibility check on its one free input. The README delegates this to operator diligence, but no code path lets a wrong launch be corrected, and an under-priced launch is profitably exploited by whoever buys first in the launch block (unprivileged amplifier). Minimal fix that preserves the design: bound priceUsdWad to a plausibility window around the expected IMD market price (for example 1e14 to 1e21, i.e. $0.0001 to $1,000 per IMD, as constants), and/or require that launch() be passed the expected startingPriceQuote as an argument that must equal the stored value, so a stale or mistyped observation cannot be executed unnoticed.","line":101,"path":"src/PlaygroundLauncher.sol","reproduction":"Fixture: test/helpers/ProtocolFixture.sol world (real factory, implementation, hook, PoolManager, PositionManager, Permit2, IMD runtime). Owner intends IMD = $1.00 (P = 1e18) but types 1e16: launcher.setImdUsdPrice(1e16, uint64(block.timestamp)) succeeds; launcher.startingPriceQuote() == 2_000_000_000_000_000 (0.002 IMD per PG, 100x the intended 0.00002 IMD); launcher.launch() succeeds and returns the PG token with 950,000,000 PG locked single-sided at that price. With IMD really at $1 the opening FDV is $2,000,000 instead of $20,000, and nothing in PlaygroundLauncher or ERC20T can move or withdraw the position. Same sequence with setImdUsdPrice(1, ts) gives quote 20000000000000000000000000000000 and still launches; setImdUsdPrice(2e31, ts) gives quote 1 and still launches. Expected: inputs outside any plausible IMD price range revert before an irreversible launch. Actual: every value in [1, 2e31] launches.","severity":"low","snippet":"        if (priceUsdWad == 0 || priceUsdWad > PRICE_NUMERATOR) revert InvalidPrice();","title":"Price input accepted across 31 orders of magnitude; a scale slip launches irreversibly at the wrong FDV"},{"citation":"resolved","description":"External-boundary corner case. _checkDependencies() requires IMD.symbol() to equal the string \"IMD\". IMD (0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7) is a LayerZero OFT whose live runtime exposes updateSymbol(string) (selector 0x537f5312) and updateNameAndSymbol(string,string) (0xeaf9d194) to its owner (currently 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7). Because IMD, HOOK and the check itself are compile-time constants and the launcher has no setter, any symbol change by that third party makes launch() and preview() revert with IncompatibleDependencies forever; the only recovery is deploying a new launcher. The check buys no safety: the IMD address is fixed, so the token identity cannot differ, and the decimals() == 18 check is what the price math actually relies on. Minimal fix: drop the symbol comparison (keep the decimals check and the hook externalBases registration check), or compare against a value the owner can refresh.","line":181,"path":"src/PlaygroundLauncher.sol","reproduction":"test/scratch/Symbol.t.sol (run: forge test --match-path test/scratch/Symbol.t.sol -vv), using the real IMD runtime from the fixture: vm.clearMockedCalls(); write an owner into IMD storage slot 0 (its Ownable slot, found by scanning owner()); vm.prank(imdOwner); IImdAdmin(IMD).updateSymbol(\"IMD\") -> launcher.launch() succeeds (sanity, then reverted with a snapshot). Then vm.prank(imdOwner); IImdAdmin(IMD).updateSymbol(\"IMD v2\"); launcher.launch() reverts IncompatibleDependencies and launcher.preview(true) reverts IncompatibleDependencies. No PlaygroundLauncher function can change IMD, HOOK or skip _checkDependencies, so the owner can never launch from this contract. Expected: a cosmetic metadata change on a fixed-address dependency does not disable the launch. Actual: launcher is dead until redeployed.","severity":"low","snippet":"                || keccak256(bytes(IERC20TToken(IMD).symbol())) != keccak256(\"IMD\")","title":"Launch readiness depends on IMD's owner-mutable symbol string; a rename permanently bricks the launcher"}],"hash":"07aabce4ce368bae46b64279e4dd2a3eaabe183a58cc65bf926f8127ce99a6f7","nodeId":"c1d87291-eafd-46f7-88e2-2a9a4481502b","outcome":"completed","summary":"The review is complete. The findings file at `.imd-findings.json` holds two low-severity findings and eleven coverage rows, with both snippets verified against the tree and the JSON parsed cleanly.\n\n**What I covered.** The Math Precision, Boundary and Numerical Gap passes over `PlaygroundLauncher`, traced through the verified factory and ERC20T sources and exercised against the real deployed bytecode in the fixtures. I also checked the live mainnet state through a public RPC. The owner's price formula, the factory's tick alignment, supply conservation, the 250/15/235 basis-point tax split, the one-hour freshness window, and the reentrancy guard all hold. Third-party pre-initialization of the predicted PG/IMD pool is rejected by the real hook. Every live dependency value matches the launcher's constants, including the three fixture code hashes.\n\n**Findings, both low.**\n- **Unbounded price input on an irreversible launch.** The launcher accepts any IMD/USD price from 1 to 2e31 and the factory launches at every one of them. A scale slip such as typing 1e16 for a $1 IMD launches at a $2,000,000 valuation with the liquidity locked forever. A plausibility window on the input is the minimal fix.\n- **Launch readiness tied to IMD's mutable symbol.** The dependency check compares the IMD symbol string, which the IMD owner can change through its live `updateSymbol` function. A rename permanently disables both launch and preview, confirmed with the real IMD runtime. The check protects nothing since the IMD address is a constant.\n\n**Not reached.** The hook's internal fee conversion arithmetic, since its source is unverified. Only its observed runtime split was checked.\n\nNumbers worth recording for the author:\n\n| Quantity at $1 IMD | Value |\n| --- | --- |\n| Requested quote | 20,000,000,000,000 IMD base units per PG |\n| Effective quote after tick alignment | 20,046,436,793,152 (+0.232%) |\n| Opening FDV | $20,046.44 |\n| Dust locked in PG contract | 155 base units |\n\nThe two scratch tests under `test/scratch/` reproduce the probes and are not part of the submission.","treeHash":null,"usage":{"cachedInputTokens":1282646,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":35868,"runtime":"claude","turns":36,"wallClockMs":536735}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"9812c5faf226f7c7","findings":[{"citation":"resolved","description":"_checkDependencies() (called by launch() and preview()) requires IMD.symbol() to equal the literal \"IMD\". IMD at 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7 is a LayerZero OFT whose runtime (test/fixtures/ImdBytecode.sol, the eth_getCode snapshot) contains the selectors 0x537f5312 updateSymbol(string) and 0xeaf9d194 updateNameAndSymbol(string,string), both owner-only. IMD, HOOK and the comparison are compile-time constants and the launcher has no setter, so if IMD's owner changes the symbol before launch() has run, launch() and preview() revert IncompatibleDependencies forever and the only recovery is a new launcher deployment (a new launch). The check adds no safety: the IMD address is fixed, so token identity cannot differ; the decimals()==18 check is what the price math relies on. After a successful launch nothing reads the symbol, so this is a pre-launch liveness issue only. Reported by audit_math; reproduced against the real IMD runtime. Minimal fix preserving the design: drop the symbol comparison (keep the decimals and externalBases checks), or compare against a value the owner can refresh.","line":181,"path":"src/PlaygroundLauncher.sol","reproduction":"test/scratch/Repro.t.sol test_imdSymbolRenameBricksLauncher (forge test --match-path test/scratch/Repro.t.sol): ProtocolFixture world, vm.clearMockedCalls() so the real IMD symbol() runs; write the test contract into IMD's Ownable owner slot (found by scanning slots 0..63 until owner()==this); call IImdAdmin(IMD).updateSymbol(\"IMD\") -> launcher.launch() succeeds (sanity, reverted via snapshot). Then IImdAdmin(IMD).updateSymbol(\"IMD v2\"). Expected: a cosmetic metadata change on a fixed-address dependency does not disable the launch. Actual: launcher.launch() reverts PlaygroundLauncher.IncompatibleDependencies, launcher.preview(true) reverts IncompatibleDependencies, launcher.token()==address(0), and no PlaygroundLauncher function can change IMD, HOOK or skip _checkDependencies. Test passes (i.e. the brick is confirmed).","severity":"low","snippet":"|| keccak256(bytes(IERC20TToken(IMD).symbol())) != keccak256(\"IMD\")","title":"Launch readiness depends on IMD's owner-mutable symbol string; a rename before launch bricks the launcher permanently"},{"citation":"resolved","description":"quotePrice() only rejects 0 and values above 2e31, so setImdUsdPrice accepts any IMD/USD price from $1e-18 to $2e13 per IMD and launch() proceeds at every value in that range (verified against the real factory/hook bytecode for P = 1, 1e16 and 2e31). launch() is one-way: the PG/IMD position NFT is minted to 0xdEaD, beforeLaunch blocks any later setImdUsdPrice, and PG cannot be re-created, so a decimals or scale mistake in the single operator-typed number fixes the opening valuation forever. The brief's $20,000 FDV is enforced only by the formula, not by any plausibility bound on its one free input. An over-stated P (e.g. 1e20 typed for 1e18) under-prices PG 100x and the first buyer in the launch block profits at the project's expense; an under-stated P over-prices it. The README delegates this to operator diligence, but no code path lets a wrong launch be corrected. Reported by audit_math; reproduced. Minimal fix preserving the design: bound priceUsdWad to a plausibility window around IMD's expected market price as constants (e.g. 1e14..1e21, $0.0001..$1,000 per IMD), and/or make launch() take the expected startingPriceQuote as an argument that must equal the stored value so a mistyped or stale observation cannot execute unnoticed.","line":101,"path":"src/PlaygroundLauncher.sol","reproduction":"test/scratch/Repro.t.sol test_scaleSlipLaunchesAtWrongFdv (forge test --match-path test/scratch/Repro.t.sol -vv): ProtocolFixture world (real factory, implementation, hook, PoolManager, PositionManager, Permit2, IMD runtime). Owner intends IMD = $1.00 (P = 1e18) but calls launcher.setImdUsdPrice(1e16, uint64(block.timestamp)): succeeds; launcher.startingPriceQuote() == 2_000_000_000_000_000 (0.002 IMD per PG, 100x the intended 0.00002); launcher.launch() succeeds with 950,000,000 PG locked single-sided at that price; effectivePriceWei*1e18*1e9/1e36 = 2,009,861 USD FDV at a real $1 IMD instead of 20,000; a corrective setImdUsdPrice(1e18, ts) then reverts AlreadyLaunched. Same sequence with setImdUsdPrice(1, ts) gives quote 2e31 and still launches; setImdUsdPrice(2e31, ts) gives quote 1 and still launches. Expected: inputs outside any plausible IMD price range revert before an irreversible launch. Actual: every value in [1, 2e31] launches.","severity":"low","snippet":"if (priceUsdWad == 0 || priceUsdWad > PRICE_NUMERATOR) revert InvalidPrice();","title":"Price input accepted across 31 orders of magnitude; a scale slip in the one owner-typed number launches irreversibly at the wrong FDV"},{"citation":"resolved","description":"Merged from audit_permissions, audit_flow and audit_economics (same root cause, line 158). launch() installs the brief's terms correctly at creation (taxBps 250, feeRecipient and feeDecayRecipient 0xcB58AdA9F7338Bfbe06Ec647f27DE8D0664dddaC, launchTaxBps 0, 15 bps protocol share inside the 250) and then hands ERC20T ownership to the launcher's immutable owner ($owner, which README names as 0x1EE3ffadfE138415A2ddaedeEBe5F46616fA413d, a different party from the beneficiary). The inherited ERC20T owner functions setTaxBps (30..500 bps, docs/reference/ERC20T.sol.txt lines 249-259) and setFeeRecipient (lines 263-270) have no timelock and need no consent from the beneficiary, so the brief's 'tax 2.5% goes to 0xcB58...' is enforced only at launch and thereafter rests on the owner's conduct. This is not a permission bypass: the launcher's own writers are onlyOwner + beforeLaunch, there is no receive/fallback, and no unprivileged path reaches these setters. It is disclosed in README.md, docs/SECURITY.md and the launch.json notes, and the brief does not name a token owner or ask for immutable fee terms, so it is recorded as a trust assumption for the requester to accept knowingly, not as a defect. If immutable terms are wanted, the scope decision is the requester's: (a) transfer token ownership to BENEFICIARY instead of owner, (b) keep ownership in the launcher (no admin surface, so tax/recipient/distributor/external-liquidity settings become permanent), or (c) renounce after launch; (b) and (c) remove the distributor administration that contract-wallet integrations need.","line":158,"path":"src/PlaygroundLauncher.sol","reproduction":"test/scratch/Repro.t.sol test_ownerRedirectsTaxAfterLaunch (forge test --match-path test/scratch/Repro.t.sol -vv): ProtocolFixture world with the ETH/IMD conversion pool funded, launcher owner = test contract. pg = launcher.launch(); pg.owner()==owner, pg.feeRecipient()==0xcB58..., pg.taxBps()==250. As owner: ITokenExtras(pg).setFeeRecipient(0xB0B); ITokenExtras(pg).setTaxBps(500). Then a trader buys with 100 IMD through the canonical PG/IMD pool. Expected per brief: 0xcB58... receives the 2.35% share, 0xB0B receives nothing. Actual (measured): 0xcB58... ETH delta = 0; 0xB0B ETH delta = 4.859321467770692040 ETH; protocol recipient delta = 0.150288292817650269 ETH (15/500 of the 5% tax); pg.taxBps()==500. Nothing in PlaygroundLauncher can prevent or reverse this once line 158 has executed.","severity":"info","snippet":"pg.transferOwnership(owner);","title":"Trust assumption: after launch the $owner (not the beneficiary) holds ERC20T admin powers that can redirect the 2.35% stream and change the 2.5% rate"}],"hash":"395a979ead3563ca07ecb339010c38550979614970d0312069d427aab325fb18","nodeId":"88af9031-3536-4050-a448-5deb6dd99752","outcome":"completed","summary":"The findings file is written and all three reproductions ran green against the real factory, hook, ERC20T and IMD bytecode.\n\n**Outcome:** no critical, high or medium defects. The launcher deploys under the CREATE2 model (one `$owner` argument, no constructor calls, 9,251 byte runtime, no forbidden opcodes), both entry points are owner-gated and launch-gated, the factory call is guarded by `_launching` so the slither/aderyn reentrancy lines are false positives, and `_checkToken` enforces every brief term on the created clone. The existing 55 tests pass.\n\n**Findings kept, in `.imd-findings.json`:**\n\n1. **Low, line 181.** The `IMD.symbol() == \"IMD\"` dependency check is against a constant address whose owner can call `updateSymbol` (selector present in the IMD runtime snapshot). A rename before launch makes `launch()` and `preview()` revert forever with no recovery except a new launcher. Reproduced with the real IMD runtime by writing its owner slot and renaming.\n2. **Low, line 101.** `quotePrice` accepts any price in [1, 2e31] and every value launches irreversibly. Typing 1e16 for a $1 IMD launches at roughly $2.0M FDV instead of $20,000, and a later corrective price set reverts `AlreadyLaunched`.\n3. **Info, line 158.** Merged from three specialists: `$owner` receives ERC20T admin and can call `setFeeRecipient` and `setTaxBps(500)` after launch. Measured: beneficiary receives 0 ETH on a 100 IMD buy afterward. It is disclosed in the README, SECURITY.md and manifest notes, so it is recorded as a trust assumption for the requester's decision, not a defect.\n\n**Dropped or recalibrated:** the permissions and flow specialists' duplicates were merged into finding 3; the economics specialist's \"low\" was lowered to info because the brief names no token owner and the power is an intentional, documented role.\n\n**Coverage:** both listed entry points answered (`launch()` finding 1, `setImdUsdPrice` finding 2), plus rows for deployability, pricing math, brief terms, the reentrancy leads and the manifest, all holding. The scratch file `test/scratch/Repro.t.sol` holds the three reproductions and is not part of the submission.","treeHash":null,"usage":{"cachedInputTokens":744511,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":23006,"runtime":"claude","turns":25,"wallClockMs":311697}},{"artifacts":[],"attempt":1,"bundleHash":"e770ac29f3241b74ca24b8dc93bc0382d8e78ea867133b26351281610cc0e15c","device":"493095393c4a2a74","findings":[],"hash":"418624f0a6c6624dd8b5421954f70ca392942cc459e971b9ee6d6fd5c6a8a5a1","nodeId":"824045e9-133c-4ff1-a994-620f3e943b64","outcome":"completed","summary":"Implemented the launcher with 1 billion PG, 5% beneficiary allocation, 95% LP allocation, IMD pairing, 2.5% inclusive tax, and no decay.\n\nAll 36 tests pass, including offline with the supplied fuzz seed. `forge build` and `forge fmt --check` pass.\n\nBefore launch, the owner must set a fresh IMD/USD quote. Valuation rounding, deployment steps, and retained token-admin powers are documented in `README.md`. No transactions were broadcast.","treeHash":"67a9e12fe6836057a9cf8d12b7059a1ac4ae0f2c","usage":{"cachedInputTokens":3424640,"inputTokens":245988,"model":"gpt-6-astra","outputTokens":36921,"runtime":"codex","turns":8,"wallClockMs":830250}},{"artifacts":[],"attempt":1,"bundleHash":"2bd0f0da711b72ef4c8633f55c281f4b41a1e5b585e3ba0e3eb032d12f52a041","device":"26d42bb29b53b9d8","findings":[],"hash":"5f923c9376438cab036820998aacdda3470c748730e853b099d7481359c51a03","nodeId":"a476e140-e02d-4dfc-8329-ec221e365305","outcome":"completed","summary":"Added failure-path, fuzz, and invariant tests under `test/`, covering launch retries, permissions, supply and fee conservation, and both token orderings.\n\n`forge build` passed. Full suite passed with the required seed: **55 tests, 49,152 invariant calls, zero failures**.","treeHash":"5c00d5693a3cb0f3f042d04f192c96295fb10ef1","usage":{"cachedInputTokens":3004672,"inputTokens":106658,"model":"gpt-6-astra","outputTokens":28363,"runtime":"codex","turns":10,"wallClockMs":712195}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"9506ecec995bdbf9","findings":[{"citation":"resolved","description":"launch() correctly installs the brief's terms at creation: taxBps 250, feeRecipient and feeDecayRecipient 0xcB58AdA9F7338Bfbe06Ec647f27DE8D0664dddaC, no launch decay, 15 bps protocol share inside the 250. It then makes the launcher's immutable owner ($owner, which the README gives as 0x1EE3ffadfE138415A2ddaedeEBe5F46616fA413d, not the beneficiary) the owner of the ERC20T. The inherited ERC20T owner powers (docs/reference/ERC20T.sol.txt setFeeRecipient, setTaxBps 30-500, setDistributors, setUseGlobalDistributors, setExternalLiquidityEnabled) let that owner redirect the beneficiary's tax share or change the rate in one call, with no timelock. The README discloses this, and the brief does not say who owns the token, so this is a trust assumption, not a permission bypass. It is recorded so the judge and the requester can confirm that the requested 'tax goes to 0xcB58...' only has to hold at launch. No fix is required unless the requester wants the fee terms enforced afterwards. In that case the minimal change is to hand token ownership to BENEFICIARY instead of owner, which keeps the distributor administration that renouncing would lose.","line":158,"path":"src/PlaygroundLauncher.sol","reproduction":"Using test/helpers/ProtocolFixture.sol (the owner is the test contract): pg = launcher.launch(); then, as the owner, ITokenExtras(pg).setFeeRecipient(owner) and ITokenExtras(pg).setTaxBps(500). Result: pg.feeRecipient() == owner and pg.taxBps() == 500, so the beneficiary's 235/250 share of every later swap tax goes to the owner. This was run locally as a scratch test and passed, confirming the power exists. Expected from the brief: the 2.5% tax pays 0xcB58AdA9F7338Bfbe06Ec647f27DE8D0664dddaC 2.35%. Actual: that holds only until the owner changes it.","severity":"info","snippet":"        pg.transferOwnership(owner);","title":"Trust assumption: token ownership handed to $owner, who can redirect the 2.35% beneficiary tax and change the rate after launch"}],"hash":"6a03e1e4369c4bd688be7cb8902d40c494b83632e64d59f47eb9d87d4af897f5","nodeId":"3af60655-8f0f-4aee-be51-50e5a0483a99","outcome":"completed","summary":"I found no defects in `PlaygroundLauncher` that need fixing. `.imd-findings.json` holds one info-level trust note and a coverage record with a row for both entry points plus four invariants. No repository files were changed; the scratch tests I wrote under `test/scratch/` have been deleted.\n\n**Checks run:**\n- **Existing suite:** all 36 tests pass.\n- **Pre-launch front-run of the pool:** a stranger initialising the PG/IMD pool at the predicted PG address, before launch, at a price of their choosing. The hook reverted that call, and `launch()` still succeeded afterwards. Holds.\n- **Live mainnet state:**\n  - The factory's implementation is the requested one, and the hook's protocol fee is 15 bps.\n  - IMD is registered and enabled as a pairing base, with symbol \"IMD\" and 18 decimals.\n  - The factory and hook code hashes match the test fixtures.\n  - The beneficiary `0xcB58…` is a plain wallet, not a contract, so it can move its 50M PG freely.\n- **Mainnet-fork rehearsal (simulation only, nothing broadcast):** with an assumed IMD price of $1, `setImdUsdPrice` then `launch()` gave 50M PG to the beneficiary and 950M PG to the pool. A buy and a sell through the live IMD→ETH conversion pool both paid the beneficiary in ETH. The beneficiary could also send PG to another wallet.\n- **Checked against the brief:**\n  - **Supply split:** 1e27 total = 50e24 to the beneficiary + 950e24 to the pool.\n  - **Tax:** 250 bps. The 15 bps protocol share comes out of the 250, as the brief asks, on both buys and sells. There is no launch decay.\n  - **Price:** the opening price targets $20,000 FDV. Rounding to the tick grid can raise it by up to about 0.6%, which the README discloses.\n- **Static-analysis leads, all rejected:**\n  - **Reentrancy (slither/aderyn):** the factory is a fixed address and nothing calls back into the launcher. Both functions that change state are owner-only, and `_launching` is set before the external call.\n  - **Ignored return at line 91:** the call is there only to validate the price.\n  - **\"Unsafe ERC20\" at line 154:** both the return value and the resulting balances are checked.\n  - **Timestamp warnings:** they enforce the one-hour price expiry on purpose.\n\n**The info note (trust assumption, not a bug):** `launch()` passes token ownership to `$owner` (`src/PlaygroundLauncher.sol:158`). The README names `0x1EE3…` as that owner, which is not the beneficiary. A test confirmed that the owner can call `setFeeRecipient` and `setTaxBps` after launch and redirect the beneficiary's 2.35%. The README discloses this and the brief doesn't say who should own the token. If the requester wants the fee terms enforced after launch, the smallest change is to hand ownership to the beneficiary instead.\n\n**Not covered:**\n- I couldn't audit the hook's source because it isn't verified. My checks ran its deployed bytecode only.\n- The IMD/USD price is entered by the owner rather than read from an oracle. That is by design and disclosed, so its accuracy is the owner's responsibility.","treeHash":null,"usage":{"cachedInputTokens":813156,"inputTokens":26,"model":"claude-opus-5-5","outputTokens":15761,"runtime":"claude","turns":16,"wallClockMs":180953}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7eaf1cd0fb3df712","findings":[{"citation":"resolved","description":"The brief sets a 2.5% tax paid to 0xcB58AdA9F7338Bfbe06Ec647f27DE8D0664dddaC (2.35% after the 0.15% protocol share). launch() hands ERC20T ownership to the launcher's owner_ ($owner, 0x1EE3ffadfE138415A2ddaedeEBe5F46616fA413d in the README), not to the beneficiary. The inherited ERC20T owner functions setTaxBps (30-500 bps) and setFeeRecipient (docs/reference/ERC20T.sol.txt lines 249-270) let that owner, with no timelock and no consent from the beneficiary, raise the tax to 5% or send the beneficiary's whole share to another address. So the brief's economics hold only at launch. They depend on the owner's trust and are not enforced by the contract. The README and SECURITY.md disclose this, so it is a trust assumption, not a permission bypass. It is reported because the brief asks for neither an owner nor a mutable tax. Possible fixes, each needing the requester's decision: transfer token ownership to BENEFICIARY, renounce ownership after launch (this loses distributor management for smart-wallet integrations), or get explicit approval of the mutable terms.","line":158,"path":"src/PlaygroundLauncher.sol","reproduction":"Use the repo fixture (ProtocolFixture._setUpProtocol, where the launcher owner is the test contract). Call launcher.launch(). Then, as the launcher owner, call ITokenExtras(pg).setTaxBps(500) and ITokenExtras(pg).setFeeRecipient(address(0xB0B)). Expected under the brief: the tax stays 250 bps paid to 0xcB58. Actual: both calls succeed, pg.taxBps()==500 and pg.feeRecipient()==0xB0B, so every later buy and sell pays 5% and none of the non-protocol share goes to 0xcB58. Checked locally with a scratch Foundry test, which passed.","severity":"low","snippet":"        pg.transferOwnership(owner);","title":"Brief's fixed 2.5% tax and 0xcB58 tax recipient can be changed after launch by the token owner, who is not the beneficiary"}],"hash":"8daceebdeff404fae9b35077d98d4419108abd8a007768cdffe64a2320b36c90","nodeId":"cc2670f4-dde9-4ab8-b43b-19c1f178adcc","outcome":"completed","summary":"The economics audit found one low-severity issue and nothing critical, high or medium. `.imd-findings.json` holds that finding plus a coverage row for each of the two entry points and four extra rows for the invariants and leads I checked. No repository files were changed, and my scratch tests are deleted.\n\n**The finding (low):** `src/PlaygroundLauncher.sol:158` hands control of the token to the launch owner (`0x1EE3…413d` in the README), who is not the beneficiary `0xcB58…ddaC`. After launch that owner can raise the tax to 5% or send the beneficiary's 2.35% to any other address, at any time. I confirmed both changes go through after a local launch. The README and `docs/SECURITY.md` already disclose this, so it is a trust assumption rather than a bypass. I reported it because the brief asks for neither an owner nor a changeable tax. Each possible fix needs your decision:\n- hand the token to the beneficiary instead;\n- give up ownership after launch, which also removes the ability to approve smart-wallet integrations later;\n- explicitly accept the changeable terms.\n\n**What holds against the brief:**\n- **Supply:** 1,000,000,000 PG, with exactly 50,000,000 (5%) to `0xcB58…` and 950,000,000 in the locked LP position. The only leftover is tiny rounding dust, which stays locked in the token contract. Nobody can withdraw the position.\n- **Tax:** 2.5% on buys and sells. The 0.15% protocol share comes out of the 2.5%, not on top: the hook on mainnet reports 15, and the swap tests with the real deployed code show the protocol gets 15/250 of fees. There is no launch decay fee.\n- **Starting valuation:** the price formula gives at least $20,000 and at most about 0.6% more, because the pool can only start on fixed price steps. This holds whichever way the token address sorts against IMD. The dollar figure depends on the IMD price the owner enters; nothing on-chain checks it.\n- **Recipients:** both the beneficiary and owner addresses are plain wallets on mainnet, so fee payouts in ETH can't be blocked by a contract refusing them.\n- **Static-analysis leads:** the reentrancy warnings don't hold. Every call goes to fixed, known contracts, only the owner can launch, and any failure undoes the whole launch. The timestamp, return-value and ERC20 warnings are intentional checks.\n- **Pre-launch interference:** I tested whether someone could set up the pool early at a bad price, since the token's address is predictable. The hook refuses it and the launch still succeeds.\n\n**Worth knowing, not reported as defects:**\n- At this valuation liquidity is thin. With IMD at $1, one buyer spending $20,000 gets about 474M PG, roughly 47% of supply. That follows from the brief's $20k start with no decay fee.\n- The hook's own source isn't published, so I judged its behaviour from tests run on its live code and from on-chain reads, not from reading its source.\n- The IMD-to-ETH pool used to convert fees and the hook's admin are outside this contract's control.\n\nAll 36 existing tests pass.","treeHash":null,"usage":{"cachedInputTokens":725387,"inputTokens":24,"model":"claude-opus-5-5","outputTokens":13913,"runtime":"claude","turns":15,"wallClockMs":198957}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"72ae9b5bbd1a54b6","findings":[],"hash":"9506570a739841b4612eb7e1ce181893df760ac90429809f63cb8f76735201af","nodeId":"88af9031-3536-4050-a448-5deb6dd99752","outcome":"failed","summary":"could not start claude: spawn claude ENOENT","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":null,"outputTokens":0,"runtime":"claude","turns":0,"wallClockMs":19}},{"artifacts":[],"attempt":1,"bundleHash":"60ccff43893d8cb225618195dc5c7372257e8bcbb58fbf95854dee6d47c00e68","device":"313844d2b9a5b66c","findings":[],"hash":"ab78062754b834a6da05dc7e0df81610defd09d349c70359136145d68f8383ae","nodeId":"f3560508-dc79-444e-90ac-31c4729fd9c1","outcome":"completed","summary":"Created [launch.json](/root/nft2/.identitymd/work/8e3d8881-e131-4adf-9956-563aea8af28f/f3560508-dc79-444e-90ac-31c4729fd9c1/launch.json) for `PlaygroundLauncher` with `$owner`.\n\nManifest structure and constructor ABI checks passed. `forge build` succeeded; all 36 tests passed with the supplied fuzz seed. Only `launch.json` changed outside the permitted scratch directory.","treeHash":"0b88254b161625f26671843e4ff22f9e3ed48e81","usage":{"cachedInputTokens":193024,"inputTokens":29759,"model":"gpt-6-astra","outputTokens":2829,"runtime":"codex","turns":3,"wallClockMs":65276}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7e64d4917fa814e6","findings":[{"citation":"resolved","description":"Area: Trust Gap, seam access x asymmetry. This is not a permission bypass: the launcher itself is correctly guarded (onlyOwner + beforeLaunch on both writers, no receive/fallback, immutable owner, constant beneficiary and fee settings). It is the documented consequence of handing the ERC20T clone to the launch owner (live: 0x1EE3ffadfE138415A2ddaedeEBe5F46616fA413d, an EOA with no code at block 26209003) who is a different party from the fee beneficiary 0xcB58AdA9F7338Bfbe06Ec647f27DE8D0664dddaC (also an EOA). ERC20T.setFeeRecipient and ERC20T.setTaxBps (30-500 bps) are onlyOwner on the token, so once line 158 runs, the brief's terms 'tax 2.5% ... goes to 0xcB58...' hold only as long as that owner leaves them alone. There is no pending-fee accrual to rug (the hook pays per swap) and no unprivileged amplifier, so by the Pashov validation gates this is not a defect; it is recorded because the requester should decide knowingly. If immutability of the fee terms is wanted, the scope decision is either (a) keep ownership in the launcher, which has no admin surface and would make tax, recipient, distributor and external-liquidity settings permanent, or (b) have the owner renounce after launch. Both remove documented operator powers (distributor approvals for contract wallets, external liquidity), so this is the requester's call, not a fix the reviewer prescribes. Separately verified and NOT a finding: the shared hook's administrator (live owner 0xDf99bd1218E7EB288CfFeCF9775385167Bb09B2D) can only block the launch before it happens by setExternalBaseEnabled(IMD,false) (launcher reverts ImdPairingUnavailable, retry works after re-enable); after launch, disabling IMD does not stop PG trading or the beneficiary payout (probe: 100 IMD buy still paid the beneficiary 2.354884611592452621 ETH with IMD disabled), and the global distributor registry does not let a hook-approved contract move PG between non-distributor wallets (transferFrom from the beneficiary reverted).","line":158,"path":"src/PlaygroundLauncher.sol","reproduction":"State: ProtocolFixture (real factory/ERC20T/hook/v4 bytecode at block 26,208,919), base ETH/IMD pool funded, launcher.launch() succeeded, so pg.owner() == $owner, pg.feeRecipient() == 0xcB58..., pg.taxBps() == 250. Calls, all from $owner: (1) pg.setFeeRecipient(0xOTHER) (2) pg.setTaxBps(500). Then any trader buys with 100 IMD via the canonical pool. Expected per brief: 0xcB58... receives 2.35% of the 2.5% tax, 0xOTHER receives nothing. Actual (measured): 0xcB58... balance delta = 0 wei; 0xOTHER balance delta = 4.859321467770692040 ETH (94% of a 5% tax); pg.taxBps() == 500. Nothing in PlaygroundLauncher can prevent or reverse this once line 158 has executed; before that line the token is owned by the launcher, which exposes no setter.","severity":"info","snippet":"        pg.transferOwnership(owner);","title":"Trust assumption: after launch the $owner EOA inherits ERC20T powers that can redirect the promised 2.35% stream and change the 2.5% tax"}],"hash":"f39837a3dd9d89d0ce8200c6df1cd66a8f546fdf7a051f58168f053d2c5b9d6e","nodeId":"249050d5-9689-4a36-8ef5-71777730140c","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds the result. No source file was changed and the scratch probe was removed.\n\n**Outcome: no defect in the launcher's permission model.** The audit covered the Access Control, Trust Gap and Asymmetry guides against `src/PlaygroundLauncher.sol`, with the factory and ERC20T reference sources read for the inherited behaviour.\n\nWhat I verified:\n\n- **Access control.** Only two state-changing entry points exist, and both carry the same `onlyOwner` plus `beforeLaunch` guards. There is no weaker writer of any storage slot, no receive or fallback, no initializer, no proxy, and the owner is immutable and validated against zero, self, and every protocol address. Reentry during the factory call is blocked by the in-progress flag. The static-analysis reentrancy leads are not exploitable because the only reentrant path requires the owner and is refused.\n- **Asymmetry.** The price setter's bounds mirror the reader's exactly. The config handed to the factory matches the post-launch assertions field for field. Preview and launch use the same dependency checks and price source.\n- **Live state.** Through a public RPC I confirmed the factory's implementation, the hook's pool manager and 15 bps protocol fee, IMD registration and symbol, and the position manager bindings all match the constants. The owner and the beneficiary are both EOAs.\n- **Existing suite.** All 36 tests pass.\n\n**One info-level entry, recorded as a trust assumption rather than a bypass.** After launch, ownership of the PG token passes to the launch owner, who can call `setFeeRecipient` and `setTaxBps` on the token. I measured it: after those two calls, a 100 IMD buy paid the beneficiary nothing and paid the new recipient about 4.86 ETH at a 5% tax. The brief's \"2.5% to 0xcB58...\" therefore holds only while that owner leaves the settings alone. Making the terms permanent would mean the launcher keeping token ownership or the owner renouncing, which removes other documented operator powers, so that is the requester's decision and the file says so.\n\nAlso checked and found harmless: the shared hook's administrator can only delay the launch before it runs, and disabling IMD afterwards did not stop trading or beneficiary payouts. The global distributor registry cannot move PG between ordinary wallets.\n\nCoverage rows are written for both listed entry points, the constructor, and five invariants. Nothing was left unreached.","treeHash":null,"usage":{"cachedInputTokens":951920,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":24439,"runtime":"claude","turns":35,"wallClockMs":376834}}],"verification":[{"checks":[{"durationMs":1801,"exitCode":0,"name":"build","output":"Compiling 34 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.72s\nCompiler run successful!\n","passed":true},{"durationMs":179,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 18 tests for test/PlaygroundFailures.t.sol:PlaygroundFailuresTest\n[PASS] testFuzz_missingDependencyFailsAndCanBeRepaired(uint8) (runs: 512, μ: 1118804, ~: 1115302)\nLogs:\n  Bound result 1\n\n[PASS] test_badFactoryResultRejectedAndRetryWorks() (gas: 1098129)\n[PASS] test_dependencyCallbacksCannotReenterLaunchOrChangePrice() (gas: 1318074)\n[PASS] test_factoryFailureDoesNotConsumeLaunch() (gas: 1104363)\n[PASS] test_failedDistributionRollsBackClonePoolAndOwnership() (gas: 2103720)\n[PASS] test_failedOwnershipHandoffRollsBackEntireLaunch() (gas: 2115772)\n[PASS] test_hookCanDisableNewImdPairsAndRetryWorksAfterEnable() (gas: 1162251)\n[PASS] test_noOpTransferCannotReportSuccessfulDistribution() (gas: 1068665)\n[PASS] test_onlyOneLaunchAndNoReconfigurationAfterSuccess() (gas: 1063505)\n[PASS] test_ownerCannotWithdrawOrTransferLockedLpNft() (gas: 1095288)\n[PASS] test_positionManagerMustMatchPoolManagerAndPermit2() (gas: 133172)\n[PASS] test_protocolFeeCannotBeAddedOnTopOrSilentlyChanged() (gas: 62245)\n[PASS] test_tokenAdministrationGoesToOwnerNotFactoryOrLauncher() (gas: 1112485)\n[PASS] test_unregisteredImdFails() (gas: 72523)\n[PASS] test_wrongChainCannotLaunch() (gas: 42172)\n[PASS] test_wrongImdMetadataRejected() (gas: 137347)\n[PASS] test_wrongImplementationRejected() (gas: 60514)\n[PASS] test_wrongPoolManagerRejected() (gas: 61163)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 69.23ms (82.34ms CPU time)\n\nRan 12 tests for test/PlaygroundPricing.t.sol:PlaygroundPricingTest\n[PASS] testFuzz_ceilPriceNeverUndervaluesOrOverRounds(uint256) (runs: 512, μ: 13775, ~: 13514)\nLogs:\n  Bound result 10087813535240780789288349875572\n\n[PASS] testFuzz_nonOwnerCannotConfigureOrLaunch(address) (runs: 512, μ: 54669, ~: 54669)\n[PASS] test_constructorRejectsMissingOwnerAndProtocolOwners() (gas: 43011)\n[PASS] test_constructorWorksWithoutDependenciesAndPreservesExplicitOwner() (gas: 241384)\n[PASS] test_futureAndOldObservationsRejected() (gas: 58486)\n[PASS] test_nonpayableFunctionsRejectEth() (gas: 65474)\n[PASS] test_pricingExamplesAndRefresh() (gas: 194295)\n[PASS] test_quoteCannotBeUsedBeforeItsObservation() (gas: 82489)\n[PASS] test_quoteExpiryBoundaryAndRefresh() (gas: 163410)\n[PASS] test_runtimeFitsDeploymentFloorAndHasNoEscapeOpcodes() (gas: 4898936)\n[PASS] test_unconfiguredPriceBlocksLaunchAndPreviewPrice() (gas: 45318)\n[PASS] test_zeroAndUnrepresentablePricesRejectedWithoutChangingQuote() (gas: 139545)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 74.25ms (140.96ms CPU time)\n\nRan 6 tests for test/PlaygroundIntegration.t.sol:PlaygroundIntegrationTest\n[PASS] testFuzz_realLaunchConservesSupplyAcrossPricesAndAddressOrders(uint64,uint256) (runs: 512, μ: 1187625, ~: 1199253)\nLogs:\n  Bound result 2\n  Bound result 6553969804936559\n\n[PASS] test_actualLaunchWorksInBothAddressOrders() (gas: 1070299)\n[PASS] test_previewUsesBothCurrencyOrdersAndTargetsTwentyThousandDollars() (gas: 141255)\n[PASS] test_realBuyAndSellPayProtocolAndBeneficiary() (gas: 3106528)\n[PASS] test_realFactoryCreatesTokenAllocatesAndLocksLiquidity() (gas: 1285682)\n[PASS] test_realTokenTaxIs250BpsWithNoDecay() (gas: 1102826)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 74.29ms (79.18ms CPU time)\n\nRan 3 test suites in 74.88ms (217.77ms CPU time): 36 tests passed, 0 failed, 0 skipped (36 total tests)\n","passed":true},{"durationMs":48,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"PlaygroundLauncher.launch()\",\"PlaygroundLauncher.setImdUsdPrice(uint256,uint64)\"],\"files\":{\".gitignore\":3,\"README.md\":86,\"docs/DEPENDENCIES.md\":29,\"docs/SECURITY.md\":23,\"docs/abi/ERC20T.json\":1457,\"docs/abi/ERC20TFactory.json\":546,\"docs/dependency-snapshot.json\":51,\"docs/reference/ERC20T.sol.txt\":519,\"docs/reference/ERC20TFactory.sol.txt\":232,\"foundry.toml\":17,\"remappings.txt\":1,\"src/PlaygroundLauncher.sol\":207,\"src/interfaces/IERC20TFactory.sol\":47,\"src/interfaces/ILaunchDependencies.sol\":36,\"test/PlaygroundFailures.t.sol\":256,\"test/PlaygroundIntegration.t.sol\":158,\"test/PlaygroundPricing.t.sol\":143,\"test/fixtures/FactoryBytecode.sol\":9,\"test/fixtures/HookBytecode.sol\":9,\"test/fixtures/ImdBytecode.sol\":9,\"test/fixtures/ImplementationBytecode.sol\":9,\"test/fixtures/Permit2Bytecode.sol\":9,\"test/fixtures/PoolManagerBytecode.sol\":9,\"test/fixtures/PositionManagerBytecode.sol\":9,\"test/helpers/ProtocolFixture.sol\":76,\"test/helpers/V4TestInterfaces.sol\":127},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":564,"exitCode":0,"name":"slither","output":"[medium/medium] reentrancy-no-eth at src/PlaygroundLauncher.sol:142: Reentrancy in PlaygroundLauncher.launch() (src/PlaygroundLauncher.sol#142-163):\n[medium/medium] reentrancy-no-eth at src/PlaygroundLauncher.sol:142: Reentrancy in PlaygroundLauncher.launch() (src/PlaygroundLauncher.sol#142-163):\n[low/medium] reentrancy-events at src/PlaygroundLauncher.sol:142: Reentrancy in PlaygroundLauncher.launch() (src/PlaygroundLauncher.sol#142-163):\n[low/medium] timestamp at src/PlaygroundLauncher.sol:105: PlaygroundLauncher.startingPriceQuote() (src/PlaygroundLauncher.sol#105-111) uses timestamp for comparisons\n[low/medium] timestamp at src/PlaygroundLauncher.sol:90: PlaygroundLauncher.setImdUsdPrice(uint256,uint64) (src/PlaygroundLauncher.sol#90-97) uses timestamp for comparisons","passed":true},{"durationMs":231,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/PlaygroundLauncher.sol:147: Reentrancy: State change after external call (5 places)\n[low] centralization-risk at src/PlaygroundLauncher.sol:90: Centralization Risk (2 places)\n[low] large-numeric-literal at src/PlaygroundLauncher.sol:22: Large Numeric Literal (3 places)\n[low] literal-instead-of-constant at src/PlaygroundLauncher.sol:180: Literal Instead of Constant (2 places)\n[low] unchecked-return at src/PlaygroundLauncher.sol:91: Unchecked Return\n[low] unsafe-erc20-operation at src/PlaygroundLauncher.sol:154: Unsafe ERC20 Operation","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"418624f0a6c6624dd8b5421954f70ca392942cc459e971b9ee6d6fd5c6a8a5a1","verifiedTreeHash":"67a9e12fe6836057a9cf8d12b7059a1ac4ae0f2c","verifierVersion":"0.1.0+d952fceb"},{"checks":[{"durationMs":4200,"exitCode":0,"name":"build","output":"Compiling 39 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.12s\nCompiler run successful!\n","passed":true},{"durationMs":10679,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 5 tests for test/PlaygroundTokenFailures.t.sol:PlaygroundTokenFailuresTest\n[PASS] test_approvalAloneCannotBypassDistributionPolicyAndFailedSpendKeepsAllowance() (gas: 722459)\n[PASS] test_completedSwapDoesNotAuthorizeLaterUnrelatedPoolTransfers() (gas: 513438)\n[PASS] test_launchClearsBothErc20AndPermit2Allowances() (gas: 41865)\n[PASS] test_ownerCannotSetOutOfRangeTaxOrForbiddenRecipients() (gas: 561653)\n[PASS] test_unsupportedExactOutputRollsBackAndDoesNotPreventAnExactInputTrade() (gas: 618731)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 5.54ms (2.06ms CPU time)\n\nRan 6 tests for test/PlaygroundPostconditions.t.sol:PlaygroundPostconditionsTest\n[PASS] testFuzz_higherImdUsdPriceNeverRaisesThePgImdQuote(uint256,uint256) (runs: 1000, μ: 21966, ~: 21920)\nLogs:\n  Bound result 426\n  Bound result 1743\n\n[PASS] test_beneficiaryMayAlsoBeTheExplicitOwner() (gas: 1129247)\n[PASS] test_eoaOwnerCanLaunchWithoutReceivingTheBeneficiaryAllocation() (gas: 1142368)\n[PASS] test_everyMalformedFactoryResultFailsBeforeDistributionAndCanRetry() (gas: 18540069)\n[PASS] test_quotePinsOneWeiAndLargestAcceptedPrice() (gas: 25935)\n[PASS] test_tokenAndImplementationRejectReinitialization() (gas: 1126266)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 13.41ms (20.22ms CPU time)\n\nRan 18 tests for test/PlaygroundFailures.t.sol:PlaygroundFailuresTest\n[PASS] testFuzz_missingDependencyFailsAndCanBeRepaired(uint8) (runs: 512, μ: 1118915, ~: 1115302)\nLogs:\n  Bound result 2\n\n[PASS] test_badFactoryResultRejectedAndRetryWorks() (gas: 1098129)\n[PASS] test_dependencyCallbacksCannotReenterLaunchOrChangePrice() (gas: 1318074)\n[PASS] test_factoryFailureDoesNotConsumeLaunch() (gas: 1104363)\n[PASS] test_failedDistributionRollsBackClonePoolAndOwnership() (gas: 2103720)\n[PASS] test_failedOwnershipHandoffRollsBackEntireLaunch() (gas: 2115772)\n[PASS] test_hookCanDisableNewImdPairsAndRetryWorksAfterEnable() (gas: 1162251)\n[PASS] test_noOpTransferCannotReportSuccessfulDistribution() (gas: 1068665)\n[PASS] test_onlyOneLaunchAndNoReconfigurationAfterSuccess() (gas: 1063505)\n[PASS] test_ownerCannotWithdrawOrTransferLockedLpNft() (gas: 1095288)\n[PASS] test_positionManagerMustMatchPoolManagerAndPermit2() (gas: 133172)\n[PASS] test_protocolFeeCannotBeAddedOnTopOrSilentlyChanged() (gas: 62245)\n[PASS] test_tokenAdministrationGoesToOwnerNotFactoryOrLauncher() (gas: 1112485)\n[PASS] test_unregisteredImdFails() (gas: 72523)\n[PASS] test_wrongChainCannotLaunch() (gas: 42172)\n[PASS] test_wrongImdMetadataRejected() (gas: 137347)\n[PASS] test_wrongImplementationRejected() (gas: 60514)\n[PASS] test_wrongPoolManagerRejected() (gas: 61163)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 74.85ms (85.60ms CPU time)\n\nRan 12 tests for test/PlaygroundPricing.t.sol:PlaygroundPricingTest\n[PASS] testFuzz_ceilPriceNeverUndervaluesOrOverRounds(uint256) (runs: 512, μ: 13775, ~: 13514)\nLogs:\n  Bound result 18\n\n[PASS] testFuzz_nonOwnerCannotConfigureOrLaunch(address) (runs: 512, μ: 54669, ~: 54669)\n[PASS] test_constructorRejectsMissingOwnerAndProtocolOwners() (gas: 43011)\n[PASS] test_constructorWorksWithoutDependenciesAndPreservesExplicitOwner() (gas: 241384)\n[PASS] test_futureAndOldObservationsRejected() (gas: 58486)\n[PASS] test_nonpayableFunctionsRejectEth() (gas: 65474)\n[PASS] test_pricingExamplesAndRefresh() (gas: 194295)\n[PASS] test_quoteCannotBeUsedBeforeItsObservation() (gas: 82489)\n[PASS] test_quoteExpiryBoundaryAndRefresh() (gas: 163410)\n[PASS] test_runtimeFitsDeploymentFloorAndHasNoEscapeOpcodes() (gas: 4898936)\n[PASS] test_unconfiguredPriceBlocksLaunchAndPreviewPrice() (gas: 45318)\n[PASS] test_zeroAndUnrepresentablePricesRejectedWithoutChangingQuote() (gas: 139545)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 76.88ms (26.84ms CPU time)\n\nRan 6 tests for test/PlaygroundIntegration.t.sol:PlaygroundIntegrationTest\n[PASS] testFuzz_realLaunchConservesSupplyAcrossPricesAndAddressOrders(uint64,uint256) (runs: 512, μ: 1187604, ~: 1199253)\nLogs:\n  Bound result 10\n  Bound result 999999999999000000131072\n\n[PASS] test_actualLaunchWorksInBothAddressOrders() (gas: 1070299)\n[PASS] test_previewUsesBothCurrencyOrdersAndTargetsTwentyThousandDollars() (gas: 141255)\n[PASS] test_realBuyAndSellPayProtocolAndBeneficiary() (gas: 3106528)\n[PASS] test_realFactoryCreatesTokenAllocatesAndLocksLiquidity() (gas: 1285682)\n[PASS] test_realTokenTaxIs250BpsWithNoDecay() (gas: 1102826)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 80.92ms (86.87ms CPU time)\n\nRan 2 tests for test/PlaygroundLifecycleInvariant.t.sol:PlaygroundLifecycleInvariantTest\n[PASS]\nPlaygroundLifecycleInvariantTest invariants:\n[PASS] invariant_completedLaunchKeepsItsAllocationAndOwner\n[PASS] invariant_onlySuccessfulOwnerCallsChangeLauncherState\n PlaygroundLifecycleInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭----------------------------+-------------------+-------+---------+----------╮\n| Contract                   | Selector          | Calls | Reverts | Discards |\n+=============================================================================+\n| PlaygroundLifecycleHandler | advanceTime       | 2746  | 0       | 0        |\n|----------------------------+-------------------+-------+---------+----------|\n| PlaygroundLifecycleHandler | configure         | 2712  | 0       | 0        |\n|----------------------------+-------------------+-------+---------+----------|\n| PlaygroundLifecycleHandler | invalidQuote      | 2754  | 0       | 0        |\n|----------------------------+-------------------+-------+---------+----------|\n| PlaygroundLifecycleHandler | launch            | 2732  | 0       | 0        |\n|----------------------------+-------------------+-------+---------+----------|\n| PlaygroundLifecycleHandler | preview           | 2708  | 0       | 0        |\n|----------------------------+-------------------+-------+---------+----------|\n| PlaygroundLifecycleHandler | unauthorizedCalls | 2732  | 0       | 0        |\n╰----------------------------+-------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 3\n  Bound result 127\n  Bound result 449602280185279716787307\n  Bound result 3275\n  Bound result 2\n  Bound result 65539\n  Bound result 854973091798390307261027\n  Bound result 244\n  Bound result 373\n  Bound result 1165\n  Bound result 831174243842396248725460\n  Bound result 732\n  Bound result 999999999999000000023936\n  Bound result 365\n  Bound result 65536\n  Bound result 3\n  Bound result 3186\n  Bound result 1239\n  Bound result 65543\n  Bound result 0\n  Bound result 81662\n  Bound result 3\n  Bound result 13\n  Bound result 96\n  Bound result 131071\n  Bound result 85982\n  Bound result 0\n  Bound result 999999999999000000003971\n  Bound result 2086\n  Bound result 1000000000000000000000\n  Bound result 800\n  Bound result 867\n  Bound result 705101247237265756872979\n  Bound result 14\n  Bound result 66036\n  Bound result 1\n  Bound result 69632\n  Bound result 69136\n  Bound result 3\n  Bound result 814548581918300607658180\n  Bound result 710\n  Bound result 0\n  Bound result 65536\n  Bound result 1\n  Bound result 3\n  Bound result 98230\n  Bound result 65801\n  Bound result 2\n  Bound result 7199\n  Bound result 3885\n  Bound result 0\n\n[PASS] test_lifecycleHandlerReachesExpiryRetryAndTerminalState() (gas: 2031790)\nLogs:\n  Bound result 0\n  Bound result 1000000000000000000\n  Bound result 0\n  Bound result 3600\n  Bound result 2000000000000000000\n  Bound result 0\n  Bound result 3000000000000000000\n  Bound result 0\n  Bound result 2\n  Bound result 74565\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.28s (2.28s CPU time)\n\nRan 3 tests for test/PlaygroundTradingInvariant.t.sol:PlaygroundTradingReverseOrderInvariantTest\n[PASS]\nPlaygroundTradingReverseOrderInvariantTest invariants:\n[PASS] invariant_allPgIsAccountedForAndOnlyExplicitBurnsReduceSupply\n[PASS] invariant_liquidityRemainsLockedAndCustodyIsReleased\n[PASS] invariant_publicActivityCannotChangeLaunchTerms\n[PASS] invariant_quoteAndNativeValueAreConserved\n PlaygroundTradingReverseOrderInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------------------+----------------------------+-------+---------+----------╮\n| Contract                 | Selector                   | Calls | Reverts | Discards |\n+====================================================================================+\n| PlaygroundTradingHandler | advanceTime                | 2040  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | burn                       | 2066  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | buy                        | 2048  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | buyThenSell                | 2008  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | overspend                  | 2098  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | sell                       | 2032  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | transferWallet             | 2046  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | unauthorizedAdministration | 2046  | 0       | 0        |\n╰--------------------------+----------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 2\n  Bound result 49999998999999999999999982\n  Bound result 0\n  Bound result 0\n  Bound result 242\n  Bound result 2\n  Bound result 2394\n  Bound result 1\n  Bound result 235\n  Bound result 0\n  Bound result 255\n  Bound result 2\n  Bound result 11950\n  Bound result 4\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 15284647762482692096\n  Bound result 0\n  Bound result 118436\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 95\n  Bound result 0\n  Bound result 0\n  Bound result 244\n  Bound result 1\n  Bound result 990144368512671202858\n  Bound result 6\n  Bound result 276443124\n  Bound result 2\n  Bound result 430874602235052057076\n  Bound result 7312\n  Bound result 502313\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 3820541755393773\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 10277\n  Bound result 2\n  Bound result 23727968782008604612857182\n  Bound result 0\n  Bound result 11714\n  Bound result 1\n  Bound result 7912\n  Bound result 1\n  Bound result 11155111\n  Bound result 1\n  Bound result 921457185285197823\n  Bound result 517151\n  Bound result 0\n  Bound result 7200\n  Bound result 0\n  Bound result 22784\n  Bound result 4\n  Bound result 0\n  Bound result 5\n  Bound result 1769\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 3\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1865\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 418838\n  Bound result 30\n  Bound result 3\n  Bound result 2\n  Bound result 0\n  Bound result 29\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 685854893834575226598\n  Bound result 1\n  Bound result 131453258406\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 1\n  Bound result 7200\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 7513\n  Bound result 0\n  Bound result 5803\n  Bound result 2\n  Bound result 4581746002749759173\n  Bound result 0\n  Bound result 7406\n  Bound result 2\n  Bound result 4778\n\n[PASS] test_handlersExerciseTradesTransfersBurnsAndFailures() (gas: 3485451)\nLogs:\n  Bound result 0\n  Bound result 100000000000000000000\n  Bound result 1\n  Bound result 25000000000000000000\n  Bound result 0\n  Bound result 4838301495002750601074144\n  Bound result 2\n  Bound result 20000000000000000000\n  Bound result 0\n  Bound result 1\n  Bound result 1000000000000000000000\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 500000000000000000000\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 1000000000000000000000000000\n  Bound result 0\n  Bound result 604800\n\n[PASS] test_oneWeiTradesAndFullWalletBalanceEdges() (gas: 2606806)\nLogs:\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 48637\n  Bound result 0\n  Bound result 1\n  Bound result 50000000000000000000000000\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 49999999999999999999999999\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 10.17s (10.17s CPU time)\n\nRan 3 tests for test/PlaygroundTradingInvariant.t.sol:PlaygroundTradingInvariantTest\n[PASS]\nPlaygroundTradingInvariantTest invariants:\n[PASS] invariant_allPgIsAccountedForAndOnlyExplicitBurnsReduceSupply\n[PASS] invariant_liquidityRemainsLockedAndCustodyIsReleased\n[PASS] invariant_publicActivityCannotChangeLaunchTerms\n[PASS] invariant_quoteAndNativeValueAreConserved\n PlaygroundTradingInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------------------+----------------------------+-------+---------+----------╮\n| Contract                 | Selector                   | Calls | Reverts | Discards |\n+====================================================================================+\n| PlaygroundTradingHandler | advanceTime                | 2040  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | burn                       | 2066  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | buy                        | 2048  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | buyThenSell                | 2008  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | overspend                  | 2098  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | sell                       | 2032  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | transferWallet             | 2046  | 0       | 0        |\n|--------------------------+----------------------------+-------+---------+----------|\n| PlaygroundTradingHandler | unauthorizedAdministration | 2046  | 0       | 0        |\n╰--------------------------+----------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 3\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 2230\n  Bound result 1\n  Bound result 235\n  Bound result 1\n  Bound result 255\n  Bound result 1\n  Bound result 8788\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 240600703\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 15284647762482692096\n  Bound result 3\n  Bound result 118436\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 5\n  Bound result 20369\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 95\n  Bound result 0\n  Bound result 2\n  Bound result 244\n  Bound result 1\n  Bound result 990144368512671202858\n  Bound result 6\n  Bound result 0\n  Bound result 2\n  Bound result 430874602235052057076\n  Bound result 320069\n  Bound result 502313\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 3820541755393773\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 10277\n  Bound result 2\n  Bound result 0\n  Bound result 3\n  Bound result 11730\n  Bound result 1\n  Bound result 7503\n  Bound result 1\n  Bound result 11155111\n  Bound result 1\n  Bound result 921457185285197823\n  Bound result 517151\n  Bound result 1\n  Bound result 7200\n  Bound result 0\n  Bound result 22985\n  Bound result 4\n  Bound result 0\n  Bound result 5\n  Bound result 1586\n  Bound result 1\n  Bound result 22947\n  Bound result 4\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1763\n  Bound result 0\n  Bound result 0\n  Bound result 21523\n  Bound result 450\n  Bound result 30\n  Bound result 3\n  Bound result 2\n  Bound result 0\n  Bound result 29\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 685854893834575226598\n  Bound result 2\n  Bound result 10000000000000\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 1\n  Bound result 7200\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 7491\n  Bound result 2\n  Bound result 5803\n  Bound result 2\n  Bound result 4581746002749759173\n  Bound result 1\n  Bound result 7179\n  Bound result 2\n  Bound result 3955227378219716327230788\n\n[PASS] test_handlersExerciseTradesTransfersBurnsAndFailures() (gas: 3456182)\nLogs:\n  Bound result 0\n  Bound result 100000000000000000000\n  Bound result 1\n  Bound result 25000000000000000000\n  Bound result 0\n  Bound result 4838301495002750601074144\n  Bound result 2\n  Bound result 20000000000000000000\n  Bound result 0\n  Bound result 1\n  Bound result 1000000000000000000000\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 500000000000000000000\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 1000000000000000000000000000\n  Bound result 0\n  Bound result 604800\n\n[PASS] test_oneWeiTradesAndFullWalletBalanceEdges() (gas: 2576879)\nLogs:\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 48635\n  Bound result 0\n  Bound result 1\n  Bound result 50000000000000000000000000\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 49999999999999999999999999\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 10.57s (10.57s CPU time)\n\nRan 8 test suites in 10.58s (23.27s CPU time): 55 tests passed, 0 failed, 0 skipped (55 total tests)\n","passed":true},{"durationMs":58,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"PlaygroundLauncher.launch()\",\"PlaygroundLauncher.setImdUsdPrice(uint256,uint64)\"],\"files\":{\".gitignore\":3,\"README.md\":86,\"docs/DEPENDENCIES.md\":29,\"docs/SECURITY.md\":23,\"docs/abi/ERC20T.json\":1457,\"docs/abi/ERC20TFactory.json\":546,\"docs/dependency-snapshot.json\":51,\"docs/reference/ERC20T.sol.txt\":519,\"docs/reference/ERC20TFactory.sol.txt\":232,\"foundry.toml\":17,\"remappings.txt\":1,\"src/PlaygroundLauncher.sol\":207,\"src/interfaces/IERC20TFactory.sol\":47,\"src/interfaces/ILaunchDependencies.sol\":36,\"test/PlaygroundFailures.t.sol\":256,\"test/PlaygroundIntegration.t.sol\":158,\"test/PlaygroundLifecycleInvariant.t.sol\":182,\"test/PlaygroundPostconditions.t.sol\":166,\"test/PlaygroundPricing.t.sol\":143,\"test/PlaygroundTokenFailures.t.sol\":152,\"test/PlaygroundTradingInvariant.t.sol\":193,\"test/README.md\":34,\"test/fixtures/FactoryBytecode.sol\":9,\"test/fixtures/HookBytecode.sol\":9,\"test/fixtures/ImdBytecode.sol\":9,\"test/fixtures/ImplementationBytecode.sol\":9,\"test/fixtures/Permit2Bytecode.sol\":9,\"test/fixtures/PoolManagerBytecode.sol\":9,\"test/fixtures/PositionManagerBytecode.sol\":9,\"test/helpers/PlaygroundTradingHandler.sol\":216,\"test/helpers/ProtocolFixture.sol\":76,\"test/helpers/V4TestInterfaces.sol\":127},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"5f923c9376438cab036820998aacdda3470c748730e853b099d7481359c51a03","verifiedTreeHash":"5c00d5693a3cb0f3f042d04f192c96295fb10ef1","verifierVersion":"0.1.0+d952fceb"},{"checks":[{"durationMs":3111,"exitCode":0,"name":"build","output":"Compiling 34 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.97s\nCompiler run successful!\n","passed":true},{"durationMs":369,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 6 tests for test/PlaygroundIntegration.t.sol:PlaygroundIntegrationTest\n[PASS] testFuzz_realLaunchConservesSupplyAcrossPricesAndAddressOrders(uint64,uint256) (runs: 512, μ: 1187625, ~: 1199253)\nLogs:\n  Bound result 2\n  Bound result 961159366026085119018911\n\n[PASS] test_actualLaunchWorksInBothAddressOrders() (gas: 1070299)\n[PASS] test_previewUsesBothCurrencyOrdersAndTargetsTwentyThousandDollars() (gas: 141255)\n[PASS] test_realBuyAndSellPayProtocolAndBeneficiary() (gas: 3106528)\n[PASS] test_realFactoryCreatesTokenAllocatesAndLocksLiquidity() (gas: 1285682)\n[PASS] test_realTokenTaxIs250BpsWithNoDecay() (gas: 1102826)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 219.11ms (224.70ms CPU time)\n\nRan 12 tests for test/PlaygroundPricing.t.sol:PlaygroundPricingTest\n[PASS] testFuzz_ceilPriceNeverUndervaluesOrOverRounds(uint256) (runs: 512, μ: 13775, ~: 13514)\nLogs:\n  Bound result 20000000000000000000000\n\n[PASS] testFuzz_nonOwnerCannotConfigureOrLaunch(address) (runs: 512, μ: 54669, ~: 54669)\n[PASS] test_constructorRejectsMissingOwnerAndProtocolOwners() (gas: 43011)\n[PASS] test_constructorWorksWithoutDependenciesAndPreservesExplicitOwner() (gas: 241384)\n[PASS] test_futureAndOldObservationsRejected() (gas: 58486)\n[PASS] test_nonpayableFunctionsRejectEth() (gas: 65474)\n[PASS] test_pricingExamplesAndRefresh() (gas: 194295)\n[PASS] test_quoteCannotBeUsedBeforeItsObservation() (gas: 82489)\n[PASS] test_quoteExpiryBoundaryAndRefresh() (gas: 163410)\n[PASS] test_runtimeFitsDeploymentFloorAndHasNoEscapeOpcodes() (gas: 4898936)\n[PASS] test_unconfiguredPriceBlocksLaunchAndPreviewPrice() (gas: 45318)\n[PASS] test_zeroAndUnrepresentablePricesRejectedWithoutChangingQuote() (gas: 139545)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 222.40ms (308.41ms CPU time)\n\nRan 18 tests for test/PlaygroundFailures.t.sol:PlaygroundFailuresTest\n[PASS] testFuzz_missingDependencyFailsAndCanBeRepaired(uint8) (runs: 512, μ: 1118804, ~: 1115302)\nLogs:\n  Bound result 1\n\n[PASS] test_badFactoryResultRejectedAndRetryWorks() (gas: 1098129)\n[PASS] test_dependencyCallbacksCannotReenterLaunchOrChangePrice() (gas: 1318074)\n[PASS] test_factoryFailureDoesNotConsumeLaunch() (gas: 1104363)\n[PASS] test_failedDistributionRollsBackClonePoolAndOwnership() (gas: 2103720)\n[PASS] test_failedOwnershipHandoffRollsBackEntireLaunch() (gas: 2115772)\n[PASS] test_hookCanDisableNewImdPairsAndRetryWorksAfterEnable() (gas: 1162251)\n[PASS] test_noOpTransferCannotReportSuccessfulDistribution() (gas: 1068665)\n[PASS] test_onlyOneLaunchAndNoReconfigurationAfterSuccess() (gas: 1063505)\n[PASS] test_ownerCannotWithdrawOrTransferLockedLpNft() (gas: 1095288)\n[PASS] test_positionManagerMustMatchPoolManagerAndPermit2() (gas: 133172)\n[PASS] test_protocolFeeCannotBeAddedOnTopOrSilentlyChanged() (gas: 62245)\n[PASS] test_tokenAdministrationGoesToOwnerNotFactoryOrLauncher() (gas: 1112485)\n[PASS] test_unregisteredImdFails() (gas: 72523)\n[PASS] test_wrongChainCannotLaunch() (gas: 42172)\n[PASS] test_wrongImdMetadataRejected() (gas: 137347)\n[PASS] test_wrongImplementationRejected() (gas: 60514)\n[PASS] test_wrongPoolManagerRejected() (gas: 61163)\nSuite result: ok. 18 passed; 0 failed; 0 skipped; finished in 229.01ms (325.81ms CPU time)\n\nRan 3 test suites in 229.85ms (670.52ms CPU time): 36 tests passed, 0 failed, 0 skipped (36 total tests)\n","passed":true},{"durationMs":93,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"PlaygroundLauncher.launch()\",\"PlaygroundLauncher.setImdUsdPrice(uint256,uint64)\"],\"files\":{\".gitignore\":3,\"README.md\":86,\"docs/DEPENDENCIES.md\":29,\"docs/SECURITY.md\":23,\"docs/abi/ERC20T.json\":1457,\"docs/abi/ERC20TFactory.json\":546,\"docs/dependency-snapshot.json\":51,\"docs/reference/ERC20T.sol.txt\":519,\"docs/reference/ERC20TFactory.sol.txt\":232,\"foundry.toml\":17,\"launch.json\":10,\"remappings.txt\":1,\"src/PlaygroundLauncher.sol\":207,\"src/interfaces/IERC20TFactory.sol\":47,\"src/interfaces/ILaunchDependencies.sol\":36,\"test/PlaygroundFailures.t.sol\":256,\"test/PlaygroundIntegration.t.sol\":158,\"test/PlaygroundPricing.t.sol\":143,\"test/fixtures/FactoryBytecode.sol\":9,\"test/fixtures/HookBytecode.sol\":9,\"test/fixtures/ImdBytecode.sol\":9,\"test/fixtures/ImplementationBytecode.sol\":9,\"test/fixtures/Permit2Bytecode.sol\":9,\"test/fixtures/PoolManagerBytecode.sol\":9,\"test/fixtures/PositionManagerBytecode.sol\":9,\"test/helpers/ProtocolFixture.sol\":76,\"test/helpers/V4TestInterfaces.sol\":127},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"ab78062754b834a6da05dc7e0df81610defd09d349c70359136145d68f8383ae","verifiedTreeHash":"0b88254b161625f26671843e4ff22f9e3ed48e81","verifierVersion":"0.1.0+d952fceb"}]}