{"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":"67a13eac-a06c-4de4-bce8-7617cf59640e","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"8d400bc2e7d5ea191f45bb49205094d64d425abc4df5c8dccaa6a650e90a78ec","dependsOn":["build_contract_project","write_foundry_tests","manifest"],"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":"1a1ae06ac4447420d9858f5610ea9debfc6a79d341d62fa9839aee5146f149c4","dependsOn":["build_contract_project","write_foundry_tests","manifest"],"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":"6b68096e017a0c6a57409ece7f5c784cc478ebe8c3969dad4ddc1bea4d95689f","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"05ec7333bd2e590deb4d2b13fd762ee8282f5ea39fc7266277442ec667894886","dependsOn":["build_contract_project","write_foundry_tests","manifest"],"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":"424f375e65a121cff33610c83dabb93a2321d3182d93fae955548f64b44f5554","dependsOn":["build_contract_project","write_foundry_tests","manifest"],"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":"e487f40c291efe46133f57033962f308128ebaf7ba6b0a5ee542e77fcc41bbe5","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"6e3e328aa196f6965a2821b098b101e9ff09eef55cdaafaec1d6ea18007b96f6","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"6e3e328aa196f6965a2821b098b101e9ff09eef55cdaafaec1d6ea18007b96f6","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"a66384dd8c1bdd1c928b26b290102a4565140afd4e1085595e763df19f065a6f","dependsOn":["build_contract_project","write_foundry_tests"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"23699f52dd48636da5b2887ae76b0be8150cb04e735e39ac8a7f962b95091320","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":"[SIMD-LAUNCH]\nA custom token: shitpaper (SHITPAPER).\nToken name: shitpaper\nToken symbol: SHITPAPER\nToken supply: 1,000,000,000 with 18 decimals, all minted once to the deployer in the constructor.\nMinting after launch: none, the supply is fixed forever.\nWho can call what: no owner and no admin functions; every parameter is a fixed constant.\n\nWhat it does:\n1. The token contract SHITPAPERToken mints exactly 1,000,000,000 tokens with 18 decimals to the deployer.\n2. 10% of total supply is allocated to the swarm’s Merkle distributor and not minted or transferred by the contract.\n3. 90% of the supply seeds the Uniswap v4 pool paired with IMD, managed by PoolManager at 0x000000000004444c5dc75cB358380D2e3dE08A90.\n4. The pool fee is fixed at 1.25% (12500 in launch.json), with tick spacing 60.\n5. A 3% fee applies only to transfers originating from the PoolManager (buys). This fee is deducted from the amount the buyer receives.\n6. No fee applies to transfers to the PoolManager (sells) or wallet-to-wallet transfers.\n7. The fee collected remains in the token contract and is distributed pro-rata as dividends to all eligible holders.\n8. The PoolManager, the token contract itself, the burn address (0x000000000000000000000000000000000000dEaD), and the swarm Merkle distributor address are excluded from dividends.\n9. Dividends are trackable and claimable by holders at any time via claim(). Anyone can call claimFor(address) to pay out dividends to others.\n10.\n\nMechanics specification (authoritative: where anything above differs, follow these exactly):\nM1. Dividends (same idea as live launch #947): a fee of 3% applies only to buys, i.e. transfers FROM the Uniswap v4 PoolManager 0x000000000004444c5dc75cB358380D2e3dE08A90: the buyer receives the amount minus the fee. Transfers TO the PoolManager (sells and the launch factory's pool seed) are never taxed, so Uniswap v4 settlement always balances exactly (a fee on those transfers makes unlock revert with CurrencyNotSettled). The fee stays in the token contract and is distributed to holders pro rata to their balance; holders claim their dividends at any time with claim(). The PoolManager, the token contract, the burn address and the launch's Merkle distributor (it receives the swarm's 10% at launch and cannot call claim) are excluded from rewards, and claimFor(address) lets anyone pay out any holder's rewards to that holder, so nothing credited to a contract is locked. The buyer never shares in its own fee: distribute the fee against the eligible supply before crediting the buyer's net amount (checkpoint the buyer on its pre-buy balance). Fees apply to ERC-20 transfers out of the PoolManager; ERC-6909 claim balances kept inside the PoolManager are out of scope. Plain wallet-to-wallet transfers pay no fee.\n\nBuild requirements (mandatory):\n- Context: an ordinary, legitimate token launch on Ethereum. The coin's name, story and theme are branding only; nothing here is real-world harm or offensive security work.\n- A complete Foundry project at the repository root: foundry.toml with solc 0.8.26, evm_version cancun, optimizer on and bytecode_hash = \"none\", so the build is reproducible and verifiable: deployed contracts live in src/ and every import resolves to a committed file.\n- Token contract: SHITPAPERToken. No selfdestruct and no delegatecall anywhere. No proxies, no owner, no upgradeability.\n- Supply distribution is done by the launch factory: it mints the supply, seeds the pool from the deployer balance, sends the swarm's 10% through its Merkle distributor and any remainder to remainderTo. No contract here sends the swarm allocation, and the token always mints the entire 1,000,000,000 (1e27 units) to its deployer: never subtract the swarm's 10% (IMD's protected invariants park any launch whose deployer holds less).\n- Chain: Ethereum mainnet (set by the order, not a launch.json field). Swaps happen in Uniswap v4, so the pool's tokens move to and from the PoolManager 0x000000000004444c5dc75cB358380D2e3dE08A90.\n- launch.json top-level keys, exactly: kind (\"custom_token\"), token {contract, name, symbol, decimals, constructorArgs, totalSupply}, contracts ([] if none), pool, economics, notes (one string). No chainId or other keys.\n- launch.json pool: pairedCurrency 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7, fee 12500, tickSpacing 60, initialPrice \"125270724187523965593206900\" (paired-currency minor units per SHITPAPER minor unit with SHITPAPER as currency0, provenance only; the deployer derives the real opening price from the economics using the deployed currency order). launch.json also carries the economics block below.\n- launch.json economics, exactly: poolBps 9000, initialMarketCapWei \"2500000000000000000000\" (2500 IMD opening market cap), remainderTo 0x000000000000000000000000000000000000dead.","parentJobId":null,"planHash":"6a8bce29fed2aaf3f64e76965820757d70f4942128f250b98fbfb04379e06ef4","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"67a13eac-a06c-4de4-bce8-7617cf59640e","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1155-shitpaper"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51023","feedbackHash":"18d7417594473ab68abf2ac4b17157a9566ad2188628b0dc3dab4b1bab5b007d","nodeKey":"audit_economics","submissionHash":"8d400bc2e7d5ea191f45bb49205094d64d425abc4df5c8dccaa6a650e90a78ec","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50955","feedbackHash":"6b5c5a171bf07bd992619521a0b0a3882f93b3fcb6b298895b4e60a13ccc901d","nodeKey":"audit_flow","submissionHash":"1a1ae06ac4447420d9858f5610ea9debfc6a79d341d62fa9839aee5146f149c4","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51287","feedbackHash":"768696baec5879463a5dbbabcf7fc80aca44e948a1b9da2775f139bf33fbe33f","nodeKey":"audit_judge","submissionHash":"6b68096e017a0c6a57409ece7f5c784cc478ebe8c3969dad4ddc1bea4d95689f","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51298","feedbackHash":"70653bc0486cc07fc3b5fcceb0369556f2945099f7a6ab0d054aa509dc74f7e5","nodeKey":"audit_math","submissionHash":"05ec7333bd2e590deb4d2b13fd762ee8282f5ea39fc7266277442ec667894886","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50974","feedbackHash":"9eca2f61d5240b1df5833d7182c8966ef39be26f4181ce6fac9e2f04b6a6b45a","nodeKey":"audit_permissions","submissionHash":"424f375e65a121cff33610c83dabb93a2321d3182d93fae955548f64b44f5554","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52289","feedbackHash":"8853bed84b7cd6f80b472e2899f3f8017e42cda2d9d6ef9fa3cf6bf4b307583e","nodeKey":"build_contract_project","submissionHash":"e487f40c291efe46133f57033962f308128ebaf7ba6b0a5ee542e77fcc41bbe5","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52170","feedbackHash":"20a92877bd86d06b15d0d954b2a4e54bb45bcaebad7b64267c40d2dc7e2a5d78","nodeKey":"manifest","submissionHash":"a66384dd8c1bdd1c928b26b290102a4565140afd4e1085595e763df19f065a6f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52223","feedbackHash":"9477719fe41ad78572ce2603b89dba2681739c1e95f7c143e9c52228fe8897f5","nodeKey":"write_foundry_tests","submissionHash":"23699f52dd48636da5b2887ae76b0be8150cb04e735e39ac8a7f962b95091320","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"2c75f645c4d40af7809f350cccd1e0120af41244f9fa7fcbee93463adbf23f4d","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2d027bc56749d95c","findings":[{"citation":"resolved","description":"Boundary x invariant seam. _resolveDistributor() assumes that whatever address the factory's distributorOf(launchNumber) returns was, until now, an ordinary eligible holder whose balance is part of eligibleSupply, and so removes balanceOf(dist) from eligibleSupply on first resolution. That assumption is false when the answer is one of the addresses _isExcluded() already hard-codes (the PoolManager, the token contract itself, or 0x...dEaD): their balances were never added to eligibleSupply. If eligibleSupply < held the subtraction panics (0x11) and, because _resolveDistributor() runs at the top of every _update() and the cache is only written after the subtraction, every transfer, sell, buy and claim reverts forever: the token is bricked. If eligibleSupply >= held the subtraction silently succeeds and the invariant eligibleSupply == sum(balances of eligible accounts) is broken; later sells underflow at line 191 (`eligibleSupply -= value`) once enough holders sell, and distributions are credited against too small a supply so that the sum of claimable dividends can exceed the contract's balance. Precondition: the launch factory must answer distributorOf with the burn address, the PoolManager or the token itself. That is a factory misconfiguration, not the documented launch flow, which is why this is low rather than high; the cost of guarding against it is one comparison. Minimal fix: in _resolveDistributor(), treat an answer that is already in the hard-coded excluded set as unknown (return address(0) without caching), or only subtract `held` when the resolved address was not already excluded.","line":275,"path":"src/SHITPAPERToken.sol","reproduction":"Scratch test (run on this tree, passes = defect present). Factory deploys SHITPAPERToken(factory, PM=0x000000000004444c5dc75cB358380D2e3dE08A90, 947). factory.transfer(PM, 9e26); factory.transfer(0xdEaD, 1e26) -> eligibleSupply == 0, dead holds 1e26. factory.setDistributor(947, 0xdEaD). vm.prank(PM); token.transfer(ALICE, 1000e18) -> reverts with Panic(0x11) at line 275 (0 - 1e26). Every subsequent transfer (e.g. vm.prank(PM); token.transfer(PM, 1)) reverts the same way: expected a 3% buy to succeed and later transfers to work; actual: permanent revert. Variant with address(this): after two 1000e18 buys (Alice 970e18, Bob 970e18, contract holds 60e18 of fees, eligibleSupply 1940e18), factory.setDistributor(947, address(token)); Alice transfers 1 wei to Bob -> eligibleSupply becomes 1880e18 although eligible balances still sum to 1940e18. Bob sells 970e18+1 to the PoolManager (ok), then Alice selling 970e18-1 reverts with Panic(0x11) at line 191. Expected: both sells succeed.","severity":"low","snippet":"            eligibleSupply -= held;","title":"Distributor resolution subtracts the resolved address's balance from eligibleSupply even when that address was never counted (hardcoded-excluded answer bricks or corrupts accounting)"},{"citation":"resolved","description":"Boundary: external staticcall return consumed by caller logic. _resolveDistributor() guards `!ok` and `data.length != 32` and the NatSpec/README promise that a factory 'with no code or no answer yet leaves it unknown; nothing reverts'. The remaining corner case is not guarded: a 32-byte word whose upper 12 bytes are not zero. abi.decode(data, (address)) validates the padding in solc 0.8 and reverts, and because the lookup is repeated on every _update() until a non-zero distributor is cached, every transfer, buy, sell and claim reverts for as long as the factory keeps returning that word. Precondition: the factory's distributorOf must return a non-canonical 32-byte value (for example a bytes32 or a uint256 in which the address is packed with other data). The real factory's mapping getter returns a clean address, so this is a factory-misbehaviour case and low severity; it is reported because the contract explicitly claims to tolerate malformed answers. Minimal fix: decode as uint256 and reject (return address(0)) when the value exceeds type(uint160).max, or mask to 160 bits.","line":266,"path":"src/SHITPAPERToken.sol","reproduction":"Scratch test on this tree: DirtyFactory.distributorOf(uint64) returns bytes32(uint256(1) << 200 | uint160(0xD157)). DirtyFactory deploys SHITPAPERToken(address(this), PM, 1) then calls token.transfer(0xA11CE, 1e18) from the factory: the call reverts (abi.decode padding check) and token.distributor() stays 0. Expected per the contract's own documentation: the transfer succeeds and the distributor stays unknown. Actual: every transfer reverts while the factory returns that word.","severity":"low","snippet":"        dist = abi.decode(data, (address));","title":"A 32-byte factory answer with non-zero upper bytes makes abi.decode revert inside every transfer, contrary to the stated 'nothing reverts' guarantee for bad factory answers"},{"citation":"resolved","description":"Math precision: zero-rounding and rounding direction. buyFeeOn(amount) = amount * 300 / 10000 floors, so any transfer out of the PoolManager of 33 wei or less pays no fee (33 * 300 / 10000 = 0), and every buy under-pays by up to 1 wei relative to a fee rounded up. The guide says fees should round up. Impact is dust: a buyer who wanted to avoid the fee would need one swap per 33 wei of an 18-decimal token, paying far more in gas and the 1.25% LP fee than the 1 wei of fee avoided, and holders lose at most 1 wei per buy. Not compounding. Recorded so the author can decide whether to round the fee up; the existing fuzz test testFuzz_dustBuysBelowThirtyFourWeiPayNothing documents the current behaviour as intended.","line":155,"path":"src/SHITPAPERToken.sol","reproduction":"After the launch flow (distributor set, 9e26 in the PoolManager, remainder to 0xdEaD): vm.prank(PM); token.transfer(ALICE, 33) -> balanceOf(ALICE) == 33, balanceOf(token) == 0, no BuyFeeCollected event. vm.prank(PM); token.transfer(ALICE, 34) -> balanceOf(token) == 1. Expected with a rounded-up fee: 1 wei of fee on the 33-wei buy.","severity":"info","snippet":"        return amount * BUY_FEE_BPS / BPS_DENOMINATOR;","title":"Buy fee floors to zero for buys of 33 wei or less (fee rounds in the buyer's favour)"}],"hash":"05ec7333bd2e590deb4d2b13fd762ee8282f5ea39fc7266277442ec667894886","nodeId":"b62f665a-cd1c-4a8f-84ad-9757afdfbbe4","outcome":"completed","summary":"The review is complete. The findings file is written at the repository root, the scratch tests are removed, and no tracked file was changed.\n\n**Outcome.** The arithmetic in the token is sound on every normal path. I found no loss-of-funds defect in the Math Precision, Boundary or Numerical Gap areas. Three items are recorded, two low and one informational, all with reproductions I ran against this tree.\n\n**Findings written to .imd-findings.json**\n\n- **Low, resolution adjustment underflow.** When the factory's distributor lookup answers with an address the contract already excludes by constant (the burn address, the PoolManager, or the token itself), the first resolution subtracts that address's balance from the eligible supply although it was never added. With the burn address holding the launch remainder this panics on every transfer forever, bricking the token. With the token's own address it silently corrupts the eligible supply so later sells revert and dividends are over-credited. Precondition is a factory misconfiguration, hence low. Fix is a one-line check that an already-excluded answer is treated as unknown.\n- **Low, unguarded decode of the factory answer.** A 32-byte answer with non-zero upper bytes passes the length check and then reverts inside the decode, on every transfer, contradicting the contract's own claim that malformed answers never revert. Fix is to decode as a word and reject anything above 160 bits.\n- **Info, fee floor.** Buys of 33 wei or less pay no fee, and every buy under-pays by up to 1 wei versus a rounded-up fee. Dust, not compounding, and the existing fuzz suite documents it as intended.\n\n**Coverage.** All five entry points have rows. Approve, claim and claimFor hold. Transfer and transferFrom hold on every from/to class I traced (mint, buy, sell, seed, wallet, claim, self-transfer, zero value) and carry the findings above. I also recorded four invariant rows: eligible supply equals the sum of eligible balances, the contract always covers what it owes, no intermediate overflow is reachable (worst case accumulator about 2.7e61 with one wei eligible), and the manifest is schema-correct with a plausible provenance price.\n\n**Not reached.** No fork run against live mainnet state; the vendored v4 PoolManager tests stand in for it. Economics outside my area, such as sandwiching a large buy to capture its fee share early after launch, were noted but not reported since the pro-rata rule is mandated by the brief.","treeHash":null,"usage":{"cachedInputTokens":1209709,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":32599,"runtime":"claude","turns":24,"wallClockMs":490192}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3c7630b22a73c1fb","findings":[{"citation":"resolved","description":"The exclusion of the launch's Merkle distributor rests entirely on one assumption the token cannot check: that the factory exposes a getter whose signature is exactly distributorOf(uint64). The brief only says the launch number is 'uint64 or wider', and the real ProjectFactory source is not in the tree. If the factory's mapping is keyed by uint256 (getter distributorOf(uint256)), or is a function with a different name or return shape, the staticcall fails (!ok or data.length != 32) and _resolveDistributor returns address(0) forever: nothing reverts, so the failure is silent. The distributor then holds 1e26 tokens as an eligible holder. Right after launch it is the ONLY eligible holder (pool, token and 0xdEaD are excluded, the factory holds 0), so it receives 100% of the first buy's fee and the dominant share thereafter until contributors' claims drain it. claimFor(distributor) is callable by anyone and pays those dividends to the distributor contract, which only pays Merkle leaves, so they are permanently stuck; while unclaimed they sit in the token contract instead of reaching holders. The protected harness (.imd/reads/protected/custom_token/Token.protected.t.sol:33) declares mapping(uint64 => address) public distributorOf, so under that harness the lookup works and this does not fire; it is a single-point ABI dependency with silent failure, reported so the author can confirm it against the deployed factory or harden the lookup (e.g. also try distributorOf(uint256), or treat a failed lookup as a reason to keep retrying with both selectors).","line":264,"path":"src/SHITPAPERToken.sol","reproduction":"State: a factory contract F with `mapping(uint256 => address) public distributorOf;` deploys SHITPAPERToken(F, PM, 947). F sets distributorOf[947] = 0xD157, transfers 1e26 to 0xD157, 9e26 to the PoolManager, remainder to 0xdEaD (the normal launch order). Observed: token.distributor() == address(0); eligibleSupply == 1e26 (expected 0). Then PoolManager transfers 1_000_000e18 to ALICE (a buy): fee 30_000e18, pendingDistribution == 0, claimableDividendOf(0xD157) == 30_000e18, claimableDividendOf(ALICE) == 0. A second buy of 1_000_000e18 to BOB: claimableDividendOf(0xD157) == 59_711.79e18, ALICE == 288.2e18. claimFor(0xD157) succeeds and pays 59_711.79e18 to the distributor. Expected per spec: the distributor is excluded, both fees (60_000e18) go to ALICE (first fee pending, then paid with the second), and claimFor(0xD157) reverts with ExcludedFromDividends. Scratch test: test_wideSelectorLeavesDistributorEligible in test/scratch/Probe.t.sol (removed).","severity":"low","snippet":"            FACTORY.staticcall(abi.encodeWithSignature(\"distributorOf(uint64)\", LAUNCH_NUMBER));","title":"Distributor lookup is bound to the exact selector distributorOf(uint64); any other factory ABI leaves the swarm distributor eligible and routes early fees to it, where they are stuck"},{"citation":"resolved","description":"When the distributor is first resolved, the code assumes every token the resolved address holds was previously counted in eligibleSupply (`held` is subtracted unconditionally). That holds for any fresh address, but not if the factory's distributorOf(launchNumber) returns an address that was already excluded (the PoolManager, the token itself or 0xdEaD): their balances were never added to eligibleSupply, so `eligibleSupply -= held` reverts with Panic(0x11). Because _resolveDistributor runs at the top of every _update and every _claim while distributor is still zero, and the revert prevents it from ever being cached, every transfer, transferFrom, claim and claimFor reverts from then on, including the PoolManager's take during swaps: the pool is dead and all balances are frozen with no recovery path (no owner, no admin). The precondition is a factory misconfiguration by a trusted party, so this is a robustness issue rather than a reachable attack, but the blast radius is total and the fix is one line: only adjust eligibleSupply when the resolved address was not already excluded (or require held <= eligibleSupply and otherwise skip the adjustment).","line":275,"path":"src/SHITPAPERToken.sol","reproduction":"State: factory F (normal distributorOf(uint64) getter) deploys the token, transfers 9e26 to the PoolManager (eligibleSupply becomes 1e26, the factory's residual), then sets distributorOf[947] = PoolManager (0x000000000004444c5dc75cB358380D2e3dE08A90). Call: vm.prank(PoolManager); token.transfer(ALICE, 1e18). Actual: reverts with 0x4e487b71...11 (arithmetic underflow) from `eligibleSupply -= held` where held = 9e26 > eligibleSupply = 1e26. Every subsequent transfer/claim from any account reverts the same way, since distributor is never cached. Expected: the transfer succeeds (the PoolManager was already excluded; nothing needed adjusting). Scratch test: test_distributorAlreadyExcludedBricks in test/scratch/Probe.t.sol (removed).","severity":"low","snippet":"            eligibleSupply -= held;","title":"_resolveDistributor underflows eligibleSupply when the factory names an already-excluded address as distributor, permanently reverting every transfer and swap"},{"citation":"resolved","description":"Dividends are credited against eligibleSupply as it stands at the instant of each buy, with no time weighting. A searcher who sees a large buy in the mempool can buy first (paying 3% on its own gross, which goes to pre-existing holders), receive the lion's share of the victim's 3% as the now-largest eligible holder, claim it, and sell everything back untaxed. Early after launch, when eligibleSupply is small relative to a single buy, the attacker's share approaches 100% of the victim's fee, so for a victim buy larger than the attacker's own buy the dividend leg alone is profitable before counting the ordinary sandwich price gain (minus two 1.25% pool fees). This follows directly from the brief's mechanics M1 ('distributed to holders pro rata to their balance' at the buy, buyer checkpointed on pre-buy balance) and is not a deviation from it; it is reported so the requester knows the fee is MEV-extractable rather than reaching passive holders, and can decide whether that is acceptable. A fix would change the agreed design (e.g. time-weighted or delayed distribution).","line":176,"path":"src/SHITPAPERToken.sol","reproduction":"State after the launch flow: eligibleSupply == 970_000e18 (ALICE, who bought 1_000_000e18 gross). Attacker buys A = 10_000_000e18 gross from the PoolManager: pays fee 300_000e18 (all credited to ALICE), receives 9_700_000e18. Victim BOB buys V = 10_000_000e18 gross: fee 300_000e18 distributed against 10_670_000e18; attacker's claimFor pays 272_727.27e18 (90.9% of the victim's fee), ALICE gets 27_272.73e18. With V = 20_000_000e18 the attacker captures 545_454e18 against 300_000e18 paid. Expected under a passive-holder reading of 'dividends to holders': the fee reaches holders who were there before the trade; actual: whoever is largest at the instant of the buy takes it. Scratch test: test_sandwichCapturesVictimFee in test/scratch/Probe.t.sol (removed).","severity":"info","snippet":"            _distribute(fee);","title":"Instantaneous pro-rata snapshot lets a sandwicher capture most of a victim's buy fee (design property of the brief, documented for the author)"}],"hash":"1a1ae06ac4447420d9858f5610ea9debfc6a79d341d62fa9839aee5146f149c4","nodeId":"02ee2003-0f6b-4345-bffb-9778d23e89bb","outcome":"completed","summary":"Review complete. The findings are in `.imd-findings.json` at the repository root, with coverage rows for all five entry points and four invariants. No tracked file was changed, and the scratch tests were removed.\n\n**Outcome:** the token's fee and dividend control flow is correct against the brief. I found no critical, high or medium defect. Three items are recorded, two low and one informational.\n\n**What I traced and confirmed holds**\n\n- **Buy fee path.** The fee fires only when the sender is the PoolManager and the recipient is not exempt. Both legs leave the PoolManager, so Uniswap v4 take and settle balance exactly. Sells, the seed, distributor claims and wallet transfers pay nothing.\n- **Dividend accounting.** The fee is distributed against the pre-buy eligible supply, both sides are checkpointed on pre-transfer balances, and the eligible supply tracks every balance writer. Floor rounding keeps the contract solvent. I checked overflow bounds on the accumulator and per-holder product and they are unreachable.\n- **Claims.** Settle, zero the owed amount, then an untaxed transfer from the contract. Payouts go to the named holder only. Excluded accounts revert.\n- **Deployment and manifest.** The constructor mints the full supply to the factory and calls nothing. The manifest keys, argument order, supply, pool and economics match the brief. Runtime bytecode has no delegatecall or selfdestruct.\n- **Vendored code.** OpenZeppelin ERC20 v5.3.0 is unmodified, committed as plain files, with no submodules.\n\n**Findings**\n\n1. **Low.** The distributor lookup hard-codes the selector for a getter keyed by uint64. If the real factory's getter differs, the failure is silent, the swarm distributor stays eligible, and it captures almost all early fees. Anyone can then pay those fees to the distributor, where they are stuck. The protected harness matches the selector, so this holds under the harness. I reported it so the author can confirm it against the deployed factory.\n2. **Low.** If the factory ever names an already-excluded address as distributor, the eligible-supply subtraction underflows. Every transfer, claim and swap then reverts forever. The precondition is a trusted-party misconfiguration, but the fix is a one-line guard.\n3. **Info.** The instantaneous pro-rata snapshot is sandwich-able. A searcher buying ahead of a large buy captures most of that buy's fee. This follows from the brief's mechanics, so it is documented rather than flagged as a deviation.\n\n**Not reached.** No fork run against live mainnet state, and no test through the Universal Router or Permit2 path. The vendored real PoolManager tests cover direct swaps only. A non-factory liquidity provider withdrawing through the PoolManager pays the 3% fee, which follows the spec but is untested.","treeHash":null,"usage":{"cachedInputTokens":946881,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":37369,"runtime":"claude","turns":21,"wallClockMs":586251}},{"artifacts":[],"attempt":1,"bundleHash":"71d480cb6cd15b811c2df62974b3d55b2c59c1b1d2b7c7f1b15efda2bc6f82ed","device":"f20ec62b0213db3f","findings":[{"description":"When a buy happens while eligibleSupply is 0 (right after launch: everything sits in the PoolManager, the distributor and 0x...dEaD), the fee is parked in pendingDistribution and paid out with the next distribution. At that point the first buyer is usually the only eligible holder, so it receives its own 3% back in full plus the second buyer's fee. The mechanics spec says the buyer never shares in its own fee; the implementation honours that for every buy with a non-zero eligible supply, and this deferral is a reasonable choice over stranding the fee, but it is a deliberate deviation at the launch's first trade that the requester should be aware of. No funds are at risk and the contract stays solvent.","line":217,"path":"src/SHITPAPERToken.sol","reproduction":"After the launch flow (eligibleSupply == 0): PoolManager transfers 1000e18 to Alice (fee 30e18 -> pendingDistribution). PoolManager transfers 3000e18 to Bob (fee 90e18). Expected under a strict reading: Alice claimable == 90e18. Actual: Alice claimable == 120e18 (test_secondBuyDistributesPendingAndNewFeeToFirstBuyer and test_buyDistributesProRataToPriorHolders assert the actual behaviour).","severity":"info","title":"First buyer after launch is paid its own fee back on the next distribution"},{"description":"The distributor is read lazily from factory.distributorOf(launchNumber). Until that returns non-zero, the distributor address is an ordinary holder: it counts in eligibleSupply, accrues dividends, and a transfer from the PoolManager to it would be taxed. On resolution its balance is removed from eligibleSupply and any settled dividends are forfeited (they stay in the contract unowed). The documented launch flow registers the distributor before sending the swarm's share, so this never triggers there; it only matters if a different factory ordering is ever used. A factory with no code, a reverting distributorOf, or a wrongly-shaped answer leaves the distributor unknown forever, in which case claimFor(distributor) pays dividends to it rather than locking them.","line":260,"path":"src/SHITPAPERToken.sol","reproduction":"factory.move(token, DISTRIBUTOR, 1e26) before factory.setDistributor(947, DISTRIBUTOR): eligibleSupply == 1e26 and a PoolManager->Alice buy of 1000e18 credits 30e18 to the distributor. After setDistributor and any transfer: distributor() == DISTRIBUTOR, eligibleSupply drops by 1e26, claimableDividendOf(DISTRIBUTOR) == 0 and the 30e18 is stranded in the contract (test_distributorFundedBeforeRegistrationIsRemovedFromEligibleSupplyOnResolution).","severity":"info","title":"Distributor is a taxed, dividend-earning holder until the factory registers it"},{"description":"buyFeeOn(amount) = amount * 300 / 10000 floors to 0 for amount < 34. Splitting a buy into sub-34-wei transfers avoids the fee entirely, but at ~1e-17 tokens per transfer the gas cost makes it meaningless. Documented here so nobody mistakes the fuzz result for a defect.","line":154,"path":"src/SHITPAPERToken.sol","reproduction":"vm.prank(POOL_MANAGER); token.transfer(CAROL, 33): CAROL receives 33, contract receives 0 (testFuzz_dustBuysBelowThirtyFourWeiPayNothing).","severity":"info","title":"Buys below 34 wei pay no fee (floor rounding)"},{"description":"The fee is taken on the ERC-20 transfer out of the PoolManager, i.e. on take(). A router that takes to itself and then transfers the full swap delta to the end user reverts with ERC20InsufficientBalance, because it only received 97%. This is inherent to the requested buy-fee design (any fee-on-transfer token behaves this way) and is not a defect in the token; routers that take directly to the recipient, or sweep their balance, work. Verified with a real PoolManager that take() to the recipient, exact-input and exact-output buys, and sells all settle without CurrencyNotSettled.","line":168,"path":"src/SHITPAPERToken.sol","reproduction":null,"severity":"info","title":"Routers that forward the quoted amount verbatim will see a 3% shortfall"}],"hash":"23699f52dd48636da5b2887ae76b0be8150cb04e735e39ac8a7f962b95091320","nodeId":"ea822203-94d7-4fbc-9077-be18682abb66","outcome":"completed","summary":"Final build and test pass: 67 tests, 0 failures. The work is complete.\n\n**What I delivered** (all under `test/`, nothing outside it changed except the requested findings file):\n\n- `test/SHITPAPERToken.v4.t.sol`: the launch against a real Uniswap v4 PoolManager built in place at its mainnet address, with a mock IMD at IMD's address so currency ordering matches mainnet. It seeds just under 90% single-sided at the launch.json price with fee 12500 and tick spacing 60, then ordinary traders swap. It checks the seed settles exactly with no fee, exact-input and exact-output buys deliver 97% with 3% kept, the fee event carries the gross amount, a buy taken to a third wallet taxes that wallet, sells settle exactly with no fee, claimed dividends can be sold whole, the pool survives many round trips, and a fuzzed buy-then-sell for any amount.\n- `test/SHITPAPERToken.fuzz.t.sol`: 15 property tests. Fee is exactly 3% floored, sells and wallet transfers pay nothing, transferFrom out of the PoolManager is taxed regardless of spender, pro-rata split on pre-buy balances, buyer earns on pre-buy balance only, pending fee is paid with the next distribution, transfers move future not past dividends, claim pays exactly claimable once, claimFor never pays the caller, excluded accounts never earn and cannot claim, and the ERC-20 failure paths (over-balance, zero receiver, allowance exact and infinite).\n- `test/SHITPAPERToken.invariant.t.sol`: a handler driving buys, sells, transfers, transferFrom, burns, donations to the contract, distributor claims, claim and claimFor over 256 runs of depth 40. Invariants: supply fixed and balances sum to it, eligibleSupply equals the sum of eligible balances, the contract holds at least what it owes and no more than donations plus rounding dust, fees equal distributed plus pending, claimed never exceeds distributed, excluded accounts never earn. I confirmed with a deliberately wrong scratch invariant that the handler reaches distributions and claims.\n- `test/SHITPAPERToken.edge.t.sol`: 25 tests on constants, admin-call rejection, bytecode scan for DELEGATECALL/CALLCODE/SELFDESTRUCT, self and zero transfers, fee-exempt recipients, donations not redistributed, burn address, claimFor(0) reverts, contract holder paid via claimFor, event sequences, 50 tiny distributions staying solvent, a near-whole-pool fee against one wei of eligible supply, and the distributor resolution corners (funded before registration, resolved as sender or recipient, deployer without code, reverting or malformed factory answer, cached once, per-launch-number lookup).\n- `test/vendor/`: Uniswap v4-core `src/` at commit 46c6834 and solmate's `Owned.sol`, vendored as plain files with one relative-import patch, documented in `test/vendor/README.md`. Required because remappings are protected and the verifier has no network.\n\n**Findings.** I found no defect in the token; every rule in the brief holds under fuzzing and random sequences. `.imd-findings.json` records four info-level observations without proofs: the first post-launch buyer gets its own parked fee back on the next distribution, the distributor is an ordinary taxed holder until the factory registers it, buys under 34 wei round to no fee, and routers that forward the quoted amount verbatim will be 3% short.\n\n**Still owed:** a fork run against live mainnet state. The PoolManager here is the real v4-core bytecode built offline, but IMD is a mock.","treeHash":"9c81382585ab1dfec3231115afcd28fd28c2e29a","usage":{"cachedInputTokens":1569482,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":59904,"runtime":"claude","turns":31,"wallClockMs":884181}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"98b4506bef931d13","findings":[{"citation":"resolved","description":"Asymmetry (view <-> modify pair). isExcludedFromDividends (line 145), isTaxedTransfer (line 150) and claimableDividendOf (line 139) answer from _knownDistributor(), i.e. the storage cache `distributor`, which is only written by _resolveDistributor() during a state-changing call. _update (line 165) and _claim (line 200) instead call _resolveDistributor(), which staticcalls FACTORY.distributorOf(LAUNCH_NUMBER) and treats a non-zero answer as excluded immediately. So once the factory has registered the distributor but before any transfer or claim has run (and note a reverting claimFor(distributor) rolls the cache write back, so it does not close the window), the views say the distributor is an ordinary, taxed, dividend-earning holder while the writers already treat it as excluded and fee-exempt. No funds are at risk: eligibleSupply, the fee and the exclusion applied on-chain are all correct; only off-chain readers and integrators (indexers, the launch UI, anyone deciding whether to call claimFor) are told the opposite of what the contract will do. Minimal fix that preserves the design: give the views a view-only resolver that performs the same staticcall when the cache is empty (returning the factory's answer without storing it), so view and writer agree in every state.","line":254,"path":"src/SHITPAPERToken.sol","reproduction":"Deploy SHITPAPERToken(factory, 0x000000000004444c5dc75cB358380D2e3dE08A90, 947) from a factory exposing distributorOf(uint64). Call factory.setDistributor(947, 0xD157) and make no transfer. Expected: isExcludedFromDividends(0xD157) == true and isTaxedTransfer(POOL_MANAGER, 0xD157) == false, matching what the writers do. Actual: distributor() == 0, isExcludedFromDividends(0xD157) == false, isTaxedTransfer(POOL_MANAGER, 0xD157) == true; yet claimFor(0xD157) reverts with ExcludedFromDividends(0xD157) (and the revert leaves the views unchanged), and a PoolManager -> 0xD157 transfer of 1000e18 arrives whole (balance 1000e18, no fee) although the view had reported it as taxed. Only after that successful transfer do the views flip to excluded/untaxed. Verified with a scratch Foundry test (test/scratch/Probe.t.sol, test_viewWindowAfterRegistrationBeforeFirstTransfer, passing against the current code).","severity":"low","snippet":"    function _knownDistributor() private view returns (address) {\n        return distributor;\n    }","title":"View functions read the cached distributor while transfers and claims resolve it live, so the views contradict the writers between the factory's registration and the first successful transfer"},{"citation":"resolved","description":"Trust-gap lens (economics x asymmetry), reported for the author's awareness and not as a defect: mechanics M1 asks for pro-rata distribution against the eligible supply before the buyer is credited, and the code does exactly that. The consequence at launch is that every excluded account (PoolManager 90%, distributor 10%, 0xdead remainder) holds the whole supply, eligibleSupply is 0, the first buy's fee waits in pendingDistribution, and the first buyer becomes the only eligible holder. The second buy's fee plus the pending fee are then credited 100% to that first holder regardless of how little it holds. A bot buying 34 wei in the launch block captures 3% of the next real buy. Unprivileged, cheap, and reversible by selling, but it is the direct consequence of the requested rule rather than a coding error; an alternative (e.g. not distributing while eligibleSupply is below some floor) would change the agreed economics and is a scope decision for the requester. Dividend sandwiching later in the pool's life is bounded by the attacker's own 3% buy fee plus two 1.25% LP fees and is only profitable while the victim's buy exceeds roughly 1.8x the eligible supply.","line":216,"path":"src/SHITPAPERToken.sol","reproduction":"After the launch flow (10% to the registered distributor, 90% to the PoolManager, remainder to 0xdead) eligibleSupply() == 0. PoolManager transfers 34 wei to ALICE: fee 1 wei goes to pendingDistribution, ALICE holds 33 wei, eligibleSupply == 33. PoolManager then transfers 1_000_000e18 to BOB: fee 30_000e18 is distributed against 33 wei of eligible supply. Expected under the spec: pro-rata to eligible holders, which is only ALICE. Actual: claimableDividendOf(ALICE) == 30_000e18 (+1 wei pending) and claimableDividendOf(BOB) == 0, i.e. a 34-wei position is credited the whole 30_000e18 fee. Verified with test/scratch/Probe.t.sol, test_tinyFirstHolderCapturesWholeNextFee.","severity":"info","snippet":"        uint256 supply = eligibleSupply;\n        if (supply == 0) {\n            pendingDistribution = amount;\n            return;\n        }","title":"Right after launch the eligible supply is zero, so the first buyer, however small, is credited the entire fee of the next buy (spec-conformant pro-rata behaviour, recorded as an economic property)"}],"hash":"424f375e65a121cff33610c83dabb93a2321d3182d93fae955548f64b44f5554","nodeId":"7d81d6a3-a167-4fd3-aaab-456159908d74","outcome":"completed","summary":"Both paths are intentionally excluded by the repository, so the working tree is clean apart from the deliverable and my scratch directory. The review is complete.\n\n**Outcome: no exploitable defect in the permission model.** The token has no owner, no admin surface, no mint path after the constructor, and the only external call is a staticcall to the launch factory. The vendored OpenZeppelin files are byte-identical to upstream v5.3.0. All 67 existing tests pass offline, and my five scratch probes confirmed the behaviour I traced.\n\n**What I reported in `.imd-findings.json`:**\n\n- **Low, view/writer asymmetry.** The three dividend views read the cached distributor, while transfers and claims resolve it live from the factory. Between the factory registering the distributor and the first successful transfer, the views say it is taxed and eligible while `claimFor` already reverts and a PoolManager transfer to it arrives untaxed. No funds are affected. The fix is a view-only resolver so both sides agree.\n- **Info, launch economics.** Right after launch the eligible supply is zero, so a 34-wei first buyer is credited the entire fee of the next buy. This is exactly the pro-rata rule the mechanics spec requests, so I recorded it as a property for the author, not a defect.\n\n**Coverage:** all five entry points hold, plus seven invariant and trust rows. One lead was deliberately left out of the findings: a factory that answered an already-excluded holder as the distributor would underflow the eligible-supply subtraction and block transfers, but that requires the trusted factory to misbehave. The only check still owed is a fork run against live mainnet state, which cannot run here.","treeHash":null,"usage":{"cachedInputTokens":1384876,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":36893,"runtime":"claude","turns":17,"wallClockMs":584523}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f2156c7086c7a2b8","findings":[{"citation":"resolved","description":"M1 requires that a buyer never shares in its own fee. Right after launch every token sits in excluded accounts (PoolManager, Merkle distributor, 0xdEaD), so eligibleSupply is 0 and _distribute() parks the first buy's fee in pendingDistribution (line 217-219). The first buyer's net amount is then credited and it becomes the entire eligible supply. On the next buy, line 215 adds the parked fee to the new fee and line 224 credits all of it against the eligible supply, i.e. entirely to the first buyer, who thereby recovers its own fee in full (minus 1 wei of floor rounding) on top of the second buyer's fee. The same refund recurs whenever every eligible holder has sold out: the next buyer's fee is returned to that buyer at the following buy. Impact is bounded (3% of one buy, no compounding, funds stay among holders), so low. Merged: audit_economics finding 1 (same root cause). Minimal fix preserving the design: when eligibleSupply == 0 do not credit the parked fee to the next distribution (treat it as residue that stays in the contract), or distribute pendingDistribution only after the buyer's checkpoint and net credit so the buyer that paid it is excluded from it.","line":215,"path":"src/SHITPAPERToken.sol","reproduction":"FactoryStub (mapping(uint64=>address) public distributorOf) deploys SHITPAPERToken(factory, 0x000000000004444c5dc75cB358380D2e3dE08A90, 947); factory.setDistributor(947, 0xD157); factory.transfer(0xD157, 1e26); factory.transfer(PM, 9e26) -> eligibleSupply()==0. 1) vm.prank(PM); token.transfer(ALICE, 1_000_000e18): pendingDistribution()==30_000e18, balanceOf(ALICE)==970_000e18, claimableDividendOf(ALICE)==0. 2) vm.prank(PM); token.transfer(BOB, 1_000e18). Expected per M1: ALICE's claimable is at most BOB's 30e18 fee. Actual: claimableDividendOf(ALICE)==30_029_999_999_999_999_999_999; vm.prank(ALICE); token.claim() leaves ALICE with 1_000_029_999_999_999_999_999_999 tokens for a 1_000_000e18 gross buy. Verified by test/scratch/Repro.t.sol::test_firstBuyerGetsOwnFeeBack (passes against this tree).","severity":"low","snippet":"        amount += pendingDistribution;","title":"Fee parked while eligibleSupply == 0 is paid to whoever is eligible at the next buy, so the first buyer gets its own 3% fee back"},{"citation":"resolved","description":"On first resolution the code assumes everything the distributor holds was previously counted in eligibleSupply and subtracts balanceOf(dist) unconditionally. That is false if factory.distributorOf(launchNumber) answers an address _isExcluded() already hard-codes (the PoolManager, this contract, or 0xdEaD): their balances were never added. If eligibleSupply < held the subtraction panics (0x11); because _resolveDistributor() runs at the top of every _update() and _claim() and the cache write is rolled back by the revert, every transfer, transferFrom, claim and claimFor reverts from then on, including the PoolManager's take during swaps, with no owner or recovery path. If eligibleSupply >= held it silently succeeds and breaks the invariant eligibleSupply == sum(eligible balances): later sells underflow at line 191 and distributions are credited against too small a supply. Precondition: a misconfigured launch factory (the real factory deploys a fresh MerkleDistributor per launch), hence low rather than high. Merged: audit_math finding 1 and audit_flow finding 2 (same root cause). Minimal fix: only adjust eligibleSupply when the resolved address was not already in the hard-coded excluded set (or skip the adjustment when held > eligibleSupply).","line":275,"path":"src/SHITPAPERToken.sol","reproduction":"Same FactoryStub as finding 1. factory.transfer(PM, 9e26); factory.transfer(0xdEaD, 1e26) -> eligibleSupply()==0. factory.setDistributor(947, 0xdEaD). vm.prank(PM); token.transfer(ALICE, 1000e18): expected a normal 3% buy; actual: reverts Panic(0x11) at line 275 (0 - 1e26). Afterwards vm.prank(PM); token.transfer(PM, 1) and token.claimFor(ALICE) revert the same way and distributor() stays 0. Variant with address(token): after launch and two buys of 1000e18 (ALICE 970e18, BOB 970e18, contract holds 60e18, eligibleSupply 1940e18), factory.setDistributor(947, address(token)); vm.prank(ALICE); token.transfer(BOB, 1) -> eligibleSupply()==1880e18 although eligible balances sum to 1940e18; vm.prank(BOB); token.transfer(PM, 970e18+1) succeeds; vm.prank(ALICE); token.transfer(PM, 970e18-1) reverts Panic(0x11) at line 191. Verified by test/scratch/Repro.t.sol::test_alreadyExcludedDistributorBricks and ::test_tokenAsDistributorCorruptsEligibleSupply.","severity":"low","snippet":"            eligibleSupply -= held;","title":"_resolveDistributor subtracts the resolved address's balance from eligibleSupply even if that address was never counted; a factory naming an already-excluded address bricks every transfer or corrupts "},{"citation":"resolved","description":"isExcludedFromDividends (line 145), isTaxedTransfer (line 150) and claimableDividendOf (line 139) answer from _knownDistributor(), i.e. the storage cache, which is only written inside a state-changing call. _update (line 165) and _claim (line 200) call _resolveDistributor(), which staticcalls the factory and treats a non-zero answer as excluded immediately. Once the factory has registered the distributor but before any transfer or claim has succeeded, the views report the distributor as an ordinary taxed, dividend-earning holder while the writers already treat it as excluded and fee-exempt. A reverting claimFor(distributor) does not close the window because the revert rolls the cache write back. No funds are at risk; off-chain readers and integrators are told the opposite of what the contract does. Minimal fix: give the views a view-only resolver that performs the same staticcall when the cache is empty.","line":255,"path":"src/SHITPAPERToken.sol","reproduction":"Same FactoryStub. factory.setDistributor(947, 0xD157) and make no transfer. Expected: isExcludedFromDividends(0xD157)==true and isTaxedTransfer(PM, 0xD157)==false. Actual: distributor()==0, isExcludedFromDividends(0xD157)==false, isTaxedTransfer(PM, 0xD157)==true; yet token.claimFor(0xD157) reverts ExcludedFromDividends(0xD157) and leaves the views unchanged; then factory.transfer(PM, 9e26); vm.prank(PM); token.transfer(0xD157, 1000e18) arrives whole (balanceOf==1000e18, no fee) although the view had said it was taxed; only now does isExcludedFromDividends(0xD157) flip to true. Verified by test/scratch/Repro.t.sol::test_viewWriterAsymmetry.","severity":"low","snippet":"        return distributor;","title":"View functions read the cached distributor while transfers and claims resolve it live, so the views contradict the writers between the factory's registration and the first successful transfer"},{"citation":"resolved","description":"Fees are credited against eligibleSupply as it stands at the instant of each buy, with no holding period, and sells pay no fee. A searcher who sees a large buy can buy first (paying 3% plus the 1.25% pool fee), receive the share of the victim's 3% proportional to its balance over the eligible supply, claimFor, and sell back untaxed in the same block paying only the pool fee. This is profitable when the victim's buy exceeds roughly 1.8x the eligible supply, which is realistic early in the pool's life. Likewise, right after launch eligibleSupply is 0, so a 34-wei first buy becomes 100% of the eligible supply and is credited 3% of the next real buy. Both follow directly from M1 (pro rata to balance at the buy, buyer checkpointed on its pre-buy balance) and are not implementation defects; a mitigation (holding period, time-weighted accrual, taxed sells) would change the agreed design and is a scope decision. Merged: audit_economics finding 2, audit_flow finding 3, audit_permissions finding 2.","line":224,"path":"src/SHITPAPERToken.sol","reproduction":"After the launch flow: vm.prank(PM); token.transfer(ALICE, 1_000_000e18); vm.prank(PM); token.transfer(BOB, 1e18) (flushes pending). Attacker front-runs: vm.prank(PM); token.transfer(ATTACKER, 10_000_000e18) (pays 300_000e18). Victim: vm.prank(PM); token.transfer(BOB, 10_000_000e18) (pays 300_000e18). token.claimFor(ATTACKER) pays 272_727_247_933_886_551_464_858 (~90.9% of the victim's fee); ATTACKER then transfers its whole balance to PM with no fee. Dust variant: from eligibleSupply 0, vm.prank(PM); token.transfer(ALICE, 34) -> eligibleSupply 33; vm.prank(PM); token.transfer(BOB, 1_000_000e18) -> claimableDividendOf(ALICE)==30_000e18, claimableDividendOf(BOB)==0. Verified by test/scratch/Repro.t.sol::test_sandwich and ::test_tinyFirstHolder.","severity":"info","snippet":"        rewardPerTokenStored += amount * PRECISION / supply;","title":"Instant pro-rata snapshot with untaxed sells: a front-run buy captures most of a large buy's fee and a dust-sized first holder captures the whole next fee (design property of M1, for the requester's a"}],"hash":"6b68096e017a0c6a57409ece7f5c784cc478ebe8c3969dad4ddc1bea4d95689f","nodeId":"f354999d-4c84-497f-b21d-18843a4dfc99","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds the result. No tracked file was changed; only the findings file and my scratch test under `test/scratch/` were created.\n\n**Outcome.** The token is sound for its launch: the build is reproducible, the supply is minted whole to the factory, settlement with the v4 PoolManager balances exactly, and no entry point loses or freezes funds under the documented factory. The existing suite of 67 tests passes. I kept four findings, none above low, each reproduced with a scratch test that passes against this tree.\n\n**Findings kept**\n1. **Low, parked first-buy fee refunded.** With nobody eligible after launch, the first buy's fee is parked and then credited at the next buy to the first buyer, who recovers its own fee. This contradicts M1's \"buyer never shares in its own fee\". Merged from the economics specialist.\n2. **Low, distributor resolution underflow.** If the factory ever names an already-excluded address as distributor, the balance subtraction panics on every transfer, or silently corrupts the eligible supply. Requires a misconfigured factory, so low. Merged from the math and flow specialists.\n3. **Low, view and writer disagree.** Between registration and the first transfer, the view functions report the distributor as taxed and eligible while transfers and claims already treat it as excluded. Merged from the permissions specialist.\n4. **Info, instant pro-rata snapshot.** A front-run buy captures most of a large buy's fee and exits untaxed, and a 34-wei first holder takes the whole next fee. This is the behaviour M1 asks for, recorded for the requester's awareness. Merged from three specialists.\n\n**Dropped.** The factory-ABI mismatch and the dirty 32-byte word findings rest on a factory interface that contradicts the protected harness, which declares a plain uint64-keyed getter. The 33-wei fee floor is 1 wei of dust in the buyer's favour and is documented as intended.\n\n**Coverage.** All five entry points are answered, plus four invariant and build rows. Transfer and transferFrom are marked against finding 1 since both share the hook where the refund lives.","treeHash":null,"usage":{"cachedInputTokens":793023,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":26252,"runtime":"claude","turns":13,"wallClockMs":394415}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ca080fd306399669","findings":[{"citation":"resolved","description":"M1 says the buyer never shares in its own fee. Right after launch every token sits in the PoolManager, the Merkle distributor and 0xdEaD, all excluded, so eligibleSupply is 0. The first buy's fee cannot be distributed and is parked in pendingDistribution. The first buyer's net amount is then credited and it becomes 100% of the eligible supply. On the next buy, _distribute adds the parked fee to the new fee and credits all of it against eligibleSupply, i.e. entirely to the first buyer. The first buyer therefore gets its own fee back in full (minus 1 wei of floor rounding) and additionally earns the second buyer's whole fee. More generally, whenever all eligible holders have sold out, the next buyer's fee is refunded to that buyer on the following buy. Combined with the spec-prescribed ordering (fee distributed against the pre-buy eligible supply, which includes the buyer's existing balance), an early dominant holder pays an effective buy fee near zero: with 970 tokens eligible and a 10,000,000 buy, 299,700 of the 300,000 fee returns to the buyer. The second effect is what M1 prescribes and is noted for context; the pending refund is not described by the brief. Economic impact is bounded (3% of the first buy, no compounding), so low. Fix option that preserves the design: when supply == 0, keep the fee in the contract but do not credit it to the next distribution (treat it like the rounding residue), or credit pending only against eligible supply that excludes the buyer in that buy by distributing pending after the buyer's checkpoint is set.","line":217,"path":"src/SHITPAPERToken.sol","reproduction":"State after launch: factory transferred 10% to the distributor (registered via distributorOf), 90% to PM = 0x000000000004444c5dc75cB358380D2e3dE08A90, eligibleSupply == 0. 1) vm.prank(PM); token.transfer(A, 1_000_000e18): fee 30_000e18, pendingDistribution == 30_000e18, claimableDividendOf(A) == 0, balanceOf(A) == 970_000e18. 2) vm.prank(PM); token.transfer(B, 1_000e18): fee 30e18, _distribute(30e18 + 30_000e18) against eligibleSupply 970_000e18. Actual: claimableDividendOf(A) == 30_029_999_999_999_999_999_999 (30,030e18 - 1 wei), A.claim() pays that and A ends with 1,000,029.99e18 tokens for a 1,000,000e18 gross buy: it paid no fee at all and collected B's. Expected per M1: A never receives its own 30_000e18 fee; A's claimable after step 2 should be at most 30e18 (B's fee).","severity":"low","snippet":"        if (supply == 0) {\n            pendingDistribution = amount;\n            return;\n        }","title":"First buyer recovers its own 3% fee: fees parked while eligibleSupply == 0 are paid to whoever is eligible at the next buy"},{"citation":"resolved","description":"Fees are distributed instantly and pro rata to balances at the moment of the buy, with no holding period, and sells are untaxed. An MEV searcher who sees a large buy in the mempool can buy first (paying 3% + 1.25% pool fee), receive a share of the victim's 3% fee proportional to its balance over the eligible supply, claim, and sell back in the same block paying only the 1.25% pool fee. Gain = 0.03 * V * a / (E + a); cost = 0.03 * a + 2 * 0.0125 * a + slippage, so it is profitable whenever V > ~1.83 * (E + a), which is realistic in the early life of the pool when E (eligible supply) is small and buys are large relative to it. This is inherent to the mechanics M1 asks for (instant pro-rata distribution, untaxed sells), so it is reported as an economic property for the author to accept knowingly, not as an implementation defect. Mitigations would change the agreed design (e.g. a minimum holding period before accrual, or taxing sells).","line":224,"path":"src/SHITPAPERToken.sol","reproduction":"State after launch as in finding 1. 1) PM.transfer(holder, 5_000_000e18); PM.transfer(X, 1e18) to flush pending; eligibleSupply == 4_850_000.97e18. 2) Attacker front-runs: PM.transfer(attacker, 20_000_000e18): attacker pays 600_000e18 fee, holds 19_400_000e18. 3) Victim: PM.transfer(victim, 50_000_000e18): fee 1_500_000e18 distributed against 24_250_000.97e18 eligible. Actual: claimableDividendOf(attacker) == 1_199_999_952_000_001_919_999_923 (~1.2M tokens); attacker.claim() then attacker.transfer(PM, balance) is untaxed. Net before pool fees: +599_999.95e18 tokens; after 2 x 1.25% pool fee on ~20M (~492k tokens equivalent) still positive. The victim and existing holders receive correspondingly less of the victim's fee (holder 5M gets 1.5M * 4.85/24.25 = 300k instead of 1.5M).","severity":"info","snippet":"        rewardPerTokenStored += amount * PRECISION / supply;","title":"Dividend sandwich: a front-run buy before a large buy captures a share of the victim's fee and exits untaxed, profitable when the large buy exceeds roughly 1.8x the eligible supply"}],"hash":"8d400bc2e7d5ea191f45bb49205094d64d425abc4df5c8dccaa6a650e90a78ec","nodeId":"64a7ad3e-d3e9-4886-babe-5088844fe0da","outcome":"completed","summary":"The review is complete and the findings file is written. The git status is clean apart from the untracked findings file (it is ignored by `.gitignore` or shows nothing to change), the scratch directory is removed, and both snippets match the source lines exactly.\n\n**Outcome:** no critical, high or medium defects in `src/SHITPAPERToken.sol` from the Economic Security, Invariant and Flow Gap lenses. Two economic observations are recorded in `.imd-findings.json`, both with concrete reproductions I ran in Foundry.\n\n**Findings**\n- **Low: first buyer recovers its own fee.** Right after launch the eligible supply is zero, so the first buy's 3% fee is parked in `pendingDistribution`. The next buy pays it out entirely to the first buyer, who then holds 100% of the eligible supply. For a 1,000,000-token first buy, the buyer gets its 30,000 fee back (minus 1 wei) plus the second buyer's fee. The brief says the buyer never shares in its own fee. Impact is bounded and non-compounding.\n- **Info: dividend sandwich.** Instant pro-rata distribution with untaxed sells lets a searcher front-run a large buy, collect part of the victim's fee, claim and exit. With 4.85M eligible, a 20M front-run and a 50M victim buy nets about 600k tokens before pool fees. This is inherent to the mechanics the brief asks for, so it is recorded for the author to accept knowingly.\n\n**What held**\n- Fee only on transfers out of the PoolManager, nothing on sells or the seed, so v4 settlement balances. The repo's own suite exercises this against a real PoolManager built at the mainnet address.\n- `eligibleSupply` stays equal to the sum of non-excluded balances across every writer, including late distributor resolution.\n- The contract always holds at least what it owes plus pending. Accumulator arithmetic cannot overflow at any realistic volume.\n- `claim` and `claimFor` pay only the account itself, revert for excluded accounts, and make no external call beyond a staticcall to the factory.\n- Supply is fixed, no owner, no delegatecall or selfdestruct in source or vendored OpenZeppelin files, no submodules, and `launch.json` matches the brief's keys, values and lowercase addresses.\n\n**Coverage:** all five entry points have rows (approve, claim, claimFor hold; transfer and transferFrom reference finding 1), plus five invariant rows. Not reached: a fork run against live mainnet and the real factory's `distributorOf`, which no network here allows. LP liquidity removals are taxed 3% because the brief defines any transfer from the PoolManager as a buy; noted as spec-intended.","treeHash":null,"usage":{"cachedInputTokens":1152510,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":24273,"runtime":"claude","turns":17,"wallClockMs":446898}},{"artifacts":[],"attempt":1,"bundleHash":"6ead2d85d4436b004e513df1341cd4ba99790ee510874d6bbb89c7e9170669cf","device":"fa99051b60a858d6","findings":[],"hash":"a66384dd8c1bdd1c928b26b290102a4565140afd4e1085595e763df19f065a6f","nodeId":"48c0eee5-ebf0-4cf1-8458-5030b884c42d","outcome":"completed","summary":"`launch.json` is complete and verified against the accepted implementation. Only that file changed.\n\n**What the manifest describes**\n\n- Token `SHITPAPERToken`, name shitpaper, symbol SHITPAPER, 18 decimals, totalSupply 1000000000000000000000000000. That is exactly what the constructor mints to msg.sender.\n- constructorArgs `$factory`, `$poolManager`, `$launchNumber`, matching the declared order `(address, address, uint64)` in src/SHITPAPERToken.sol.\n- contracts is an empty list. The accepted tree has no application contracts.\n- pool copied from the task: IMD pair address in lowercase, fee 12500, tickSpacing 60, initialPrice \"125270724187523965593206900\".\n- economics copied verbatim from the job.\n- Six top-level keys only, no chainId. Notes is one string of about 1200 characters.\n\n**What I changed**\n\nThe manifest from earlier accepted work was already correct, so I kept it and only tightened the notes. The closing sentence now names the constructor signature and states that the factory, not the manifest, seeds the pool and forwards the remainder. The earlier wording about the swarm's share is gone so the notes don't read as an allocation claim.\n\n**Checks**\n\n- JSON parses, key sets for token, pool and economics match the schema, fee, tickSpacing and decimals are numbers, every uint256 and address is a string.\n- `forge build` succeeds with solc 0.8.26.\n- `forge test` passes 67 of 67 tests across 5 suites, including the in-place Uniswap v4 PoolManager suite and the invariant suite.\n- The protected harness requirements all hold in the source: whole supply minted to the deployer, no fee on transfers to the PoolManager or from the factory, no delegatecall or selfdestruct, no owner.\n\nStill owed outside this run: a fork test against live mainnet state, since neither this machine nor the verifier has network access.","treeHash":"012f7184ef4272f92988d89c6b0cfb46976cb043","usage":{"cachedInputTokens":220612,"inputTokens":130,"model":"claude-fable-5-1","outputTokens":3782,"runtime":"claude","turns":10,"wallClockMs":81880}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ea89e16822824c6f","findings":[],"hash":"c7a803f6acfb9178859341772c16ff021f0d5cf0d7b122a81f4a53ca9870a11e","nodeId":"a7f57c91-16c3-428c-9870-8e6a9729c1f1","outcome":"failed","summary":"bundle upload failed: fetch failed","treeHash":null,"usage":{"cachedInputTokens":1219494,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":49833,"runtime":"claude","turns":37,"wallClockMs":660022}},{"artifacts":[],"attempt":2,"bundleHash":"022c2bb6afbb33f178ce7ef303491ac30b9ae52ec6c68733d22d7dd52f73b1da","device":"ee9fbaf2480d1034","findings":[],"hash":"e487f40c291efe46133f57033962f308128ebaf7ba6b0a5ee542e77fcc41bbe5","nodeId":"a7f57c91-16c3-428c-9870-8e6a9729c1f1","outcome":"completed","summary":"The work is committed on main with a clean tree and no submodules.\n\n**Delivered** (all at the repository root):\n- `src/SHITPAPERToken.sol`: fixed supply of 1e27 units minted once to the deployer, no owner or admin surface, no delegatecall or selfdestruct. A 3% fee applies only to transfers whose sender is the PoolManager and is distributed to eligible holders before the buyer's net amount is credited. Transfers to the PoolManager and wallet-to-wallet transfers pay nothing. The PoolManager, the token contract, the burn address and the Merkle distributor are excluded. The distributor is read lazily from the factory's `distributorOf(uint64)` at transfer time and cached, so the constructor calls nothing.\n- `foundry.toml`: solc 0.8.26, cancun, optimizer on, bytecode hash none, no ffi or filesystem permissions.\n- `launch.json` with exactly the required keys, constructor args `$factory`, `$poolManager`, `$launchNumber`, the IMD pair at fee 12500 and tick spacing 60, and the economics block verbatim.\n- `test/SHITPAPERToken.t.sol`: 17 smoke tests covering deploy and supply, untaxed swarm and seed flows, the buy fee, pro-rata distribution, buyer exclusion from its own fee, claim and claimFor, excluded-account reverts, allowance and balance failures.\n- Vendored forge-std v1.9.7 and the five OpenZeppelin v5.3.0 files the token imports, as plain files under `lib/`.\n- `README.md` documenting mechanics, launch flow, assumptions and open items.\n\n**Verification**: `forge build`, `forge test` (17 passed) and `forge fmt --check` all pass. In a scratch project I also drove the token through a real Uniswap v4 PoolManager built at the mainnet address: the seed went through, a buy paid exactly 3%, a second buy distributed to the first trader, claimFor paid out, and the sell settled exactly. The runtime bytecode has no DELEGATECALL, CALLCODE or SELFDESTRUCT.\n\n**One design fix worth knowing**: an early version returned per-distribution rounding remainders to a pending bucket, which could leave the contract a few wei short of claims. The whole fee is now counted as distributed and the dust stays in the contract, so it always holds at least what it owes.\n\n**Still owed by later contributors**: the full fuzz and invariant suite, a fork run against live mainnet state, and an independent adversarial review.","treeHash":"2e51ec527bd5cd10c8291a63603dec827deb989c","usage":{"cachedInputTokens":1084706,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":48676,"runtime":"claude","turns":25,"wallClockMs":648099}}],"verification":[{"checks":[{"durationMs":3408,"exitCode":0,"name":"build","output":"Compiling 77 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.15s\nCompiler run successful!\n","passed":true},{"durationMs":3385,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 9 tests for test/SHITPAPERToken.v4.t.sol:SHITPAPERTokenV4Test\n[PASS] testFuzz_buyThenSellSettlesForAnyAmount(uint256) (runs: 64, μ: 1348430, ~: 1348627)\nLogs:\n  Bound result 314183877839617354627\n\n[PASS] test_buyTakenToAnotherWalletTaxesTheRecipient() (gas: 1159962)\n[PASS] test_buyThroughSwapPaysThreePercentToTheContract() (gas: 1218728)\n[PASS] test_claimedDividendsCanBeSoldWhole() (gas: 2435171)\n[PASS] test_exactOutputBuyDeliversNetOfFee() (gas: 1134197)\n[PASS] test_poolKeepsWorkingAcrossManyRoundTrips() (gas: 7032299)\n[PASS] test_secondBuyDistributesPendingAndNewFeeToFirstBuyer() (gas: 2200642)\n[PASS] test_seedSettlesExactlyAndPaysNoFee() (gas: 78360)\n[PASS] test_sellThroughSwapIsNotTaxedAndSettles() (gas: 1345841)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 61.72ms (43.43ms CPU time)\n\nRan 17 tests for test/SHITPAPERToken.t.sol:SHITPAPERTokenTest\n[PASS] test_buyDistributesProRataToPriorHolders() (gas: 717092)\n[PASS] test_buyPaysThreePercentToTheContract() (gas: 444740)\n[PASS] test_buyToExcludedRecipientIsNotTaxed() (gas: 308168)\n[PASS] test_buyerSharesOnPreBuyBalanceButNotOnNetAmount() (gas: 674520)\n[PASS] test_claimForExcludedAccountReverts() (gas: 330890)\n[PASS] test_claimForPaysTheHolderNotTheCaller() (gas: 610842)\n[PASS] test_claimPaysOutAndStopsDoubleClaims() (gas: 701402)\n[PASS] test_contractBalanceCoversPendingAndUnclaimed() (gas: 745642)\n[PASS] test_deploy_mintsWholeSupplyToDeployer() (gas: 102477)\n[PASS] test_deploy_revertsOnZeroAddresses() (gas: 3943)\n[PASS] test_noMintOrAdminSurface() (gas: 156510)\n[PASS] test_seedAndSellToPoolManagerAreNotTaxed() (gas: 246716)\n[PASS] test_swarmShareArrivesWholeAndIsClaimableWhole() (gas: 288503)\n[PASS] test_transferAfterAccrualKeepsDividendsWithTheEarner() (gas: 820528)\n[PASS] test_transferFromRequiresAllowance() (gas: 115530)\n[PASS] test_transferRevertsOnInsufficientBalance() (gas: 49588)\n[PASS] test_walletToWalletTransferIsNotTaxed() (gas: 189242)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 93.16ms (24.71ms CPU time)\n\nRan 25 tests for test/SHITPAPERToken.edge.t.sol:SHITPAPERTokenEdgeTest\n[PASS] test_burnAddressAccumulatesWithoutEarning() (gas: 652456)\n[PASS] test_buyEmitsFeeTransferAndDistributionEvents() (gas: 549468)\n[PASS] test_buyToFeeExemptRecipientsIsNotTaxed() (gas: 659938)\n[PASS] test_claimEmitsEventsAndTransferFromTheContract() (gas: 659779)\n[PASS] test_claimForZeroAddressReverts() (gas: 300372)\n[PASS] test_claimWithNothingOwedPaysZeroAndEmitsNothing() (gas: 302549)\n[PASS] test_contractHolderIsPaidThroughClaimFor() (gas: 752796)\n[PASS] test_deployerWithoutCodeLeavesTheDistributorUnknownAndTransfersWork() (gas: 122496)\n[PASS] test_differentLaunchNumberReadsItsOwnDistributor() (gas: 290329)\n[PASS] test_distributorFundedBeforeRegistrationIsRemovedFromEligibleSupplyOnResolution() (gas: 709105)\n[PASS] test_distributorIsCachedOnceAndNotReReadIfTheFactoryChangesIt() (gas: 449344)\n[PASS] test_distributorResolvedWhileItIsTheRecipientDoesNotDoubleCount() (gas: 219666)\n[PASS] test_distributorResolvedWhileItIsTheSenderDoesNotDoubleCount() (gas: 238483)\n[PASS] test_hugeFeeAgainstOneWeiOfEligibleSupplyDoesNotOverflowLater() (gas: 1033410)\n[PASS] test_malformedFactoryAnswerIsIgnored() (gas: 405202)\n[PASS] test_manyTinyDistributionsNeverMakeTheContractInsolvent() (gas: 9051728)\n[PASS] test_parametersAreTheBriefsConstants() (gas: 49531)\n[PASS] test_privilegedCallsNeitherMoveNorFreezeAHolder() (gas: 505325)\n[PASS] test_revertingFactoryLookupDoesNotBlockTransfers() (gas: 674600)\n[PASS] test_runtimeCodeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 5344965)\n[PASS] test_selfTransferChangesNothing() (gas: 744528)\n[PASS] test_tokensSentToTheContractAreNotRedistributed() (gas: 635279)\n[PASS] test_unresolvedDistributorIsTaxedAndEligibleUntilTheFactoryRegistersIt() (gas: 32568)\n[PASS] test_viewsAgreeWithState() (gas: 354437)\n[PASS] test_zeroAmountTransfersSucceedAndChargeNothing() (gas: 379289)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 95.05ms (44.90ms CPU time)\n\nRan 15 tests for test/SHITPAPERToken.fuzz.t.sol:SHITPAPERTokenFuzzTest\n[PASS] testFuzz_allowanceIsEnforcedExactly(uint256,uint256,uint256) (runs: 256, μ: 274507, ~: 254534)\nLogs:\n  Bound result 2910000000000000000000\n  Bound result 2480214288758848287446\n  Bound result 50\n\n[PASS] testFuzz_buyFeeIsExactlyThreePercentFloored(uint256) (runs: 256, μ: 276342, ~: 280770)\nLogs:\n  Bound result 3\n\n[PASS] testFuzz_buyerEarnsOnPreBuyBalanceOnly(uint256,uint256,uint256) (runs: 256, μ: 427545, ~: 437001)\nLogs:\n  Bound result 2910000000000000000000\n  Bound result 245571306825368186193864038\n  Bound result 50\n\n[PASS] testFuzz_claimForPaysTheHolderNeverTheCaller(address,uint256,uint256) (runs: 256, μ: 450752, ~: 453816)\nLogs:\n  Bound result 147677953117403025164380424\n  Bound result 160374547216649340840082706\n\n[PASS] testFuzz_claimPaysExactlyClaimableOnceAndContractStaysSolvent(uint256,uint256,uint256) (runs: 256, μ: 698537, ~: 707712)\nLogs:\n  Bound result 205155115602055675861011100\n  Bound result 6065\n  Bound result 174949365440155955315320607\n\n[PASS] testFuzz_dustBuysBelowThirtyFourWeiPayNothing(uint256) (runs: 256, μ: 196135, ~: 198791)\nLogs:\n  Bound result 31\n\n[PASS] testFuzz_excludedAccountsNeverAccrueAndCannotClaim(uint256,uint256) (runs: 256, μ: 630724, ~: 630781)\nLogs:\n  Bound result 31133536184691190762091847\n  Bound result 35\n\n[PASS] testFuzz_feeIsSplitProRataOnPreBuyBalances(uint256,uint256,uint256) (runs: 256, μ: 523546, ~: 523468)\nLogs:\n  Bound result 2910000000000000000000\n  Bound result 245571306825368186193864038\n  Bound result 50\n\n[PASS] testFuzz_infiniteAllowanceIsNotDecremented(uint256,uint256) (runs: 256, μ: 289320, ~: 290220)\nLogs:\n  Bound result 31133536184691190762091847\n  Bound result 1\n\n[PASS] testFuzz_movingTokensMovesFutureNotPastDividends(uint256,uint256,uint256) (runs: 256, μ: 657370, ~: 659089)\nLogs:\n  Bound result 205555345212223559994508408\n  Bound result 6065\n  Bound result 58883378398725560139929797\n\n[PASS] testFuzz_pendingFeeIsPaidWithTheNextDistribution(uint256,uint256) (runs: 256, μ: 440523, ~: 440557)\nLogs:\n  Bound result 30069493068510363666794723\n  Bound result 35\n\n[PASS] testFuzz_sellsAndWalletTransfersPayNothing(uint256,uint256,uint256) (runs: 256, μ: 332520, ~: 334520)\nLogs:\n  Bound result 2910000000000000000000\n  Bound result 2480214288758848287446\n  Bound result 50\n\n[PASS] testFuzz_transferAboveBalanceReverts(uint256,uint256) (runs: 256, μ: 353694, ~: 355290)\nLogs:\n  Bound result 161488565478082017978238420\n  Bound result 115792089237316195423570985008687907853269984665640402550892105925895151724531\n\n[PASS] testFuzz_transferFromThePoolManagerIsTaxedWhoeverSpends(uint256,address) (runs: 256, μ: 290830, ~: 290704)\nLogs:\n  Bound result 20575\n\n[PASS] testFuzz_transferToZeroAddressReverts(uint256) (runs: 256, μ: 219906, ~: 219679)\nLogs:\n  Bound result 517440285\n\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 104.51ms (1.10s CPU time)\n\nRan 1 test for test/SHITPAPERToken.invariant.t.sol:SHITPAPERTokenInvariantTest\n[PASS]\nSHITPAPERTokenInvariantTest invariants:\n[PASS] invariant_contractHoldsWhatItOwesAndNotMuchMore\n[PASS] invariant_eligibleSupplyIsTheSumOfEligibleBalances\n[PASS] invariant_excludedAccountsNeverEarn\n[PASS] invariant_feesAreAccountedFor\n[PASS] invariant_supplyIsFixed\n SHITPAPERTokenInvariantTest invariants (runs: 256, calls: 10240, reverts: 0)\n\n╭----------+------------------+-------+---------+----------╮\n| Contract | Selector         | Calls | Reverts | Discards |\n+==========================================================+\n| Handler  | burn             | 968   | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | buy              | 1048  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | claim            | 1051  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | claimFor         | 1057  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | claimForExcluded | 1021  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | distributorClaim | 1016  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | donate           | 1017  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | sell             | 1030  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | transfer         | 986   | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | transferFrom     | 1046  | 0       | 0        |\n╰----------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 73037589521787522327808731\n  Bound result 9810\n  Bound result 0\n  Bound result 0\n  Bound result 75000000000000000000\n  Bound result 0\n  Bound result 1023\n  Bound result 18647405999331808266777764\n  Bound result 16667925092151535058316656\n  Bound result 4219959539008069801322101\n  Bound result 0\n  Bound result 312\n  Bound result 6836\n  Bound result 244\n  Bound result 10000000000000000000000\n  Bound result 750\n  Bound result 91011000000000000000000\n  Bound result 0\n  Bound result 6835\n  Bound result 0\n  Bound result 217088114446308776523301\n  Bound result 65536\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.26s (3.23s CPU time)\n\nRan 5 test suites in 3.27s (3.61s CPU time): 67 tests passed, 0 failed, 0 skipped (67 total tests)\n","passed":true},{"durationMs":86,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SHITPAPERToken.approve(address,uint256)\",\"SHITPAPERToken.claim()\",\"SHITPAPERToken.claimFor(address)\",\"SHITPAPERToken.transfer(address,uint256)\",\"SHITPAPERToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":103,\"foundry.toml\":17,\"launch.json\":24,\"src/SHITPAPERToken.sol\":279,\"test/SHITPAPERToken.edge.t.sol\":437,\"test/SHITPAPERToken.fuzz.t.sol\":297,\"test/SHITPAPERToken.invariant.t.sol\":248,\"test/SHITPAPERToken.t.sol\":287,\"test/SHITPAPERToken.v4.t.sol\":444,\"test/vendor/README.md\":7,\"test/vendor/solmate/src/auth/Owned.sol\":44,\"test/vendor/v4-core/licenses/BUSL_LICENSE\":63,\"test/vendor/v4-core/licenses/MIT_LICENSE\":7,\"test/vendor/v4-core/src/ERC6909.sol\":90,\"test/vendor/v4-core/src/ERC6909Claims.sol\":23,\"test/vendor/v4-core/src/Extsload.sol\":64,\"test/vendor/v4-core/src/Exttload.sol\":40,\"test/vendor/v4-core/src/NoDelegateCall.sol\":33,\"test/vendor/v4-core/src/PoolManager.sol\":394,\"test/vendor/v4-core/src/ProtocolFees.sol\":71,\"test/vendor/v4-core/src/interfaces/IExtsload.sol\":21,\"test/vendor/v4-core/src/interfaces/IExttload.sol\":15,\"test/vendor/v4-core/src/interfaces/IHooks.sol\":152,\"test/vendor/v4-core/src/interfaces/IPoolManager.sol\":217,\"test/vendor/v4-core/src/interfaces/IProtocolFees.sol\":52,\"test/vendor/v4-core/src/interfaces/callback/IUnlockCallback.sol\":10,\"test/vendor/v4-core/src/interfaces/external/IERC20Minimal.sol\":48,\"test/vendor/v4-core/src/interfaces/external/IERC6909Claims.sol\":66,\"test/vendor/v4-core/src/libraries/BitMath.sol\":49,\"test/vendor/v4-core/src/libraries/CurrencyDelta.sol\":42,\"test/vendor/v4-core/src/libraries/CurrencyReserves.sol\":39,\"test/vendor/v4-core/src/libraries/CustomRevert.sol\":120,\"test/vendor/v4-core/src/libraries/FixedPoint128.sol\":8,\"test/vendor/v4-core/src/libraries/FixedPoint96.sol\":10,\"test/vendor/v4-core/src/libraries/FullMath.sol\":117,\"test/vendor/v4-core/src/libraries/Hooks.sol\":344,\"test/vendor/v4-core/src/libraries/LPFeeLibrary.sol\":79,\"test/vendor/v4-core/src/libraries/LiquidityMath.sol\":20,\"test/vendor/v4-core/src/libraries/Lock.sol\":28,\"test/vendor/v4-core/src/libraries/NonzeroDeltaCount.sol\":35,\"test/vendor/v4-core/src/libraries/ParseBytes.sol\":29,\"test/vendor/v4-core/src/libraries/Pool.sol\":620,\"test/vendor/v4-core/src/libraries/Position.sol\":103,\"test/vendor/v4-core/src/libraries/ProtocolFeeLibrary.sol\":47,\"test/vendor/v4-core/src/libraries/SafeCast.sol\":60,\"test/vendor/v4-core/src/libraries/SqrtPriceMath.sol\":292,\"test/vendor/v4-core/src/libraries/StateLibrary.sol\":345,\"test/vendor/v4-core/src/libraries/SwapMath.sol\":108,\"test/vendor/v4-core/src/libraries/TickBitmap.sol\":121,\"test/vendor/v4-core/src/libraries/TickMath.sol\":238,\"test/vendor/v4-core/src/libraries/TransientStateLibrary.sol\":48,\"test/vendor/v4-core/src/libraries/UnsafeMath.sol\":29,\"test/vendor/v4-core/src/types/BalanceDelta.sol\":72,\"test/vendor/v4-core/src/types/BeforeSwapDelta.sol\":38,\"test/vendor/v4-core/src/types/Currency.sol\":118,\"test/vendor/v4-core/src/types/PoolId.sol\":17,\"test/vendor/v4-core/src/types/PoolKey.sol\":22,\"test/vendor/v4-core/src/types/PoolOperation.sol\":26,\"test/vendor/v4-core/src/types/Slot0.sol\":95},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"23699f52dd48636da5b2887ae76b0be8150cb04e735e39ac8a7f962b95091320","verifiedTreeHash":"9c81382585ab1dfec3231115afcd28fd28c2e29a","verifierVersion":"0.1.0+c4d32abc"},{"checks":[{"durationMs":3216,"exitCode":0,"name":"build","output":"Compiling 77 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.05s\nCompiler run successful!\n","passed":true},{"durationMs":3517,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 9 tests for test/SHITPAPERToken.v4.t.sol:SHITPAPERTokenV4Test\n[PASS] testFuzz_buyThenSellSettlesForAnyAmount(uint256) (runs: 64, μ: 1348465, ~: 1348627)\nLogs:\n  Bound result 30000000000000000000\n\n[PASS] test_buyTakenToAnotherWalletTaxesTheRecipient() (gas: 1159962)\n[PASS] test_buyThroughSwapPaysThreePercentToTheContract() (gas: 1218728)\n[PASS] test_claimedDividendsCanBeSoldWhole() (gas: 2435171)\n[PASS] test_exactOutputBuyDeliversNetOfFee() (gas: 1134197)\n[PASS] test_poolKeepsWorkingAcrossManyRoundTrips() (gas: 7032299)\n[PASS] test_secondBuyDistributesPendingAndNewFeeToFirstBuyer() (gas: 2200642)\n[PASS] test_seedSettlesExactlyAndPaysNoFee() (gas: 78360)\n[PASS] test_sellThroughSwapIsNotTaxedAndSettles() (gas: 1345841)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 37.81ms (37.84ms CPU time)\n\nRan 17 tests for test/SHITPAPERToken.t.sol:SHITPAPERTokenTest\n[PASS] test_buyDistributesProRataToPriorHolders() (gas: 717092)\n[PASS] test_buyPaysThreePercentToTheContract() (gas: 444740)\n[PASS] test_buyToExcludedRecipientIsNotTaxed() (gas: 308168)\n[PASS] test_buyerSharesOnPreBuyBalanceButNotOnNetAmount() (gas: 674520)\n[PASS] test_claimForExcludedAccountReverts() (gas: 330890)\n[PASS] test_claimForPaysTheHolderNotTheCaller() (gas: 610842)\n[PASS] test_claimPaysOutAndStopsDoubleClaims() (gas: 701402)\n[PASS] test_contractBalanceCoversPendingAndUnclaimed() (gas: 745642)\n[PASS] test_deploy_mintsWholeSupplyToDeployer() (gas: 102477)\n[PASS] test_deploy_revertsOnZeroAddresses() (gas: 3943)\n[PASS] test_noMintOrAdminSurface() (gas: 156510)\n[PASS] test_seedAndSellToPoolManagerAreNotTaxed() (gas: 246716)\n[PASS] test_swarmShareArrivesWholeAndIsClaimableWhole() (gas: 288503)\n[PASS] test_transferAfterAccrualKeepsDividendsWithTheEarner() (gas: 820528)\n[PASS] test_transferFromRequiresAllowance() (gas: 115530)\n[PASS] test_transferRevertsOnInsufficientBalance() (gas: 49588)\n[PASS] test_walletToWalletTransferIsNotTaxed() (gas: 189242)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 78.79ms (5.37ms CPU time)\n\nRan 25 tests for test/SHITPAPERToken.edge.t.sol:SHITPAPERTokenEdgeTest\n[PASS] test_burnAddressAccumulatesWithoutEarning() (gas: 652456)\n[PASS] test_buyEmitsFeeTransferAndDistributionEvents() (gas: 549468)\n[PASS] test_buyToFeeExemptRecipientsIsNotTaxed() (gas: 659938)\n[PASS] test_claimEmitsEventsAndTransferFromTheContract() (gas: 659779)\n[PASS] test_claimForZeroAddressReverts() (gas: 300372)\n[PASS] test_claimWithNothingOwedPaysZeroAndEmitsNothing() (gas: 302549)\n[PASS] test_contractHolderIsPaidThroughClaimFor() (gas: 752796)\n[PASS] test_deployerWithoutCodeLeavesTheDistributorUnknownAndTransfersWork() (gas: 122496)\n[PASS] test_differentLaunchNumberReadsItsOwnDistributor() (gas: 290329)\n[PASS] test_distributorFundedBeforeRegistrationIsRemovedFromEligibleSupplyOnResolution() (gas: 709105)\n[PASS] test_distributorIsCachedOnceAndNotReReadIfTheFactoryChangesIt() (gas: 449344)\n[PASS] test_distributorResolvedWhileItIsTheRecipientDoesNotDoubleCount() (gas: 219666)\n[PASS] test_distributorResolvedWhileItIsTheSenderDoesNotDoubleCount() (gas: 238483)\n[PASS] test_hugeFeeAgainstOneWeiOfEligibleSupplyDoesNotOverflowLater() (gas: 1033410)\n[PASS] test_malformedFactoryAnswerIsIgnored() (gas: 405202)\n[PASS] test_manyTinyDistributionsNeverMakeTheContractInsolvent() (gas: 9051728)\n[PASS] test_parametersAreTheBriefsConstants() (gas: 49531)\n[PASS] test_privilegedCallsNeitherMoveNorFreezeAHolder() (gas: 505325)\n[PASS] test_revertingFactoryLookupDoesNotBlockTransfers() (gas: 674600)\n[PASS] test_runtimeCodeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 5344965)\n[PASS] test_selfTransferChangesNothing() (gas: 744528)\n[PASS] test_tokensSentToTheContractAreNotRedistributed() (gas: 635279)\n[PASS] test_unresolvedDistributorIsTaxedAndEligibleUntilTheFactoryRegistersIt() (gas: 32568)\n[PASS] test_viewsAgreeWithState() (gas: 354437)\n[PASS] test_zeroAmountTransfersSucceedAndChargeNothing() (gas: 379289)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 79.41ms (25.33ms CPU time)\n\nRan 15 tests for test/SHITPAPERToken.fuzz.t.sol:SHITPAPERTokenFuzzTest\n[PASS] testFuzz_allowanceIsEnforcedExactly(uint256,uint256,uint256) (runs: 256, μ: 277657, ~: 300396)\nLogs:\n  Bound result 175564249878371661808970242\n  Bound result 152238086930388139792015033\n  Bound result 25\n\n[PASS] testFuzz_buyFeeIsExactlyThreePercentFloored(uint256) (runs: 256, μ: 279145, ~: 280770)\nLogs:\n  Bound result 65871423384593\n\n[PASS] testFuzz_buyerEarnsOnPreBuyBalanceOnly(uint256,uint256,uint256) (runs: 256, μ: 426876, ~: 436306)\nLogs:\n  Bound result 26396097386192946784\n  Bound result 110285940440928698\n  Bound result 54292423967543378957574276\n\n[PASS] testFuzz_claimForPaysTheHolderNeverTheCaller(address,uint256,uint256) (runs: 256, μ: 450291, ~: 453804)\nLogs:\n  Bound result 76982777000461486192224095\n  Bound result 121893589891470167886695\n\n[PASS] testFuzz_claimPaysExactlyClaimableOnceAndContractStaysSolvent(uint256,uint256,uint256) (runs: 256, μ: 698637, ~: 707772)\nLogs:\n  Bound result 26396097386192946784\n  Bound result 110285940440928698\n  Bound result 54292423967543378957574276\n\n[PASS] testFuzz_dustBuysBelowThirtyFourWeiPayNothing(uint256) (runs: 256, μ: 196366, ~: 198791)\nLogs:\n  Bound result 7\n\n[PASS] testFuzz_excludedAccountsNeverAccrueAndCannotClaim(uint256,uint256) (runs: 256, μ: 630719, ~: 630781)\nLogs:\n  Bound result 118517301681762976030822233\n  Bound result 36\n\n[PASS] testFuzz_feeIsSplitProRataOnPreBuyBalances(uint256,uint256,uint256) (runs: 256, μ: 523451, ~: 523303)\nLogs:\n  Bound result 175564249878371661808970242\n  Bound result 168513534625843140440744348\n  Bound result 249999999999999999999999992\n\n[PASS] testFuzz_infiniteAllowanceIsNotDecremented(uint256,uint256) (runs: 256, μ: 289570, ~: 290232)\nLogs:\n  Bound result 8192\n  Bound result 7\n\n[PASS] testFuzz_movingTokensMovesFutureNotPastDividends(uint256,uint256,uint256) (runs: 256, μ: 657749, ~: 659087)\nLogs:\n  Bound result 243307371201345843768724345\n  Bound result 54474315552623100321416111\n  Bound result 25\n\n[PASS] testFuzz_pendingFeeIsPaidWithTheNextDistribution(uint256,uint256) (runs: 256, μ: 440502, ~: 440546)\nLogs:\n  Bound result 143092435818585370832010913\n  Bound result 36\n\n[PASS] testFuzz_sellsAndWalletTransfersPayNothing(uint256,uint256,uint256) (runs: 256, μ: 333072, ~: 334544)\nLogs:\n  Bound result 425564249878371661808970242\n  Bound result 380059723139613977335564041\n  Bound result 25\n\n[PASS] testFuzz_transferAboveBalanceReverts(uint256,uint256) (runs: 256, μ: 355204, ~: 355336)\nLogs:\n  Bound result 121716736081014813638395316\n  Bound result 10521107315753217253013041559813741036668\n\n[PASS] testFuzz_transferFromThePoolManagerIsTaxedWhoeverSpends(uint256,address) (runs: 256, μ: 290786, ~: 290616)\nLogs:\n  Bound result 1571\n\n[PASS] testFuzz_transferToZeroAddressReverts(uint256) (runs: 256, μ: 219923, ~: 219705)\nLogs:\n  Bound result 65871423384593\n\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 79.47ms (1.05s CPU time)\n\nRan 1 test for test/SHITPAPERToken.invariant.t.sol:SHITPAPERTokenInvariantTest\n[PASS]\nSHITPAPERTokenInvariantTest invariants:\n[PASS] invariant_contractHoldsWhatItOwesAndNotMuchMore\n[PASS] invariant_eligibleSupplyIsTheSumOfEligibleBalances\n[PASS] invariant_excludedAccountsNeverEarn\n[PASS] invariant_feesAreAccountedFor\n[PASS] invariant_supplyIsFixed\n SHITPAPERTokenInvariantTest invariants (runs: 256, calls: 10240, reverts: 0)\n\n╭----------+------------------+-------+---------+----------╮\n| Contract | Selector         | Calls | Reverts | Discards |\n+==========================================================+\n| Handler  | burn             | 1009  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | buy              | 1017  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | claim            | 962   | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | claimFor         | 1040  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | claimForExcluded | 1031  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | distributorClaim | 1063  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | donate           | 1043  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | sell             | 1047  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | transfer         | 1011  | 0       | 0        |\n|----------+------------------+-------+---------+----------|\n| Handler  | transferFrom     | 1017  | 0       | 0        |\n╰----------+------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 8192\n  Bound result 10079\n  Bound result 24576\n  Bound result 0\n  Bound result 8555567647665821\n  Bound result 4159\n  Bound result 151518637\n  Bound result 6703\n  Bound result 190207899138117\n  Bound result 43\n  Bound result 0\n  Bound result 0\n  Bound result 1780\n  Bound result 18066308719121\n  Bound result 2619521447\n  Bound result 0\n  Bound result 0\n  Bound result 88842974929\n  Bound result 0\n  Bound result 14124363155\n  Bound result 947\n  Bound result 1024\n  Bound result 4194304\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 33\n  Bound result 131718346\n  Bound result 500000000000000000000\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.41s (3.41s CPU time)\n\nRan 5 test suites in 3.41s (3.69s CPU time): 67 tests passed, 0 failed, 0 skipped (67 total tests)\n","passed":true},{"durationMs":79,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SHITPAPERToken.approve(address,uint256)\",\"SHITPAPERToken.claim()\",\"SHITPAPERToken.claimFor(address)\",\"SHITPAPERToken.transfer(address,uint256)\",\"SHITPAPERToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":103,\"foundry.toml\":17,\"launch.json\":24,\"src/SHITPAPERToken.sol\":279,\"test/SHITPAPERToken.edge.t.sol\":437,\"test/SHITPAPERToken.fuzz.t.sol\":297,\"test/SHITPAPERToken.invariant.t.sol\":248,\"test/SHITPAPERToken.t.sol\":287,\"test/SHITPAPERToken.v4.t.sol\":444,\"test/vendor/README.md\":7,\"test/vendor/solmate/src/auth/Owned.sol\":44,\"test/vendor/v4-core/licenses/BUSL_LICENSE\":63,\"test/vendor/v4-core/licenses/MIT_LICENSE\":7,\"test/vendor/v4-core/src/ERC6909.sol\":90,\"test/vendor/v4-core/src/ERC6909Claims.sol\":23,\"test/vendor/v4-core/src/Extsload.sol\":64,\"test/vendor/v4-core/src/Exttload.sol\":40,\"test/vendor/v4-core/src/NoDelegateCall.sol\":33,\"test/vendor/v4-core/src/PoolManager.sol\":394,\"test/vendor/v4-core/src/ProtocolFees.sol\":71,\"test/vendor/v4-core/src/interfaces/IExtsload.sol\":21,\"test/vendor/v4-core/src/interfaces/IExttload.sol\":15,\"test/vendor/v4-core/src/interfaces/IHooks.sol\":152,\"test/vendor/v4-core/src/interfaces/IPoolManager.sol\":217,\"test/vendor/v4-core/src/interfaces/IProtocolFees.sol\":52,\"test/vendor/v4-core/src/interfaces/callback/IUnlockCallback.sol\":10,\"test/vendor/v4-core/src/interfaces/external/IERC20Minimal.sol\":48,\"test/vendor/v4-core/src/interfaces/external/IERC6909Claims.sol\":66,\"test/vendor/v4-core/src/libraries/BitMath.sol\":49,\"test/vendor/v4-core/src/libraries/CurrencyDelta.sol\":42,\"test/vendor/v4-core/src/libraries/CurrencyReserves.sol\":39,\"test/vendor/v4-core/src/libraries/CustomRevert.sol\":120,\"test/vendor/v4-core/src/libraries/FixedPoint128.sol\":8,\"test/vendor/v4-core/src/libraries/FixedPoint96.sol\":10,\"test/vendor/v4-core/src/libraries/FullMath.sol\":117,\"test/vendor/v4-core/src/libraries/Hooks.sol\":344,\"test/vendor/v4-core/src/libraries/LPFeeLibrary.sol\":79,\"test/vendor/v4-core/src/libraries/LiquidityMath.sol\":20,\"test/vendor/v4-core/src/libraries/Lock.sol\":28,\"test/vendor/v4-core/src/libraries/NonzeroDeltaCount.sol\":35,\"test/vendor/v4-core/src/libraries/ParseBytes.sol\":29,\"test/vendor/v4-core/src/libraries/Pool.sol\":620,\"test/vendor/v4-core/src/libraries/Position.sol\":103,\"test/vendor/v4-core/src/libraries/ProtocolFeeLibrary.sol\":47,\"test/vendor/v4-core/src/libraries/SafeCast.sol\":60,\"test/vendor/v4-core/src/libraries/SqrtPriceMath.sol\":292,\"test/vendor/v4-core/src/libraries/StateLibrary.sol\":345,\"test/vendor/v4-core/src/libraries/SwapMath.sol\":108,\"test/vendor/v4-core/src/libraries/TickBitmap.sol\":121,\"test/vendor/v4-core/src/libraries/TickMath.sol\":238,\"test/vendor/v4-core/src/libraries/TransientStateLibrary.sol\":48,\"test/vendor/v4-core/src/libraries/UnsafeMath.sol\":29,\"test/vendor/v4-core/src/types/BalanceDelta.sol\":72,\"test/vendor/v4-core/src/types/BeforeSwapDelta.sol\":38,\"test/vendor/v4-core/src/types/Currency.sol\":118,\"test/vendor/v4-core/src/types/PoolId.sol\":17,\"test/vendor/v4-core/src/types/PoolKey.sol\":22,\"test/vendor/v4-core/src/types/PoolOperation.sol\":26,\"test/vendor/v4-core/src/types/Slot0.sol\":95},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a66384dd8c1bdd1c928b26b290102a4565140afd4e1085595e763df19f065a6f","verifiedTreeHash":"012f7184ef4272f92988d89c6b0cfb46976cb043","verifierVersion":"0.1.0+c4d32abc"},{"checks":[{"durationMs":763,"exitCode":0,"name":"build","output":"Compiling 26 files with Solc 0.8.26\nSolc 0.8.26 finished in 669.52ms\nCompiler run successful!\n","passed":true},{"durationMs":75,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 17 tests for test/SHITPAPERToken.t.sol:SHITPAPERTokenTest\n[PASS] test_buyDistributesProRataToPriorHolders() (gas: 717092)\n[PASS] test_buyPaysThreePercentToTheContract() (gas: 444740)\n[PASS] test_buyToExcludedRecipientIsNotTaxed() (gas: 308168)\n[PASS] test_buyerSharesOnPreBuyBalanceButNotOnNetAmount() (gas: 674520)\n[PASS] test_claimForExcludedAccountReverts() (gas: 330890)\n[PASS] test_claimForPaysTheHolderNotTheCaller() (gas: 610842)\n[PASS] test_claimPaysOutAndStopsDoubleClaims() (gas: 701402)\n[PASS] test_contractBalanceCoversPendingAndUnclaimed() (gas: 745642)\n[PASS] test_deploy_mintsWholeSupplyToDeployer() (gas: 102477)\n[PASS] test_deploy_revertsOnZeroAddresses() (gas: 3943)\n[PASS] test_noMintOrAdminSurface() (gas: 156510)\n[PASS] test_seedAndSellToPoolManagerAreNotTaxed() (gas: 246716)\n[PASS] test_swarmShareArrivesWholeAndIsClaimableWhole() (gas: 288503)\n[PASS] test_transferAfterAccrualKeepsDividendsWithTheEarner() (gas: 820528)\n[PASS] test_transferFromRequiresAllowance() (gas: 115530)\n[PASS] test_transferRevertsOnInsufficientBalance() (gas: 49588)\n[PASS] test_walletToWalletTransferIsNotTaxed() (gas: 189242)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 3.28ms (5.28ms CPU time)\n\nRan 1 test suite in 3.99ms (3.28ms CPU time): 17 tests passed, 0 failed, 0 skipped (17 total tests)\n","passed":true},{"durationMs":39,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SHITPAPERToken.approve(address,uint256)\",\"SHITPAPERToken.claim()\",\"SHITPAPERToken.claimFor(address)\",\"SHITPAPERToken.transfer(address,uint256)\",\"SHITPAPERToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":103,\"foundry.toml\":17,\"launch.json\":24,\"src/SHITPAPERToken.sol\":279,\"test/SHITPAPERToken.t.sol\":287},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":508,"exitCode":0,"name":"slither","output":"slither: no results at low impact or above","passed":true},{"durationMs":235,"exitCode":0,"name":"aderyn","output":"[low] large-numeric-literal at src/SHITPAPERToken.sol:27: Large Numeric Literal (2 places)\n[low] unused-public-function at src/SHITPAPERToken.sol:138: Public Function Not Used Internally","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"e487f40c291efe46133f57033962f308128ebaf7ba6b0a5ee542e77fcc41bbe5","verifiedTreeHash":"2e51ec527bd5cd10c8291a63603dec827deb989c","verifierVersion":"0.1.0+c4d32abc"}]}