{"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":"b38c8eb4-553e-4a46-981b-b212ff65ea31","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"a79fea25d643db545569e98505b0ae704483759eb50406111cc0e091651338fd","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":"a94ca50e45291f0c343b2c94520fadbb4103ca599f120d7f0259f3ba8c8652e2","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":"1f36ec50b83c0a9ac6bbf7df2f2c5782f7591cb8130a21a5c40e044ecbf1efc1","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"f89f8dbfaf183ef672dc42cb369798d7efefd7f046b90c8c2d7cfc0708b6fb97","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":"fa0434add173bd951bb46b083498868b0165653d3ad682a18120c6166d293104","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":"651b00567a356f2183e2e00f18c41bafe4aa4a0bdaf94b96e138679b9e0e0405","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b6503de65ad02f845827887c23da4c3b56ccc5df7a459db263bae6e549d92f7f","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"b6503de65ad02f845827887c23da4c3b56ccc5df7a459db263bae6e549d92f7f","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"8815cadfd6a394797f02381097786df1ea5567c10e6d2abdc32849d90f62a043","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"a48304f794635ffe50b6f1c537f8221f031bf2f4d28302df788ed464b806b1e1","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"A custom token: SwarmInu (SI).\nToken name: SwarmInu\nToken symbol: SI\nToken supply: 1,000,000,000 with 18 decimals, all minted once to the deployer in the constructor.\nWhat it does: 2% FEE THAT GOES TO THE OWNER 0x66522f25035C3FAFd2c6D950a506FDa457E06344, launch it on uniswap v4 with one sided liquidity just our supply and IMD based on 400 IMD tokens, but don't add tokens of IMD just one side with the full supply","parentJobId":null,"planHash":"d0e3d76803be38749ce7caf2529bda469efda63a551bb9f036fdb6accee9fc43","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"b38c8eb4-553e-4a46-981b-b212ff65ea31","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-843-swarminu"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51429","feedbackHash":"e890d40168e7dbbe1ec0e4e4c4713aec616abe660e8e1830dccfa1c482587a8c","nodeKey":"audit_economics","submissionHash":"a79fea25d643db545569e98505b0ae704483759eb50406111cc0e091651338fd","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51566","feedbackHash":"5c3b58d86f5cfe9fdde0797bcc695e6a3ba6e17ff8b284a590110ed9a732011f","nodeKey":"audit_flow","submissionHash":"a94ca50e45291f0c343b2c94520fadbb4103ca599f120d7f0259f3ba8c8652e2","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52180","feedbackHash":"7638b9f04938810b39eea01c74807597b2c0f10562a9f176aac45d515f31989e","nodeKey":"audit_judge","submissionHash":"cbb17e8103317ef90640f999b99b2310c250b82342b98379735d40f7b483f65e","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51515","feedbackHash":"4596d00a21d3a19d035a8d5b87d2981a3f050b763e288003048230d1fda6953f","nodeKey":"audit_judge","submissionHash":"1f36ec50b83c0a9ac6bbf7df2f2c5782f7591cb8130a21a5c40e044ecbf1efc1","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51040","feedbackHash":"796193791935133c385b5b2fa888a812134df448328325c6097467b6cc790954","nodeKey":"audit_math","submissionHash":"f89f8dbfaf183ef672dc42cb369798d7efefd7f046b90c8c2d7cfc0708b6fb97","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51511","feedbackHash":"27d325bad0929866da76451e58574b952bec1f49ba12e36a917b88b6994249b9","nodeKey":"audit_permissions","submissionHash":"fa0434add173bd951bb46b083498868b0165653d3ad682a18120c6166d293104","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51156","feedbackHash":"1e15a92ceab68362f50b449ef2f537ee17a111c5040a0d1a335d895706233da1","nodeKey":"build_contract_project","submissionHash":"651b00567a356f2183e2e00f18c41bafe4aa4a0bdaf94b96e138679b9e0e0405","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52286","feedbackHash":"89c3419421e153b78b59c43f5043ca9c6ea20835f785652297dc9fa974b981ca","nodeKey":"build_contract_project","submissionHash":"a606a0c63be510a7077f48b381ff065ba0ce5cad5d5793e0f7cea8c54f8a9a2f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52093","feedbackHash":"d751276d37a063bedfb3a25f1e0c73c9169abfdc37089bbcddc2da6b2d84dc53","nodeKey":"manifest","submissionHash":"8815cadfd6a394797f02381097786df1ea5567c10e6d2abdc32849d90f62a043","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51226","feedbackHash":"fc4c615c3386f6241e52128b38e31e47034fcef08f04058304822e69bb39fbdf","nodeKey":"manifest","submissionHash":"000dafc89e1d55c32c4af67471ee843a33b33ce29327dd99f639ebba1f526572","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"50971","feedbackHash":"5246da118a7a696289244b59dff3682744edcca9b710b89cc581be22bad5ad9d","nodeKey":"write_foundry_tests","submissionHash":"676ff7930a520f05a5eb6a44bfc4b6a79fac398ee7aeac28acdc2508dbc8a51d","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51537","feedbackHash":"2877e6c759d9f9dbf2c4dd5360ee9e11b7be913c3337414c5705436cdfc8cbae","nodeKey":"write_foundry_tests","submissionHash":"a48304f794635ffe50b6f1c537f8221f031bf2f4d28302df788ed464b806b1e1","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"4509f5a742819bc36d60e7963df46818fd4e1ced61c66d439f7689ab405e8022","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"75e7dca114b3b8557ad804254005997b168a8bc4ec0324dc6fdf9ca85f678835","device":"720122d0ca9f60ca","findings":[],"hash":"000dafc89e1d55c32c4af67471ee843a33b33ce29327dd99f639ebba1f526572","nodeId":"5ee12e80-51c0-4159-b618-c94ea6b80e48","outcome":"completed","summary":"Created [launch.json](/Users/hhyy/.lobster_wallets/identitymd/work/b38c8eb4-553e-4a46-981b-b212ff65ea31/5ee12e80-51c0-4159-b618-c94ea6b80e48/launch.json) with the exact supply, constructor placeholders, required economics, IMD pair, and fee-exemption notes.\n\nManifest and ABI checks passed. `forge build` succeeded; `forge test` passed all 49 tests. Only `launch.json` changed outside permitted scratch space.","treeHash":"22b839e8d60186c4f9ba7ba4599b0604ebe17533","usage":{"cachedInputTokens":170368,"inputTokens":30902,"model":"gpt-6-astra","outputTokens":3098,"runtime":"codex","turns":3,"wallClockMs":120485}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ea89e16822824c6f","findings":[{"citation":"resolved","description":"Settlement of round-one item 98dc9652. The author answered 'not reproducible' because the tree they revised contained no launch.json. That was true of their node, but the combined tree under review (commit 9631d6d) contains both files: launch.json was added by the manifest contributor in d19e8e6 and its notes were updated this round in eb4cdf6 to describe the taxed payouts, so the manifest is current with the code. The second half of the original item is fixed: the dangling test reference is gone, README line 63 now cites test_transferRoutedThroughThePoolManagerPaysTheFee, which exists in test/SwarmInuLaunch.t.sol and passes. The first half persists: README lines 98-100 ('Economics, as read from the brief') present initialMarketCapWei 400000000000000000000, poolBps 9000 and 'only rounding dust' to remainderTo, and lines 108-127 derive the opening price and the launch tests' 900,000,000 SI seed from those figures, while launch.json line 18 carries poolBps 8800, initialMarketCapWei 2500000000000000000000 and remainderTo = the fee wallet, and its notes state these 'govern instead of the earlier 400 IMD estimate'. At 8800 bps the requester's remainder is 1e27 * (9000 - 8800) / 10000 = 20,000,000 SI (2% of supply), not dust, and it goes to the fee-exempt fee wallet. Economics are copied from the job verbatim and the manifest is authoritative, so this is not a code or manifest defect and does not affect the token's behaviour or the protected floor; the README itself says the manifest 'is written by a separate step'. It is recorded so a reader does not take the README's seed size, opening price and remainder as what will deploy. No action is required of the token author beyond aligning the README table (or labelling it as the brief's original reading superseded by launch.json).","line":98,"path":"README.md","reproduction":"Open README.md lines 98-100 and launch.json line 18 side by side. README: initialMarketCapWei 400000000000000000000, poolBps 9000, remainder 'rounding dust'. launch.json: initialMarketCapWei 2500000000000000000000, poolBps 8800, remainderTo 0x66522f25035c3fafd2c6d950a506fda457e06344. Expected: one set of launch economics. Actual: two, and the README's seed (900,000,000 SI) and price (sqrtPriceX96 50108289675009586237282760 for SI as currency0) differ from what the deployer derives from the manifest (880,000,000 SI; sqrt(2500e18/1e27 * 2^192) = 125270724187523965593206900 as launch.json pool.initialPrice records). The dangling-test half of the original item is settled: `forge test --match-test RoutedThroughThePoolManager` runs test_transferRoutedThroughThePoolManagerPaysTheFee, 1 passed.","severity":"info","snippet":"| `economics.initialMarketCapWei` | `400000000000000000000` | \"based on 400 IMD tokens\": the whole 1,000,000,000 SI valued at 400 IMD, with IMD at 18 decimals |","title":"README economics table still presents 400 IMD cap / poolBps 9000 / dust remainder while the accepted launch.json carries 2500e18 / 8800 / 2% of supply to the fee wallet (documentation only; carried ov"}],"hash":"1f36ec50b83c0a9ac6bbf7df2f2c5782f7591cb8130a21a5c40e044ecbf1efc1","nodeId":"015f5f4b-3d4c-4e81-a006-1dca2e2dcf50","outcome":"completed","summary":"The review is settled. The medium finding is fixed, the trust-assumption advisory is documented, and one documentation disagreement from round one still stands. The findings file is written and no tracked file changed.\n\n**Round-one medium (PoolManager fee bypass) is fixed.** The exemption at `src/SwarmInu.sol:73` now reads `if (to == poolManager) return true;`, so only payments into the PoolManager are exact and every payout pays 2%. I ran all three attached proofs as scratch copies against the revised code and they pass. The project's own relay and ERC-6909 claim tests pin the corrected numbers, and the launch tests against the real PoolManager seed single-sided, buy net of fee, and sell the whole net balance back in both currency orders. The protected floor only needs a positive buy and a complete sell-back, which both hold.\n\n| Check | Result |\n|---|---|\n| Attached proofs (3 files) | 5 passed, 0 failed |\n| Project suite | 71 passed, 0 failed |\n| `forge fmt --check` on project files | clean |\n\n**Round-one advisory on factory powers is settled as documented.** The code is unchanged by design, and the README Trust section now states the operator exemption, the live distributor record, and the deployer's duty to check the factory's allowance-consuming entry points.\n\n**One info item carried over.** The author answered that the README versus manifest disagreement did not reproduce because their tree had no launch.json. The combined tree does have it. The dangling test reference half is fixed, but the README economics table at line 98 still shows the 400 IMD cap, poolBps 9000 and a dust remainder, while launch.json carries 2500e18, 8800 and a 2% remainder to the fee wallet. The manifest governs and its notes now match the taxed-payout code, so this does not affect the token or the launch floor. It stays at info.\n\n**Coverage.** All three entry points are marked holds, with three invariant rows for the fix, the launch flows, and the trust assumption. No new defects were found in my own pass over the fee path, allowance handling, and the distributor lookup.","treeHash":null,"usage":{"cachedInputTokens":482370,"inputTokens":194,"model":"claude-fable-5-1","outputTokens":9185,"runtime":"claude","turns":15,"wallClockMs":291401}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"34d50a3af6e87087","findings":[],"hash":"2cf5879c54ad4a5452b94f3d59a996b046489e53c0e6315534697347a89e9622","nodeId":"053df0b7-25e3-41ed-befe-92b8b2ce5135","outcome":"failed","summary":"could not restore accepted work: accepted work conflicts with a dependency, which plan validation should have prevented: ","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":null,"outputTokens":0,"runtime":"codex","turns":0,"wallClockMs":768}},{"artifacts":[],"attempt":1,"bundleHash":"dd4b8f69b33beb625bdcc2dd71ef07ac44463fcfa1dafdbe5246b58286131335","device":"1ccda5cdb3f24f3e","findings":[],"hash":"651b00567a356f2183e2e00f18c41bafe4aa4a0bdaf94b96e138679b9e0e0405","nodeId":"ab530157-0d6a-493a-9fd5-d02903279cce","outcome":"completed","summary":"Fixed the PoolManager bypass: outgoing SI now pays 2%, while incoming sells and seeding remain exempt. Added regression tests and documented router effects and factory trust assumptions.\n\nRecorded all findings in [.imd-responses.json](/home/imd/.identitymd/work/b38c8eb4-553e-4a46-981b-b212ff65ea31/ab530157-0d6a-493a-9fd5-d02903279cce/.imd-responses.json). The reported economics mismatch was not reproducible; economics remain unchanged.\n\nValidation passed: `forge build`, all 51 permanent tests, both supplied proof tests, and `forge fmt --check`.","treeHash":"8dc8d503509f3a155254607b4273efaa5a5b5b6e","usage":{"cachedInputTokens":677376,"inputTokens":87360,"model":"gpt-6-astra","outputTokens":9525,"runtime":"codex","turns":4,"wallClockMs":283694}},{"artifacts":[],"attempt":1,"bundleHash":"c9ba43e547a174aa21cb7860b0b139e0c9dad7a6577c7ddf86b6c5346e4777f3","device":"35c52a5b502e847c","findings":[{"description":"The unconditional exemption for any transfer into or out of poolManager also exempts permissionless non-swap relays. An ordinary holder can approve a relay that calls unlock, sync(SI), transferFrom(holder, manager, amount), settle(), and take(SI, recipient, amount). Both SI legs are exempt and the manager ends with its original balance. The owner receives no fee even though the economic operation is a wallet-to-wallet transfer. This is acknowledged in the existing README, but contradicts the requested 2% fee and should be resolved as an economic/design limitation, not blessed by a passing regression test. Exact launch and real swap settlement must remain supported by any resolution.","line":72,"path":"src/SwarmInu.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SwarmInu} from \"src/SwarmInu.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\n\ncontract FeeBypassRelay is IUnlockCallback {\n    IPoolManager private immutable manager;\n    SwarmInu private immutable token;\n\n    constructor(IPoolManager manager_, SwarmInu token_) {\n        manager = manager_;\n        token = token_;\n    }\n\n    function send(address to, uint256 amount) external {\n        manager.unlock(abi.encode(msg.sender, to, amount));\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        require(msg.sender == address(manager));\n        (address from, address to, uint256 amount) = abi.decode(data, (address, address, uint256));\n        Currency currency = Currency.wrap(address(token));\n        manager.sync(currency);\n        require(token.transferFrom(from, address(manager), amount));\n        manager.settle();\n        manager.take(currency, to, amount);\n        return \"\";\n    }\n}\n\ncontract PoolManagerFeeBypassProof is Test {\n    function test_walletTransferCannotAvoidTwoPercentThroughPoolManager() public {\n        address factory = address(0xFAC7);\n        address alice = address(0xA11CE);\n        address bob = address(0xB0B);\n        address feeWallet = 0x66522f25035C3FAFd2c6D950a506FDa457E06344;\n        IPoolManager manager = new PoolManager(address(this));\n        vm.prank(factory);\n        SwarmInu token = new SwarmInu(factory, address(manager), 7);\n        vm.prank(factory);\n        token.transfer(alice, 100e18);\n        FeeBypassRelay relay = new FeeBypassRelay(manager, token);\n        vm.startPrank(alice);\n        token.approve(address(relay), 100e18);\n        relay.send(bob, 100e18);\n        vm.stopPrank();\n\n        assertEq(token.balanceOf(alice), 0);\n        assertEq(token.balanceOf(address(manager)), 0);\n        // No swap, pool, privileged caller, or IMD is involved. The requested\n        // wallet transfer fee should still reach the owner.\n        assertEq(token.balanceOf(feeWallet), 2e18, \"wallet transfer bypassed the owner's 2% fee\");\n        assertEq(token.balanceOf(bob), 98e18);\n    }\n}","reproduction":"Run the attached self-contained proof with forge test --match-path test/scratch/PoolManagerFeeBypass.t.sol -vv. Deploy the real vendored Uniswap v4 PoolManager and SwarmInu with that manager. Fund ordinary holder 0xA11CE with 100e18 SI from the factory, approve the relay for 100e18, and relay to 0xB0B without initializing or swapping in any pool. Expected: holder debited 100e18, fee wallet 0x66522f25035C3FAFd2c6D950a506FDa457E06344 credited 2e18 and recipient credited 98e18. Actual: holder debited 100e18, fee wallet credited 0 and recipient credited 100e18; manager final SI balance is zero. Locally reproduced failure: wallet transfer bypassed the owner's 2% fee: 0 != 2000000000000000000.","severity":"medium","title":"Anyone can bypass the 2% wallet transfer fee through PoolManager flash accounting"}],"hash":"676ff7930a520f05a5eb6a44bfc4b6a79fac398ee7aeac28acdc2508dbc8a51d","nodeId":"053df0b7-25e3-41ed-befe-92b8b2ce5135","outcome":"completed","summary":"Added failure-path tests, five fuzz properties, and three invariants covering 16,384 random calls.\n\n`forge build` and `forge test` pass: **65 passed, 0 failed**.\n\nReported a **medium-severity fee bypass** with a reproduced failing proof in [.imd-findings.json](/home/identitymd5/.identitymd/work/b38c8eb4-553e-4a46-981b-b212ff65ea31/053df0b7-25e3-41ed-befe-92b8b2ce5135/.imd-findings.json): routing 100 SI through PoolManager pays the owner zero instead of 2 SI.\n\nOffline Uniswap integration passes; live-chain fork validation remains outstanding.","treeHash":"377e187423b9f09e57591d8d0941ed7c40a8fe32","usage":{"cachedInputTokens":1209088,"inputTokens":94536,"model":"gpt-6-astra","outputTokens":14714,"runtime":"codex","turns":6,"wallClockMs":484444}},{"artifacts":[],"attempt":1,"bundleHash":"d7400bf2300eea0eeace407529180914c255a75f8fac887ee415ace01ae9aff1","device":"5658a656572d8dd1","findings":[],"hash":"8815cadfd6a394797f02381097786df1ea5567c10e6d2abdc32849d90f62a043","nodeId":"5ee12e80-51c0-4159-b618-c94ea6b80e48","outcome":"completed","summary":"Updated [launch.json](/home/seat25/.identitymd/work/b38c8eb4-553e-4a46-981b-b212ff65ea31/5ee12e80-51c0-4159-b618-c94ea6b80e48/launch.json) to describe the accepted fee behavior accurately: PoolManager payouts pay 2% unless otherwise exempt; incoming transfers remain exempt.\n\nValidated schema, constructor ABI, supply, and exact economics. Offline build, all 51 tests, a second 1,024-run fuzz check, and formatting checks passed.\n\nOnly `launch.json` changed for submission.","treeHash":"e59486c2aaa85ba0dd2eef17817ec72136d288d9","usage":{"cachedInputTokens":239488,"inputTokens":43118,"model":"gpt-6-astra","outputTokens":3001,"runtime":"codex","turns":3,"wallClockMs":82487}},{"artifacts":[],"attempt":1,"bundleHash":"e96b9014d72494b6d020a496d00721c920bfc8a68c0ef0f8caf6a808f75c501f","device":"d45dfe49455d60bf","findings":[],"hash":"a48304f794635ffe50b6f1c537f8221f031bf2f4d28302df788ed464b806b1e1","nodeId":"053df0b7-25e3-41ed-befe-92b8b2ce5135","outcome":"completed","summary":"Added three test files under `test/` covering failure paths, boundary values, fee accounting, allowances, and PoolManager claim backing.\n\n`forge build` and `forge test` pass: **71 tests, 0 failures**, including **49,152 invariant calls**.\n\nNo confirmed defects found. Live-chain fork validation remains untested.","treeHash":"2510e8ae9effa2ad95017d5b32d391fd180f2cc5","usage":{"cachedInputTokens":1594752,"inputTokens":101540,"model":"gpt-6-astra","outputTokens":15350,"runtime":"codex","turns":8,"wallClockMs":472275}},{"artifacts":[],"attempt":1,"bundleHash":"e49bb1413a0862bb99ccf5c12f280a4cf0dada3159b084e77a18a90e13ac42de","device":"fcb71e606c933181","findings":[],"hash":"a606a0c63be510a7077f48b381ff065ba0ce5cad5d5793e0f7cea8c54f8a9a2f","nodeId":"ab530157-0d6a-493a-9fd5-d02903279cce","outcome":"completed","summary":"SwarmInu (SI) is built and committed, but one thing needs your decision before launch: **swaps in the Uniswap v4 pool will not pay the 2% fee.**\n\n`forge build`, `forge test` (49 passing) and `forge fmt --check` all pass with solc 0.8.26, including from a clean offline clone of the commit.\n\n## The fee limitation\n\nEvery v4 buy and sell is a transfer to or from the PoolManager, and the launch rules require those to move exact amounts. So the PoolManager is exempt, with these consequences:\n\n- **Where the fee applies:** wallet-to-wallet transfers and transfers through any other contract (v2/v3 pools, bridges, routers that hold tokens).\n- **Where it does not:** anything going straight to or from the v4 PoolManager, which is all trading in the launch pool.\n- **Avoidable by design:** a holder can route a transfer through the PoolManager and skip the fee. There is a test that demonstrates this.\n\nIf you meant a fee on every buy and sell, a transfer tax cannot deliver that on this launch path; it would need a swap-level fee in the pool itself, which this launch does not offer. The README spells this out.\n\n## What was built\n\n- **Token:** `src/SwarmInu.sol` mints 1,000,000,000 SI (18 decimals) once to the deployer. Ordinary transfers pay 2% to `0x66522f25035C3FAFd2c6D950a506FDa457E06344`.\n- **No admin powers:** there is no owner, mint, burn, pause or blacklist. The fee rate and the fee wallet are fixed forever, so if that wallet is lost the fees still go there.\n- **Exemptions:** the launch factory, the v4 PoolManager, the launch's distributor and the fee wallet itself.\n- **Launch tests:** against a real v4 PoolManager, the pool opens at a 400 IMD market cap, 900,000,000 SI seeds it with zero IMD, and a trader buys and sells exact amounts. Both currency orderings are covered.\n- **Protected check:** I ran the supplied protected test locally and it passed in both orderings. That run used my own stand-ins for the three network files it imports, so it is a rehearsal, not the real verification.\n\n## Readings of your brief to confirm\n\n- **\"Full supply\" means 90%.** The network sends 10% to the swarm's distributor before the pool is seeded, so I documented a pool share of 9000 bps.\n- **\"400 IMD\" is the opening market cap** for the whole supply, assuming IMD has 18 decimals. That is 0.0000004 IMD per SI.\n- **\"Owner\" means the wallet that receives the fee.** It has no control over the token.\n\n## Still open\n\n- **IMD address and decimals:** no `network.json` was provided, so neither is in the repository.\n- **Pool fee tier and tick spacing:** the brief names neither; the tests use 1% and 200 as an illustration only.\n- **No deploy script:** the factory performs the launch, and nothing here broadcasts or holds keys.\n- **Not audited:** Slither, Mythril and long fuzz runs were not run. The token takes a fee from other people's transfers and should get an independent review before release.\n\nDependencies (OpenZeppelin ERC20, forge-std, Uniswap v4-core, one solmate file) are vendored as plain files under `lib/`, with no submodules. The README covers launch parameters, assumptions and responsibilities.","treeHash":"d01ce7fd7871e87def426ef21b551492e0b3301e","usage":{"cachedInputTokens":2419886,"inputTokens":57,"model":"claude-fable-5-1","outputTokens":65545,"runtime":"claude","turns":30,"wallClockMs":687993}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3987a51ff810f3b9","findings":[{"citation":"resolved","description":"isFeeExempt() exempts the PoolManager both as sender and as recipient. Exempting transfers INTO the PoolManager is required: v4 credits a payment by the balance difference between sync() and settle(), so a taxed payment leaves the swap short and reverts. Exempting transfers OUT of the PoolManager (take(), i.e. from == poolManager) is not required by the launch floor: a payout is a plain token.transfer from the PoolManager, nothing in v4 checks what the recipient received, and the protected test only asserts that the trader buys something and can then sell back exactly what it holds. Because payouts are exempt, two things follow for the owner's economics. (a) Fee pushed to zero by anyone: a holder pays SI into the PoolManager (exempt, to == poolManager) and in the same unlock takes the same amount out to any address (exempt, from == poolManager). No pool is touched, no swap happens, the owner receives nothing. One relay contract deployed once by anyone serves every holder, so the 2% becomes voluntary for everybody except users who call transfer() directly; the only cost is ~50k extra gas. (b) No fee on trading: every buy on the launch pool is a PoolManager payout and every sell is a payment in, so the pool that holds 90% of the supply generates zero fee revenue; the fee is collected only on wallet-to-wallet hops. The README documents both as a known limit and states this 'cannot be closed without taxing the PoolManager'. That is only half true: narrowing the exemption to `to == poolManager` (tax payouts, keep payments exempt) closes the relay and taxes buys while sells still settle exactly. I verified this variant against a real PoolManager in both currency orders: the swarm share and the single-sided seed arrive whole, a trader buys (receives 98% of the swap delta, owner gets 2%) and sells back everything it holds, and the relay now pays 2%. Trade-off the requester must decide, not the author alone: with payouts taxed a buyer receives 98% of the quoted output (standard tax-token behaviour; a router that takes to itself and then forwards is taxed twice), which satisfies the protected floor test as written but not the launch-rule prose that 'traders buy from the PoolManager' exactly. If the requester accepts the current design, the brief's '2% fee' should be re-stated as 'a fee on direct wallet-to-wallet transfers that any contract can avoid', because as deployed it is not an enforced 2%.","line":72,"path":"src/SwarmInu.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {SwarmInu} from \"src/SwarmInu.sol\";\n\n/// @dev Minimal factory stand-in: deploys the token so it holds the supply and answers distributorOf.\ncontract FactoryStub {\n    mapping(uint64 => address) public distributorOf;\n\n    function deployToken(address poolManager, uint64 launchNumber) external returns (SwarmInu) {\n        return new SwarmInu(address(this), poolManager, launchNumber);\n    }\n\n    function move(SwarmInu token, address to, uint256 amount) external returns (bool) {\n        return token.transfer(to, amount);\n    }\n}\n\n/// @dev Anyone can deploy this once; afterwards any holder moves SI to any wallet with no fee by routing the\n/// transfer through the PoolManager's flash accounting. No pool is needed and no swap happens.\ncontract FeeFreeRelay is IUnlockCallback {\n    IPoolManager private immutable manager;\n\n    constructor(IPoolManager manager_) {\n        manager = manager_;\n    }\n\n    function relay(address token, address to, uint256 amount) external {\n        manager.unlock(abi.encode(token, to, amount));\n    }\n\n    function unlockCallback(bytes calldata data) external override returns (bytes memory) {\n        require(msg.sender == address(manager), \"not the pool manager\");\n        (address token, address to, uint256 amount) = abi.decode(data, (address, address, uint256));\n        manager.sync(Currency.wrap(token));\n        SwarmInu(token).transfer(address(manager), amount); // to == poolManager: exempt\n        manager.settle();\n        manager.take(Currency.wrap(token), to, amount); // from == poolManager: exempt\n        return \"\";\n    }\n}\n\ncontract FeeBypassTest is Test {\n    address constant FEE_RECIPIENT = 0x66522f25035C3FAFd2c6D950a506FDa457E06344;\n    address constant ALICE = address(0xA11CE);\n    address constant BOB = address(0xB0B);\n\n    IPoolManager manager;\n    FactoryStub factory;\n    SwarmInu token;\n    FeeFreeRelay relay;\n\n    function setUp() public {\n        manager = new PoolManager(address(this));\n        factory = new FactoryStub();\n        token = factory.deployToken(address(manager), 1);\n        relay = new FeeFreeRelay(manager);\n        factory.move(token, ALICE, 1_000e18);\n    }\n\n    /// @dev A direct 100 SI wallet-to-wallet transfer pays 2 SI. The same 100 SI routed through the PoolManager\n    /// arrives whole and the fee recipient gets nothing. Fails on the code as it is; passes once a PoolManager\n    /// payout (`from == poolManager`) is no longer fee-exempt.\n    function test_routingThroughThePoolManagerMustStillPayTheTwoPercentFee() public {\n        // Alice hands the relay 100 SI. This hop is an ordinary transfer and pays the fee: relay holds 98.\n        vm.prank(ALICE);\n        token.transfer(address(relay), 100e18);\n        assertEq(token.balanceOf(address(relay)), 98e18);\n        assertEq(token.balanceOf(FEE_RECIPIENT), 2e18);\n\n        // The relay moves 98 SI to Bob through the PoolManager. An ordinary 98 SI transfer would pay 1.96 SI.\n        relay.relay(address(token), BOB, 98e18);\n\n        assertEq(token.balanceOf(address(relay)), 0, \"the relay kept nothing\");\n        assertEq(token.balanceOf(address(manager)), 0, \"the pool manager kept nothing\");\n        assertEq(\n            token.balanceOf(FEE_RECIPIENT),\n            2e18 + (98e18 * 200) / 10_000,\n            \"the hop through the pool manager paid no fee: Bob received 98 SI whole and the owner got nothing for it\"\n        );\n        assertEq(token.balanceOf(BOB), 98e18 - (98e18 * 200) / 10_000);\n    }\n}","reproduction":"State: token deployed by a factory with poolManager = a real v4 PoolManager; ALICE holds 1000 SI; anyone has deployed a relay contract implementing IUnlockCallback. Calls: (1) ALICE: token.transfer(relay, 100e18) -> relay holds 98e18, FEE_RECIPIENT 2e18 (ordinary hop, fee paid). (2) relay.relay(token, BOB, 98e18) -> inside unlockCallback: manager.sync(SI); token.transfer(poolManager, 98e18) [to == poolManager, exempt]; manager.settle(); manager.take(SI, BOB, 98e18) [from == poolManager, exempt]. Expected under the brief's '2% fee to the owner': FEE_RECIPIENT balance 2e18 + 1.96e18 = 3.96e18 and BOB 96.04e18. Actual: FEE_RECIPIENT stays at 2e18 and BOB receives 98e18 whole. Same mechanism for trading: trader.swap exact-input 0.01 IMD -> PoolManager take() pays the trader the full delta, FEE_RECIPIENT unchanged (existing test test_traderBuysAndSellsExactly asserts balanceOf(FEE_RECIPIENT) == 0 after a buy and a sell). Fix check: with line 72 changed to `if (to == poolManager) return true;` the proof passes, and the launch flows (swarm share, seed, buy, sell-all) still succeed in both currency orders (verified in test/scratch/BuyTaxedVariant.t.sol against a scratch copy of the token).","severity":"medium","snippet":"        if (from == poolManager || to == poolManager) return true;","title":"The 2% fee is skipped on every PoolManager payout, so any holder moves SI fee-free through v4 flash accounting and no trade on the launch pool ever pays the owner"},{"citation":"resolved","description":"Two exemptions depend entirely on the launch factory rather than on who holds the tokens. First, `operator == factory` exempts any transferFrom the factory initiates, whatever `from` and `to` are. The launch flows the floor requires (factory -> distributor, factory -> PoolManager seed, factory -> remainderTo) are already covered by `from == factory`, so the operator clause adds surface without a documented launch flow that needs it: if the real ProjectFactory exposes any path that calls token.transferFrom(from, to, amount) with a caller-chosen `to` (a pull helper, a multicall, a rescue routine), that path is a fee-free transfer for anyone who approved the factory. Second, `distributor()` is read from the factory at every ordinary transfer, so whoever can change the factory's distributorOf(launchNumber) record (an upgradeable or admin-controlled factory) can grant the distributor's fee exemption to any address at any time. Neither can mint, freeze or move an unapproved balance, and the README already records the second point under Trust. Reported for the record so the judge and requester see the privileged surface explicitly; not a defect in the token on its own.","line":71,"path":"src/SwarmInu.sol","reproduction":"State: ALICE holds 100e18 SI and has called token.approve(factory, 100e18). Call: factory executes token.transferFrom(ALICE, BOB, 100e18) (in this tree: MockProjectFactory.pull(token, ALICE, BOB, 100e18), existing test test_factoryAsSpenderMovesExactAmounts). Result: BOB receives 100e18, FEE_RECIPIENT 0. The same transfer submitted by ALICE herself credits BOB 98e18 and FEE_RECIPIENT 2e18. Distributor record: factory.setDistributor(launchNumber, X) followed by X sending 100e18 to BOB -> BOB receives 100e18, no fee (existing test test_exemptionFollowsTheFactorysCurrentAnswer). Minimal narrowing if the real factory does not need it: drop `operator == factory` and keep `from == factory || to == factory`.","severity":"info","snippet":"        if (operator == factory || from == factory || to == factory) return true;","title":"Trust assumption: the factory as transferFrom operator moves any holder's approved SI fee-free between arbitrary parties, and it alone chooses which address receives the distributor exemption"}],"hash":"a79fea25d643db545569e98505b0ae704483759eb50406111cc0e091651338fd","nodeId":"8e0b37b3-16fb-4235-b607-d8180cf47c61","outcome":"completed","summary":"The tracked tree is unchanged, the source file is restored, and the only failing test in the full run is my scratch proof, which fails on the current code by design. The project's own 49 tests still pass.\n\n## Review result\n\nThe findings are in `.imd-findings.json` with two findings and nine coverage rows covering all three entry points plus the invariants I checked.\n\n**Finding 1, medium.** The fee exemption for PoolManager payouts makes the 2% fee avoidable by anyone and means no trade on the launch pool pays the owner. A holder pays SI into the PoolManager and takes it out to another wallet inside one unlock. Both legs are exempt, so the owner receives nothing. One public relay contract serves every holder, so the fee is only paid by users who call transfer directly. The README documents this as a known limit and says it cannot be closed without taxing the PoolManager. That is only half true. Only payments into the PoolManager must be exempt for v4 settlement. I built a scratch variant that keeps payments exempt but taxes payouts and ran it against a real PoolManager in both currency orders. The swarm share and seed arrived whole, a trader bought and sold back everything, and the relay paid 2%. The proof test fails on the current code and passes with the one-line change. The trade-off is that buyers would receive 98% of the quoted output, which the protected floor test accepts but the launch-rule prose about exact buys does not clearly allow. That is the requester's decision, not the author's.\n\n**Finding 2, info.** Trust assumptions on the factory: as a transferFrom operator it moves any approved balance fee-free between arbitrary parties, and it alone names the address that gets the distributor exemption. Neither can mint, freeze or move an unapproved balance.\n\n**What holds.** Supply is fixed, balances conserve across fee and exempt paths, the sender is always debited exactly the stated value, all launch flows move exact amounts, a misbehaving factory can only remove the distributor exemption and cannot revert or silently tax a transfer, fee arithmetic cannot overflow, and the README's opening price values reproduce. The aderyn lead about large numeric literals is cosmetic and was left out.\n\n**Not reached.** The real ProjectFactory and MerkleDistributor code are not in the tree, so the factory-operator and distributor-sweep surfaces are recorded as trust assumptions rather than reproduced defects.","treeHash":null,"usage":{"cachedInputTokens":1135995,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":34960,"runtime":"claude","turns":28,"wallClockMs":570949}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"d0653dc91b6e2259","findings":[{"citation":"resolved","description":"isFeeExempt() skips the fee whenever the Uniswap v4 PoolManager is the sender or the recipient, regardless of who the operator is and regardless of whether a swap is happening. The PoolManager's unlock()/sync()/settle()/take()/mint()/burn() surface is public, so any holder can move SI from wallet A to wallet B with zero fee by (1) paying SI into the PoolManager (sync + transfer, exempt because to == poolManager) and (2) taking it out to B (PoolManager.transfer, exempt because from == poolManager). No pool, swap or liquidity is involved. Two further consequences: (a) ERC-6909 claims: a holder can mint claim tokens (id = uint160(token)) inside the PoolManager and those claims are a persistent, freely transferable, fee-free representation of SI (verified in test/scratch/Probe.t.sol::test_erc6909ClaimsAreAFeeFreeWrapper); (b) no custom contract is needed on chains with the canonical v4 Universal Router: a V4_SWAP command whose action list is just [SETTLE(SI, amount, payerIsUser=true), TAKE(SI, recipient, amount)] performs the same fee-free transfer, since Permit2 transferFrom(user -> poolManager) and PoolManager.transfer(recipient) are both exempt. The repository already discloses this as a known limit (README 'What the fee does not cover', test_knownLimit_transferRoutedThroughThePoolManagerPaysNoFee) and is correct that it cannot be closed at the token level while both directions through the PoolManager are exempt, because the token cannot distinguish a swap settlement from a relay. It is reported here because the brief's primary requirement ('2% fee that goes to the owner') is therefore unenforceable against anyone willing to spend the gas of one unlock() call, and because the ERC-6909 and router routes make the bypass cheaper and more permanent than the README's wording suggests. Fix is a scope decision for the requester, not a code change this review can prescribe: either accept and document that the fee only binds naive wallet-to-wallet transfers, or (design change) tax transfers OUT of the PoolManager (from == poolManager, i.e. buys and takes arrive at 98%) while keeping transfers INTO it exact so sells and the seed still settle. The latter still passes the protected harness (it only requires bought > 0 and that the full bought amount can be sold back) but conflicts with the launch text's 'traders buy from ... the PoolManager ... move exactly what they say', so it needs the network's ruling before adoption; a v4 hook-level fee is outside this launch's manifest.","line":72,"path":"src/SwarmInu.sol","reproduction":"State: token deployed by factory F with poolManager = a real v4 PoolManager P; F.distributorOf(launchNumber) = D; F.transfer(ALICE, 1000e18). Sequence (any caller, e.g. a 30-line relay contract R implementing IUnlockCallback): ALICE.transfer(R, 1000e18) is taxed once (R gets 980e18) -- or ALICE approves R and R uses transferFrom inside the callback, in which case even that hop is exempt because to == P. R calls P.unlock(data); in unlockCallback: P.sync(SI); SI.transferFrom(ALICE, P, 1000e18) [exempt: to == poolManager]; P.settle(); P.take(SI, BOB, 1000e18) [exempt: from == poolManager]. Expected (per brief): BOB receives 980e18 and FEE_RECIPIENT 20e18. Actual: BOB balance == 1000e18, FEE_RECIPIENT balance == 0, ALICE == 0. ERC-6909 variant (test/scratch/Probe.t.sol, passes on current code): wrap: sync, transferFrom(ALICE, P, 1000e18), settle, P.mint(ALICE, uint160(SI), 1000e18); ALICE then P.transfer(anyone, uint160(SI), 1000e18) moves the claim with no SI Transfer event at all; the holder of the claim later P.burn + P.take(SI, BOB, 1000e18) -> BOB 1000e18, FEE_RECIPIENT 0. The repository's own test test_knownLimit_transferRoutedThroughThePoolManagerPaysNoFee in test/SwarmInuLaunch.t.sol also demonstrates the relay form against a real PoolManager.","severity":"medium","snippet":"        if (from == poolManager || to == poolManager) return true;","title":"The 2% fee is avoidable by any holder through the PoolManager exemption (flash-accounting relay, ERC-6909 claims, router SETTLE/TAKE)"},{"citation":"resolved","description":"feeOn() truncates. The auditing checklist's rule is that fees round in the protocol's favour (up). Here a transfer of 1..49 minor units pays zero fee and any taxed transfer leaks the fractional wei to the recipient. The README documents this and it is economically irrelevant at 18 decimals (gas to split a transfer into 49-wei pieces exceeds the fee by many orders of magnitude), so no change is required; recorded for completeness because it is a concrete checklist item with a concrete input.","line":81,"path":"src/SwarmInu.sol","reproduction":"factory.transfer(ALICE, 1000e18); vm.prank(ALICE); token.transfer(BOB, 49). Expected under round-up: fee 1, BOB 48. Actual: feeOn(49) == 0, BOB == 49, FEE_RECIPIENT == 0 (test_feeRoundsDownSoDustBelowFiftyWeiIsFree pins this).","severity":"info","snippet":"        return (value * FEE_BPS) / BPS_DENOMINATOR;","title":"Fee rounds down, so transfers below 50 minor units pay nothing and every taxed transfer under-collects by up to 1 wei"}],"hash":"a94ca50e45291f0c343b2c94520fadbb4103ca599f120d7f0259f3ba8c8652e2","nodeId":"d17d9dfc-0bc6-4ffb-a5c7-d937c3e29fbc","outcome":"completed","summary":"The findings file is valid, the cited snippets match the tree, and no tracked file changed (the findings file and scratch test are both git-ignored).\n\n**Outcome:** the token's control flow is sound in my area, with one substantive design-level defect and one informational note, recorded in `.imd-findings.json` with full coverage rows for all three entry points.\n\n**What I covered**\n\n- **Execution trace.** Both transfer entry points through OZ v5.4.0 `_transfer` into the overridden `_update`. The exempt path moves exact amounts; the taxed path debits the sender once, credits the fee then the remainder, conserves supply, and reverts with the whole-amount error. `transferFrom` spends the full value of allowance before the transfer, so allowance and balance accounting agree.\n- **Periphery.** The vendored OZ `ERC20` and `Context` carry the v5.4.0 and v5.0.1 headers and contain nothing beyond upstream. The `distributor()` assembly copies one word, checks `ok` and the return size, and rejects dirty high bits. A gas sweep from 5k to 400k call gas found no window where the factory lookup is starved yet the transfer completes, so a claim cannot be griefed into paying the fee by a tight gas limit.\n- **First principles.** The constructor never makes an external call because the mint short-circuits on `from == 0`. The view `isFeeExempt` is the same function the write path uses, so view and write cannot diverge. The only dynamic exemption is the distributor, which follows the factory's current answer. That is a trust assumption on the factory, not a bypass.\n\n**Findings**\n\n1. **Medium.** The fee is avoidable by anyone through the PoolManager exemption. Paying SI into the PoolManager and taking it out to another wallet moves it with no fee, and ERC-6909 claims minted inside the PoolManager are a persistent fee-free wrapper of SI. I verified the ERC-6909 route against a real PoolManager in a scratch test. The README already discloses the relay form. I reported it because the brief's main requirement is unenforceable against anyone willing to spend one `unlock` call, and I laid out the one in-token alternative, taxing outflows from the PoolManager, as a scope decision that needs the network's ruling rather than a change I can prescribe.\n2. **Info.** The fee rounds down, so transfers under 50 minor units pay nothing. Economically irrelevant at 18 decimals and already documented.\n\n**Trust assumptions to carry forward:** the factory chooses the one exempt distributor address and acts as an exempt operator. The fee wallet has no power beyond receiving fees. The real factory must expose `distributorOf(uint64)` exactly as the protected harness does, which I could not verify from this tree.\n\n**Not reached:** the launch manifest and IMD's real address and decimals do not exist in this repository, so the opening-price inputs were checked only against the test harness arithmetic, which I verified by hand for both currency orders.","treeHash":null,"usage":{"cachedInputTokens":887567,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":31496,"runtime":"claude","turns":27,"wallClockMs":480849}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"c722c2e9ac9aa084","findings":[{"citation":"resolved","description":"Merged from five specialist reports (write_foundry_tests de90f3f2, audit_math bfa2e08e, audit_flow 8e5a68a3, audit_permissions a3ee6d19, audit_economics 8dc64c02): one root cause. isFeeExempt() skips the fee whenever the Uniswap v4 PoolManager is the sender OR the recipient, regardless of operator and regardless of whether any pool, swap or liquidity is involved. The PoolManager's unlock()/sync()/settle()/take()/mint()/burn() surface is permissionless, so any account can (a) pay SI into the PoolManager (to == poolManager, exempt) and in the same unlock take() the same amount out to any address (from == poolManager, exempt), or (b) pay in and mint ERC-6909 claim tokens (id = uint160(token)), which are then a persistent, freely transferable, fee-free representation of SI that never touches SwarmInu._update and can later be burned and taken out to any address. One relay contract deployed once by anyone serves every holder; the only cost is gas. The brief's primary requirement ('2% FEE THAT GOES TO THE OWNER') is therefore voluntary for anyone who routes around transfer(), and the launch pool that holds 88-90% of the supply also generates no fee on any buy or sell. The README discloses the relay form ('What the fee does not cover', item 2) but its statement that it 'cannot be closed without taxing the PoolManager' is only half true, and the test it cites (test_knownLimit_transferRoutedThroughThePoolManagerPaysNoFee) is not in the tree. Only the inbound leg (to == poolManager) must be exact: v4 credits settle() by balance difference, so a short payment reverts a sell or the seed. The outbound leg (take(), from == poolManager) is a plain currency.transfer whose received amount nothing in v4 checks. I verified with a scratch copy whose line 72 reads `if (to == poolManager) return true;` against the real vendored PoolManager in both currency orders (test/scratch/PatchedLaunch.t.sol, 2 passed): the swarm share and the single-sided seed arrive whole, no launch flow pays a fee, a trader buys (receives owed - feeOn(owed), fee recipient gets feeOn(owed)) and sells back everything it holds, and the relay now pays 2%; the attached proof passes against that copy (test/scratch/PatchedProof.t.sol, 2 passed). Trade-off that needs the requester's decision rather than a silent change: with payouts taxed, v4 buys pay 2% (sells still do not), quoted swap output overstates what a buyer receives by 2%, and a router that takes to itself and forwards is taxed twice; this satisfies the protected floor as written (it only asserts bought > 0 and sell-all succeeds) but departs from the launch prose that traders 'buy from the PoolManager' exactly, so it should be confirmed with the network before adoption. The alternative is to keep the current code and restate the fee as 'a fee on direct wallet-to-wallet transfers that anyone can avoid via the PoolManager', and correct the README sentence. No holder funds are at risk; the victim is the fee recipient's revenue.","line":72,"path":"src/SwarmInu.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {SwarmInu} from \"src/SwarmInu.sol\";\n\n/// @notice Stands in for the launch factory: deploys the token so it holds the supply and answers distributorOf.\ncontract FactoryStub {\n    mapping(uint64 => address) public distributorOf;\n\n    function deployToken(address poolManager, uint64 launchNumber) external returns (SwarmInu) {\n        return new SwarmInu(address(this), poolManager, launchNumber);\n    }\n\n    function move(SwarmInu token, address to, uint256 amount) external returns (bool) {\n        return token.transfer(to, amount);\n    }\n}\n\n/// @notice An ordinary holder's helper. It is not the factory, not the distributor, not the fee recipient: nothing the\n/// token has any reason to exempt. It moves tokens through the PoolManager's flash accounting without touching a pool.\ncontract Bypass is IUnlockCallback {\n    IPoolManager private immutable manager;\n    SwarmInu private immutable token;\n\n    constructor(IPoolManager manager_, SwarmInu token_) {\n        manager = manager_;\n        token = token_;\n    }\n\n    /// @dev Pay `amount` in, take `amount` out to `to`, in one unlock. Both legs are exempt, so no fee is paid.\n    function relay(address to, uint256 amount) external {\n        manager.unlock(abi.encode(uint8(0), to, amount));\n    }\n\n    /// @dev Pay `amount` in and keep it as ERC-6909 claim tokens on the PoolManager.\n    function wrap(uint256 amount) external {\n        manager.unlock(abi.encode(uint8(1), address(this), amount));\n    }\n\n    /// @dev Hand claim tokens to another account. Claims are a plain ERC-6909 balance on the PoolManager: no SI\n    /// transfer happens, so the SI fee logic is never reached.\n    function sendClaims(address to, uint256 amount) external {\n        manager.transfer(to, uint256(uint160(address(token))), amount);\n    }\n\n    /// @dev Burn claim tokens and take the underlying SI out to `to`.\n    function unwrap(address to, uint256 amount) external {\n        manager.unlock(abi.encode(uint8(2), to, amount));\n    }\n\n    function unlockCallback(bytes calldata data) external override returns (bytes memory) {\n        require(msg.sender == address(manager), \"not the pool manager\");\n        (uint8 mode, address to, uint256 amount) = abi.decode(data, (uint8, address, uint256));\n        Currency currency = Currency.wrap(address(token));\n        if (mode == 0) {\n            manager.sync(currency);\n            token.transfer(address(manager), amount);\n            manager.settle();\n            manager.take(currency, to, amount);\n        } else if (mode == 1) {\n            manager.sync(currency);\n            token.transfer(address(manager), amount);\n            manager.settle();\n            manager.mint(to, currency.toId(), amount);\n        } else {\n            manager.burn(address(this), currency.toId(), amount);\n            manager.take(currency, to, amount);\n        }\n        return \"\";\n    }\n}\n\n/// @notice Any holder can move SI to any other account without paying the 2% fee, by passing it through the\n/// Uniswap v4 PoolManager that the token exempts in both directions. The intended behaviour is that an ordinary\n/// transfer between two non-exempt accounts pays feeOn(value) to FEE_RECIPIENT.\ncontract FeeBypassViaPoolManagerTest is Test {\n    address constant FEE_RECIPIENT = 0x66522f25035C3FAFd2c6D950a506FDa457E06344;\n    address constant BOB = address(0xB0B);\n    address constant CAROL = address(0xCA201);\n    uint64 constant LAUNCH = 7;\n\n    PoolManager manager;\n    FactoryStub factory;\n    SwarmInu token;\n\n    function setUp() public {\n        manager = new PoolManager(address(this));\n        factory = new FactoryStub();\n        token = factory.deployToken(address(manager), LAUNCH);\n    }\n\n    /// @dev Pay in, take out to Bob: Bob receives the whole amount and the fee recipient receives nothing.\n    function test_holderMovesTokensToAnotherWalletThroughThePoolManagerWithoutPayingTheFee() public {\n        Bypass alice = new Bypass(manager, token);\n        factory.move(token, address(alice), 1_000e18);\n        assertFalse(token.isFeeExempt(address(alice), address(alice), BOB), \"alice is an ordinary holder\");\n\n        alice.relay(BOB, 1_000e18);\n\n        // What should happen: a 1,000 SI transfer from an ordinary holder to Bob pays 20 SI to the fee recipient.\n        assertEq(token.balanceOf(FEE_RECIPIENT), token.feeOn(1_000e18), \"the fee recipient was paid the 2% fee\");\n        assertEq(token.balanceOf(BOB), 1_000e18 - token.feeOn(1_000e18), \"Bob received the amount net of the fee\");\n    }\n\n    /// @dev Wrap into ERC-6909 claims, hand the claims to Carol, Carol unwraps to herself: a fee-free wrapper that\n    /// exists for the life of the token, with no pool, hook or privileged party involved.\n    function test_claimTokensOnThePoolManagerAreAFeeFreeWrapperForTheToken() public {\n        Bypass alice = new Bypass(manager, token);\n        Bypass carol = new Bypass(manager, token);\n        factory.move(token, address(alice), 1_000e18);\n\n        alice.wrap(1_000e18);\n        assertEq(manager.balanceOf(address(alice), uint256(uint160(address(token)))), 1_000e18);\n        alice.sendClaims(address(carol), 1_000e18);\n        carol.unwrap(CAROL, 1_000e18);\n\n        // What should happen: SI changed hands between two ordinary accounts, so 2% is owed to the fee recipient.\n        assertEq(token.balanceOf(FEE_RECIPIENT), token.feeOn(1_000e18), \"the fee recipient was paid the 2% fee\");\n        assertEq(token.balanceOf(CAROL), 1_000e18 - token.feeOn(1_000e18), \"Carol received the amount net of the fee\");\n    }\n}","reproduction":"State: SwarmInu deployed by a factory F with poolManager = a real Uniswap v4 PoolManager PM (new PoolManager(address(this)) from the vendored lib/v4-core); F.transfer(alice, 1000e18) where alice is an ordinary holder (isFeeExempt(alice, alice, bob) == false). Path A (relay), inside one PM.unlock() from a contract alice controls: PM.sync(SI); SI.transfer(PM, 1000e18) [exempt: to == poolManager]; PM.settle(); PM.take(SI, bob, 1000e18) [exempt: from == poolManager]. Expected per the brief: bob = 980e18, FEE_RECIPIENT 0x66522f25035C3FAFd2c6D950a506FDa457E06344 = 20e18. Actual: bob = 1000e18, FEE_RECIPIENT = 0, PM final SI balance 0, no pool initialized. Path B (claims): alice: PM.sync; SI.transfer(PM, 1000e18); PM.settle(); PM.mint(alice, uint160(SI), 1000e18). Later, outside any unlock: PM.transfer(carol, uint160(SI), 1000e18) (ERC-6909; SwarmInu never called, no SI Transfer event). carol: PM.unlock -> PM.burn(carol, id, 1000e18); PM.take(SI, carol, 1000e18). Expected: 20e18 to FEE_RECIPIENT. Actual: carol = 1000e18, FEE_RECIPIENT = 0. Ran: forge test --match-path test/scratch/Proof_a3ee6d198785.t.sol -> 2 failed with 'the fee recipient was paid the 2% fee: 0 != 20000000000000000000'. The other two attached proofs (Proof_de90f3f28f23: holder approves a relay that uses transferFrom(holder, PM) + take, 0 != 2e18; Proof_8dc64c02e883: taxed hop to relay then relay through PM, 2e18 != 3.96e18) fail on this code for the same reason. All three pass against the scratch copy with line 72 narrowed to `if (to == poolManager) return true;`.","severity":"medium","snippet":"        if (from == poolManager || to == poolManager) return true;","title":"Any holder moves SI fee-free through the exempted PoolManager (flash-accounting relay and ERC-6909 claims), so the requested 2% fee binds only direct wallet-to-wallet transfers"},{"citation":"resolved","description":"Merged from audit_permissions 5d1dd60f and audit_economics e34486ff; documented as a trust assumption, not a vulnerability (the launch rules ask the token to read distributorOf(launchNumber) at transfer time, and an intentional factory role is not a defect). Two powers rest entirely on the launch factory. First, `operator == factory` exempts any transferFrom the factory submits whatever `from` and `to` are; the launch flows the floor needs (factory -> distributor, factory -> PoolManager seed, factory -> remainderTo) are already covered by `from == factory`, so the operator clause adds surface that only matters if the real ProjectFactory exposes a path calling token.transferFrom with a caller-chosen destination. Second, distributor() (line 75) returns whatever the factory's distributorOf(launchNumber) says now, with no latch and no code check, so whoever can change that record (an upgradeable or admin-controlled factory) can grant the distributor's fee exemption to any address at any time, and moving it away from the real MerkleDistributor makes later claims arrive 2% short. Neither power can mint, freeze, burn or move an unapproved balance; the distributor lookup is a 100,000-gas staticcall that copies one word, so a misbehaving factory can add gas but never make a transfer revert (verified by the existing factory-without-code, reverting, gas-burning, short, dirty and oversized-answer tests). The README's Trust section states the second point. No unprivileged amplifier exists, so this is not a finding against the code; it is recorded so the requester and judge see the actor and preconditions. Optional hardening if the real factory does not need it: drop `operator == factory`, and/or latch the first non-zero distributor answer.","line":71,"path":"src/SwarmInu.sol","reproduction":"Operator clause: factory.move(token, ALICE, 100e18); vm.prank(ALICE); token.approve(factory, 100e18); factory.pull(token, ALICE, BOB, 100e18) (MockProjectFactory.pull calls token.transferFrom). Result: BOB = 100e18, FEE_RECIPIENT = 0 (existing test_factoryAsSpenderMovesExactAmounts). The same transferFrom submitted by any other spender credits BOB 98e18 and FEE_RECIPIENT 2e18 (test_transferFromPaysTheFeeAndSpendsTheFullAllowance). Distributor record: with distributorOf(LAUNCH) == 0, DISTRIBUTOR.transfer(ALICE, 100e18) -> ALICE 98e18; then factory.setDistributor(LAUNCH, DISTRIBUTOR); DISTRIBUTOR.transfer(BOB, 100e18) -> BOB 100e18, FEE_RECIPIENT unchanged at 2e18 (existing test_exemptionFollowsTheFactorysCurrentAnswer). Substituting any address X for DISTRIBUTOR in setDistributor gives X the same exemption.","severity":"info","snippet":"        if (operator == factory || from == factory || to == factory) return true;","title":"Trust assumption: the factory alone names the one fee-exempt distributor address, read live at every transfer, and as transferFrom operator moves any approved balance fee-free"},{"citation":"resolved","description":"Documentation only; no code or manifest-schema defect. README.md lines 93-95 present initialMarketCapWei 400000000000000000000, poolBps 9000 and 'rounding dust' to remainderTo as the launch economics, and line 59 cites test_knownLimit_transferRoutedThroughThePoolManagerPaysNoFee as demonstrating the PoolManager relay. launch.json line 18 (the accepted manifest, whose notes say these economics 'govern instead of the earlier 400 IMD estimate') carries poolBps 8800, initialMarketCapWei 2500000000000000000000 and remainderTo 0x66522f25035c3fafd2c6d950a506fda457e06344, which at 8800 bps sends 20,000,000 SI (2% of supply) to the fee wallet rather than dust, and that wallet is fee-exempt as a sender. The cited test is not present in any test file in the tree: git history shows it was added in commit 053f80c, still present in d19e8e6, and removed in 9a2531c while the README sentence stayed. The audit_math info item about IMD's decimals (26d03c0d) could not be reproduced against the tree: economics are copied from the job verbatim and no network.json is supplied, so it stays an open evidence item for the manifest/admission step, not a finding. A reader relying on the README before launch would expect a different seed size, price and remainder than the manifest deploys; the README should be brought in line with launch.json and the dangling test reference removed or the test restored.","line":93,"path":"README.md","reproduction":"Open README.md lines 93-95 and launch.json line 18 side by side: 400000000000000000000 vs 2500000000000000000000, 9000 vs 8800, 'rounding dust' vs 2% of supply (1000000000000000000000000000 * (9000 - 8800) / 10000 = 20000000000000000000000000) to the fee wallet. Run `forge test --match-test knownLimit`: 0 tests match (expected: the test the README line 59 names runs).","severity":"info","snippet":"| `economics.initialMarketCapWei` | `400000000000000000000` | \"based on 400 IMD tokens\": the whole 1,000,000,000 SI valued at 400 IMD, with IMD at 18 decimals |","title":"README launch parameters and cited known-limit test disagree with the tree: README says 400 IMD cap / poolBps 9000 and cites a test that does not exist, launch.json carries 2500e18 / 8800 / remainderT"}],"hash":"cbb17e8103317ef90640f999b99b2310c250b82342b98379735d40f7b483f65e","nodeId":"015f5f4b-3d4c-4e81-a006-1dca2e2dcf50","outcome":"completed","summary":"The review is complete. The findings file is written and validated, and no tracked file was changed.\n\n**Outcome.** One real defect survives, merged from five specialist reports, plus two informational notes. The token's supply, fee arithmetic, allowance handling, distributor lookup, launch flows and opcode surface all hold.\n\n**Findings written to `.imd-findings.json`:**\n\n1. **Medium, `src/SwarmInu.sol:72`.** Any holder moves SI fee-free through the exempted PoolManager, via a flash-accounting relay or ERC-6909 claim tokens. All five specialist reports describe this same root cause, so they are one finding. I ran all three attached proofs and each fails on the current code for the stated reason. I also built a patched scratch copy that exempts only transfers into the PoolManager and verified against the real vendored PoolManager, in both currency orders, that the swarm share and seed still arrive whole, a trader buys and sells everything back, and the relay now pays 2%. The attached proof passes against that copy. The fix is a design trade-off (v4 buys would pay 2%) that departs from the launch prose on exact pool flows, so it needs the requester's decision rather than a silent change. The attached proof is the permissions specialist's, kept because it covers both the relay and the claims path.\n\n2. **Info, `src/SwarmInu.sol:71`.** Trust assumption, merged from two specialists: the factory alone names the fee-exempt distributor, read live at every transfer, and as transferFrom operator it moves any approved balance fee-free. No unprivileged amplifier, so not a vulnerability.\n\n3. **Info, `README.md:93`.** The README's launch parameters (400 IMD cap, poolBps 9000) disagree with the accepted manifest (2500e18, 8800, remainder to the fee wallet), and the README cites a known-limit test that was removed in commit 9a2531c.\n\n**Dropped.** The two rounding-down reports reproduce but are documented, bounded to 1 wei and not amplifiable. The IMD-decimals report could not be reproduced against the tree since no network data is supplied. Both are recorded in coverage rows instead.\n\n**Coverage.** All three entry points are answered: approve holds, transfer and transferFrom carry finding 1. Seven invariant rows record what else I traced.","treeHash":null,"usage":{"cachedInputTokens":1386174,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":30077,"runtime":"claude","turns":33,"wallClockMs":496960}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"df74f6c887684f20","findings":[{"citation":"resolved","description":"Boundary (sentinel-address branch): isFeeExempt() exempts every transfer whose sender or recipient is the Uniswap v4 PoolManager, regardless of operator and regardless of whether a pool is involved. The PoolManager's unlock()/sync()/settle()/take() flash accounting lets any caller pay a currency in and take the same amount out to an arbitrary address inside one unlock, touching no pool. Both legs (holder -> PoolManager, PoolManager -> recipient) hit the line above and skip the fee, so an ordinary wallet-to-wallet transfer of any size can be executed with zero fee for roughly 100k gas. The brief asks for a '2% fee that goes to the owner'; with this exemption the fee is collected only from holders who do not use the relay. The author documents this in README.md ('What the fee does not cover') and reproduces it in test/SwarmInuLaunch.t.sol:test_knownLimit_transferRoutedThroughThePoolManagerPaysNoFee. It is reported here because it is the one material gap between the requested behaviour and the delivered behaviour, and because the token cannot distinguish a swap's take() from a relay's take(). Launch rules require pool flows to settle exactly, so narrowing the exemption (e.g. taxing from == poolManager) would turn buys into a 2% buy tax and change the agreed design; a fee that also covers v4 trades needs a pool-level mechanism (a hook), which this launch does not provide. Scope decision for the requester: accept the documented limit, or change the design.","line":72,"path":"src/SwarmInu.sol","reproduction":"State: token deployed with poolManager = a live v4 PoolManager; HOLDER owns 100e18 SI (any non-exempt address). Call sequence from a relay contract R owned by HOLDER (as in test/utils/LaunchHarness.sol PoolManagerRelay): HOLDER transfers 100e18 to R (pays 2e18 fee once, or funds R from an exempt source); R calls poolManager.unlock(data); in unlockCallback R calls poolManager.sync(SI), SI.transfer(poolManager, 100e18) [from=R,to=poolManager -> exempt, poolManager credited 100e18], poolManager.settle(), poolManager.take(SI, BOB, 100e18) [from=poolManager,to=BOB -> exempt]. Expected per brief: BOB receives 98e18 and FEE_RECIPIENT 2e18. Actual: BOB receives 100e18, FEE_RECIPIENT receives 0. Confirmed by the existing test: `forge test --match-test test_knownLimit_transferRoutedThroughThePoolManagerPaysNoFee` asserts balanceOf(BOB)==100e18 and balanceOf(FEE_RECIPIENT)==0. Scaled: a holder moving 1,000,000e18 SI through the relay keeps 20,000e18 SI that the fee recipient would otherwise receive.","severity":"medium","snippet":"        if (from == poolManager || to == poolManager) return true;","title":"PoolManager sentinel exemption lets any holder move SI fee-free through v4 flash accounting, so the 2% fee is optional for anyone who routes around it"},{"citation":"resolved","description":"Math precision / boundary x precision seam: fee = floor(value * 200 / 10000) = floor(value / 50). At value < 50 the fee truncates to zero; at any value the fee recipient receives up to 1 wei less than 2%. Splitting a transfer of V into n pieces saves at most n-1 wei in total, and each extra transfer costs >= 21k gas plus ~50k for the transfer and the capped factory staticcall, so the leak is not economically amplifiable: with 18 decimals, 49 wei is 4.9e-17 SI. The README documents the rounding direction. No funds are at risk and the supply invariant (sender debited exactly value; fee + (value - fee) == value) holds. Recorded for completeness of the math review; if the requester prefers fees to round in the recipient's favour, use ceiling division (value * 200 + 9999) / 10000, which keeps fee <= value for all value >= 1 and leaves the two-leg accounting unchanged.","line":81,"path":"src/SwarmInu.sol","reproduction":"ALICE holds 1e18 SI (funded by the factory). ALICE.transfer(BOB, 49): expected 2% = 0.98 wei; actual fee 0, BOB receives 49, FEE_RECIPIENT 0. ALICE.transfer(BOB, 50): fee 1 (exact 1.0). ALICE.transfer(BOB, 99): exact 1.98, actual fee 1, BOB receives 98. Verified in test/scratch/MathBoundary.t.sol:test_roundingEdges and in the existing test_feeRoundsDownSoDustBelowFiftyWeiIsFree. Overflow of value * 200 is unreachable from a transfer: the balance check at line 93 bounds value <= totalSupply = 1e27 before feeOn runs (1e27 * 200 < 2^256); only the public pure view feeOn(x) with x > 2^256/200 reverts, harmlessly.","severity":"info","snippet":"        return (value * FEE_BPS) / BPS_DENOMINATOR;","title":"Fee rounds down: transfers below 50 wei pay nothing and every ordinary transfer under-pays by up to 1 wei (bounded dust)"},{"citation":"resolved","description":"Math precision (decimal mismatch) on a launch input rather than on token code. economics.initialMarketCapWei is denominated in the paired currency's minor units, and the deployer derives the opening sqrtPriceX96 from it. The README states 400e18 on the assumption that IMD has 18 decimals and flags the assumption as undecided; no network.json or launch.json is present in the tree, so neither the IMD address nor its decimals could be checked here. If IMD has d != 18 decimals the opening market cap is off by a factor of 10^(18-d): with d = 6 the pool would open at a 400,000,000,000,000 IMD cap (4e14 IMD), i.e. 1e12 times too expensive, and the single-sided seed would be unbuyable at any sane price. The token-side arithmetic in the README (sqrtPriceX96 = 50108289675009586237282760 for SI as currency0, 125270724187523965593206900784803 for SI as currency1; ticks -147326 / 147325) was recomputed independently and is correct for 1e27 supply against 400e18 minor units. Needed evidence before the manifest step: IMD's address and decimals from network.json (or cast call decimals() on the launch chain), then confirm 400 * 10^decimals is the figure copied into economics.initialMarketCapWei.","line":93,"path":"README.md","reproduction":"Inputs: supply 1e27, initialMarketCapWei 400000000000000000000. If IMD.decimals() == 18: price = 4e-7 IMD/SI, cap 400 IMD (intended). If IMD.decimals() == 6: the deployer still derives sqrtPriceX96 = 50108289675009586237282760 from the same minor-unit figure, but 400000000000000000000 minor units is then 4e14 IMD, so the pool opens at 4e-7 IMD-minor-units per SI-wei = 0.4 IMD per SI, a 400,000,000,000,000 IMD market cap, 1e12 times the 400 IMD the brief asks for; the correct figure for a 6-decimal IMD would be 400000000. Expected: 400 IMD cap. Actual: depends on an unverified external decimals value.","severity":"info","snippet":"| `economics.initialMarketCapWei` | `400000000000000000000` | \"based on 400 IMD tokens\": the whole 1,000,000,000 SI valued at 400 IMD, with IMD at 18 decimals |","title":"Opening-cap figure 400000000000000000000 assumes IMD has 18 decimals; IMD's address and decimals are unverified in this repository"}],"hash":"f89f8dbfaf183ef672dc42cb369798d7efefd7f046b90c8c2d7cfc0708b6fb97","nodeId":"83259169-57aa-4faa-a958-3fd5117c9ca5","outcome":"completed","summary":"The review is complete. The findings file is valid JSON, all three snippets match their cited lines, and the coverage record answers every listed entry point plus five invariant and boundary rows.\n\n**Outcome.** The token's arithmetic is sound in the assigned areas. I found no critical or high defects, so no proof files are attached. The findings file holds one medium and two informational items.\n\n**What I checked in depth (Math Precision, Boundary, Numerical Gap):**\n- The fee formula at `src/SwarmInu.sol:81` cannot overflow on a transfer. The balance pre-check at line 93 bounds `value` to the 1e27 supply before the multiply runs.\n- The two-leg transfer conserves value exactly: the sender is debited the full amount and the fee leg plus the remainder leg sum to it, so total supply equals the sum of balances after every path.\n- The capped `staticcall` in `distributor()` degrades safely under no code, revert, short, dirty or oversized answers. I also tested EIP-150 gas starvation across gas limits from 1k to 120k: a starved lookup never lets a taxed claim through, because the 1/64 remainder cannot finish the balance writes, so the whole call reverts.\n- The README's opening-price figures and ticks for both currency orders were recomputed independently and are correct for the stated inputs.\n\n**Findings recorded:**\n1. **Medium.** The PoolManager sentinel exemption at line 72 lets any holder relay tokens through v4 flash accounting with zero fee, so the requested 2% fee is optional for anyone who routes around it. The author documents this and tests it. No code fix preserves the launch rules, so it is a scope decision for the requester: accept the limit or move the fee to a pool-level hook.\n2. **Info.** The fee rounds down. Transfers below 50 wei pay nothing and every transfer under-pays by at most 1 wei. The leak is dust and not economically amplifiable.\n3. **Info.** The 400 IMD cap figure in the README assumes IMD has 18 decimals, and neither a network.json nor a launch.json exists in the tree to confirm it. If IMD's decimals differ, the opening market cap is off by a power of ten.\n\n**Coverage.** `approve` holds. `transfer` and `transferFrom` carry finding 1. Nothing in my area was left unreached. Outside my area, I did not trace the real factory's `distributorOf` timing at claim time, which lives outside this repository.","treeHash":null,"usage":{"cachedInputTokens":714453,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":23093,"runtime":"claude","turns":22,"wallClockMs":358885}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fbcdfc017217af1f","findings":[{"citation":"resolved","description":"Area: Trust Gap (economics x asymmetry) and Access Control. isFeeExempt() exempts the PoolManager both as sender and as recipient. The PoolManager is a permissionless contract: any account can call unlock(), sync()/transfer()/settle() SI in, and take() it out to any address, or mint() ERC-6909 claim tokens for it. So the 2% fee formula differs by path, not by actor: wallet->wallet pays feeOn(value), wallet->PoolManager->wallet pays nothing, and whoever picks the second path (anyone, no pool, no hook, no privileged party) keeps the 2%. The ERC-6909 variant is stronger than the relay the README documents: SI can be held and traded indefinitely as PoolManager claim tokens, which never touch SwarmInu._update, and unwrapped to any address fee-free. The victim is the fee recipient 0x66522f25035C3FAFd2c6D950a506FDa457E06344, who loses the fee on every transfer routed this way. No holder funds are at risk. The README (section 'What the fee does not cover', item 2) states 'This cannot be closed without taxing the PoolManager' and presents it as a requirement of the launch path. That is only true for the inbound leg. Only `to == poolManager` must be exact: v4 credits a settle() by balance difference, so a short payment reverts a sell or the seed. v4's take() (PoolManager.sol line 291-296) performs `currency.transfer(to, amount)` and never checks what the recipient received, so a transfer `from == poolManager` may carry the fee without reverting any swap. I verified this with a scratch copy of the token where line 72 reads `if (to == poolManager) return true;`: against a real PoolManager in both currency orders the swarm share arrives whole, the single-sided seed arrives whole, a trader buys (receiving owed - feeOn(owed)) and sells everything back exactly, no launch flow pays a fee, and the relay now pays 2% (test/scratch/PatchedFloor.t.sol, 2 passed). Tradeoff for the requester: with that change v4 buys pay the 2% (sells still do not), and UIs quoting the swap delta overstate what the buyer receives by 2%. Keeping the current behaviour is also a valid choice, but then the fee is avoidable by anyone at gas cost only and the README's 'cannot be closed' statement should be corrected. This needs a scope decision, not a silent change.","line":72,"path":"src/SwarmInu.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {SwarmInu} from \"src/SwarmInu.sol\";\n\n/// @notice Stands in for the launch factory: deploys the token so it holds the supply and answers distributorOf.\ncontract FactoryStub {\n    mapping(uint64 => address) public distributorOf;\n\n    function deployToken(address poolManager, uint64 launchNumber) external returns (SwarmInu) {\n        return new SwarmInu(address(this), poolManager, launchNumber);\n    }\n\n    function move(SwarmInu token, address to, uint256 amount) external returns (bool) {\n        return token.transfer(to, amount);\n    }\n}\n\n/// @notice An ordinary holder's helper. It is not the factory, not the distributor, not the fee recipient: nothing the\n/// token has any reason to exempt. It moves tokens through the PoolManager's flash accounting without touching a pool.\ncontract Bypass is IUnlockCallback {\n    IPoolManager private immutable manager;\n    SwarmInu private immutable token;\n\n    constructor(IPoolManager manager_, SwarmInu token_) {\n        manager = manager_;\n        token = token_;\n    }\n\n    /// @dev Pay `amount` in, take `amount` out to `to`, in one unlock. Both legs are exempt, so no fee is paid.\n    function relay(address to, uint256 amount) external {\n        manager.unlock(abi.encode(uint8(0), to, amount));\n    }\n\n    /// @dev Pay `amount` in and keep it as ERC-6909 claim tokens on the PoolManager.\n    function wrap(uint256 amount) external {\n        manager.unlock(abi.encode(uint8(1), address(this), amount));\n    }\n\n    /// @dev Hand claim tokens to another account. Claims are a plain ERC-6909 balance on the PoolManager: no SI\n    /// transfer happens, so the SI fee logic is never reached.\n    function sendClaims(address to, uint256 amount) external {\n        manager.transfer(to, uint256(uint160(address(token))), amount);\n    }\n\n    /// @dev Burn claim tokens and take the underlying SI out to `to`.\n    function unwrap(address to, uint256 amount) external {\n        manager.unlock(abi.encode(uint8(2), to, amount));\n    }\n\n    function unlockCallback(bytes calldata data) external override returns (bytes memory) {\n        require(msg.sender == address(manager), \"not the pool manager\");\n        (uint8 mode, address to, uint256 amount) = abi.decode(data, (uint8, address, uint256));\n        Currency currency = Currency.wrap(address(token));\n        if (mode == 0) {\n            manager.sync(currency);\n            token.transfer(address(manager), amount);\n            manager.settle();\n            manager.take(currency, to, amount);\n        } else if (mode == 1) {\n            manager.sync(currency);\n            token.transfer(address(manager), amount);\n            manager.settle();\n            manager.mint(to, currency.toId(), amount);\n        } else {\n            manager.burn(address(this), currency.toId(), amount);\n            manager.take(currency, to, amount);\n        }\n        return \"\";\n    }\n}\n\n/// @notice Any holder can move SI to any other account without paying the 2% fee, by passing it through the\n/// Uniswap v4 PoolManager that the token exempts in both directions. The intended behaviour is that an ordinary\n/// transfer between two non-exempt accounts pays feeOn(value) to FEE_RECIPIENT.\ncontract FeeBypassViaPoolManagerTest is Test {\n    address constant FEE_RECIPIENT = 0x66522f25035C3FAFd2c6D950a506FDa457E06344;\n    address constant BOB = address(0xB0B);\n    address constant CAROL = address(0xCA201);\n    uint64 constant LAUNCH = 7;\n\n    PoolManager manager;\n    FactoryStub factory;\n    SwarmInu token;\n\n    function setUp() public {\n        manager = new PoolManager(address(this));\n        factory = new FactoryStub();\n        token = factory.deployToken(address(manager), LAUNCH);\n    }\n\n    /// @dev Pay in, take out to Bob: Bob receives the whole amount and the fee recipient receives nothing.\n    function test_holderMovesTokensToAnotherWalletThroughThePoolManagerWithoutPayingTheFee() public {\n        Bypass alice = new Bypass(manager, token);\n        factory.move(token, address(alice), 1_000e18);\n        assertFalse(token.isFeeExempt(address(alice), address(alice), BOB), \"alice is an ordinary holder\");\n\n        alice.relay(BOB, 1_000e18);\n\n        // What should happen: a 1,000 SI transfer from an ordinary holder to Bob pays 20 SI to the fee recipient.\n        assertEq(token.balanceOf(FEE_RECIPIENT), token.feeOn(1_000e18), \"the fee recipient was paid the 2% fee\");\n        assertEq(token.balanceOf(BOB), 1_000e18 - token.feeOn(1_000e18), \"Bob received the amount net of the fee\");\n    }\n\n    /// @dev Wrap into ERC-6909 claims, hand the claims to Carol, Carol unwraps to herself: a fee-free wrapper that\n    /// exists for the life of the token, with no pool, hook or privileged party involved.\n    function test_claimTokensOnThePoolManagerAreAFeeFreeWrapperForTheToken() public {\n        Bypass alice = new Bypass(manager, token);\n        Bypass carol = new Bypass(manager, token);\n        factory.move(token, address(alice), 1_000e18);\n\n        alice.wrap(1_000e18);\n        assertEq(manager.balanceOf(address(alice), uint256(uint160(address(token)))), 1_000e18);\n        alice.sendClaims(address(carol), 1_000e18);\n        carol.unwrap(CAROL, 1_000e18);\n\n        // What should happen: SI changed hands between two ordinary accounts, so 2% is owed to the fee recipient.\n        assertEq(token.balanceOf(FEE_RECIPIENT), token.feeOn(1_000e18), \"the fee recipient was paid the 2% fee\");\n        assertEq(token.balanceOf(CAROL), 1_000e18 - token.feeOn(1_000e18), \"Carol received the amount net of the fee\");\n    }\n}","reproduction":"State: SwarmInu deployed by a factory F with poolManager = a Uniswap v4 PoolManager PM. Alice is an ordinary holder (isFeeExempt(alice, alice, bob) == false) with 1,000e18 SI received from F.\nPath A (relay), inside one PM.unlock() from a contract Alice controls: PM.sync(SI); SI.transfer(PM, 1000e18) [exempt: to == poolManager]; PM.settle(); PM.take(SI, bob, 1000e18) [exempt: from == poolManager].\nExpected (intended fee rule, README 'Fee' row): fee recipient balance = feeOn(1000e18) = 20e18, Bob = 980e18.\nActual: fee recipient balance = 0, Bob = 1000e18. The existing test test_knownLimit_transferRoutedThroughThePoolManagerPaysNoFee shows the same numbers.\nPath B (claims): Alice: PM.sync; SI.transfer(PM, 1000e18); PM.settle(); PM.mint(alice, uint160(SI), 1000e18). Later, with no unlock: PM.transfer(carol, uint160(SI), 1000e18) (ERC-6909, SwarmInu never called). Carol: PM.unlock -> PM.burn(carol, id, 1000e18); PM.take(SI, carol, 1000e18).\nExpected: 20e18 to the fee recipient. Actual: 0; Carol holds 1000e18.\nProof: test/scratch/FeeBypassViaPoolManager.t.sol fails on the current code with 'the fee recipient was paid the 2% fee: 0 != 20000000000000000000' (2 failed) and passes when line 72 exempts only `to == poolManager` (verified via a patched copy).","severity":"medium","snippet":"        if (from == poolManager || to == poolManager) return true;","title":"Any holder moves SI fee-free through the exempted PoolManager (flash-accounting relay and ERC-6909 claims), and the outbound leg can be taxed without breaking the launch floor"},{"citation":"resolved","description":"Area: Access Control / Trust Gap, documented as a trust assumption rather than a defect (the requested design reads the distributor from the factory at transfer time, which is what the launch rules call for). The exemption is read live and unconditionally trusted: distributor() returns whatever the factory's distributorOf(launchNumber) says now. There is no checkpoint, no one-shot latch and no code check on the returned address. Actor: the operator of the network's ProjectFactory (or anyone who can upgrade it or write its record). Precondition: the factory's record for this launch number is changeable after launch. Effect: the named address sends and receives SI without the 2% fee, from the moment the record changes, and the exemption of the real MerkleDistributor is lost, so later claims arrive 2% short. The token cannot be frozen, minted or drained by this power; the only in-flight value affected is future fee revenue and the exactness of future claims. No unprivileged amplifier exists, so this is not reported as a vulnerability. The README's Trust section already states it; it is recorded here so the judge sees the actor and preconditions. Possible hardening (scope decision): latch the first non-zero distributor answer into storage, or restrict the exemption to addresses with code.","line":75,"path":"src/SwarmInu.sol","reproduction":"State: token deployed by factory F, F.distributorOf(launchNumber) == 0. Alice holds 200e18 from F.\n1. Alice.transfer(bob, 100e18): Bob gets 98e18, fee recipient 2e18 (Alice is not exempt).\n2. F sets distributorOf(launchNumber) = alice (in the mock: factory.setDistributor(LAUNCH, ALICE)).\n3. Alice.transfer(carol, 100e18): Carol gets 100e18, fee recipient unchanged at 2e18.\nThe existing test test_exemptionFollowsTheFactorysCurrentAnswer shows exactly this sequence with DISTRIBUTOR in Alice's place.","severity":"info","snippet":"        address distributor_ = distributor();\n        return distributor_ != address(0) && (from == distributor_ || to == distributor_);","title":"Trust assumption: whoever controls ProjectFactory.distributorOf chooses one fee-exempt address at any time"}],"hash":"fa0434add173bd951bb46b083498868b0165653d3ad682a18120c6166d293104","nodeId":"234cacd3-097a-4be6-b23c-db617f35751b","outcome":"completed","summary":"The only failures are the two tests in my scratch proof, which is the intended state. All 49 project tests pass, and the working tree is unchanged apart from the findings file and the gitignored scratch folder.\n\n## Review result\n\nThe findings are in `.imd-findings.json`: one medium, one info, and a coverage row for all three entry points plus seven invariants.\n\n**Medium: the 2% fee is avoidable by any holder through the PoolManager exemption.** The token exempts the Uniswap v4 PoolManager as both sender and recipient. The PoolManager is permissionless, so any holder can pay SI in and take it out to another wallet inside one unlock, or mint ERC-6909 claim tokens and trade those indefinitely without ever touching the token's fee logic. The fee recipient loses the 2% on every transfer routed this way. A self-contained proof under test/scratch fails on the current code with the fee recipient at zero instead of 20 SI on a 1,000 SI move. The README documents the relay variant as a known limit and says it cannot be closed without breaking the launch. I checked that claim with a patched copy that exempts only transfers into the PoolManager. Against a real PoolManager in both currency orders the swarm share, the single-sided seed, a buy and a sell back all still succeed, no launch flow pays a fee, and the relay now pays 2%. This works because v4's take() never checks what the recipient received, while settle() does. The tradeoff is that v4 buys would then pay the 2%, so the finding is framed as a scope decision for the requester, not a silent change.\n\n**Info: the factory's distributor record is a live, unconditional fee exemption.** Whoever controls ProjectFactory.distributorOf can name any address exempt at any time and drop the real distributor's exemption. No holder balance is at risk and there is no unprivileged amplifier, so it is recorded as a trust assumption with actor and preconditions, as the adapter asks.\n\n**What held.** Supply is fixed and minted once to the deployer. There is no owner, setter, pause, blacklist, mint, burn or proxy surface. The fee branch and exempt branch of the transfer override both debit exactly the stated value. The distributor lookup cannot revert a transfer under any factory misbehaviour. The approve entry point is untouched OpenZeppelin code.\n\n**Not reached.** The manifest economics, including the 400 IMD market-cap reading and the quoted sqrtPrice values, are outside my area and no launch.json exists yet. Slither and aderyn reported nothing above low, and the one aderyn note is a numeric-literal style remark with no defect behind it.","treeHash":null,"usage":{"cachedInputTokens":1409928,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":31882,"runtime":"claude","turns":36,"wallClockMs":473538}}],"verification":[{"checks":[{"durationMs":3209,"exitCode":0,"name":"build","output":"Compiling 75 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.98s\nCompiler run successful!\n","passed":true},{"durationMs":183,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 12 tests for test/SwarmInuLaunch.t.sol:SwarmInuLaunchTest\n[PASS] test_boughtTokensPayTheFeeOnceTheyMoveBetweenWallets() (gas: 1738160)\n[PASS] test_buyingRaisesThePrice() (gas: 1766848)\n[PASS] test_buyingWithoutImdReverts() (gas: 1517866)\n[PASS] test_knownLimit_transferRoutedThroughThePoolManagerPaysNoFee() (gas: 1238715)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency0() (gas: 894065)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency1() (gas: 902099)\n[PASS] test_openingPriceIsA400ImdMarketCap() (gas: 46690)\n[PASS] test_seedBeyondTheFactorysBalanceReverts() (gas: 583372)\n[PASS] test_seedSpanningTheOpeningPriceNeedsImdAndReverts() (gas: 640302)\n[PASS] test_sellingMoreThanHeldReverts() (gas: 1772196)\n[PASS] test_traderBuysAndSellsExactly_tokenAsCurrency0() (gas: 1845341)\n[PASS] test_traderBuysAndSellsExactly_tokenAsCurrency1() (gas: 1853634)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 17.65ms (27.12ms CPU time)\n\nRan 37 tests for test/SwarmInu.t.sol:SwarmInuTest\n[PASS] testFuzz_ordinaryTransferConservesValue(address,uint256) (runs: 256, μ: 210866, ~: 212886)\nLogs:\n  Bound result 50108289675009586237282760\n\n[PASS] test_claimedTokensPayTheFeeWhenTheClaimantMovesThem() (gas: 259305)\n[PASS] test_constructorRejectsAZeroFactory() (gas: 3994)\n[PASS] test_constructorRejectsAZeroPoolManager() (gas: 6103)\n[PASS] test_dirtyAnswerMeansNoDistributor() (gas: 233169)\n[PASS] test_distributorFundingAndClaimsAreExact() (gas: 286392)\n[PASS] test_distributorOfAnotherLaunchIsNotExempt() (gas: 221263)\n[PASS] test_exemptionFollowsTheFactorysCurrentAnswer() (gas: 278962)\n[PASS] test_factoryAsSpenderMovesExactAmounts() (gas: 182118)\n[PASS] test_factoryCannotMoveAHoldersBalanceWithoutAllowance() (gas: 102461)\n[PASS] test_factoryMovesExactAmounts() (gas: 85927)\n[PASS] test_factoryWithoutCodeMeansNoDistributor() (gas: 108153)\n[PASS] test_feeOn() (gas: 42333)\n[PASS] test_feeRecipientHasNoPowerOverHolders() (gas: 92124)\n[PASS] test_feeRecipientSendsAndReceivesWithoutAFee() (gas: 189205)\n[PASS] test_feeRoundsDownSoDustBelowFiftyWeiIsFree() (gas: 228420)\n[PASS] test_gasBurningFactoryCannotFreezeTransfers() (gas: 431985)\n[PASS] test_isFeeExempt() (gas: 206664)\n[PASS] test_metadata() (gas: 75566)\n[PASS] test_noAdministrativeSurface() (gas: 1431182)\n[PASS] test_nobodyCanExemptThemselves() (gas: 572480)\n[PASS] test_ordinaryTransferPaysTwoPercentToTheRecipient() (gas: 191711)\n[PASS] test_oversizedAnswerIsReadAsOneWord() (gas: 197768)\n[PASS] test_revertingFactoryMeansNoDistributor() (gas: 238763)\n[PASS] test_runtimeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 3592782)\n[PASS] test_selfTransferStillPaysTheFee() (gas: 143765)\n[PASS] test_shortAnswerMeansNoDistributor() (gas: 202668)\n[PASS] test_supplyGoesToTheDeployerEvenWhenItIsNotTheFactory() (gas: 22347)\n[PASS] test_transferBeyondBalanceReverts() (gas: 97593)\n[PASS] test_transferFromIntoThePoolManagerIsExact() (gas: 178355)\n[PASS] test_transferFromPaysTheFeeAndSpendsTheFullAllowance() (gas: 240339)\n[PASS] test_transferFromWithoutAllowanceReverts() (gas: 91826)\n[PASS] test_transferToTheZeroAddressReverts() (gas: 89113)\n[PASS] test_transfersIntoAndOutOfThePoolManagerAreExact() (gas: 189267)\n[PASS] test_transfersToTheFactoryAreExact() (gas: 123121)\n[PASS] test_wholeSupplyIsMintedOnceToTheDeployer() (gas: 41813)\n[PASS] test_zeroValueTransferSucceedsAndPaysNothing() (gas: 49915)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 17.70ms (61.64ms CPU time)\n\nRan 2 test suites in 20.29ms (35.36ms CPU time): 49 tests passed, 0 failed, 0 skipped (49 total tests)\n","passed":true},{"durationMs":98,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SwarmInu.approve(address,uint256)\",\"SwarmInu.transfer(address,uint256)\",\"SwarmInu.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":200,\"foundry.toml\":21,\"launch.json\":20,\"src/SwarmInu.sol\":98,\"test/SwarmInu.t.sol\":441,\"test/SwarmInuLaunch.t.sol\":287,\"test/utils/FactoryMocks.sol\":85,\"test/utils/LaunchHarness.sol\":192},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"000dafc89e1d55c32c4af67471ee843a33b33ce29327dd99f639ebba1f526572","verifiedTreeHash":"22b839e8d60186c4f9ba7ba4599b0604ebe17533","verifierVersion":"0.1.0+94826a22"},{"checks":[{"durationMs":3682,"exitCode":0,"name":"build","output":"Compiling 76 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.45s\nCompiler run successful!\n","passed":true},{"durationMs":186,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/SwarmInuClaims.t.sol:SwarmInuClaimsTest\n[PASS] test_claimRedemptionPaysTheFeeAfterClaimsChangeHands() (gas: 403013)\n[PASS] test_redeemingMoreClaimsThanHeldRevertsWithoutMovingSi() (gas: 88987)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.56ms (657.37µs CPU time)\n\nRan 12 tests for test/SwarmInuLaunch.t.sol:SwarmInuLaunchTest\n[PASS] test_boughtTokensPayTheFeeOnceTheyMoveBetweenWallets() (gas: 1760537)\n[PASS] test_buyingRaisesThePrice() (gas: 1811390)\n[PASS] test_buyingWithoutImdReverts() (gas: 1517977)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency0() (gas: 893998)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency1() (gas: 902010)\n[PASS] test_openingPriceIsA400ImdMarketCap() (gas: 46690)\n[PASS] test_seedBeyondTheFactorysBalanceReverts() (gas: 583350)\n[PASS] test_seedSpanningTheOpeningPriceNeedsImdAndReverts() (gas: 640302)\n[PASS] test_sellingMoreThanHeldReverts() (gas: 1802939)\n[PASS] test_traderBuysNetOfFeeAndSellsAll_tokenAsCurrency0() (gas: 1903991)\n[PASS] test_traderBuysNetOfFeeAndSellsAll_tokenAsCurrency1() (gas: 1912329)\n[PASS] test_transferRoutedThroughThePoolManagerPaysTheFee() (gas: 1288563)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 3.25ms (14.35ms CPU time)\n\nRan 37 tests for test/SwarmInu.t.sol:SwarmInuTest\n[PASS] testFuzz_ordinaryTransferConservesValue(address,uint256) (runs: 256, μ: 209940, ~: 212706)\nLogs:\n  Bound result 1\n\n[PASS] test_claimedTokensPayTheFeeWhenTheClaimantMovesThem() (gas: 259171)\n[PASS] test_constructorRejectsAZeroFactory() (gas: 3994)\n[PASS] test_constructorRejectsAZeroPoolManager() (gas: 6103)\n[PASS] test_dirtyAnswerMeansNoDistributor() (gas: 233080)\n[PASS] test_distributorFundingAndClaimsAreExact() (gas: 286258)\n[PASS] test_distributorOfAnotherLaunchIsNotExempt() (gas: 221174)\n[PASS] test_exemptionFollowsTheFactorysCurrentAnswer() (gas: 278828)\n[PASS] test_factoryAsSpenderMovesExactAmounts() (gas: 182096)\n[PASS] test_factoryCannotMoveAHoldersBalanceWithoutAllowance() (gas: 102461)\n[PASS] test_factoryMovesExactAmounts() (gas: 85927)\n[PASS] test_factoryWithoutCodeMeansNoDistributor() (gas: 108086)\n[PASS] test_feeOn() (gas: 42333)\n[PASS] test_feeRecipientHasNoPowerOverHolders() (gas: 92124)\n[PASS] test_feeRecipientSendsAndReceivesWithoutAFee() (gas: 189159)\n[PASS] test_feeRoundsDownSoDustBelowFiftyWeiIsFree() (gas: 228286)\n[PASS] test_gasBurningFactoryCannotFreezeTransfers() (gas: 431918)\n[PASS] test_isFeeExempt() (gas: 211726)\n[PASS] test_metadata() (gas: 75544)\n[PASS] test_noAdministrativeSurface() (gas: 1431115)\n[PASS] test_nobodyCanExemptThemselves() (gas: 572413)\n[PASS] test_ordinaryTransferPaysTwoPercentToTheRecipient() (gas: 191644)\n[PASS] test_oversizedAnswerIsReadAsOneWord() (gas: 197811)\n[PASS] test_revertingFactoryMeansNoDistributor() (gas: 238674)\n[PASS] test_runtimeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 3556664)\n[PASS] test_selfTransferStillPaysTheFee() (gas: 143676)\n[PASS] test_shortAnswerMeansNoDistributor() (gas: 202601)\n[PASS] test_supplyGoesToTheDeployerEvenWhenItIsNotTheFactory() (gas: 22325)\n[PASS] test_transferBeyondBalanceReverts() (gas: 97526)\n[PASS] test_transferFromIntoThePoolManagerIsExact() (gas: 178399)\n[PASS] test_transferFromPaysTheFeeAndSpendsTheFullAllowance() (gas: 240272)\n[PASS] test_transferFromWithoutAllowanceReverts() (gas: 91826)\n[PASS] test_transferToTheZeroAddressReverts() (gas: 89113)\n[PASS] test_transfersIntoThePoolManagerAreExactAndPayoutsPayTheFee() (gas: 241115)\n[PASS] test_transfersToTheFactoryAreExact() (gas: 123099)\n[PASS] test_wholeSupplyIsMintedOnceToTheDeployer() (gas: 41900)\n[PASS] test_zeroValueTransferSucceedsAndPaysNothing() (gas: 49848)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 12.41ms (30.63ms CPU time)\n\nRan 3 test suites in 13.38ms (17.21ms CPU time): 51 tests passed, 0 failed, 0 skipped (51 total tests)\n","passed":true},{"durationMs":91,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SwarmInu.approve(address,uint256)\",\"SwarmInu.transfer(address,uint256)\",\"SwarmInu.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":215,\"foundry.toml\":21,\"src/SwarmInu.sol\":99,\"test/SwarmInu.t.sol\":441,\"test/SwarmInuClaims.t.sol\":104,\"test/SwarmInuLaunch.t.sol\":295,\"test/utils/FactoryMocks.sol\":85,\"test/utils/LaunchHarness.sol\":192},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1641,"exitCode":0,"name":"slither","output":"slither: no results at low impact or above","passed":true},{"durationMs":870,"exitCode":0,"name":"aderyn","output":"[low] large-numeric-literal at src/SwarmInu.sol:24: Large Numeric Literal (2 places)","passed":true},{"durationMs":3083,"exitCode":0,"name":"proof 6d6221e2e64d","output":"Compiling 73 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.11s\nCompiler run successful!\n\nRan 2 tests for test/imd-proof-33ba1bc3/Proof_6d6221e2e64d.t.sol:FeeBypassViaPoolManagerTest\n[PASS] test_claimTokensOnThePoolManagerAreAFeeFreeWrapperForTheToken() (gas: 1850729)\n[PASS] test_holderMovesTokensToAnotherWalletThroughThePoolManagerWithoutPayingTheFee() (gas: 965074)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.69ms (1.27ms CPU time)\n\nRan 1 test suite in 4.55ms (1.69ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"651b00567a356f2183e2e00f18c41bafe4aa4a0bdaf94b96e138679b9e0e0405","verifiedTreeHash":"8dc8d503509f3a155254607b4273efaa5a5b5b6e","verifierVersion":"0.1.0+94826a22"},{"checks":[{"durationMs":4860,"exitCode":0,"name":"build","output":"Compiling 77 files with Solc 0.8.26\nSolc 0.8.26 finished in 4.61s\nCompiler run successful!\n","passed":true},{"durationMs":27047,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/SwarmInuLaunch.t.sol:SwarmInuLaunchTest\n[PASS] test_boughtTokensPayTheFeeOnceTheyMoveBetweenWallets() (gas: 1738061)\n[PASS] test_buyingRaisesThePrice() (gas: 1766818)\n[PASS] test_buyingWithoutImdReverts() (gas: 1517836)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency0() (gas: 893963)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency1() (gas: 901997)\n[PASS] test_openingPriceIsA400ImdMarketCap() (gas: 46712)\n[PASS] test_seedBeyondTheFactorysBalanceReverts() (gas: 583372)\n[PASS] test_seedSpanningTheOpeningPriceNeedsImdAndReverts() (gas: 640324)\n[PASS] test_sellingMoreThanHeldReverts() (gas: 1772166)\n[PASS] test_traderBuysAndSellsExactly_tokenAsCurrency0() (gas: 1845311)\n[PASS] test_traderBuysAndSellsExactly_tokenAsCurrency1() (gas: 1853604)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 75.79ms (18.42ms CPU time)\n\nRan 37 tests for test/SwarmInu.t.sol:SwarmInuTest\n[PASS] testFuzz_ordinaryTransferConservesValue(address,uint256) (runs: 256, μ: 210811, ~: 212898)\nLogs:\n  Bound result 60435999306702168734416301\n\n[PASS] test_claimedTokensPayTheFeeWhenTheClaimantMovesThem() (gas: 259305)\n[PASS] test_constructorRejectsAZeroFactory() (gas: 3994)\n[PASS] test_constructorRejectsAZeroPoolManager() (gas: 6103)\n[PASS] test_dirtyAnswerMeansNoDistributor() (gas: 233169)\n[PASS] test_distributorFundingAndClaimsAreExact() (gas: 286392)\n[PASS] test_distributorOfAnotherLaunchIsNotExempt() (gas: 221263)\n[PASS] test_exemptionFollowsTheFactorysCurrentAnswer() (gas: 278962)\n[PASS] test_factoryAsSpenderMovesExactAmounts() (gas: 182118)\n[PASS] test_factoryCannotMoveAHoldersBalanceWithoutAllowance() (gas: 102461)\n[PASS] test_factoryMovesExactAmounts() (gas: 85927)\n[PASS] test_factoryWithoutCodeMeansNoDistributor() (gas: 108153)\n[PASS] test_feeOn() (gas: 42333)\n[PASS] test_feeRecipientHasNoPowerOverHolders() (gas: 92124)\n[PASS] test_feeRecipientSendsAndReceivesWithoutAFee() (gas: 189205)\n[PASS] test_feeRoundsDownSoDustBelowFiftyWeiIsFree() (gas: 228420)\n[PASS] test_gasBurningFactoryCannotFreezeTransfers() (gas: 431985)\n[PASS] test_isFeeExempt() (gas: 206664)\n[PASS] test_metadata() (gas: 75566)\n[PASS] test_noAdministrativeSurface() (gas: 1431182)\n[PASS] test_nobodyCanExemptThemselves() (gas: 572480)\n[PASS] test_ordinaryTransferPaysTwoPercentToTheRecipient() (gas: 191711)\n[PASS] test_oversizedAnswerIsReadAsOneWord() (gas: 197768)\n[PASS] test_revertingFactoryMeansNoDistributor() (gas: 238763)\n[PASS] test_runtimeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 3592782)\n[PASS] test_selfTransferStillPaysTheFee() (gas: 143765)\n[PASS] test_shortAnswerMeansNoDistributor() (gas: 202668)\n[PASS] test_supplyGoesToTheDeployerEvenWhenItIsNotTheFactory() (gas: 22347)\n[PASS] test_transferBeyondBalanceReverts() (gas: 97593)\n[PASS] test_transferFromIntoThePoolManagerIsExact() (gas: 178355)\n[PASS] test_transferFromPaysTheFeeAndSpendsTheFullAllowance() (gas: 240339)\n[PASS] test_transferFromWithoutAllowanceReverts() (gas: 91826)\n[PASS] test_transferToTheZeroAddressReverts() (gas: 89113)\n[PASS] test_transfersIntoAndOutOfThePoolManagerAreExact() (gas: 189267)\n[PASS] test_transfersToTheFactoryAreExact() (gas: 123121)\n[PASS] test_wholeSupplyIsMintedOnceToTheDeployer() (gas: 41813)\n[PASS] test_zeroValueTransferSucceedsAndPaysNothing() (gas: 49915)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 76.25ms (99.10ms CPU time)\n\nRan 15 tests for test/SwarmInuAdversarial.t.sol:SwarmInuAdversarialTest\n[PASS] testFuzz_approvalOverwriteReplacesRatherThanAddsAndCannotUnderpayFee(uint256,uint256) (runs: 1000, μ: 168332, ~: 168477)\nLogs:\n  Bound result 10000000000000000\n  Bound result 17153\n\n[PASS] testFuzz_feeRoundingLeavesLessThanOneWeiUncharged(uint256) (runs: 1000, μ: 21290, ~: 21383)\nLogs:\n  Bound result 3\n\n[PASS] testFuzz_launchNumberBoundariesDoNotReadAnotherLaunch(uint64) (runs: 1000, μ: 266676, ~: 266782)\n[PASS] testFuzz_overdrawRestoresFiniteAllowanceAndAllBalances(uint256,uint8) (runs: 1000, μ: 199286, ~: 201452)\nLogs:\n  Bound result 1067845366\n\n[PASS] testFuzz_walletRoundTripLosesExactlyTheTwoCollectedFees(uint256) (runs: 1000, μ: 184318, ~: 186637)\nLogs:\n  Bound result 164473800408018173358603609\n\n[PASS] test_exactAllowanceCannotBeSpentTwice() (gas: 204898)\n[PASS] test_exemptRolesCannotSpendWithoutApproval() (gas: 200601)\n[PASS] test_fullSupplyTransferAndDelegatedSelfTransfer() (gas: 248075)\n[PASS] test_infiniteAllowanceSurvivesRepeatedTaxedSpendsAndCanBeRevoked() (gas: 284134)\n[PASS] test_maxUintTransferFailsWithBalanceErrorBeforeFeeArithmetic() (gas: 139168)\n[PASS] test_oneWeiAndZeroTransfersEmitTheirActualAmounts() (gas: 135018)\n[PASS] test_poolAndDistributorAsOperatorsDoNotExemptOrdinaryWalletTransfers() (gas: 276304)\n[PASS] test_zeroRecipientRevertsForTaxedAndExemptCallersAndRestoresAllowance() (gas: 225127)\n[PASS] test_zeroSenderAndZeroSpenderAreRejectedEvenForZeroAmounts() (gas: 96203)\n[PASS] test_zeroTransferFromWithoutApprovalStillEmitsTransfer() (gas: 97353)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 76.31ms (355.37ms CPU time)\n\nRan 2 tests for test/SwarmInuInvariant.t.sol:SwarmInuInvariantTest\n[PASS]\nSwarmInuInvariantTest invariants:\n[PASS] invariant_balancesAndFeesMatchTheIndependentLedger\n[PASS] invariant_onlySuccessfulAuthorizedSpendsReduceAllowances\n[PASS] invariant_supplyIsFixedAndEveryTokenIsAccountedFor\n SwarmInuInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭-----------------+---------------------+-------+---------+----------╮\n| Contract        | Selector            | Calls | Reverts | Discards |\n+====================================================================+\n| SwarmInuHandler | approve             | 1996  | 0       | 0        |\n|-----------------+---------------------+-------+---------+----------|\n| SwarmInuHandler | approveAndSpend     | 2111  | 0       | 0        |\n|-----------------+---------------------+-------+---------+----------|\n| SwarmInuHandler | changeDistributor   | 1981  | 0       | 0        |\n|-----------------+---------------------+-------+---------+----------|\n| SwarmInuHandler | rejectInvalidCall   | 2060  | 0       | 0        |\n|-----------------+---------------------+-------+---------+----------|\n| SwarmInuHandler | transfer            | 2075  | 0       | 0        |\n|-----------------+---------------------+-------+---------+----------|\n| SwarmInuHandler | transferDust        | 2064  | 0       | 0        |\n|-----------------+---------------------+-------+---------+----------|\n| SwarmInuHandler | transferFrom        | 2029  | 0       | 0        |\n|-----------------+---------------------+-------+---------+----------|\n| SwarmInuHandler | transferFullBalance | 2068  | 0       | 0        |\n╰-----------------+---------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 14846504833202989563131682\n  Bound result 7347\n  Bound result 79847467700762629534503813\n  Bound result 89578639722199016423258098\n  Bound result 188492910783749248389189817\n  Bound result 6895\n  Bound result 4965\n  Bound result 124999999999999999999999998\n  Bound result 127\n  Bound result 75315905455279822569376111\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 20015405880954239542069408\n  Bound result 18367349850373646290766676\n  Bound result 90\n  Bound result 766\n  Bound result 95\n  Bound result 75315905455279822569376111\n  Bound result 0\n  Bound result 1000\n  Bound result 641\n  Bound result 100\n  Bound result 163\n  Bound result 32441107633553183016972307\n  Bound result 6707\n  Bound result 2727\n  Bound result 0\n  Bound result 65\n  Bound result 0\n  Bound result 7078\n  Bound result 0\n  Bound result 261\n  Bound result 5812\n  Bound result 6387\n  Bound result 3963891460\n  Bound result 0\n  Bound result 3\n  Bound result 62\n  Bound result 0\n  Bound result 58\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1000\n\n[PASS] test_handlerSequenceExercisesSuccessAndRollback() (gas: 3570974)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 50\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 26.86s (26.86s CPU time)\n\nRan 4 test suites in 26.87s (27.09s CPU time): 65 tests passed, 0 failed, 0 skipped (65 total tests)\n","passed":true},{"durationMs":124,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SwarmInu.approve(address,uint256)\",\"SwarmInu.transfer(address,uint256)\",\"SwarmInu.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":200,\"foundry.toml\":21,\"src/SwarmInu.sol\":98,\"test/SwarmInu.t.sol\":441,\"test/SwarmInuAdversarial.t.sol\":238,\"test/SwarmInuInvariant.t.sol\":247,\"test/SwarmInuLaunch.t.sol\":272,\"test/TESTING.md\":41,\"test/utils/FactoryMocks.sol\":85,\"test/utils/LaunchHarness.sol\":192},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"676ff7930a520f05a5eb6a44bfc4b6a79fac398ee7aeac28acdc2508dbc8a51d","verifiedTreeHash":"377e187423b9f09e57591d8d0941ed7c40a8fe32","verifierVersion":"0.1.0+94826a22"},{"checks":[{"durationMs":1988,"exitCode":0,"name":"build","output":"Compiling 76 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.85s\nCompiler run successful!\n","passed":true},{"durationMs":100,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/SwarmInuClaims.t.sol:SwarmInuClaimsTest\n[PASS] test_claimRedemptionPaysTheFeeAfterClaimsChangeHands() (gas: 403013)\n[PASS] test_redeemingMoreClaimsThanHeldRevertsWithoutMovingSi() (gas: 88987)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.19ms (444.18µs CPU time)\n\nRan 12 tests for test/SwarmInuLaunch.t.sol:SwarmInuLaunchTest\n[PASS] test_boughtTokensPayTheFeeOnceTheyMoveBetweenWallets() (gas: 1760537)\n[PASS] test_buyingRaisesThePrice() (gas: 1811390)\n[PASS] test_buyingWithoutImdReverts() (gas: 1517977)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency0() (gas: 893998)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency1() (gas: 902010)\n[PASS] test_openingPriceIsA400ImdMarketCap() (gas: 46690)\n[PASS] test_seedBeyondTheFactorysBalanceReverts() (gas: 583350)\n[PASS] test_seedSpanningTheOpeningPriceNeedsImdAndReverts() (gas: 640302)\n[PASS] test_sellingMoreThanHeldReverts() (gas: 1802939)\n[PASS] test_traderBuysNetOfFeeAndSellsAll_tokenAsCurrency0() (gas: 1903991)\n[PASS] test_traderBuysNetOfFeeAndSellsAll_tokenAsCurrency1() (gas: 1912329)\n[PASS] test_transferRoutedThroughThePoolManagerPaysTheFee() (gas: 1288563)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 9.00ms (8.66ms CPU time)\n\nRan 37 tests for test/SwarmInu.t.sol:SwarmInuTest\n[PASS] testFuzz_ordinaryTransferConservesValue(address,uint256) (runs: 256, μ: 210338, ~: 212730)\nLogs:\n  Bound result 1464\n\n[PASS] test_claimedTokensPayTheFeeWhenTheClaimantMovesThem() (gas: 259171)\n[PASS] test_constructorRejectsAZeroFactory() (gas: 3994)\n[PASS] test_constructorRejectsAZeroPoolManager() (gas: 6103)\n[PASS] test_dirtyAnswerMeansNoDistributor() (gas: 233080)\n[PASS] test_distributorFundingAndClaimsAreExact() (gas: 286258)\n[PASS] test_distributorOfAnotherLaunchIsNotExempt() (gas: 221174)\n[PASS] test_exemptionFollowsTheFactorysCurrentAnswer() (gas: 278828)\n[PASS] test_factoryAsSpenderMovesExactAmounts() (gas: 182096)\n[PASS] test_factoryCannotMoveAHoldersBalanceWithoutAllowance() (gas: 102461)\n[PASS] test_factoryMovesExactAmounts() (gas: 85927)\n[PASS] test_factoryWithoutCodeMeansNoDistributor() (gas: 108086)\n[PASS] test_feeOn() (gas: 42333)\n[PASS] test_feeRecipientHasNoPowerOverHolders() (gas: 92124)\n[PASS] test_feeRecipientSendsAndReceivesWithoutAFee() (gas: 189159)\n[PASS] test_feeRoundsDownSoDustBelowFiftyWeiIsFree() (gas: 228286)\n[PASS] test_gasBurningFactoryCannotFreezeTransfers() (gas: 431918)\n[PASS] test_isFeeExempt() (gas: 211726)\n[PASS] test_metadata() (gas: 75544)\n[PASS] test_noAdministrativeSurface() (gas: 1431115)\n[PASS] test_nobodyCanExemptThemselves() (gas: 572413)\n[PASS] test_ordinaryTransferPaysTwoPercentToTheRecipient() (gas: 191644)\n[PASS] test_oversizedAnswerIsReadAsOneWord() (gas: 197811)\n[PASS] test_revertingFactoryMeansNoDistributor() (gas: 238674)\n[PASS] test_runtimeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 3556664)\n[PASS] test_selfTransferStillPaysTheFee() (gas: 143676)\n[PASS] test_shortAnswerMeansNoDistributor() (gas: 202601)\n[PASS] test_supplyGoesToTheDeployerEvenWhenItIsNotTheFactory() (gas: 22325)\n[PASS] test_transferBeyondBalanceReverts() (gas: 97526)\n[PASS] test_transferFromIntoThePoolManagerIsExact() (gas: 178399)\n[PASS] test_transferFromPaysTheFeeAndSpendsTheFullAllowance() (gas: 240272)\n[PASS] test_transferFromWithoutAllowanceReverts() (gas: 91826)\n[PASS] test_transferToTheZeroAddressReverts() (gas: 89113)\n[PASS] test_transfersIntoThePoolManagerAreExactAndPayoutsPayTheFee() (gas: 241115)\n[PASS] test_transfersToTheFactoryAreExact() (gas: 123099)\n[PASS] test_wholeSupplyIsMintedOnceToTheDeployer() (gas: 41900)\n[PASS] test_zeroValueTransferSucceedsAndPaysNothing() (gas: 49848)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 9.26ms (24.31ms CPU time)\n\nRan 3 test suites in 9.89ms (20.45ms CPU time): 51 tests passed, 0 failed, 0 skipped (51 total tests)\n","passed":true},{"durationMs":41,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SwarmInu.approve(address,uint256)\",\"SwarmInu.transfer(address,uint256)\",\"SwarmInu.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":215,\"foundry.toml\":21,\"launch.json\":20,\"src/SwarmInu.sol\":99,\"test/SwarmInu.t.sol\":441,\"test/SwarmInuClaims.t.sol\":104,\"test/SwarmInuLaunch.t.sol\":295,\"test/utils/FactoryMocks.sol\":85,\"test/utils/LaunchHarness.sol\":192},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"8815cadfd6a394797f02381097786df1ea5567c10e6d2abdc32849d90f62a043","verifiedTreeHash":"e59486c2aaa85ba0dd2eef17817ec72136d288d9","verifierVersion":"0.1.0+94826a22"},{"checks":[{"durationMs":3477,"exitCode":0,"name":"build","output":"Compiling 79 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.28s\nCompiler run successful!\n","passed":true},{"durationMs":27902,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/SwarmInuClaims.t.sol:SwarmInuClaimsTest\n[PASS] test_claimRedemptionPaysTheFeeAfterClaimsChangeHands() (gas: 403013)\n[PASS] test_redeemingMoreClaimsThanHeldRevertsWithoutMovingSi() (gas: 88987)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.47ms (390.66µs CPU time)\n\nRan 12 tests for test/SwarmInuLaunch.t.sol:SwarmInuLaunchTest\n[PASS] test_boughtTokensPayTheFeeOnceTheyMoveBetweenWallets() (gas: 1760537)\n[PASS] test_buyingRaisesThePrice() (gas: 1811390)\n[PASS] test_buyingWithoutImdReverts() (gas: 1517977)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency0() (gas: 893998)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency1() (gas: 902010)\n[PASS] test_openingPriceIsA400ImdMarketCap() (gas: 46690)\n[PASS] test_seedBeyondTheFactorysBalanceReverts() (gas: 583350)\n[PASS] test_seedSpanningTheOpeningPriceNeedsImdAndReverts() (gas: 640302)\n[PASS] test_sellingMoreThanHeldReverts() (gas: 1802939)\n[PASS] test_traderBuysNetOfFeeAndSellsAll_tokenAsCurrency0() (gas: 1903991)\n[PASS] test_traderBuysNetOfFeeAndSellsAll_tokenAsCurrency1() (gas: 1912329)\n[PASS] test_transferRoutedThroughThePoolManagerPaysTheFee() (gas: 1288563)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 30.41ms (13.03ms CPU time)\n\nRan 37 tests for test/SwarmInu.t.sol:SwarmInuTest\n[PASS] testFuzz_ordinaryTransferConservesValue(address,uint256) (runs: 256, μ: 209932, ~: 212694)\nLogs:\n  Bound result 84351576\n\n[PASS] test_claimedTokensPayTheFeeWhenTheClaimantMovesThem() (gas: 259171)\n[PASS] test_constructorRejectsAZeroFactory() (gas: 3994)\n[PASS] test_constructorRejectsAZeroPoolManager() (gas: 6103)\n[PASS] test_dirtyAnswerMeansNoDistributor() (gas: 233080)\n[PASS] test_distributorFundingAndClaimsAreExact() (gas: 286258)\n[PASS] test_distributorOfAnotherLaunchIsNotExempt() (gas: 221174)\n[PASS] test_exemptionFollowsTheFactorysCurrentAnswer() (gas: 278828)\n[PASS] test_factoryAsSpenderMovesExactAmounts() (gas: 182096)\n[PASS] test_factoryCannotMoveAHoldersBalanceWithoutAllowance() (gas: 102461)\n[PASS] test_factoryMovesExactAmounts() (gas: 85927)\n[PASS] test_factoryWithoutCodeMeansNoDistributor() (gas: 108086)\n[PASS] test_feeOn() (gas: 42333)\n[PASS] test_feeRecipientHasNoPowerOverHolders() (gas: 92124)\n[PASS] test_feeRecipientSendsAndReceivesWithoutAFee() (gas: 189159)\n[PASS] test_feeRoundsDownSoDustBelowFiftyWeiIsFree() (gas: 228286)\n[PASS] test_gasBurningFactoryCannotFreezeTransfers() (gas: 431918)\n[PASS] test_isFeeExempt() (gas: 211726)\n[PASS] test_metadata() (gas: 75544)\n[PASS] test_noAdministrativeSurface() (gas: 1431115)\n[PASS] test_nobodyCanExemptThemselves() (gas: 572413)\n[PASS] test_ordinaryTransferPaysTwoPercentToTheRecipient() (gas: 191644)\n[PASS] test_oversizedAnswerIsReadAsOneWord() (gas: 197811)\n[PASS] test_revertingFactoryMeansNoDistributor() (gas: 238674)\n[PASS] test_runtimeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 3556664)\n[PASS] test_selfTransferStillPaysTheFee() (gas: 143676)\n[PASS] test_shortAnswerMeansNoDistributor() (gas: 202601)\n[PASS] test_supplyGoesToTheDeployerEvenWhenItIsNotTheFactory() (gas: 22325)\n[PASS] test_transferBeyondBalanceReverts() (gas: 97526)\n[PASS] test_transferFromIntoThePoolManagerIsExact() (gas: 178399)\n[PASS] test_transferFromPaysTheFeeAndSpendsTheFullAllowance() (gas: 240272)\n[PASS] test_transferFromWithoutAllowanceReverts() (gas: 91826)\n[PASS] test_transferToTheZeroAddressReverts() (gas: 89113)\n[PASS] test_transfersIntoThePoolManagerAreExactAndPayoutsPayTheFee() (gas: 241115)\n[PASS] test_transfersToTheFactoryAreExact() (gas: 123099)\n[PASS] test_wholeSupplyIsMintedOnceToTheDeployer() (gas: 41900)\n[PASS] test_zeroValueTransferSucceedsAndPaysNothing() (gas: 49848)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 34.68ms (63.56ms CPU time)\n\nRan 16 tests for test/SwarmInuBoundaries.t.sol:SwarmInuBoundariesTest\n[PASS] testFuzz_feeRoundsDownToNearestMinorUnit(uint256) (runs: 1000, μ: 13051, ~: 12769)\nLogs:\n  Bound result 231751528354803998994626565\n\n[PASS] testFuzz_transferFromFailureIsAtomic(uint256,uint256,bool) (runs: 1000, μ: 214016, ~: 212633)\nLogs:\n  Bound result 639846430126\n  Bound result 12\n\n[PASS] testFuzz_walletRoundTripLosesExactlyFees(uint256) (runs: 1000, μ: 205314, ~: 207724)\nLogs:\n  Bound result 899150476\n\n[PASS] test_approvalReplacementAndNetOnlyApprovalCannotAuthorizeGrossSpend() (gas: 170977)\n[PASS] test_delegatedSelfTransferConsumesGrossAllowanceAndOnlyLosesFee() (gas: 176502)\n[PASS] test_entireSupplyCanBeSpentWithExactGrossAllowance() (gas: 272964)\n[PASS] test_exemptFactoryStillRollsBackAllowanceWhenBalanceIsInsufficient() (gas: 149076)\n[PASS] test_finiteAllowanceRollsBackWhenBalanceIsInsufficient() (gas: 152420)\n[PASS] test_infiniteApprovalSurvivesRepeatedTaxedSpendsAndCanBeRevoked() (gas: 368612)\n[PASS] test_maximumDirectTransferReportsBalanceErrorWithoutArithmeticPanic() (gas: 88103)\n[PASS] test_maximumTransferFromReportsBalanceErrorWithoutTakingAFee() (gas: 149537)\n[PASS] test_oneWeiMovesWithoutDustLoss() (gas: 116557)\n[PASS] test_poolAndDistributorOperatorsStillNeedApproval() (gas: 211431)\n[PASS] test_zeroAmountCannotBypassInvalidAddresses() (gas: 170739)\n[PASS] test_zeroRecipientRollsBackFiniteAllowanceAndFees() (gas: 143745)\n[PASS] test_zeroTransferFromNeedsNoAllowanceAndEmitsTransfer() (gas: 107646)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 35.37ms (103.08ms CPU time)\n\nRan 2 tests for test/SwarmInuClaimsInvariant.t.sol:SwarmInuClaimsInvariantTest\n[PASS] invariant_claimsRemainFullyBackedAndFeesAreConserved() (runs: 256, calls: 16384, reverts: 0)\n\n╭-----------------------+------------------------+-------+---------+----------╮\n| Contract              | Selector               | Calls | Reverts | Discards |\n+=============================================================================+\n| SwarmInuClaimsHandler | donate                 | 2740  | 0       | 0        |\n|-----------------------+------------------------+-------+---------+----------|\n| SwarmInuClaimsHandler | moveClaims             | 2685  | 0       | 0        |\n|-----------------------+------------------------+-------+---------+----------|\n| SwarmInuClaimsHandler | redeem                 | 2780  | 0       | 0        |\n|-----------------------+------------------------+-------+---------+----------|\n| SwarmInuClaimsHandler | rejectExcessRedemption | 2795  | 0       | 0        |\n|-----------------------+------------------------+-------+---------+----------|\n| SwarmInuClaimsHandler | rejectUnfundedWrap     | 2643  | 0       | 0        |\n|-----------------------+------------------------+-------+---------+----------|\n| SwarmInuClaimsHandler | wrap                   | 2741  | 0       | 0        |\n╰-----------------------+------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 12956114620195806954120824\n  Bound result 16028304687204714752628096\n  Bound result 53591\n  Bound result 5571\n  Bound result 17106\n  Bound result 928308117323439131\n  Bound result 597045894625449553\n  Bound result 105888248636566304064015\n  Bound result 4546\n  Bound result 61292544359797105728952307\n  Bound result 20418407573732995671325356\n  Bound result 7354\n  Bound result 3826\n  Bound result 0\n  Bound result 10\n  Bound result 9\n  Bound result 1\n\n[PASS] test_claimLifecycleCannotSpendDonationsOrRedeemTwice() (gas: 1901987)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.51s (2.51s CPU time)\n\nRan 2 tests for test/SwarmInuInvariant.t.sol:SwarmInuInvariantTest\n[PASS] invariant_supplyBalancesAndAllowancesAgreeWithModel() (runs: 256, calls: 32768, reverts: 0)\n\n╭-----------------+-----------------------------+-------+---------+----------╮\n| Contract        | Selector                    | Calls | Reverts | Discards |\n+============================================================================+\n| SwarmInuHandler | approve                     | 4006  | 0       | 0        |\n|-----------------+-----------------------------+-------+---------+----------|\n| SwarmInuHandler | approveAndSpend             | 4181  | 0       | 0        |\n|-----------------+-----------------------------+-------+---------+----------|\n| SwarmInuHandler | rejectInsufficientAllowance | 4117  | 0       | 0        |\n|-----------------+-----------------------------+-------+---------+----------|\n| SwarmInuHandler | rejectInsufficientBalance   | 4092  | 0       | 0        |\n|-----------------+-----------------------------+-------+---------+----------|\n| SwarmInuHandler | rejectZeroReceiver          | 4092  | 0       | 0        |\n|-----------------+-----------------------------+-------+---------+----------|\n| SwarmInuHandler | rotateDistributor           | 4086  | 0       | 0        |\n|-----------------+-----------------------------+-------+---------+----------|\n| SwarmInuHandler | spendAllowance              | 4061  | 0       | 0        |\n|-----------------+-----------------------------+-------+---------+----------|\n| SwarmInuHandler | transfer                    | 4133  | 0       | 0        |\n╰-----------------+-----------------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 7\n  Bound result 3395723174\n  Bound result 0\n  Bound result 49\n  Bound result 907856903\n  Bound result 251704346377505497833482285\n  Bound result 10000000000000000000\n  Bound result 20000000000000000000000000\n  Bound result 5818\n  Bound result 4000000000000000000\n  Bound result 3263\n  Bound result 0\n  Bound result 50000000000000000000\n  Bound result 8\n  Bound result 7436038644099192621874306\n  Bound result 21276034678272082163372335\n  Bound result 6283019655932542975\n  Bound result 0\n  Bound result 4095\n  Bound result 7409\n  Bound result 5789\n  Bound result 0\n  Bound result 724187523965593206900784803\n  Bound result 10000\n  Bound result 0\n  Bound result 5982919025302\n  Bound result 7061\n  Bound result 2827\n  Bound result 0\n  Bound result 1069337353390002\n  Bound result 1\n  Bound result 0\n  Bound result 51148720772881983852440362\n  Bound result 282\n  Bound result 203168687367113557899055425\n  Bound result 100000000000000000001\n  Bound result 634771144302441490678621439\n  Bound result 659918\n\n[PASS] test_handlerExercisesTaxedExemptAndRejectedPaths() (gas: 18604086)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 0\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 27.78s (27.79s CPU time)\n\nRan 6 test suites in 27.79s (30.39s CPU time): 71 tests passed, 0 failed, 0 skipped (71 total tests)\n","passed":true},{"durationMs":58,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SwarmInu.approve(address,uint256)\",\"SwarmInu.transfer(address,uint256)\",\"SwarmInu.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":215,\"foundry.toml\":21,\"src/SwarmInu.sol\":99,\"test/SwarmInu.t.sol\":441,\"test/SwarmInuBoundaries.t.sol\":219,\"test/SwarmInuClaims.t.sol\":104,\"test/SwarmInuClaimsInvariant.t.sol\":171,\"test/SwarmInuInvariant.t.sol\":243,\"test/SwarmInuLaunch.t.sol\":295,\"test/utils/FactoryMocks.sol\":85,\"test/utils/LaunchHarness.sol\":192},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a48304f794635ffe50b6f1c537f8221f031bf2f4d28302df788ed464b806b1e1","verifiedTreeHash":"2510e8ae9effa2ad95017d5b32d391fd180f2cc5","verifierVersion":"0.1.0+94826a22"},{"checks":[{"durationMs":2115,"exitCode":0,"name":"build","output":"Compiling 75 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.96s\nCompiler run successful!\n","passed":true},{"durationMs":119,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 12 tests for test/SwarmInuLaunch.t.sol:SwarmInuLaunchTest\n[PASS] test_boughtTokensPayTheFeeOnceTheyMoveBetweenWallets() (gas: 1738160)\n[PASS] test_buyingRaisesThePrice() (gas: 1766848)\n[PASS] test_buyingWithoutImdReverts() (gas: 1517866)\n[PASS] test_knownLimit_transferRoutedThroughThePoolManagerPaysNoFee() (gas: 1238715)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency0() (gas: 894065)\n[PASS] test_launchSeedsSingleSided_tokenAsCurrency1() (gas: 902099)\n[PASS] test_openingPriceIsA400ImdMarketCap() (gas: 46690)\n[PASS] test_seedBeyondTheFactorysBalanceReverts() (gas: 583372)\n[PASS] test_seedSpanningTheOpeningPriceNeedsImdAndReverts() (gas: 640302)\n[PASS] test_sellingMoreThanHeldReverts() (gas: 1772196)\n[PASS] test_traderBuysAndSellsExactly_tokenAsCurrency0() (gas: 1845341)\n[PASS] test_traderBuysAndSellsExactly_tokenAsCurrency1() (gas: 1853634)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 8.39ms (11.42ms CPU time)\n\nRan 37 tests for test/SwarmInu.t.sol:SwarmInuTest\n[PASS] testFuzz_ordinaryTransferConservesValue(address,uint256) (runs: 256, μ: 209850, ~: 212928)\nLogs:\n  Bound result 495223380371484768233528766\n\n[PASS] test_claimedTokensPayTheFeeWhenTheClaimantMovesThem() (gas: 259305)\n[PASS] test_constructorRejectsAZeroFactory() (gas: 3994)\n[PASS] test_constructorRejectsAZeroPoolManager() (gas: 6103)\n[PASS] test_dirtyAnswerMeansNoDistributor() (gas: 233169)\n[PASS] test_distributorFundingAndClaimsAreExact() (gas: 286392)\n[PASS] test_distributorOfAnotherLaunchIsNotExempt() (gas: 221263)\n[PASS] test_exemptionFollowsTheFactorysCurrentAnswer() (gas: 278962)\n[PASS] test_factoryAsSpenderMovesExactAmounts() (gas: 182118)\n[PASS] test_factoryCannotMoveAHoldersBalanceWithoutAllowance() (gas: 102461)\n[PASS] test_factoryMovesExactAmounts() (gas: 85927)\n[PASS] test_factoryWithoutCodeMeansNoDistributor() (gas: 108153)\n[PASS] test_feeOn() (gas: 42333)\n[PASS] test_feeRecipientHasNoPowerOverHolders() (gas: 92124)\n[PASS] test_feeRecipientSendsAndReceivesWithoutAFee() (gas: 189205)\n[PASS] test_feeRoundsDownSoDustBelowFiftyWeiIsFree() (gas: 228420)\n[PASS] test_gasBurningFactoryCannotFreezeTransfers() (gas: 431985)\n[PASS] test_isFeeExempt() (gas: 206664)\n[PASS] test_metadata() (gas: 75566)\n[PASS] test_noAdministrativeSurface() (gas: 1431182)\n[PASS] test_nobodyCanExemptThemselves() (gas: 572480)\n[PASS] test_ordinaryTransferPaysTwoPercentToTheRecipient() (gas: 191711)\n[PASS] test_oversizedAnswerIsReadAsOneWord() (gas: 197768)\n[PASS] test_revertingFactoryMeansNoDistributor() (gas: 238763)\n[PASS] test_runtimeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 3592782)\n[PASS] test_selfTransferStillPaysTheFee() (gas: 143765)\n[PASS] test_shortAnswerMeansNoDistributor() (gas: 202668)\n[PASS] test_supplyGoesToTheDeployerEvenWhenItIsNotTheFactory() (gas: 22347)\n[PASS] test_transferBeyondBalanceReverts() (gas: 97593)\n[PASS] test_transferFromIntoThePoolManagerIsExact() (gas: 178355)\n[PASS] test_transferFromPaysTheFeeAndSpendsTheFullAllowance() (gas: 240339)\n[PASS] test_transferFromWithoutAllowanceReverts() (gas: 91826)\n[PASS] test_transferToTheZeroAddressReverts() (gas: 89113)\n[PASS] test_transfersIntoAndOutOfThePoolManagerAreExact() (gas: 189267)\n[PASS] test_transfersToTheFactoryAreExact() (gas: 123121)\n[PASS] test_wholeSupplyIsMintedOnceToTheDeployer() (gas: 41813)\n[PASS] test_zeroValueTransferSucceedsAndPaysNothing() (gas: 49915)\nSuite result: ok. 37 passed; 0 failed; 0 skipped; finished in 10.07ms (29.23ms CPU time)\n\nRan 2 test suites in 10.73ms (18.46ms CPU time): 49 tests passed, 0 failed, 0 skipped (49 total tests)\n","passed":true},{"durationMs":62,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SwarmInu.approve(address,uint256)\",\"SwarmInu.transfer(address,uint256)\",\"SwarmInu.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":200,\"foundry.toml\":21,\"src/SwarmInu.sol\":98,\"test/SwarmInu.t.sol\":441,\"test/SwarmInuLaunch.t.sol\":287,\"test/utils/FactoryMocks.sol\":85,\"test/utils/LaunchHarness.sol\":192},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":593,"exitCode":0,"name":"slither","output":"slither: no results at low impact or above","passed":true},{"durationMs":265,"exitCode":0,"name":"aderyn","output":"[low] large-numeric-literal at src/SwarmInu.sol:24: Large Numeric Literal (2 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a606a0c63be510a7077f48b381ff065ba0ce5cad5d5793e0f7cea8c54f8a9a2f","verifiedTreeHash":"d01ce7fd7871e87def426ef21b551492e0b3301e","verifierVersion":"0.1.0+94826a22"}]}