{"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":"49dd6e61-0e5c-4f03-99b4-a3aebe0bc820","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"2d494db65048a30e67c0af040d7d2eed787acf2d7b4e13fa7689bafe37217fdf","dependsOn":["token_logo","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":"7f619c86446b1940a1318bb2bc440fd69b974ebed6a42f8c67c8d1b45cd2f899","dependsOn":["token_logo","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":"99380ead90a18bb3058f06371424904cc777c2199d4e91fb2fa3b5e802c5ca7b","dependsOn":["token_logo","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":"9f1865f5b0bff344aa94b5e3a4899e7a9caf59648b7b4c25db782ad73df2a432","dependsOn":["token_logo","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":"4b14179681593ae782f46c2f43727026bf1638f52e8fcd4f9bcc34c3854de7e3","dependsOn":["token_logo","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":"a44693c5f4401e63be8532969ee2088cc9f41b0da2fca5eceb736e2f188aca5f","dependsOn":["token_logo"],"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":"eef4f2062a49961ccf86d11a426024e45bd14274d1674fc55694742818e51cc1","dependsOn":["token_logo","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":"19abc555c115651c050eb5a37daba4d207443e71ff21e094002eb98b9a9e574c","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":["tool:image"],"skillHash":"9fa92c5200aa48ce2c9551714aaa720e895a50b88afa3346815752b923cb8378","skillId":"token-logo","tools":["image"]},"key":"token_logo","kind":"code","role":"implement","skillHash":"9fa92c5200aa48ce2c9551714aaa720e895a50b88afa3346815752b923cb8378","skillId":"token-logo","state":"accepted"},{"acceptedSubmissionHash":"26f75ac81afc74673a43312a659226f93871526ed4059c9a9546540c86710d10","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: SI TRADER (SITR).\nToken name: SI TRADER\nToken symbol: SITR\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 SITRToken contract implements an ERC-20 token named \"SI TRADER\" with symbol \"SITR\", total fixed supply 1,000,000,000 with 18 decimals minted once to the deployer.\n2. The total supply is split as follows: 10% allocated to the swarm's Merkle distributor (outside this contract, no minting or transfers done here), 90% is used to seed the Uniswap v4 PoolManager at 0x000000000004444c5dc75cB358380D2e3dE08A90 with 1.25% pool fee.\n3. A 3% fee applies only to transfers FROM the PoolManager (UNISWAP BUYs). This fee is deducted from the amount transferred to the receiver.\n4. Transfers TO the PoolManager (SELLs or pool seed) and wallet-to-wallet transfers incur no fee.\n5. The 3% fee collected remains in the token contract and is accounted as dividends for existing eligible token holders proportionally to their balances.\n6. The contract excludes from earning dividends the PoolManager, the token contract address, the burn address (0x000000000000000000000000000000000000dEaD), and the swarm distributor address (provided via constructor or constant).\n7.\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: SITRToken. 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 SITR minor unit with SITR 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":"4226f5294d91f32a949f87a45fe76f6176d8cb4ceb7e12a41b7510f119940563","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"49dd6e61-0e5c-4f03-99b4-a3aebe0bc820","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1204-si-trader"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52255","feedbackHash":"b6c465554d828d4ee3bb4bebd518f084fcfd338bec0023eca4c7498efedd58d5","nodeKey":"audit_economics","submissionHash":"2d494db65048a30e67c0af040d7d2eed787acf2d7b4e13fa7689bafe37217fdf","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52479","feedbackHash":"c7c9742fa94477e2c05b575dc034204fad638abdc16acbd1ea5543a8f2fa1e5a","nodeKey":"audit_flow","submissionHash":"7f619c86446b1940a1318bb2bc440fd69b974ebed6a42f8c67c8d1b45cd2f899","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51315","feedbackHash":"7481a58c06fec3262d5ff31cded59f62ead4f0225c26eaea2478210dca6eac2c","nodeKey":"audit_judge","submissionHash":"99380ead90a18bb3058f06371424904cc777c2199d4e91fb2fa3b5e802c5ca7b","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52131","feedbackHash":"eecc431825770f20379bda4e9f94f0d90fc3c71fed8b19704fab0b2fc01aff86","nodeKey":"audit_math","submissionHash":"9f1865f5b0bff344aa94b5e3a4899e7a9caf59648b7b4c25db782ad73df2a432","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52261","feedbackHash":"ac906edf0618e17b3c00b3d198125feb1510979c2edfcb1f116ed8fde0a40fd7","nodeKey":"audit_permissions","submissionHash":"4b14179681593ae782f46c2f43727026bf1638f52e8fcd4f9bcc34c3854de7e3","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52211","feedbackHash":"c6598349066ee953a0fabf530d66a63225f4cf2286acfa3bf6334e08c64ae5e5","nodeKey":"build_contract_project","submissionHash":"a44693c5f4401e63be8532969ee2088cc9f41b0da2fca5eceb736e2f188aca5f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51751","feedbackHash":"c55b58715b32e80cefca73d4403e5fecba9367999b2632acedc5d58ea692c2b3","nodeKey":"manifest","submissionHash":"eef4f2062a49961ccf86d11a426024e45bd14274d1674fc55694742818e51cc1","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51522","feedbackHash":"69afd9ccffba2a2099870a5e4fdd23a1d331b1490dc3b405a550cce4caac8958","nodeKey":"token_logo","submissionHash":"19abc555c115651c050eb5a37daba4d207443e71ff21e094002eb98b9a9e574c","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52209","feedbackHash":"8e4a074f5dea23f49732b1b755216fb821b598e0cb727fc05536d0ae29ccd45b","nodeKey":"write_foundry_tests","submissionHash":"26f75ac81afc74673a43312a659226f93871526ed4059c9a9546540c86710d10","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"f80bb924a01cff83c56753d5fb02a1020267f092af0521aa3bf8fc051937fa81","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"0ddee3bf2f2a73284b9508f67cee0d677ca672b1754ecb80f4a889f8239ea8d7","device":"fd7c32744e171d7d","findings":[],"hash":"19abc555c115651c050eb5a37daba4d207443e71ff21e094002eb98b9a9e574c","nodeId":"b5aa1c0c-5431-4931-919c-39f18b9fcf6f","outcome":"completed","summary":"Created five 1024×1024 PNG options in `logos/` and selected the geometric mark for `artifacts/logo.png`.\n\nBuilt-in image generation drew five drafts; all were retained. The selected mark reads clearly at 32 pixels. The alternatives’ lettering, rim or finer details made them less suitable for the primary wallet image. Descriptions and prompts are documented.\n\nAlso completed the token, launch manifest and Foundry project. `forge build` succeeded; all 23 tests passed. Live-fork and protected-harness checks were not run.","treeHash":"b4ee8cd919d36c3ae0d32faae034f28232fa2aee","usage":{"cachedInputTokens":746624,"inputTokens":59855,"model":"gpt-6-astra","outputTokens":19319,"runtime":"codex","turns":7,"wallClockMs":593265}},{"artifacts":[],"attempt":1,"bundleHash":"2f3a614c0800d3b83e451446bd58353d335bba8242a8eea6f3508d679a34db8e","device":"4539d3d0693a7444","findings":[],"hash":"26f75ac81afc74673a43312a659226f93871526ed4059c9a9546540c86710d10","nodeId":"aeb48a25-958f-4f2f-922c-6acb88d401d8","outcome":"completed","summary":"Added tests only under `test/`: edge and failure cases, bounded invariants, and real offline Uniswap v4 swaps with vendored dependencies.\n\n`forge build` and `forge test` pass: **51 tests, zero failures or skips**. Invariants exercised 4,096 random calls.\n\nNo reproducible defects found. Live Ethereum fork verification remains unrun.","treeHash":"9adf4a2c2beedf745740a8adb54085656889d41b","usage":{"cachedInputTokens":1316224,"inputTokens":94158,"model":"gpt-6-astra","outputTokens":25908,"runtime":"codex","turns":8,"wallClockMs":586064}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e06554fd2816f9d7","findings":[{"citation":"resolved","description":"Dividends are split pro rata to the balance held at the instant of each buy, with no time weighting and no minimum holding period. Balances bought in the same block (even in the same bundle) count fully. A searcher who sees a large buy in the mempool can buy first, be credited with the bulk of the victim's fee, then claim and sell back in the same block. The loss falls on the pre-existing holders, who would otherwise have received the entire fee; the attacker's only costs are its own 3% buy fee (which existing holders receive) plus the pool fee and price impact. The dividend capture is in addition to the ordinary price sandwich and is unique to this token. Economics with the existing suite's offline fixture (eligible supply 100 SITR held by one holder, pool manager holds the rest): attacker buys 1000 gross (fee 30, all to the holder), victim then buys 3000 gross (fee 90): attacker is credited 81.59 and the holder 8.41 of the victim's fee. After claimFor(attacker) and selling everything back to the manager the attacker's net SITR change is +51.59 on a 1000 gross round trip before pool fees (2 x 1.25% ~ 25) and price impact, and the holder ends with 38.41 instead of the 90 it would have received without the front-run. The capture ratio A/(E+A) approaches 100% right after launch when eligible supply is small, which is also when a bot can be first. This is a property of the specified balance-pro-rata design (M1) rather than a coding error; fixing it (e.g. excluding balances acquired in the current block from the next distribution, or a holding-period or snapshot scheme) is a design decision the requester must take, so it is reported at low severity for that decision.","line":154,"path":"src/SITRToken.sol","reproduction":"Deploy SITRToken from a factory fixture answering distributorOf; factory.transfer(distributor, 1e26); factory.transfer(holder, 100e18); factory.transfer(POOL_MANAGER, rest). Step 1 (attacker front-run): vm.prank(POOL_MANAGER); token.transfer(attacker, 1000e18) -> claimableDividends(holder) == 30e18-1. Step 2 (victim buy): vm.prank(POOL_MANAGER); token.transfer(victim, 3000e18) -> fee 90e18. Actual: claimableDividends(attacker) == 81588785046728971962 (81.59 SITR), holder gains only 8411214953271028038 (8.41 SITR) from the victim's fee. Step 3: token.claimFor(attacker); vm.prank(attacker); token.transfer(POOL_MANAGER, balanceOf(attacker)) succeeds untaxed; attacker's balance before the sell is 1051.59e18 against 1000e18 gross bought. Expected under the protocol's stated purpose (fee to existing holders): holder receives the 90 SITR.","severity":"low","snippet":"                    dividendPerShare += fee * MAGNITUDE / eligible;","title":"Same-block dividend front-running diverts most of a large buy's 3% fee from existing holders to a just-arrived buyer"},{"citation":"resolved","description":"The fee is distributed against the eligible supply, which includes the buyer's existing balance, and the buyer is then accrued on that balance against the new index. M1 says both 'the buyer never shares in its own fee' and 'checkpoint the buyer on its pre-buy balance'; the implementation and README follow the second reading. Consequence: a holder with share s of the eligible supply recovers s x 3% of every buy it makes. With eligible supply 100 SITR of which the buyer holds 99, a 10,000 gross buy pays a 300 SITR fee and the buyer is immediately credited 297 of it (claimable at once), the other holder 3. Effective fee 0.03%. Whale accumulation is therefore nearly fee-free at exactly the stage (early, small eligible supply) when the fee matters most to other holders. No code defect against the authoritative spec text; reported so the requester confirms which of the two sentences in M1 is intended.","line":157,"path":"src/SITRToken.sol","reproduction":"factory.transfer(distributor, 1e26); factory.transfer(holder, 1e18); factory.transfer(attacker, 99e18); factory.transfer(POOL_MANAGER, rest). vm.prank(POOL_MANAGER); token.transfer(attacker, 10_000e18). Actual: totalFeesCollected == 300e18, claimableDividends(attacker) == 297e18, claimableDividends(holder) == 3e18. Expected under the sentence 'the buyer never shares in its own fee': attacker credited 0 and holder credited 300e18 (or the fee split against eligible supply excluding the buyer).","severity":"info","snippet":"                // The buyer earns on its OLD balance only. Settle the new index before\n                // crediting any of this buy's net tokens, including a first-time buyer.\n                _accrue(to, distributor);","title":"A buyer's pre-buy balance shares in its own fee, so a holder owning most of the eligible supply pays an effective buy fee near 0%"},{"citation":"resolved","description":"After launchCustom the only balances are the PoolManager (pool seed), the distributor (10%) and the burn address (remainderTo), all excluded, so eligibleSupply() is 0. The first ERC-20 outflow from the PoolManager with a nonzero fee (any buy of at least 34 wei) therefore sends 3% of the gross to unallocatedFees, which no path ever distributes or withdraws. The same happens again whenever every eligible holder has sold to zero. The tokens stay counted in totalSupply, held by the token contract. This matches the README and the M1 rule that the incoming buyer never shares in its own fee, so it is not a defect against the spec; it is recorded so the requester consciously accepts that the first buyer's fee (and any fee paid into an empty holder set) is dead weight rather than, for example, carried forward into the next distribution.","line":149,"path":"src/SITRToken.sol","reproduction":"factory.transfer(distributor, 1e26); factory.transfer(POOL_MANAGER, 9e26); eligibleSupply() == 0. vm.prank(POOL_MANAGER); token.transfer(victim, 1000e18). Actual: unallocatedFees == 30e18, claimableDividends(victim) == 0, balanceOf(token) == 30e18. Then vm.prank(POOL_MANAGER); token.transfer(attacker, 1000e18); claimFor(victim); claimFor(attacker): balanceOf(token) == 30e18 + 1 wei of rounding dust and remains so under every subsequent operation (no function reduces unallocatedFees or pays it out).","severity":"info","snippet":"                if (eligible == 0) {\n                    unallocatedFees += fee;","title":"Fees collected while eligible supply is zero are locked in the contract forever, which by construction includes the launch's first buy"},{"citation":"resolved","description":"Until the distributor is pinned, every transfer and claim staticcalls the factory's distributorOf(launchNumber). A zero, reverting, empty or malformed answer makes any PoolManager outflow with fee != 0 revert with DistributorUnavailable (outflows below 34 wei pass untaxed), and an answer equal to the factory, the PoolManager, the token or the burn address makes every transfer and claim revert with InvalidDistributor. Economic consequence if the live factory's registry does not answer for this launch number (wrong selector or argument type, registration keyed differently, or written after the launch and never): the pool holds only SITR after the single-sided seed, so buys are the only way IMD enters the pool; with buys impossible, sells have nothing to withdraw and 100% of the circulating supply (the swarm's 10% and the pool's 90%) is unsellable, with no override in the token. This is the trust assumption the design takes on the factory (the protected harness defines mapping(uint64 => address) public distributorOf, which matches), documented in the README; it is reported so the deployer verifies the live factory answers distributorOf(uint64) for this launch number before trading opens. No fix inside the token is required by the spec.","line":146,"path":"src/SITRToken.sol","reproduction":"Deploy SITRToken(2) from a factory whose distributorOf(2) returns 0; factory.transfer(POOL_MANAGER, 1e27). vm.prank(POOL_MANAGER); token.transfer(victim, 1000e18) reverts DistributorUnavailable (actual) whereas a buy of 1000 SITR should deliver 970. vm.prank(POOL_MANAGER); token.transfer(victim, 33) succeeds untaxed. Register the factory itself as distributor: factory.transfer(anyone, 1) reverts InvalidDistributor on every path.","severity":"info","snippet":"                if (distributor == address(0)) revert DistributorUnavailable();","title":"Every taxed PoolManager outflow depends on factory.distributorOf(uint64) answering a valid nonzero address; if it never does, nobody can buy and, with a single-sided seed, nobody can sell either"}],"hash":"2d494db65048a30e67c0af040d7d2eed787acf2d7b4e13fa7689bafe37217fdf","nodeId":"4cfc72a3-08d2-4cdd-8df4-48cf9e62238f","outcome":"completed","summary":"The findings file is in place at the repository root (the harness excludes it from git by design), the scratch directory is removed, and no tracked file was changed.\n\n## Review result: no accounting defects, four economic properties to confirm\n\nI audited `src/SITRToken.sol` against the Economic Security, Invariant and Flow Gap guides, ran the existing 51-test suite (all pass), and reproduced each economic edge case in a scratch Foundry test before recording it. The dividend accounting is sound. Balance conservation, escrow solvency, the eligible-supply denominator, overflow headroom, the Uniswap v4 take/settle/sync path, the launch flows and the manifest all hold.\n\n**Findings written to `.imd-findings.json`** (one low, three info; none critical or high, so no proof files):\n\n1. **Low: same-block dividend front-running.** A searcher who buys right before a large buy captures most of that buy's 3% fee. With 100 SITR eligible, a 1000-gross front-run before a 3000-gross victim buy diverts 81.59 of the victim's 90 SITR fee to the attacker, who nets +51.59 SITR after claiming and selling back. The loss falls on existing holders. This is inherent to the specified balance-pro-rata design, so it is a design decision for the requester rather than a coding error.\n2. **Info: pre-buy balance shares in its own fee.** A holder owning 99% of the eligible supply pays a 300 SITR fee on a 10,000 buy and is immediately credited 297 of it. M1 contains two sentences that read differently here; the code follows \"checkpoint the buyer on its pre-buy balance\".\n3. **Info: fees paid into an empty holder set are locked forever.** By construction this includes the launch's first buy, whose 3% goes to unallocatedFees with no distribution or withdrawal path. Matches the README and spec.\n4. **Info: factory registry dependency.** Every taxed PoolManager outflow needs the factory's distributorOf(uint64) to answer. If it never does, buys revert, and with a single-sided seed sells have no IMD to withdraw, so the whole circulating supply is unsellable. The protected harness's registry matches the token's interface, so this is a deployment verification item.\n\n**Coverage.** All five ABI entry points have rows (four hold, transfer carries finding 1 as the path the economic findings live on), plus seven rows for invariants, launch flows, the v4 settlement path and the manifest. Static-analysis leads (divide-before-multiply, literal, unused public) were checked and are not defects. Not run here: a live mainnet fork and the protected harness, which need the verifier's environment.","treeHash":null,"usage":{"cachedInputTokens":1384569,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":40318,"runtime":"claude","turns":25,"wallClockMs":545108}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"dedc96e38388cb45","findings":[{"citation":"resolved","description":"Area: Access Control / Asymmetry (branch-symmetry diff, 'bad symmetry' defensive check). _transfer (line 137) and _claimFor (line 118) both call _resolveDistributor() unconditionally, before any fee logic. The code treats an UNAVAILABLE registry answer (zero, revert, malformed) asymmetrically from an INVALID one: an unavailable answer only blocks the fee-bearing path (line 146 DistributorUnavailable inside `if (fee != 0)`), so wallet-to-wallet transfers, sells and claims keep working; but an answer equal to the factory, the PoolManager, the token or 0xdEaD reverts at line 184 on every path, including zero-amount transfers, sells into the PoolManager, swarm claims out of the distributor and claim()/claimFor(). Nothing in the token can clear the state: _distributor stays zero, the registry is re-queried on every call, and the token has no setter, so the token is frozen for as long as the factory registry returns that value. The factory is a trusted party, so this is an operational-misconfiguration DoS rather than an unprivileged exploit, but the guard is strictly more restrictive than the design needs: a reserved address should be treated like an unavailable one (no pin, fee path reverts, untaxed paths continue) so that holders can still move and sell tokens. Suggested minimal fix preserving the design: in _resolveDistributor, return address(0) (do not pin) for reserved values instead of reverting, so only the fee branch at line 146 fails; or move the InvalidDistributor check behind the `fee != 0` branch.","line":181,"path":"src/SITRToken.sol","reproduction":"State: registry (factory fixture with mapping(uint64=>address) public distributorOf) answers distributorOf(launchNumber) == factory address (or POOL_MANAGER, token, 0xdEaD). alice holds 100e18, PoolManager holds 100e18, distributor not yet pinned. Calls: (1) vm.prank(alice); token.transfer(bob, 1e18) -> reverts InvalidDistributor (expected: succeeds, untaxed). (2) vm.prank(alice); token.transfer(POOL_MANAGER, 1e18) (a sell) -> reverts InvalidDistributor. (3) vm.prank(alice); token.claim() -> reverts InvalidDistributor. (4) token.claimFor(alice) -> reverts InvalidDistributor. Contrast: set distributorOf to address(0) and the same alice->bob transfer succeeds, only PoolManager->X buys revert with DistributorUnavailable. Verified with a Foundry test under test/scratch (removed): both branches behave as described.","severity":"low","snippet":"            if (\n                distributor == factory || distributor == POOL_MANAGER || distributor == address(this)\n                    || distributor == BURN_ADDRESS\n            ) revert InvalidDistributor();","title":"A reserved registry answer bricks every transfer and claim, not only taxed buys (branch asymmetry in _resolveDistributor)"},{"citation":"resolved","description":"Area: Trust Gap (access x economics). The design excludes only four fixed addresses and intentionally lets anyone call claimFor(holder) so a passive contract's rewards are never locked. Combined, any SITR held by a contract that tracks its own balance separately from balanceOf becomes a public faucet: a Uniswap v2-style pair (or any vault that measures `balanceOf - reserve`) is an eligible holder, accrues a pro-rata share of every PoolManager buy fee, and the moment any third party calls claimFor(pair) the paid amount sits above the pair's recorded reserve, where pair.skim(to) hands it to the caller instead of the pair's liquidity providers. The victim class is LPs of any secondary venue; the beneficiary is whoever front-runs with claimFor+skim. This is an inherent consequence of the agreed design (no admin exclusion list, permissionless payout) rather than a permission bypass, so it is reported at low severity for the requester's documentation and launch-time guidance (README line 42 mentions routers and custody contracts but not that third parties can trigger the payout). A fix would require a design decision (e.g. restricting claimFor to the holder or to holders that opt in, or an immutable exclusion for known pair factories), which changes the stated mechanics M1; no code change is recommended without that decision.","line":113,"path":"src/SITRToken.sol","reproduction":"State: distributor pinned; a PairLike contract P holding 100e18 SITR with reserve synced to 100e18; every other non-excluded balance is zero (rest of supply in the PoolManager). Calls: (1) vm.prank(POOL_MANAGER); token.transfer(bob, 100e18) -> fee 3e18 distributed; eligibleSupply == 100e18 so claimableDividends(P) == 3e18 (+-1 wei). (2) Unrelated address M calls token.claimFor(P) -> P.balanceOf == 103e18, P.reserve still 100e18. (3) M calls P.skim(M) -> balanceOf(M) == 3e18. Expected by LPs: the dividend earned by the pair's inventory benefits the pair; actual: an arbitrary caller takes it. Verified with a Foundry test under test/scratch (removed) using a minimal sync/skim pair.","severity":"low","snippet":"    function claimFor(address holder) external returns (uint256) {","title":"Permissionless claimFor on a non-excluded AMM pair lets any caller skim the pair's dividends (access x economics seam)"}],"hash":"4b14179681593ae782f46c2f43727026bf1638f52e8fcd4f9bcc34c3854de7e3","nodeId":"e1c7a712-427f-4b18-b43f-4ef4cd8714d2","outcome":"completed","summary":"The findings file is in place at the repository root, the scratch tests are removed, and the tree is otherwise unchanged.\n\n**Outcome.** The permission model of `SITRToken` holds: there is no owner, setter, mint, pause, blacklist, proxy, delegatecall or selfdestruct, the only writable configuration is the one-time distributor pin read from the trusted factory registry, and the escrowed fee balance has no spend path except pro-rata claims. The existing 51 tests pass offline. Two low-severity defects were substantiated, both with concrete reproductions I ran in Foundry before deleting the scratch files.\n\n- **Reserved registry answer freezes the token.** If the factory registry ever answers with the factory, PoolManager, token or burn address, every transfer, sell, swarm claim and claim call reverts, not only taxed buys. An unavailable registry correctly blocks only the fee path, so this is a branch asymmetry in the resolver. Precondition is a factory misconfiguration, so it is reported low with a minimal fix that keeps the design.\n- **Permissionless claimFor plus balance-tracking contract holders.** Any SITR held by a Uniswap v2 style pair or a reserve-tracking vault earns dividends, and a third party can call claimFor on it and then skim the excess away from the pair's liquidity providers. This follows from the agreed mechanics, so it is reported as a documentation and design-decision item rather than a code change.\n\n**Coverage.** All five entry points have rows, plus rows for the no-privileged-role invariant, pin integrity, buyer checkpointing, escrow solvency and the manifest. The manifest matches the schema and the constructor exactly. I did not run a live fork or the protected harness, which needs the verifier's factory inputs. One note for the judge: the project has no forge-std remapping, so a proof file importing \"forge-std/Test.sol\" does not compile here. No proof was needed since nothing reached high severity.","treeHash":null,"usage":{"cachedInputTokens":1077079,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":30283,"runtime":"claude","turns":25,"wallClockMs":463188}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"dfa08759ca0424de","findings":[{"citation":"resolved","description":"Execution trace of _transfer: a transfer FROM the PoolManager with amount >= 34 wei computes a nonzero fee and then requires _resolveDistributor() to have returned a nonzero address, otherwise it reverts with DistributorUnavailable. _resolveDistributor() in turn reverts with InvalidDistributor (lines 181-184) if the first nonzero registry answer equals the factory, the PoolManager, the token or 0xdead, and because that check runs on every transfer and claim before anything is pinned, such an answer blocks all transfers (including the swarm share and the pool seed) until the registry changes. The token has no fallback, setter or constructor argument for the distributor. This matches the sanctioned mechanism (the launch guide says a token calls distributorOf(launchNumber) on the factory at transfer time; the live mainnet launch #947 token uses the identical staticcall to distributorOf(uint64)), and the protected harness registers the distributor before it seeds and swaps, so with the real factory the path is not reachable. It is recorded here so the judge has the preconditions explicit: the launch factory must expose distributorOf(uint64) for this launch number and must return the real MerkleDistributor (not one of the four reserved addresses) before the first swap. No fix is proposed; a constructor-supplied fallback would contradict the brief's rule that the distributor is resolved from the factory.","line":146,"path":"src/SITRToken.sol","reproduction":"State: factory contract whose distributorOf(uint64 launchNumber) returns address(0) (never registered, wrong selector, or reverting); token deployed by it; factory.transfer(POOL_MANAGER, 1e27). Call: vm.prank(POOL_MANAGER); token.transfer(alice, 100e18). Expected by the launch floor: a buy succeeds. Actual: revert DistributorUnavailable(); only buys with amount < 34 wei (fee rounds to 0) go through. Second state: distributorOf returns the factory address itself. Call: factory.transfer(alice, 1e18). Actual: revert InvalidDistributor() on every transfer and claim while that answer stands. Both paths are already exercised by test/SITRToken.t.sol test_MalformedRegistryAllowsUntaxedTransfersButRejectsBuys and test_InvalidDistributorRevertsWithoutPinningOrMovingSupply.","severity":"info","snippet":"                if (distributor == address(0)) revert DistributorUnavailable();","title":"Fee-bearing buys depend on the factory registry answering; an invalid nonzero answer halts every transfer (trust assumption, not a code defect)"}],"hash":"7f619c86446b1940a1318bb2bc440fd69b974ebed6a42f8c67c8d1b45cd2f899","nodeId":"5546494d-1d68-4f7f-80f2-bf37497df5b5","outcome":"completed","summary":"The findings file is written at the repository root, excluded from git by the harness's own exclude rule, and the working tree is otherwise untouched. The review is complete.\n\n**Outcome: no defect of medium severity or above in SITRToken.** The control flow of all five entry points traces as intended, and the one item I recorded is an explicit trust assumption at info severity, not a code bug.\n\n**What I covered in the Execution Trace, Periphery and First Principles areas**\n\n- **Fee and dividend path in `_transfer`.** The fee is only taken when the sender is the PoolManager and the receiver is not. Eligible supply is computed before balances change, the buyer is checkpointed at its pre-buy balance before its net tokens are credited, and the gross leaves the PoolManager exactly. This matches the brief's parenthetical that a returning buyer earns only on its pre-buy balance.\n- **Index accounting.** Every balance change is preceded by an accrual at the current index, so a holder's unaccrued span always lies in a period where its balance was in the denominator. That bounds the product by total fees times 2^128, so no overflow is reachable even with a 1-wei eligible supply and whole-reserve buys.\n- **Exclusion transitions.** The only transition is pinning the distributor, and a fee can only be charged after pinning, so the distributor can never carry earned credit and the eligible denominator never lags the exclusion set.\n- **Settlement.** Transfers into the PoolManager carry no fee, so Uniswap v4 sync/settle sees the exact amount for sells and the single-sided seed. The vendored real PoolManager tests at the mainnet address confirm this, including the CurrencyNotSettled rollback.\n- **Registry periphery.** The staticcall decoder rejects empty, truncated and non-canonical return data. I fetched the live mainnet launch #947 token source and it uses the identical `distributorOf(uint64)` static call on the factory, so the interface SITR depends on is confirmed against a deployed launch.\n- **Manifest and runtime.** launch.json has exactly the required keys, lowercase addresses, constructor args matching the single uint64 parameter, and a 1,338-character notes string. The compiled runtime contains no DELEGATECALL, CALLCODE or SELFDESTRUCT outside push data.\n\n**The one recorded item (info).** Buys of 34 wei or more revert until the factory registry returns a nonzero distributor, and a registry answer equal to the factory, PoolManager, token or burn address halts every transfer with InvalidDistributor while it stands. With the real factory this is not reachable, and the existing tests already exercise both paths, so I filed it as a stated precondition for the judge rather than a defect.\n\n**Static analysis leads.** The divide-before-multiply line is the intended rounding of the fee to minor units before scaling. The aderyn notes are style only. Neither produced a finding.\n\n**Not reached.** The protected launch harness itself cannot run here because it needs the verifier's environment and the factory-side liquidity contracts, so the end-to-end factory flow is covered only by the in-repo PoolManager fixture. A live Ethereum fork run remains owed to the deployer stage.","treeHash":null,"usage":{"cachedInputTokens":1747851,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":37895,"runtime":"claude","turns":33,"wallClockMs":553636}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e3a598aae0640402","findings":[{"citation":"resolved","description":"M1 says the 3% buy fee 'is distributed to holders pro rata to their balance' and that 'nothing credited to a contract is locked'. In _transfer, when _eligibleSupply(distributor) == 0 the fee is added to unallocatedFees and to balanceOf[address(this)], but no code path ever reads unallocatedFees again: dividendPerShare is not incremented for it, _claimFor only pays accrued dividendPerShare credit, and there is no admin or sweep (by design). After the real launch flow every balance is excluded (10% in the Merkle distributor, ~90% in the PoolManager, the rounding remainder at 0xdead, factory left with 0), so eligibleSupply() is 0 until the first Merkle claim, and the first buy of the launch (in practice the launch-block snipe, which can be large) always hits this branch. It recurs whenever every eligible holder has sold to zero. The tokens stay in the token contract forever, outside circulation and outside the dividend pool. Merged from audit_math (low) and audit_economics (info, same root cause); low because nothing is stolen and the amount is bounded by 3% of the buys made in that state, but it is a concrete deviation from the stated distribution guarantee. Minimal fix that keeps 'the buyer never shares in its own fee': on the eligible != 0 branch add the parked amount to the distribution, e.g. `uint256 pending = unallocatedFees; unallocatedFees = 0; dividendPerShare += (fee + pending) * MAGNITUDE / eligible;` (the buyer is still checkpointed on its pre-buy balance by the second _accrue(to)). The protected harness does not catch this because its factory keeps the seed remainder and never forwards it to 0xdead, so eligibleSupply() is nonzero there.","line":149,"path":"src/SITRToken.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {SITRToken} from \"src/SITRToken.sol\";\n\n/// @dev Stands in for the launch factory: deploys the token (so it is msg.sender in the\n/// constructor), answers distributorOf(uint64) and moves the supply the way the factory does.\ncontract ProofFactory {\n    mapping(uint64 => address) public distributorOf;\n\n    function deploy(uint64 launchNumber) external returns (SITRToken) {\n        return new SITRToken(launchNumber);\n    }\n\n    function register(uint64 launchNumber, address distributor) external {\n        distributorOf[launchNumber] = distributor;\n    }\n\n    function move(SITRToken token, address to, uint256 amount) external {\n        require(token.transfer(to, amount), \"transfer failed\");\n    }\n}\n\n/// @notice After a standard launch every balance is excluded (distributor, PoolManager, burn\n/// address), so the first buy's 3% fee is taken while eligibleSupply() == 0. M1 says the fee is\n/// distributed to holders and nothing is locked; the code parks it in unallocatedFees and no path\n/// ever pays it out. Fails on the current tree, passes once parked fees are carried into the next\n/// distribution with a nonzero eligible supply.\ncontract UnallocatedFeesLockedTest is Test {\n    uint256 private constant SUPPLY = 1_000_000_000e18;\n    uint64 private constant LAUNCH = 1;\n    address private constant POOL_MANAGER = 0x000000000004444c5dc75cB358380D2e3dE08A90;\n    address private constant BURN = 0x000000000000000000000000000000000000dEaD;\n\n    ProofFactory private factory;\n    SITRToken private token;\n    address private distributor = makeAddr(\"merkle distributor\");\n    address private alice = makeAddr(\"alice\");\n    address private bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        factory = new ProofFactory();\n        token = factory.deploy(LAUNCH);\n        factory.register(LAUNCH, distributor);\n        // The launch flows: 10% to the distributor, 90% to the pool, remainder to 0xdead.\n        factory.move(token, distributor, SUPPLY / 10);\n        factory.move(token, POOL_MANAGER, (SUPPLY * 9) / 10);\n        factory.move(token, BURN, token.balanceOf(address(factory)));\n        assertEq(token.eligibleSupply(), 0, \"fixture: nothing eligible after launch\");\n    }\n\n    function test_firstBuyFeeIsEventuallyDistributedToHolders() public {\n        // First buy of the launch: 10,000,000 SITR gross, 300,000 SITR fee, nobody eligible yet.\n        vm.prank(POOL_MANAGER);\n        token.transfer(alice, 10_000_000e18);\n        uint256 firstFee = 300_000e18;\n        assertEq(token.balanceOf(address(token)), firstFee, \"fixture: first fee parked in the contract\");\n        assertEq(token.balanceOf(alice), 10_000_000e18 - firstFee);\n\n        // Ordinary trading afterwards: holders exist, every later fee is distributed.\n        for (uint256 i; i < 20; ++i) {\n            vm.prank(POOL_MANAGER);\n            token.transfer(bob, 1_000_000e18);\n            vm.prank(bob);\n            token.transfer(POOL_MANAGER, 500_000e18);\n        }\n\n        token.claimFor(alice);\n        token.claimFor(bob);\n\n        // Expected (M1: the fee is distributed to holders pro rata, nothing is locked): once a\n        // distribution with eligible holders has happened and everyone has claimed, the contract\n        // holds only per-distribution rounding dust. Actual: the whole first-buy fee is still there.\n        uint256 left = token.balanceOf(address(token));\n        assertLt(left, firstFee, \"the first buy's fee was never distributed to any holder\");\n        assertLe(left, 1e6, \"the contract holds more than rounding dust after every holder claimed\");\n    }\n}","reproduction":"Factory fixture deploys SITRToken(1), registers distributorOf(1)=D, then moves 100,000,000e18 to D, 900,000,000e18 to the PoolManager 0x000000000004444c5dc75cB358380D2e3dE08A90 and the rest to 0xdEaD; eligibleSupply() == 0. vm.prank(POOL_MANAGER); token.transfer(alice, 10_000_000e18): alice receives 9,700,000e18 and balanceOf(token) == unallocatedFees == 300,000e18. Then 20 rounds of PoolManager->bob 1,000,000e18 (buy) and bob->PoolManager 500,000e18 (sell), then claimFor(alice) and claimFor(bob). Expected (M1): the parked 300,000e18 is distributed in a later round and the contract holds only rounding dust after all holders claim. Actual (forge test test/scratch/UnallocatedFeesLocked.t.sol on this tree): balanceOf(token) == 300000000000000000000001, claimableDividends(alice) == claimableDividends(bob) == 0, unallocatedFees == 300000e18, and no function can move it. The same test passes against a copy of the token with the carry-forward fix above.","severity":"low","snippet":"                if (eligible == 0) {\n                    unallocatedFees += fee;","title":"Buy fees collected while eligibleSupply() is 0 (always the launch's first buy) are parked in unallocatedFees and can never be distributed or claimed"},{"citation":"resolved","description":"Until _distributor is pinned, every _transfer and _claimFor staticcalls factory.distributorOf(launchNumber). Two branches: (a) a zero, reverting, empty or malformed answer makes any PoolManager outflow whose fee != 0 (amount >= 34 wei) revert with DistributorUnavailable at line 146, while untaxed paths continue; (b) an answer equal to the factory, the PoolManager, the token or 0xdEaD reverts with InvalidDistributor at lines 181-184 on every path, including wallet transfers, sells, swarm claims out of the distributor, claim() and claimFor(), and nothing in the token can clear it (no setter, no fallback, re-queried on each call). With the sanctioned factory (the protected harness defines `mapping(uint64 => address) public distributorOf` and registers the distributor before the swarm transfer, seed and swaps, and the factory creates the distributor itself so a reserved value cannot occur) neither branch is reachable, so this is recorded as the preconditions the launch relies on, not a code defect. Merged from audit_flow (info), audit_economics (info) and audit_permissions (low, the branch asymmetry); if the author wants the token to degrade more gracefully, treating a reserved answer like an unavailable one (return address(0) without pinning) would confine the failure to taxed buys, but the brief's rule that the distributor is resolved from the factory does not require it. Economic note from audit_economics: because the seed is single-sided, if buys were impossible no IMD would ever enter the pool and sells would have nothing to withdraw, so the deployer should confirm distributorOf(launchNumber) answers before trading opens.","line":146,"path":"src/SITRToken.sol","reproduction":"Fixture factory with mapping(uint64=>address) public distributorOf; deploy SITRToken(7); factory.transfer(holder, 100e18); factory.transfer(POOL_MANAGER, 100e18). (a) register distributorOf(7)=factory: vm.prank(holder); token.transfer(victim, 1e18) reverts InvalidDistributor; holder->POOL_MANAGER 1e18 reverts InvalidDistributor; vm.prank(holder); token.claim() and token.claimFor(holder) revert InvalidDistributor. (b) register distributorOf(7)=address(0): holder->victim 1e18 succeeds; vm.prank(POOL_MANAGER); token.transfer(victim, 50e18) reverts DistributorUnavailable; vm.prank(POOL_MANAGER); token.transfer(victim, 33) succeeds untaxed (fee rounds to 0). Verified with a scratch Foundry test on this tree; also exercised by test/SITRToken.t.sol test_MalformedRegistryAllowsUntaxedTransfersButRejectsBuys and test_InvalidDistributorRevertsWithoutPinningOrMovingSupply.","severity":"info","snippet":"                if (distributor == address(0)) revert DistributorUnavailable();","title":"Fee-bearing buys and the pin depend on factory.distributorOf(uint64): an unavailable answer reverts every taxed buy, a reserved answer reverts every transfer and claim (trust assumption on the factory"},{"citation":"resolved","description":"The fee is distributed against _eligibleSupply(distributor), which includes the buyer's existing balance, and the second _accrue(to, distributor) at line 159 then credits the buyer on that pre-buy balance at the new index. M1 says both 'the buyer never shares in its own fee' and 'checkpoint the buyer on its pre-buy balance'; the code and README implement the second (parenthetical) reading, under which a buyer holding share s of the eligible supply recovers s x 3% of its own buy. Early after launch, when eligible supply is small, a whale that already holds most of it can accumulate from the pool at an effective fee near 0% while other holders receive almost nothing. This matches the authoritative mechanics text, so it is not reported as a defect; it is recorded so the requester confirms which sentence is intended. From audit_economics (info).","line":147,"path":"src/SITRToken.sol","reproduction":"Factory fixture: register distributor; factory.transfer(distributor, 1e26); factory.transfer(holder, 1e18); factory.transfer(attacker, 99e18); rest to POOL_MANAGER. vm.prank(POOL_MANAGER); token.transfer(attacker, 10_000e18). Actual (scratch test on this tree): totalFeesCollected == 300e18, claimableDividends(attacker) == 297e18, claimableDividends(holder) == 3e18. Under the reading 'the buyer never shares in its own fee' the expected split would be attacker 0 / holder 300e18.","severity":"info","snippet":"                uint256 eligible = _eligibleSupply(distributor);","title":"A buyer's pre-buy balance shares in its own fee, so a holder owning most of the eligible supply pays a near-zero effective buy fee (M1 wording ambiguity, requester to confirm)"},{"citation":"resolved","description":"dividendPerShare rises by fee * MAGNITUDE / eligible at each buy and every eligible balance present at that instant, including one bought in the same block or bundle, is credited in full. A searcher who sees a large buy in the mempool can buy first, be credited the bulk of the victim's fee, claimFor itself and sell back untaxed in the same block; the loss is borne by the pre-existing holders, who would otherwise have received the whole fee, and the capture ratio approaches 100% right after launch when eligible supply is small. This is inherent to the balance-pro-rata distribution M1 specifies (no snapshot, holding period or same-block exclusion is requested), so it is a design note for the requester rather than a coding defect. From audit_economics (low), recalibrated to info because it implements the stated mechanics.","line":154,"path":"src/SITRToken.sol","reproduction":"Factory fixture: register distributor; factory.transfer(distributor, 1e26); factory.transfer(holder, 100e18); rest to POOL_MANAGER. Step 1 vm.prank(POOL_MANAGER); token.transfer(attacker, 1000e18): holder credited 30e18-1. Step 2 vm.prank(POOL_MANAGER); token.transfer(victim, 3000e18) (fee 90e18). Actual (scratch test on this tree): claimableDividends(attacker) == 81588785046728971962, holder gains 8411214953271028038 from the victim's fee (holder total 38411214953271028037). Step 3 token.claimFor(attacker) then vm.prank(attacker); token.transfer(POOL_MANAGER, 1051588785046728971962) succeeds untaxed. Expected if the fee went to pre-existing holders: holder credited 90e18 from the victim's buy.","severity":"info","snippet":"                    dividendPerShare += fee * MAGNITUDE / eligible;","title":"Dividends are pro rata to the balance at the instant of each buy with no time weighting, so a same-block front-runner captures most of a large buy's fee from existing holders (property of the specifie"},{"citation":"resolved","description":"Only the four fixed addresses are excluded and M1 requires that anyone may call claimFor(holder). Any contract that holds SITR and tracks its own balance separately from balanceOf (a v2 pair, or any vault measuring balanceOf - reserve) is an eligible holder, accrues a share of every buy fee, and the moment a third party calls claimFor(pair) the paid amount sits above the pair's recorded reserve, where skim(to) hands it to the caller rather than the pair's LPs. The beneficiary is whoever front-runs with claimFor+skim; the victims are LPs of secondary venues. This follows from the agreed design (no admin exclusion list, permissionless payout required by M1), so no code change is recommended without a design decision; README line 42 could add that third parties can trigger a holder's payout. From audit_permissions (low), recalibrated to info.","line":113,"path":"src/SITRToken.sol","reproduction":"Factory fixture: register distributor; deploy a minimal PairLike with sync()/skim(to); factory.transfer(distributor, 1e26); factory.transfer(pair, 100e18); pair.sync(); rest to POOL_MANAGER (so the pair is the only eligible holder). vm.prank(POOL_MANAGER); token.transfer(victim, 100e18): claimableDividends(pair) == 2999999999999999999. vm.prank(attacker); token.claimFor(pair); vm.prank(attacker); pair.skim(attacker). Actual (scratch test on this tree): balanceOf(attacker) == 2999999999999999999 while pair.reserve stays 100e18.","severity":"info","snippet":"    function claimFor(address holder) external returns (uint256) {","title":"Permissionless claimFor pays dividends into any non-excluded contract holder, so a Uniswap v2-style pair's rewards can be skimmed by whoever calls claimFor then skim (consequence of the specified clai"}],"hash":"99380ead90a18bb3058f06371424904cc777c2199d4e91fb2fa3b5e802c5ca7b","nodeId":"ca467c9c-857d-42d8-99bc-e1c8d8e863b6","outcome":"completed","summary":"The review is complete and the findings file is written. Scratch tests are removed, and only `.imd-findings.json` differs from the tree.\n\n**Outcome.** The token holds up well. One low finding reopens the author's work, and four trust-assumption notes are recorded as info. Every specialist finding reproduced; two pairs of duplicates were merged.\n\n**Findings written to `.imd-findings.json`:**\n\n1. **Low, with proof.** Fees taken while eligible supply is zero are parked in `unallocatedFees` and no path ever distributes them. After the real launch flow every balance is excluded (distributor, PoolManager, 0xdead), so the launch's first buy always hits this branch and its 3% fee is locked forever. The spec says the fee is distributed and nothing is locked. The proof test fails on this tree and passes against a scratch copy with a carry-forward fix. Merged from audit_math and audit_economics.\n2. **Info.** Registry dependency: an unavailable `distributorOf` answer reverts taxed buys, a reserved answer reverts every transfer and claim. Unreachable with the sanctioned factory, recorded as the launch precondition. Merged from audit_flow, audit_economics and audit_permissions.\n3. **Info.** A buyer's pre-buy balance shares in its own fee. This follows the parenthetical in M1, so it is flagged only as a wording ambiguity for the requester.\n4. **Info.** Same-block front-running captures most of a large buy's dividend. Inherent to the balance-pro-rata design M1 specifies, downgraded from low.\n5. **Info.** Permissionless `claimFor` plus a v2 pair's `skim` lets any caller take the pair's dividends. Consequence of the required `claimFor`, downgraded from low.\n\n**My own pass found nothing further.** I checked overflow bounds in the accrual math (a holder's credit is bounded by total fees times 2^128, far below 2^256), dividend solvency, Uniswap v4 settlement exactness on seeds and sells, the deployment model (one static `$launchNumber` argument, no on-chain needs in the constructor, no delegatecall or selfdestruct), and the manifest's keys, types and values. The slither divide-before-multiply line is the intentional rounding of the fee to minor units and was dropped.\n\n**Coverage.** All five entry points are answered: `approve`, `claim` and `claimFor` hold; `transfer` and `transferFrom` carry finding 1 since both reach the parked-fee branch. Three invariant rows cover solvency, launch flows and the manifest.","treeHash":null,"usage":{"cachedInputTokens":779417,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":29173,"runtime":"claude","turns":18,"wallClockMs":417163}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"de319b702da6aa2e","findings":[{"citation":"resolved","description":"In _transfer, a buy fee taken when _eligibleSupply() is 0 is added to unallocatedFees and to balanceOf[address(this)], but no code path ever distributes or releases unallocatedFees: dividendPerShare is never incremented for it, claim()/claimFor() can only pay out accrued dividendPerShare credit, and there is no admin (by design). The tokens stay in the contract permanently, outside circulating supply and never paid to holders. After the standard launch flow (factory sends 10% to the excluded Merkle distributor, seeds about 90% into the excluded PoolManager, and sends any remainder to the excluded burn address remainderTo=0x...dead), every eligible balance is zero. So the first buy that happens before any Merkle claim (in practice the launch-block snipe) always hits this branch. That contradicts M1 ('The fee stays in the token contract and is distributed to holders pro rata ... so nothing credited to a contract is locked'). The same thing happens later whenever every eligible holder has sold to the PoolManager. Impact: a permanent loss to holders equal to 3% of every buy made while eligible supply is 0 (normally just the first buy, which can be large: 3% of a 10M SITR first buy is 300,000 SITR). Funds are not stolen, so this is low. Minimal fix that keeps 'the buyer never shares in its own fee': carry the parked amount into the next distribution where eligible > 0, for example at the top of the fee branch `uint256 pending = unallocatedFees; if (eligible != 0 && pending != 0) { unallocatedFees = 0; dividendPerShare += (fee + pending) * MAGNITUDE / eligible; }`. The buyer's pre-buy weight is still checkpointed by the second _accrue(to), so the current buyer still does not share in its own fee. The earlier buyer that paid the parked fee would receive a pro-rata share of it; the author needs to accept that tradeoff, or else distribute the parked amount on the next untaxed transfer when eligible supply becomes nonzero.","line":149,"path":"src/SITRToken.sol","reproduction":"Factory deploys SITRToken(1) and registers distributorOf(1)=D. Factory transfers 100,000,000e18 to D and 900,000,000e18 to PoolManager 0x000000000004444c5dc75cB358380D2e3dE08A90, so eligibleSupply() == 0. PoolManager transfers 10,000,000e18 to alice (the first buy): alice receives 9,700,000e18, and unallocatedFees == balanceOf(token) == 300,000e18. Then run 20 rounds of: PoolManager -> bob 1,000,000e18 (buy), bob -> PoolManager 500,000e18 (sell). Then call claimFor(alice) and claimFor(bob). Expected: the 300,000e18 first-buy fee was distributed to holders and is claimable. Actual (Foundry scratch run against this tree): balanceOf(token) == 300000000000000000000001, claimableDividends(alice) == claimableDividends(bob) == 0, and no function can ever move the 300,000e18 out of the contract.","severity":"low","snippet":"                if (eligible == 0) {\n                    unallocatedFees += fee;\n                } else {","title":"Buy fees collected while eligible supply is zero (the first buy after a standard launch) are locked in the token contract forever"}],"hash":"9f1865f5b0bff344aa94b5e3a4899e7a9caf59648b7b4c25db782ad73df2a432","nodeId":"c7b06755-e807-4fc7-89c2-3d42fab4851d","outcome":"completed","summary":"I found one defect, rated low. It's written to `.imd-findings.json`, with a coverage row for each of the five entry points and three rows for invariants I checked. No project files were changed; I deleted the scratch test after running it.\n\n**Finding 1 (low): the first buy's fee is locked forever** (`src/SITRToken.sol:149`)\n- **What happens:** if a buy is made while no eligible holder has a balance, its 3% fee is added to `unallocatedFees` and stays in the contract. Nothing ever pays it out: claims only pay what each holder has accrued, and by design there is no admin to release it.\n- **When it happens:** right after a normal launch, every balance sits with an excluded address. 10% is with the distributor, about 90% is in the PoolManager, and any remainder goes to the burn address. So the first buy before any Merkle claim always hits this case. It also happens again later if every eligible holder sells everything back to the pool.\n- **Reproduction (Foundry, against this code):** a first buy of 10,000,000 SITR parks 300,000 SITR. After 20 rounds of buying and selling and claims for both holders, the contract still holds 300,000 SITR plus 1 unit (minor unit) of rounding dust, and nobody can claim any of it. The spec (M1) says the fee is distributed to holders.\n- **Suggested fix:** add the parked amount to the next fee distributed when eligible supply is above zero. The current buyer still won't share in its own fee. The catch, which you need to decide on: the earlier buyer who paid the parked fee would get a pro-rata share of it.\n\n**What checked out:**\n- **Fee and the static-analysis lead:** the fee rounds down, so buys of 33 units or less pay nothing, which is negligible. Slither's divide-before-multiply warning is not a defect, because exactly the fee that was charged is what gets distributed.\n- **Buyer exclusion:** the buyer earns only on its balance from before the buy, as the spec requires.\n- **Overflow:** none possible. Even with 1 unit of eligible supply and a fee near the maximum, the largest intermediate value is about 3.4e65, far below the 2^256 limit.\n- **Rounding:** losses are under 1 unit per distribution, and claims keep the fractional remainder for later.\n- **Solvency:** the contract always holds at least what holders can claim plus the parked fees.\n- **Eligible supply:** it always equals the total of all non-excluded balances.\n- **Other entry points:** `approve`, `claim`, `claimFor` and `transferFrom` all behave as intended.\n- **launch.json:** it matches the constructor, and `initialPrice` is consistent with the 2,500 IMD opening market cap.\n\n**Not covered:** I didn't test the real factory's `LaunchLiquidity` seeding code, because it isn't in this repository. The finding doesn't come with a proof test, since only critical and high findings need one.","treeHash":null,"usage":{"cachedInputTokens":463726,"inputTokens":16,"model":"claude-opus-5-5","outputTokens":16870,"runtime":"claude","turns":8,"wallClockMs":182104}},{"artifacts":[],"attempt":1,"bundleHash":"73c29c1bcd73584e10f525b036fc5bce9258b9f1595c3d971e7ff3765061cc21","device":"26d42bb29b53b9d8","findings":[],"hash":"a44693c5f4401e63be8532969ee2088cc9f41b0da2fca5eceb736e2f188aca5f","nodeId":"35ae1d8b-19c8-4ded-947a-f1cd945d5a5f","outcome":"completed","summary":"Completed using the existing implementation. Fixed malformed distributor lookup handling, added two regression tests, and documented deployment responsibilities. Confirmed exact launch manifest values; protected configuration and dependencies remain unchanged.\n\nValidation passed: `forge build`, all 25 tests, and `forge fmt --check`.\n\nLive-fork and environment-dependent protected harness checks remain unrun.","treeHash":"1b5e5e3a556a7d8d9bdcdba369b80b16a3e9e206","usage":{"cachedInputTokens":963200,"inputTokens":72199,"model":"gpt-6-astra","outputTokens":8814,"runtime":"codex","turns":6,"wallClockMs":250147}},{"artifacts":[],"attempt":1,"bundleHash":"6bfa79c37a84fb20196b3c374601769676dd69a22e2eee67b8808de7f6980109","device":"500cef6ec1073663","findings":[],"hash":"eef4f2062a49961ccf86d11a426024e45bd14274d1674fc55694742818e51cc1","nodeId":"f85f5ca3-86f5-497c-b6a6-0c01b1da5c23","outcome":"completed","summary":"Updated `launch.json` notes and verified its constructor arguments, supply, pool settings, and economics match the accepted implementation and brief.\n\n`forge build` succeeded; all 51 tests passed. Only `launch.json` changed.","treeHash":"980e2062dd254abb8699207fe761e7aa88769fe6","usage":{"cachedInputTokens":294528,"inputTokens":31919,"model":"gpt-6-astra","outputTokens":2859,"runtime":"codex","turns":3,"wallClockMs":84648}}],"verification":[{"checks":[{"durationMs":360,"exitCode":0,"name":"build","output":"Compiling 2 files with Solc 0.8.26\nSolc 0.8.26 finished in 308.61ms\nCompiler run successful!\n","passed":true},{"durationMs":1709,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 23 tests for test/SITRToken.t.sol:SITRTokenTest\n[PASS] testFuzz_BuyConservationAndPreBuyProportions(uint96,uint96,uint96) (runs: 1000, μ: 729388, ~: 760021)\n[PASS] testFuzz_SequencesPreserveSupplyAndDividendSolvency(bytes32) (runs: 1000, μ: 20227079, ~: 20227151)\n[PASS] test_AllFourExcludedBalancesEarnNothing() (gas: 707674)\n[PASS] test_AllocationAndSwarmClaimArriveWhole() (gas: 262453)\n[PASS] test_BuyerNewBalanceDoesNotShareOwnFee() (gas: 444523)\n[PASS] test_ClaimForPaysHolderAndCanBeRepeated() (gas: 607431)\n[PASS] test_ClaimWorksForContractWithNoClaimEntryPoint() (gas: 550999)\n[PASS] test_ClaimedTokensEarnOnlySubsequentFees() (gas: 678130)\n[PASS] test_DistributorMayBeRegisteredAfterDeploymentAndCannotBeChanged() (gas: 771461)\n[PASS] test_EarnedDividendsStayWithSellerAfterAllTokensMove() (gas: 677456)\n[PASS] test_EntireSupplyMintedOnceToDeployer() (gas: 47554)\n[PASS] test_FractionalCreditSurvivesRepeatedCheckpoints() (gas: 1041193)\n[PASS] test_InfiniteApprovalIsPreserved() (gas: 222552)\n[PASS] test_InvalidTransfersRevertWithoutChangingAccounting() (gas: 416234)\n[PASS] test_NoEligibleHoldersDoesNotCreditFirstBuyer() (gas: 645742)\n[PASS] test_NoMintAdminOrPrivilegedBalanceMovement() (gas: 489469)\n[PASS] test_OnlyBuysPayThreePercent() (gas: 582071)\n[PASS] test_ReturningBuyerOnlyEarnsOnPreBuyBalance() (gas: 438063)\n[PASS] test_RuntimeHasNoForbiddenInstructions() (gas: 915060)\n[PASS] test_SeedBuyAndSellSettleExactManagerDeltas() (gas: 813433)\n[PASS] test_TransferCannotMoveHistoricalDividendsToReceiver() (gas: 551124)\n[PASS] test_TransferFromTaxesSourceRatherThanCallerAndUsesGrossAllowance() (gas: 656187)\n[PASS] test_ZeroAndSelfTransfersCannotCreateDividends() (gas: 378740)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 1.66s (1.78s CPU time)\n\nRan 1 test suite in 1.66s (1.66s CPU time): 23 tests passed, 0 failed, 0 skipped (23 total tests)\n","passed":true},{"durationMs":95,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SITRToken.approve(address,uint256)\",\"SITRToken.claim()\",\"SITRToken.claimFor(address)\",\"SITRToken.transfer(address,uint256)\",\"SITRToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":34,\"foundry.toml\":10,\"launch.json\":24,\"logos/README.md\":5,\"logos/logo-1.png\":3492,\"logos/logo-2.png\":2903,\"logos/logo-3.png\":2970,\"logos/logo-4.png\":5102,\"logos/logo-5.png\":3729,\"src/SITRToken.sol\":197,\"test/SITRToken.t.sol\":448},\"excluded\":[\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":366,"exitCode":0,"name":"slither","output":"[medium/medium] divide-before-multiply at src/SITRToken.sol:129: SITRToken._transfer(address,address,uint256) (src/SITRToken.sol#129-165) performs a multiplication on the result of a division:","passed":true},{"durationMs":219,"exitCode":0,"name":"aderyn","output":"[low] large-numeric-literal at src/SITRToken.sol:17: Large Numeric Literal\n[low] unused-public-function at src/SITRToken.sol:90: Public Function Not Used Internally (3 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"19abc555c115651c050eb5a37daba4d207443e71ff21e094002eb98b9a9e574c","verifiedTreeHash":"b4ee8cd919d36c3ae0d32faae034f28232fa2aee","verifierVersion":"0.1.0+fdeb4d4a"},{"checks":[{"durationMs":2531,"exitCode":0,"name":"build","output":"Compiling 72 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.36s\nCompiler run successful!\n","passed":true},{"durationMs":1659,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 9 tests for test/SITRTokenPoolManager.t.sol:SITRTokenPoolManagerTest\n[PASS] testFuzz_RealSwapRewardsExistingHolderAndAllowsPermissionlessPayout(uint96) (runs: 256, μ: 699141, ~: 698924)\nLogs:\n  Bound result 3909302033199642453\n\n[PASS] test_ExactOutputBuyPaysNetOfTransferFeeAndExactOutputSellSettlesWhole() (gas: 513455)\n[PASS] test_InternalERC6909CreditIsUntaxedUntilItBecomesAnERC20Outflow() (gas: 543830)\n[PASS] test_SecondSwapCreditsReturningContractBuyerOnlyOnItsExistingTokens() (gas: 756216)\n[PASS] test_SeedBuyAndSellAlsoWorkWithTheOppositeCurrencyOrder() (gas: 1513047)\n[PASS] test_SingleSidedLaunchFirstBuyAndSellSettleAtTheRealManagerAddress() (gas: 736098)\n[PASS] test_UnderpaidBuyRollsBackTransferTaxAndDividendAccrual() (gas: 703890)\n[PASS] test_UnderpaidSellRevertsCurrencyNotSettledAndRollsBackAllState() (gas: 892709)\n[PASS] test_ZeroSwapAndLockedManagerFailWithoutMovingTokens() (gas: 375009)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 36.43ms (39.38ms CPU time)\n\nRan 15 tests for test/SITRTokenEdges.t.sol:SITRTokenEdgesTest\n[PASS] testFuzz_ReturningBuyerUsesOnlyItsPreBuyWeight(uint96,uint96,uint96) (runs: 256, μ: 466377, ~: 477057)\nLogs:\n  Bound result 2\n  Bound result 256881989379\n  Bound result 536769492406989150234004\n\n[PASS] testFuzz_ZeroAndSelfCheckpointsPreserveFractionalRewards(uint32,uint32,uint16) (runs: 256, μ: 2582670, ~: 2575983)\nLogs:\n  Bound result 2048\n  Bound result 5222\n  Bound result 73\n\n[PASS] test_ApprovalOverwriteRevocationAndEvent() (gas: 1129539)\n[PASS] test_BuyAndClaimEventsDescribeTheActualTokenMovements() (gas: 563224)\n[PASS] test_ClaimsCommuteWhenThereIsNoInterveningDistribution() (gas: 1526842)\n[PASS] test_DistributorReleaseCannotCapturePastFees() (gas: 581094)\n[PASS] test_DonationsDoNotCreateRewardsOrEraseEarnedDividends() (gas: 872282)\n[PASS] test_ExcludedBuyRecipientsStillPayFeesWithoutReceivingRewards() (gas: 804066)\n[PASS] test_FeeRoundingThresholdsAndZeroBuy() (gas: 1059051)\n[PASS] test_LaunchRegistrationsCannotCrossContaminate() (gas: 340340)\n[PASS] test_NearlyEntireSupplyBuyAndPayoutDoNotOverflow() (gas: 580818)\n[PASS] test_NeitherFactoryNorStrangerHasAnOwnerOrParameterSetter() (gas: 1764093)\n[PASS] test_RegistryRevertDoesNotBreakUntaxedTransfersAndPinnedRegistryIsNotCalled() (gas: 644923)\n[PASS] test_TaxedTransferFromRegistryFailureRestoresGrossAllowance() (gas: 1227531)\n[PASS] test_ZeroAddressesAndMaxAmountsRevertAtomicallyAfterRewardsAccrue() (gas: 1287265)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 78.81ms (101.04ms CPU time)\n\nRan 25 tests for test/SITRToken.t.sol:SITRTokenTest\n[PASS] testFuzz_BuyConservationAndPreBuyProportions(uint96,uint96,uint96) (runs: 256, μ: 723966, ~: 760086)\n[PASS] testFuzz_SequencesPreserveSupplyAndDividendSolvency(bytes32) (runs: 256, μ: 20222096, ~: 20222097)\n[PASS] test_AllFourExcludedBalancesEarnNothing() (gas: 707771)\n[PASS] test_AllocationAndSwarmClaimArriveWhole() (gas: 262644)\n[PASS] test_BuyerNewBalanceDoesNotShareOwnFee() (gas: 444675)\n[PASS] test_ClaimForPaysHolderAndCanBeRepeated() (gas: 607516)\n[PASS] test_ClaimWorksForContractWithNoClaimEntryPoint() (gas: 551132)\n[PASS] test_ClaimedTokensEarnOnlySubsequentFees() (gas: 678101)\n[PASS] test_DistributorMayBeRegisteredAfterDeploymentAndCannotBeChanged() (gas: 772268)\n[PASS] test_EarnedDividendsStayWithSellerAfterAllTokensMove() (gas: 677554)\n[PASS] test_EntireSupplyMintedOnceToDeployer() (gas: 47629)\n[PASS] test_FractionalCreditSurvivesRepeatedCheckpoints() (gas: 1041078)\n[PASS] test_InfiniteApprovalIsPreserved() (gas: 222768)\n[PASS] test_InvalidDistributorRevertsWithoutPinningOrMovingSupply() (gas: 483551)\n[PASS] test_InvalidTransfersRevertWithoutChangingAccounting() (gas: 416494)\n[PASS] test_MalformedRegistryAllowsUntaxedTransfersButRejectsBuys() (gas: 1254366)\n[PASS] test_NoEligibleHoldersDoesNotCreditFirstBuyer() (gas: 645843)\n[PASS] test_NoMintAdminOrPrivilegedBalanceMovement() (gas: 489678)\n[PASS] test_OnlyBuysPayThreePercent() (gas: 582236)\n[PASS] test_ReturningBuyerOnlyEarnsOnPreBuyBalance() (gas: 438168)\n[PASS] test_RuntimeHasNoForbiddenInstructions() (gas: 949531)\n[PASS] test_SeedBuyAndSellSettleExactManagerDeltas() (gas: 813778)\n[PASS] test_TransferCannotMoveHistoricalDividendsToReceiver() (gas: 551189)\n[PASS] test_TransferFromTaxesSourceRatherThanCallerAndUsesGrossAllowance() (gas: 656367)\n[PASS] test_ZeroAndSelfTransfersCannotCreateDividends() (gas: 378851)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 567.82ms (618.22ms CPU time)\n\nRan 2 tests for test/SITRTokenInvariant.t.sol:SITRTokenInvariantTest\n[PASS]\nSITRTokenInvariantTest invariants:\n[PASS] invariant_EachHolderKeepsExactlyItsEarnedShareAcrossMovesAndClaims\n[PASS] invariant_EscrowCoversAllDebtsAndOnlyFeesFundDividends\n[PASS] invariant_ExcludedAccountsNeverAccrueRewards\n[PASS] invariant_SupplyPrincipalAndEligibleSupplyAreConserved\n SITRTokenInvariantTest invariants (runs: 64, calls: 4096, reverts: 0)\n\n╭-------------+----------------------------+-------+---------+----------╮\n| Contract    | Selector                   | Calls | Reverts | Discards |\n+=======================================================================+\n| SITRHandler | buy                        | 596   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | checkpoint                 | 580   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | claim                      | 585   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | emptyEligibleSupply        | 590   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | move                       | 589   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | rejectUnauthorizedTransfer | 579   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | sell                       | 577   | 0       | 0        |\n╰-------------+----------------------------+-------+---------+----------╯\n\n[PASS] test_HandlerExercisesBuySellDelegationDonationsAndClaims() (gas: 3765915)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.56s (1.56s CPU time)\n\nRan 4 test suites in 1.56s (2.24s CPU time): 51 tests passed, 0 failed, 0 skipped (51 total tests)\n","passed":true},{"durationMs":126,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SITRToken.approve(address,uint256)\",\"SITRToken.claim()\",\"SITRToken.claimFor(address)\",\"SITRToken.transfer(address,uint256)\",\"SITRToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":56,\"foundry.toml\":10,\"launch.json\":24,\"logos/README.md\":5,\"logos/logo-1.png\":3492,\"logos/logo-2.png\":2903,\"logos/logo-3.png\":2970,\"logos/logo-4.png\":5102,\"logos/logo-5.png\":3729,\"src/SITRToken.sol\":202,\"test/README.md\":52,\"test/SITRToken.t.sol\":496,\"test/SITRTokenEdges.t.sol\":297,\"test/SITRTokenInvariant.t.sol\":290,\"test/SITRTokenPoolManager.t.sol\":309,\"test/helpers/SITRTestBase.sol\":65,\"test/helpers/V4Actors.sol\":113,\"test/vendor/UPSTREAM.md\":79,\"test/vendor/forge-std/Base.sol\":42,\"test/vendor/forge-std/LICENSE-APACHE\":203,\"test/vendor/forge-std/LICENSE-MIT\":25,\"test/vendor/forge-std/StdAssertions.sol\":685,\"test/vendor/forge-std/StdChains.sol\":286,\"test/vendor/forge-std/StdCheats.sol\":829,\"test/vendor/forge-std/StdConstants.sol\":30,\"test/vendor/forge-std/StdError.sol\":15,\"test/vendor/forge-std/StdInvariant.sol\":122,\"test/vendor/forge-std/StdJson.sol\":277,\"test/vendor/forge-std/StdMath.sol\":43,\"test/vendor/forge-std/StdStorage.sol\":473,\"test/vendor/forge-std/StdStyle.sol\":333,\"test/vendor/forge-std/StdToml.sol\":277,\"test/vendor/forge-std/StdUtils.sol\":209,\"test/vendor/forge-std/Test.sol\":34,\"test/vendor/forge-std/Vm.sol\":2369,\"test/vendor/forge-std/console.sol\":1552,\"test/vendor/forge-std/console2.sol\":4,\"test/vendor/forge-std/interfaces/IMulticall3.sol\":70,\"test/vendor/forge-std/safeconsole.sol\":13937,\"test/vendor/solmate/LICENSE\":661,\"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\":392,\"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\":155,\"test/vendor/v4-core/src/interfaces/IPoolManager.sol\":235,\"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\":343,\"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/Slot0.sol\":95},\"excluded\":[\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"26f75ac81afc74673a43312a659226f93871526ed4059c9a9546540c86710d10","verifiedTreeHash":"9adf4a2c2beedf745740a8adb54085656889d41b","verifierVersion":"0.1.0+fdeb4d4a"},{"checks":[{"durationMs":402,"exitCode":0,"name":"build","output":"Compiling 2 files with Solc 0.8.26\nSolc 0.8.26 finished in 337.12ms\nCompiler run successful!\n","passed":true},{"durationMs":1733,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 25 tests for test/SITRToken.t.sol:SITRTokenTest\n[PASS] testFuzz_BuyConservationAndPreBuyProportions(uint96,uint96,uint96) (runs: 1000, μ: 729094, ~: 760086)\n[PASS] testFuzz_SequencesPreserveSupplyAndDividendSolvency(bytes32) (runs: 1000, μ: 20223594, ~: 20220225)\n[PASS] test_AllFourExcludedBalancesEarnNothing() (gas: 707771)\n[PASS] test_AllocationAndSwarmClaimArriveWhole() (gas: 262644)\n[PASS] test_BuyerNewBalanceDoesNotShareOwnFee() (gas: 444675)\n[PASS] test_ClaimForPaysHolderAndCanBeRepeated() (gas: 607516)\n[PASS] test_ClaimWorksForContractWithNoClaimEntryPoint() (gas: 551132)\n[PASS] test_ClaimedTokensEarnOnlySubsequentFees() (gas: 678101)\n[PASS] test_DistributorMayBeRegisteredAfterDeploymentAndCannotBeChanged() (gas: 772268)\n[PASS] test_EarnedDividendsStayWithSellerAfterAllTokensMove() (gas: 677554)\n[PASS] test_EntireSupplyMintedOnceToDeployer() (gas: 47629)\n[PASS] test_FractionalCreditSurvivesRepeatedCheckpoints() (gas: 1041078)\n[PASS] test_InfiniteApprovalIsPreserved() (gas: 222768)\n[PASS] test_InvalidDistributorRevertsWithoutPinningOrMovingSupply() (gas: 483551)\n[PASS] test_InvalidTransfersRevertWithoutChangingAccounting() (gas: 416494)\n[PASS] test_MalformedRegistryAllowsUntaxedTransfersButRejectsBuys() (gas: 1254366)\n[PASS] test_NoEligibleHoldersDoesNotCreditFirstBuyer() (gas: 645843)\n[PASS] test_NoMintAdminOrPrivilegedBalanceMovement() (gas: 489678)\n[PASS] test_OnlyBuysPayThreePercent() (gas: 582236)\n[PASS] test_ReturningBuyerOnlyEarnsOnPreBuyBalance() (gas: 438168)\n[PASS] test_RuntimeHasNoForbiddenInstructions() (gas: 949531)\n[PASS] test_SeedBuyAndSellSettleExactManagerDeltas() (gas: 813778)\n[PASS] test_TransferCannotMoveHistoricalDividendsToReceiver() (gas: 551189)\n[PASS] test_TransferFromTaxesSourceRatherThanCallerAndUsesGrossAllowance() (gas: 656367)\n[PASS] test_ZeroAndSelfTransfersCannotCreateDividends() (gas: 378851)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 1.67s (1.78s CPU time)\n\nRan 1 test suite in 1.67s (1.67s CPU time): 25 tests passed, 0 failed, 0 skipped (25 total tests)\n","passed":true},{"durationMs":102,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SITRToken.approve(address,uint256)\",\"SITRToken.claim()\",\"SITRToken.claimFor(address)\",\"SITRToken.transfer(address,uint256)\",\"SITRToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":56,\"foundry.toml\":10,\"launch.json\":24,\"logos/README.md\":5,\"logos/logo-1.png\":3492,\"logos/logo-2.png\":2903,\"logos/logo-3.png\":2970,\"logos/logo-4.png\":5102,\"logos/logo-5.png\":3729,\"src/SITRToken.sol\":202,\"test/SITRToken.t.sol\":498},\"excluded\":[\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":415,"exitCode":0,"name":"slither","output":"[medium/medium] divide-before-multiply at src/SITRToken.sol:134: SITRToken._transfer(address,address,uint256) (src/SITRToken.sol#134-170) performs a multiplication on the result of a division:","passed":true},{"durationMs":245,"exitCode":0,"name":"aderyn","output":"[low] large-numeric-literal at src/SITRToken.sol:17: Large Numeric Literal\n[low] unused-public-function at src/SITRToken.sol:95: Public Function Not Used Internally (3 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a44693c5f4401e63be8532969ee2088cc9f41b0da2fca5eceb736e2f188aca5f","verifiedTreeHash":"1b5e5e3a556a7d8d9bdcdba369b80b16a3e9e206","verifierVersion":"0.1.0+fdeb4d4a"},{"checks":[{"durationMs":2373,"exitCode":0,"name":"build","output":"Compiling 72 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.20s\nCompiler run successful!\n","passed":true},{"durationMs":1709,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 9 tests for test/SITRTokenPoolManager.t.sol:SITRTokenPoolManagerTest\n[PASS] testFuzz_RealSwapRewardsExistingHolderAndAllowsPermissionlessPayout(uint96) (runs: 256, μ: 699166, ~: 698924)\nLogs:\n  Bound result 9999999000000004695\n\n[PASS] test_ExactOutputBuyPaysNetOfTransferFeeAndExactOutputSellSettlesWhole() (gas: 513455)\n[PASS] test_InternalERC6909CreditIsUntaxedUntilItBecomesAnERC20Outflow() (gas: 543830)\n[PASS] test_SecondSwapCreditsReturningContractBuyerOnlyOnItsExistingTokens() (gas: 756216)\n[PASS] test_SeedBuyAndSellAlsoWorkWithTheOppositeCurrencyOrder() (gas: 1513047)\n[PASS] test_SingleSidedLaunchFirstBuyAndSellSettleAtTheRealManagerAddress() (gas: 736098)\n[PASS] test_UnderpaidBuyRollsBackTransferTaxAndDividendAccrual() (gas: 703890)\n[PASS] test_UnderpaidSellRevertsCurrencyNotSettledAndRollsBackAllState() (gas: 892709)\n[PASS] test_ZeroSwapAndLockedManagerFailWithoutMovingTokens() (gas: 375009)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 53.73ms (57.08ms CPU time)\n\nRan 15 tests for test/SITRTokenEdges.t.sol:SITRTokenEdgesTest\n[PASS] testFuzz_ReturningBuyerUsesOnlyItsPreBuyWeight(uint96,uint96,uint96) (runs: 256, μ: 469151, ~: 477093)\nLogs:\n  Bound result 2406\n  Bound result 2233625730\n  Bound result 31\n\n[PASS] testFuzz_ZeroAndSelfCheckpointsPreserveFractionalRewards(uint32,uint32,uint16) (runs: 256, μ: 2585169, ~: 2603271)\nLogs:\n  Bound result 56\n  Bound result 388608\n  Bound result 912\n\n[PASS] test_ApprovalOverwriteRevocationAndEvent() (gas: 1129539)\n[PASS] test_BuyAndClaimEventsDescribeTheActualTokenMovements() (gas: 563224)\n[PASS] test_ClaimsCommuteWhenThereIsNoInterveningDistribution() (gas: 1526842)\n[PASS] test_DistributorReleaseCannotCapturePastFees() (gas: 581094)\n[PASS] test_DonationsDoNotCreateRewardsOrEraseEarnedDividends() (gas: 872282)\n[PASS] test_ExcludedBuyRecipientsStillPayFeesWithoutReceivingRewards() (gas: 804066)\n[PASS] test_FeeRoundingThresholdsAndZeroBuy() (gas: 1059051)\n[PASS] test_LaunchRegistrationsCannotCrossContaminate() (gas: 340340)\n[PASS] test_NearlyEntireSupplyBuyAndPayoutDoNotOverflow() (gas: 580818)\n[PASS] test_NeitherFactoryNorStrangerHasAnOwnerOrParameterSetter() (gas: 1764093)\n[PASS] test_RegistryRevertDoesNotBreakUntaxedTransfersAndPinnedRegistryIsNotCalled() (gas: 644923)\n[PASS] test_TaxedTransferFromRegistryFailureRestoresGrossAllowance() (gas: 1227531)\n[PASS] test_ZeroAddressesAndMaxAmountsRevertAtomicallyAfterRewardsAccrue() (gas: 1287265)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 75.20ms (102.25ms CPU time)\n\nRan 25 tests for test/SITRToken.t.sol:SITRTokenTest\n[PASS] testFuzz_BuyConservationAndPreBuyProportions(uint96,uint96,uint96) (runs: 256, μ: 730639, ~: 760086)\n[PASS] testFuzz_SequencesPreserveSupplyAndDividendSolvency(bytes32) (runs: 256, μ: 20221546, ~: 20222843)\n[PASS] test_AllFourExcludedBalancesEarnNothing() (gas: 707771)\n[PASS] test_AllocationAndSwarmClaimArriveWhole() (gas: 262644)\n[PASS] test_BuyerNewBalanceDoesNotShareOwnFee() (gas: 444675)\n[PASS] test_ClaimForPaysHolderAndCanBeRepeated() (gas: 607516)\n[PASS] test_ClaimWorksForContractWithNoClaimEntryPoint() (gas: 551132)\n[PASS] test_ClaimedTokensEarnOnlySubsequentFees() (gas: 678101)\n[PASS] test_DistributorMayBeRegisteredAfterDeploymentAndCannotBeChanged() (gas: 772268)\n[PASS] test_EarnedDividendsStayWithSellerAfterAllTokensMove() (gas: 677554)\n[PASS] test_EntireSupplyMintedOnceToDeployer() (gas: 47629)\n[PASS] test_FractionalCreditSurvivesRepeatedCheckpoints() (gas: 1041078)\n[PASS] test_InfiniteApprovalIsPreserved() (gas: 222768)\n[PASS] test_InvalidDistributorRevertsWithoutPinningOrMovingSupply() (gas: 483551)\n[PASS] test_InvalidTransfersRevertWithoutChangingAccounting() (gas: 416494)\n[PASS] test_MalformedRegistryAllowsUntaxedTransfersButRejectsBuys() (gas: 1254366)\n[PASS] test_NoEligibleHoldersDoesNotCreditFirstBuyer() (gas: 645843)\n[PASS] test_NoMintAdminOrPrivilegedBalanceMovement() (gas: 489678)\n[PASS] test_OnlyBuysPayThreePercent() (gas: 582236)\n[PASS] test_ReturningBuyerOnlyEarnsOnPreBuyBalance() (gas: 438168)\n[PASS] test_RuntimeHasNoForbiddenInstructions() (gas: 949531)\n[PASS] test_SeedBuyAndSellSettleExactManagerDeltas() (gas: 813778)\n[PASS] test_TransferCannotMoveHistoricalDividendsToReceiver() (gas: 551189)\n[PASS] test_TransferFromTaxesSourceRatherThanCallerAndUsesGrossAllowance() (gas: 656367)\n[PASS] test_ZeroAndSelfTransfersCannotCreateDividends() (gas: 378851)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 540.51ms (584.48ms CPU time)\n\nRan 2 tests for test/SITRTokenInvariant.t.sol:SITRTokenInvariantTest\n[PASS]\nSITRTokenInvariantTest invariants:\n[PASS] invariant_EachHolderKeepsExactlyItsEarnedShareAcrossMovesAndClaims\n[PASS] invariant_EscrowCoversAllDebtsAndOnlyFeesFundDividends\n[PASS] invariant_ExcludedAccountsNeverAccrueRewards\n[PASS] invariant_SupplyPrincipalAndEligibleSupplyAreConserved\n SITRTokenInvariantTest invariants (runs: 64, calls: 4096, reverts: 0)\n\n╭-------------+----------------------------+-------+---------+----------╮\n| Contract    | Selector                   | Calls | Reverts | Discards |\n+=======================================================================+\n| SITRHandler | buy                        | 551   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | checkpoint                 | 610   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | claim                      | 594   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | emptyEligibleSupply        | 564   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | move                       | 628   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | rejectUnauthorizedTransfer | 593   | 0       | 0        |\n|-------------+----------------------------+-------+---------+----------|\n| SITRHandler | sell                       | 556   | 0       | 0        |\n╰-------------+----------------------------+-------+---------+----------╯\n\n[PASS] test_HandlerExercisesBuySellDelegationDonationsAndClaims() (gas: 3765915)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.63s (1.63s CPU time)\n\nRan 4 test suites in 1.63s (2.30s CPU time): 51 tests passed, 0 failed, 0 skipped (51 total tests)\n","passed":true},{"durationMs":129,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SITRToken.approve(address,uint256)\",\"SITRToken.claim()\",\"SITRToken.claimFor(address)\",\"SITRToken.transfer(address,uint256)\",\"SITRToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":56,\"foundry.toml\":10,\"launch.json\":24,\"logos/README.md\":5,\"logos/logo-1.png\":3492,\"logos/logo-2.png\":2903,\"logos/logo-3.png\":2970,\"logos/logo-4.png\":5102,\"logos/logo-5.png\":3729,\"src/SITRToken.sol\":202,\"test/README.md\":52,\"test/SITRToken.t.sol\":496,\"test/SITRTokenEdges.t.sol\":297,\"test/SITRTokenInvariant.t.sol\":290,\"test/SITRTokenPoolManager.t.sol\":309,\"test/helpers/SITRTestBase.sol\":65,\"test/helpers/V4Actors.sol\":113,\"test/vendor/UPSTREAM.md\":79,\"test/vendor/forge-std/Base.sol\":42,\"test/vendor/forge-std/LICENSE-APACHE\":203,\"test/vendor/forge-std/LICENSE-MIT\":25,\"test/vendor/forge-std/StdAssertions.sol\":685,\"test/vendor/forge-std/StdChains.sol\":286,\"test/vendor/forge-std/StdCheats.sol\":829,\"test/vendor/forge-std/StdConstants.sol\":30,\"test/vendor/forge-std/StdError.sol\":15,\"test/vendor/forge-std/StdInvariant.sol\":122,\"test/vendor/forge-std/StdJson.sol\":277,\"test/vendor/forge-std/StdMath.sol\":43,\"test/vendor/forge-std/StdStorage.sol\":473,\"test/vendor/forge-std/StdStyle.sol\":333,\"test/vendor/forge-std/StdToml.sol\":277,\"test/vendor/forge-std/StdUtils.sol\":209,\"test/vendor/forge-std/Test.sol\":34,\"test/vendor/forge-std/Vm.sol\":2369,\"test/vendor/forge-std/console.sol\":1552,\"test/vendor/forge-std/console2.sol\":4,\"test/vendor/forge-std/interfaces/IMulticall3.sol\":70,\"test/vendor/forge-std/safeconsole.sol\":13937,\"test/vendor/solmate/LICENSE\":661,\"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\":392,\"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\":155,\"test/vendor/v4-core/src/interfaces/IPoolManager.sol\":235,\"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\":343,\"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/Slot0.sol\":95},\"excluded\":[\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"eef4f2062a49961ccf86d11a426024e45bd14274d1674fc55694742818e51cc1","verifiedTreeHash":"980e2062dd254abb8699207fe761e7aa88769fe6","verifierVersion":"0.1.0+fdeb4d4a"}]}