{"assessments":[],"deployments":[{"attestationHash":"3ab841ed0daae8b704762d8deace9df01a98017dbbe55b859341230a4d064888","chainId":1,"contracts":[{"address":"0x2a24c66a2758bdc47d27d74a241c4df0c3a80ee0","blockNumber":26215929,"name":"MerkleDistributor","role":"distributor","txHash":"0x8a24e2102926f08e465d4cb47d116e3fd04fe69e86720dfa31a14d96a6f13c2e"},{"address":"0x6d6e7616c60bde669200522908426af1847ce60c","blockNumber":26215929,"name":"ShiftToken","role":"token","txHash":"0x8a24e2102926f08e465d4cb47d116e3fd04fe69e86720dfa31a14d96a6f13c2e"},{"address":"0x784ff9a3ac5d88a30bfff6f7f2a270161fbe6000","blockNumber":26215929,"name":"PoolInitializationGuard","role":"hook","txHash":"0x8a24e2102926f08e465d4cb47d116e3fd04fe69e86720dfa31a14d96a6f13c2e"}],"id":"e5c1c0dd-1f39-47d0-9c04-abbf6edcee05","manifestHash":"7268ac415d107f3aa207707a4f5e3268875c7f5f688815697f1532d5f8c743ee","status":"live"}],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"9b0383eb-6736-41b5-8302-16db0cc2da2f","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"bd74bcbccac04fc2c773c469c8e6326d5f2253396c4d5f1ecf5af9225e1f1317","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"97667b76ba5f4b5e464da839ea556a159bd29f2b29754e7e9709876b9070fe32","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"e3a7861aae9e4bb0cd2781a5a9399502e51a07f6ff51df212368bbf2d0545f38","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"2acbcb7e1070b2500460b4bc86a8266ec16a0e35114e90167a9183fc59c0fe80","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"6bb94068ce1c10d48a0f7665b7027d387ec6a57d4de89a01d7b15cdfa95faae8","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"78fb95a7afb9fd67ba370119cd16d4419e4a86359ace980dfe1ff4055ff5d144","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"57352b806a5c09b3be3d079818bdf7036bcaf9088fc25029539d6447c2248779","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"caa691dc31044fc644b39586de26408c7c600d3b86fbd57d1924ac7d5bf8107c","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"A custom token: NIGHTSHIFT (SHIFT).\nToken name: NIGHTSHIFT\nToken symbol: SHIFT\nToken supply: 1,000,000,000 with 18 decimals, all minted once to the deployer in the constructor.","parentJobId":null,"planHash":"f7027c3d6ff83626bfe9078a0a6c0a0b1be2bcaf13de655d3d83b3d909672f26","previousHash":"681534487738ac7f437f8785f06091ac2dfa3715c9ebae89146899445182dbe0","projectId":"9b0383eb-6736-41b5-8302-16db0cc2da2f","publication":{"commit":"b8d961f030566605d70f597c2a690695ef9c7c00","deliveredAt":"2026-10-18T00:40:57.063Z","repoUrl":"https://github.com/identity-md-launches/launch-2129-nightshift"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"145891cd9d36b520d1a7fb1c38fe7b80cb5db1ed48728789170bbfe71685a975","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2b9b0095482c54e6","findings":[],"hash":"2acbcb7e1070b2500460b4bc86a8266ec16a0e35114e90167a9183fc59c0fe80","nodeId":"5d81ddbb-017d-47b9-a68f-53f232062a1f","outcome":"completed","summary":"I found no math defects in `src/ShiftToken.sol`. `.imd-findings.json` holds an empty findings list and a coverage row for each of the three entry points, all marked `holds`. I changed no files; the project's 38 tests pass.\n\nWhat I checked under the Math Precision, Boundary and Numerical Gap guides:\n\n- **Supply:** `1_000_000_000 * 10 ** 18` comes out to exactly 1e27, which fits easily in a uint256. Aderyn's \"large numeric literal\" warning at line 43 is a style note, not a calculation error. The whole supply is minted once in the constructor, and there is no way to mint or burn afterwards, so all balances always add up to 1e27.\n- **`transfer` / `transferFrom`:** the balance subtraction skips Solidity's overflow checks, but it only runs after the code checks that the sender holds at least the amount. The addition also skips them and still can't overflow, because no balance can exceed 1e27. These cases all behave correctly:\n  - a transfer to yourself writes back the original balance;\n  - a transfer of 0 works;\n  - moving an entire balance works.\n- **Allowances:** the allowance subtraction also skips the overflow checks, but only after checking the allowance is large enough. A maximum (`type(uint256).max`) allowance is never reduced. Spending exactly the allowance leaves 0, and spending 1 more than the allowance reverts.\n- **`approve`:** it just stores the amount, so there is no arithmetic to go wrong. It rejects the zero address as spender.\n- **Rounding and precision:** there is no division, fee, percentage or cast anywhere in the contract, so those failure modes from the guides don't apply.\n\nOne quirk I left out of the report because it does no harm: `transferFrom(address(0), to, 0)` succeeds and emits a `Transfer` event from the zero address for 0 tokens. That looks like a mint of nothing and moves no value.\n\nI covered my whole assigned area and left nothing unreached.","treeHash":null,"usage":{"cachedInputTokens":142280,"inputTokens":8,"model":"claude-opus-5-5","outputTokens":1822,"runtime":"claude","turns":4,"wallClockMs":25952}},{"artifacts":[],"attempt":1,"bundleHash":"699be60f98cf7d850a13480b4a04e8613caddc00dee982ea6871e83a47e0a30e","device":"bc39660800b5f882","findings":[],"hash":"57352b806a5c09b3be3d079818bdf7036bcaf9088fc25029539d6447c2248779","nodeId":"5534c265-053f-420b-9ae1-7895b43ce8e8","outcome":"completed","summary":"Done. `launch.json` is written and is the only changed file.\n\n**What the manifest says**\n- Kind is custom_token. The token contract is `ShiftToken`, name NIGHTSHIFT, symbol SHIFT, 18 decimals.\n- Constructor args are empty, matching the accepted no-argument constructor that mints the whole supply to msg.sender.\n- totalSupply is the constructor's constant in minor units, 1e27.\n- No application contracts exist in the accepted tree, so the contracts list is empty.\n- Pool and economics are copied exactly from the launch reference: IMD pair, fee 12500, tick spacing 60, the one-to-one provenance price, and the requester's economics object verbatim.\n- Notes describe only the token's actual behavior, well under the 4000-character cap.\n\n**Checks run**\n- JSON parsed with only the schema's top-level keys and all strings and numbers typed as the schema expects.\n- `forge build` succeeded.\n- `forge test` with the verifier's fuzz seed passed all 38 tests.\n- Git status shows only the new launch.json.","treeHash":"67851716330bec29d5e83ddbd07117ca20a6bece","usage":{"cachedInputTokens":173722,"inputTokens":130,"model":"claude-fable-5-1","outputTokens":2544,"runtime":"claude","turns":9,"wallClockMs":58717}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"970da38f1d564250","findings":[],"hash":"6bb94068ce1c10d48a0f7665b7027d387ec6a57d4de89a01d7b15cdfa95faae8","nodeId":"9fab2bce-3e67-472c-b38a-caeb0ad2c6c0","outcome":"completed","summary":"I found no defects in my area, so `.imd-findings.json` holds an empty findings list and four coverage rows: all three entry points plus one invariant, each marked `holds`. I read the contract only; I wrote no test and ran no Foundry tests.\n\n**Access control:** `src/ShiftToken.sol` has no owner and no roles. It also has no mint after the constructor, no burn, pause, blocklist or upgrade path, and no privileged functions at all. The constructor mints the fixed `TOTAL_SUPPLY` of 1,000,000,000 × 10¹⁸ once to `msg.sender`, which is the factory at launch.\n\n**Trust gap:** a holder trusts nobody but themselves and the spenders they approve.\n- `transfer` moves only the caller's own balance.\n- `transferFrom` uses up the caller's allowance before moving anything. An allowance of `type(uint256).max` is treated as unlimited and is not reduced; any other allowance is checked and reduced. A failed check reverts the whole call.\n- `approve` sets only the caller's own allowance and rejects the zero address as spender.\n\n**Asymmetry:** there are no fees, exemptions or address-specific rules. The factory's payouts to the distributor and the pool, and trades through the PoolManager, move exactly the amount stated, so none of the launch transfers arrive short.\n\n**Static analysis:** aderyn's \"large numeric literal\" at line 43 is just the supply constant, `1_000_000_000 * 10 ** uint256(DECIMALS)`. It is not a defect.\n\nThe one known weakness is the standard ERC-20 approve race: changing a non-zero allowance to another value lets the spender use both the old and new amounts. The code's own comment documents it, and it is not specific to this token, so I did not report it.","treeHash":null,"usage":{"cachedInputTokens":103345,"inputTokens":6,"model":"claude-opus-5-5","outputTokens":1371,"runtime":"claude","turns":3,"wallClockMs":21150}},{"artifacts":[],"attempt":1,"bundleHash":"58a2cf20851c177b7bfd5ddcc0b8545debd0421fb93be64263ae45422d6d714d","device":"2042b7cb7b952e30","findings":[],"hash":"78fb95a7afb9fd67ba370119cd16d4419e4a86359ace980dfe1ff4055ff5d144","nodeId":"c6991f4c-d5c7-41de-911b-f0095de4c77d","outcome":"completed","summary":"The NIGHTSHIFT token project is complete, verified, and committed on main.\n\n**What was built**\n\n- `src/ShiftToken.sol`: a self-contained ERC-20 named NIGHTSHIFT, symbol SHIFT, 18 decimals. The constructor mints the full 1,000,000,000 supply once to the deployer, takes no arguments, and makes no external calls. There is no owner, mint, burn, pause, blocklist, fee, or upgrade path, so every launch flow moves tokens whole.\n- `script/DeployShiftToken.s.sol`: a reviewable deploy helper whose `deploy()` function tests call directly. It reads no environment variables.\n- `test/ShiftToken.t.sol` and `test/DeployShiftToken.t.sol`: 38 tests covering metadata, supply, transfer and allowance success paths, every revert path with exact custom errors, event emission, rejection of common admin selectors from both a stranger and the deployer, an opcode scan for DELEGATECALL, CALLCODE and SELFDESTRUCT, and five fuzz tests for conservation and bounds.\n- `foundry.toml` pins solc 0.8.26, sets `bytecode_hash = \"none\"`, disables ffi and filesystem access.\n- `lib/forge-std/` holds forge-std v1.11.0 vendored as plain files, with no submodule.\n- `README.md` documents behaviour, deployment parameters, the launch values, the empty \"After launch\" section, assumptions, operational responsibilities, and which security tools ran.\n\n**Verification**\n\n| Check | Result |\n|---|---|\n| `forge build` | clean |\n| `forge test` with the verifier's fuzz seed, empty environment, offline | 38 passed, 0 failed |\n| `forge fmt --check` | clean |\n\nA scratch test in `test/scratch/` also reproduced the protected floor's non-pool checks (CREATE2 deployment from a factory-like contract, the swarm share flow, and the admin-call lists) and passed. The pool seed and swap checks need the verifier's v4-core harness and were not reproduced locally, but a token with no transfer rules has nothing that could fail them.\n\nSlither and Mythril were not on this machine and did not run. The commit excludes the stray dotfiles and `.claude/` directory in the workspace.","treeHash":"a39138757319bcb8665b841062ec6175c07827f9","usage":{"cachedInputTokens":744819,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":22815,"runtime":"claude","turns":25,"wallClockMs":315652}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e293ff3324f7ddb5","findings":[],"hash":"97667b76ba5f4b5e464da839ea556a159bd29f2b29754e7e9709876b9070fe32","nodeId":"ad6d9b93-4887-4c0e-be21-a5da0e1b2cb4","outcome":"completed","summary":"I found no defects in `src/ShiftToken.sol`. I wrote `.imd-findings.json` with an empty findings list and a coverage row for each of the three entry points, all marked `holds`. I read the code and traced it by hand. I didn't run any Foundry tests, and I didn't open the existing test files or the supplied protected tests.\n\n- **`approve`**: it refuses the zero address as spender, sets the allowance to exactly the amount given, and emits `Approval`.\n- **`transfer`**: the balance check comes before the subtraction that skips overflow checks, so it can't wrap. Sending tokens to yourself leaves your balance unchanged. The total of all balances always stays at the fixed supply.\n- **`transferFrom`**: it spends the allowance before moving the tokens, and an allowance of the maximum value is never reduced. Any failure reverts the whole call. There is no fee or burn, so the launch transfers out of the factory, into the pool and to the distributor all arrive at their full amounts.\n- **Supply**: the constructor mints 1,000,000,000 × 10^18 to the deployer once. There is no way to mint or burn after that, no owner role, and no `delegatecall` or `selfdestruct`.\n\nThe static analysis line about a large number at `src/ShiftToken.sol:43` refers to the supply constant. It's correct and harmless, so I didn't report it.\n\nOne minor behaviour I didn't treat as a defect: anyone can call `transferFrom` with the zero address as the sender and an amount of 0. It succeeds and logs a zero-value transfer from the zero address. That moves no tokens and changes no balances.","treeHash":null,"usage":{"cachedInputTokens":99840,"inputTokens":6,"model":"claude-opus-5-5","outputTokens":1327,"runtime":"claude","turns":3,"wallClockMs":17374}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"b57ae3a96321a0e1","findings":[{"citation":"resolved","description":"`_transfer` validates `to` but never `from`. `transferFrom(address(0), to, 0)` passes `_spendAllowance` (allowance 0 is not < amount 0) and `_transfer` (balance 0 is not < amount 0), so the call returns true and emits `Approval(address(0), caller, 0)` and `Transfer(address(0), to, 0)`. A `Transfer` whose `from` is the zero address is the ERC-20 convention for a mint, so any unprivileged account can publish zero-value mint-shaped events naming any recipient. No value moves and `totalSupply()` is a compile-time constant, so supply, balances and the launch flows are unaffected; the only effect is on off-chain consumers that key on `from == address(0)` (mint indexers, explorers, supply trackers that count mint events) and on strict ERC-20 conformance (OpenZeppelin's ERC20 reverts with `ERC20InvalidSender` here). Nonzero amounts from the zero address cannot succeed: the zero address can never hold a balance because `to == address(0)` is refused on every path, so `transferFrom(address(0), to, 1)` reverts with `InsufficientAllowance` (allowance is checked first). Minimal fix that preserves intended behaviour: add `if (from == address(0)) revert ZeroAddress();` at the top of `_transfer` (the constructor writes `_balances` directly, so it is unaffected).","line":137,"path":"src/ShiftToken.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ShiftToken} from \"src/ShiftToken.sol\";\n\n/// Fails on the current code: `transferFrom(address(0), to, 0)` succeeds and emits a mint-shaped\n/// `Transfer(address(0), to, 0)`. Passes once `_transfer` rejects `from == address(0)`.\ncontract ZeroSenderTest is Test {\n    ShiftToken token;\n    address bob = address(0xB0B);\n    address mallory = address(0xBAD);\n\n    function setUp() public {\n        token = new ShiftToken();\n    }\n\n    function test_transferFromZeroAddressSenderReverts() public {\n        vm.prank(mallory);\n        vm.expectRevert();\n        token.transferFrom(address(0), bob, 0);\n    }\n}","reproduction":"State: fresh ShiftToken, any caller M with no balance and no allowance. Call: M -> token.transferFrom(address(0), BOB, 0). Expected: revert (sender is the zero address; OpenZeppelin-style ERC20InvalidSender) or at least no mint-shaped event. Actual: returns true, emits Approval(0x0000000000000000000000000000000000000000, M, 0) and Transfer(0x0000000000000000000000000000000000000000, BOB, 0); balanceOf(BOB) stays 0 and totalSupply() stays 1000000000000000000000000000. Verified with test/scratch/ZeroSender.t.sol (fails on current code: 'next call did not revert as expected'). Counter-check: M -> transferFrom(address(0), BOB, 1) reverts InsufficientAllowance(M, 0, 1), so no nonzero value can ever leave the zero address.","severity":"info","snippet":"    function _transfer(address from, address to, uint256 amount) private {\n        if (to == address(0)) revert ZeroAddress();","title":"_transfer does not reject the zero address as sender: anyone can emit a mint-shaped Transfer(0x0, to, 0) via transferFrom"}],"hash":"bd74bcbccac04fc2c773c469c8e6326d5f2253396c4d5f1ecf5af9225e1f1317","nodeId":"4d350aef-c6a4-4ba6-aba8-31594b31ddb2","outcome":"completed","summary":"The review is complete. The findings file is written at the repository root, the scratch tests are removed, and no tracked file changed.\n\n**Result: one info-level finding, nothing in the economic, invariant or flow-gap area that moves or freezes value.**\n\n`src/ShiftToken.sol` is a 165-line fixed-supply ERC-20 with no owner, no external calls, no hooks and a pure constant `totalSupply()`. Most failure modes in the three assigned guides are structurally absent, and I confirmed the rest by execution rather than by reading:\n\n- **Conservation invariant holds.** A stateful fuzz over transfer, approve and transferFrom, including self-transfers and unlimited allowances, kept the sum of balances equal to the supply and the zero address at zero balance. The `unchecked` block is guarded by the prior balance check and the supply bound, and self-transfer re-reads storage so it cannot double a balance.\n- **Launch flows arrive whole.** Factory to distributor, distributor to claimant, factory to pool and pool to trader all move exactly the amount requested. There is no fee, burn, rebase, pause or blocklist, and every mutating function returns true, so Uniswap v4's sync/settle balance deltas are exact.\n- **Supply cannot grow and nothing is privileged.** The compiled ABI has only the three listed state-changing entry points, no receive or fallback. A scan of the runtime bytecode found no CALL, DELEGATECALL, CALLCODE, STATICCALL, CREATE, CREATE2 or SELFDESTRUCT.\n- **The one defect (info).** `_transfer` validates `to` but never `from`, so any account can call `transferFrom(address(0), BOB, 0)` and get a successful call that emits a mint-shaped `Transfer(0x0, BOB, 0)` and an `Approval(0x0, caller, 0)`. No value moves and the supply is a constant, so only off-chain indexers that treat a zero-address sender as a mint are affected. OpenZeppelin's ERC20 rejects this sender. A fail-now/pass-when-fixed Foundry proof is attached, and the fix is one line at the top of `_transfer`.\n\nCoverage: all three entry points have rows (approve and transfer hold, transferFrom carries the info finding), plus four invariant rows for conservation, non-growing supply, the constructor mint and the economic-security checklist. Nothing in the assigned area was left unreached.","treeHash":null,"usage":{"cachedInputTokens":856006,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":16598,"runtime":"claude","turns":26,"wallClockMs":240454}},{"artifacts":[],"attempt":1,"bundleHash":"451f57593c3e35c89c8060be7aa35a56c8d44cb185d639c5fab4efd1898beb5d","device":"1b657df861f7b08b","findings":[],"hash":"caa691dc31044fc644b39586de26408c7c600d3b86fbd57d1924ac7d5bf8107c","nodeId":"9f12b55e-6d99-46c8-bfd6-d46e3abbe588","outcome":"completed","summary":"I added invariant tests and more edge-case tests for NIGHTSHIFT (SHIFT). With the verifier's fuzz seed, `forge build` succeeds and `forge test` passes all 56 tests (38 existing, 18 new). I found no defects, so I didn't write `.imd-findings.json`.\n\nThe token in `src/ShiftToken.sol` is a plain fixed-supply ERC-20 with no owner and no functions for minting, pausing, blocking addresses or fees. Its name, symbol, 18 decimals and 1,000,000,000 × 10¹⁸ supply minted to the deployer all match the brief. The earlier tests already covered metadata, the main transfer and approval paths, and the absence of admin functions. What was missing was invariant tests, which the criteria require because the token keeps balances.\n\n**`test/ShiftToken.invariant.t.sol`** (256 runs × 64 calls, set in the file itself):\n- **Handler:** a handler contract makes random calls across five accounts, including the deployer. Each call is a transfer, a transfer to the zero address, an approval, a spend from someone else's allowance, or a spend by an outsider with no allowance.\n- **Amounts:** they are picked to hit the edges often: zero, exactly the balance or allowance, one over it, and the largest possible value.\n- **Checks on every call:** the handler keeps its own record of every balance and allowance and predicts whether each call should succeed. It checks the exact error when a call fails, and that a failed call changes nothing.\n- **Invariants after each sequence:**\n  - the total supply never changes;\n  - the five accounts' balances always add up to the full supply;\n  - nothing ever lands at the zero address, the handler or the token itself;\n  - every balance and allowance matches the handler's record.\n- **Guard:** a final check that each run actually called the token, so the suite can't pass without testing anything.\n\n**`test/ShiftToken.edges.t.sol`** (17 tests, 4 of them fuzzed at 1,000 runs):\n- **Zero amounts:** a `transferFrom` of 0 with no allowance succeeds and emits both events.\n- **Allowance boundaries:**\n  - spending exactly the allowance leaves zero, and the next wei fails;\n  - an allowance of the maximum value minus one still goes down when spent;\n  - an unlimited allowance emits no Approval when spent and is still limited by the owner's balance.\n- **Self cases:**\n  - an owner needs an allowance from themselves to use `transferFrom` on their own tokens;\n  - sending from an owner back to the same owner still uses up the allowance.\n- **Failed calls:**\n  - a failed call leaves balances and allowances untouched;\n  - when both the allowance and the balance are too low, the allowance error is the one reported;\n  - spending from the zero address fails, and sending to it keeps the allowance.\n- **Calls and return values:** each function returns exactly `true`; an unknown function or a call with no data fails.\n\nI didn't commit anything: the two new files are untracked in `test/`.","treeHash":"6ceca8a8f6bb90b0bbcf6515e7cdbb6793fb4ae3","usage":{"cachedInputTokens":389088,"inputTokens":20,"model":"claude-opus-5-5","outputTokens":11591,"runtime":"claude","turns":12,"wallClockMs":238693}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a8006a8757108cd3","findings":[{"citation":"resolved","description":"Merged from audit_economics (sole reporter); reproduced against the code and its attached proof run here (fails on current code with 'next call did not revert as expected'). `_transfer` rejects `to == address(0)` but not `from == address(0)`. `transferFrom(address(0), to, 0)` passes `_spendAllowance` (allowance 0 is not < 0, so it writes 0 and emits Approval(0x0, caller, 0)) and `_transfer` (balance 0 is not < 0), returns true and emits `Transfer(address(0), to, 0)`, the ERC-20 convention for a mint. Any unprivileged account can therefore publish zero-value mint-shaped events naming any recipient. No value moves: `totalSupply()` is a compile-time constant, `_balances[address(0)]` can never be funded because every path refuses `to == address(0)`, and `transferFrom(address(0), to, 1)` reverts with InsufficientAllowance(caller, 0, 1). Impact is limited to off-chain consumers that key on `from == address(0)` (mint indexers, explorers, supply trackers) and to strict conformance with the widely used OpenZeppelin behaviour (ERC20InvalidSender). Severity stays informational: no funds, balances or launch flows are affected. Minimal fix preserving the intended design: add `if (from == address(0)) revert ZeroAddress();` at the top of `_transfer` (the constructor writes `_balances` directly and is unaffected).","line":137,"path":"src/ShiftToken.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ShiftToken} from \"src/ShiftToken.sol\";\n\n/// Fails on the current code: `transferFrom(address(0), to, 0)` succeeds and emits a mint-shaped\n/// `Transfer(address(0), to, 0)`. Passes once `_transfer` rejects `from == address(0)`.\ncontract ZeroSenderTest is Test {\n    ShiftToken token;\n    address bob = address(0xB0B);\n    address mallory = address(0xBAD);\n\n    function setUp() public {\n        token = new ShiftToken();\n    }\n\n    function test_transferFromZeroAddressSenderReverts() public {\n        vm.prank(mallory);\n        vm.expectRevert();\n        token.transferFrom(address(0), bob, 0);\n    }\n}","reproduction":"State: fresh `new ShiftToken()`; caller M = 0xBAD holds no balance and no allowance. Call: vm.prank(M); token.transferFrom(address(0), 0xB0B, 0). Expected: revert (sender is the zero address), or at least no Transfer event with from == 0x0. Actual: returns true; emits Approval(0x0000000000000000000000000000000000000000, 0xBAD, 0) and Transfer(0x0000000000000000000000000000000000000000, 0xB0B, 0); balanceOf(0xB0B) stays 0 and totalSupply() stays 1000000000000000000000000000. Counter-check: transferFrom(address(0), 0xB0B, 1) from M reverts InsufficientAllowance(0xBAD, 0, 1). Proof test (specialist's, re-run here as test/scratch/ZeroSender.t.sol): FAIL 'next call did not revert as expected'.","severity":"info","snippet":"    function _transfer(address from, address to, uint256 amount) private {\n        if (to == address(0)) revert ZeroAddress();","title":"_transfer never validates `from`: transferFrom(address(0), to, 0) succeeds and emits a mint-shaped Transfer(0x0, to, 0)"}],"hash":"e3a7861aae9e4bb0cd2781a5a9399502e51a07f6ff51df212368bbf2d0545f38","nodeId":"90eb0427-2b2c-48b7-a7c8-96b79c0559fc","outcome":"completed","summary":"Review complete. `.imd-findings.json` is written with one finding and a full coverage record. The scratch tests were removed, so the tree is unchanged apart from the findings file.\n\n**Outcome.** The token is a plain, correct fixed-supply ERC-20. Of the four specialists, only audit_economics reported anything, and that single informational finding reproduces. Nothing else surfaced in my own pass.\n\n**Finding kept (info).** `_transfer` in `src/ShiftToken.sol:137` never validates the sender. Calling transferFrom with the zero address as sender and a zero amount succeeds and emits a mint-shaped Transfer event from the zero address. I re-ran the specialist's proof and it fails on the current code as stated. No value moves, the zero address can never hold a balance, and a nonzero amount reverts on the allowance check. Impact is limited to off-chain indexers and strict OpenZeppelin-style conformance, so severity stays informational. The one-line fix is to reject a zero sender in `_transfer`.\n\n**Dropped or merged.** There were no duplicates to merge. The aderyn large-literal lead is the supply constant, which evaluates correctly to 1e27 and is confirmed by the existing tests.\n\n**Coverage.** All three entry points are answered.\n\n| Entry point | Verdict |\n|---|---|\n| approve | holds |\n| transfer | holds |\n| transferFrom | finding 1 (info) |\n\nI also recorded three invariant rows as holding: fixed supply with no privileged surface, launch flows arriving whole, and deployability against the manifest. The existing suite passes with 56 tests. My own scratch checks confirmed self-transfer, infinite allowance passthrough, allowance decrement, zero-address rejections, the missing receive function and the constant supply. Creation and runtime bytecode are far under the protocol limits, and the manifest's empty constructor arguments match the argument-less constructor.","treeHash":null,"usage":{"cachedInputTokens":316055,"inputTokens":162,"model":"claude-fable-5-1","outputTokens":8488,"runtime":"claude","turns":14,"wallClockMs":151461}}],"verification":[{"checks":[{"durationMs":970,"exitCode":0,"name":"build","output":"Compiling 24 files with Solc 0.8.26\nSolc 0.8.26 finished in 899.93ms\nCompiler run successful!\n","passed":true},{"durationMs":96,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/DeployShiftToken.t.sol:DeployShiftTokenTest\n[PASS] test_deployMintsSupplyToTheScriptAsDeployer() (gas: 1174502)\n[PASS] test_everyDeploymentIsIndependent() (gas: 1619603)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 442.53µs (266.31µs CPU time)\n\nRan 36 tests for test/ShiftToken.t.sol:ShiftTokenTest\n[PASS] testFuzz_allowanceAccounting(uint256,uint256) (runs: 256, μ: 202011, ~: 205009)\nLogs:\n  Bound result 242302386000423060661653946\n  Bound result 138882649950478597979235658\n\n[PASS] testFuzz_supplyNeverChanges(address,address,uint256,uint256) (runs: 256, μ: 126116, ~: 129286)\nLogs:\n  Bound result 1\n  Bound result 1\n\n[PASS] testFuzz_transferAboveBalanceReverts(uint256,uint256) (runs: 256, μ: 102399, ~: 103336)\nLogs:\n  Bound result 242302386000423191881256408\n  Bound result 351148541072066064046160238\n\n[PASS] testFuzz_transferConservesSupply(address,uint256,uint256) (runs: 256, μ: 174820, ~: 176338)\nLogs:\n  Bound result 465955238269748856426792477\n  Bound result 3\n\n[PASS] testFuzz_transferFromAboveAllowanceReverts(uint256,uint256) (runs: 256, μ: 147928, ~: 148745)\nLogs:\n  Bound result 365382843355133552636218525\n  Bound result 365382843355133552636218528\n\n[PASS] test_approveDoesNotRequireBalance() (gas: 62401)\n[PASS] test_approveOverwritesNotAccumulates() (gas: 92488)\n[PASS] test_approveRevertsForZeroSpender() (gas: 32431)\n[PASS] test_approveSetsAllowanceAndEmits() (gas: 76875)\n[PASS] test_approveZeroClearsAllowance() (gas: 87548)\n[PASS] test_constructorEmitsMintTransfer() (gas: 238178)\n[PASS] test_constructorMakesNoExternalCalls() (gas: 9593)\n[PASS] test_constructorMintsWholeSupplyToDeployer() (gas: 25133)\n[PASS] test_contractRejectsEther() (gas: 38782)\n[PASS] test_deployerIsWhoeverCallsTheConstructor() (gas: 12434)\n[PASS] test_metadata() (gas: 47534)\n[PASS] test_noMintPauseBlocklistOrOwnerFunctionsExist() (gas: 865527)\n[PASS] test_runtimeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 759967)\n[PASS] test_supplyIsOneBillionWithEighteenDecimals() (gas: 11671)\n[PASS] test_transferFromCannotMoveTheDeployersSupplyWithoutApproval() (gas: 38430)\n[PASS] test_transferFromRevertsAboveAllowance() (gas: 150514)\n[PASS] test_transferFromRevertsToZeroAddress() (gas: 147959)\n[PASS] test_transferFromRevertsWhenOwnerBalanceTooLow() (gas: 157670)\n[PASS] test_transferFromRevertsWithoutAllowance() (gas: 102391)\n[PASS] test_transferFromSpendsAllowanceAndMovesTokens() (gas: 218981)\n[PASS] test_transferFromToSpender() (gas: 182912)\n[PASS] test_transferFromUnlimitedAllowanceIsNotReduced() (gas: 187814)\n[PASS] test_transferMovesExactAmount() (gas: 162493)\n[PASS] test_transferRevertsFromEmptyAccount() (gas: 37652)\n[PASS] test_transferRevertsOnInsufficientBalance() (gas: 109578)\n[PASS] test_transferRevertsToZeroAddress() (gas: 94662)\n[PASS] test_transferRevertsToZeroAddressEvenForZeroAmount() (gas: 32462)\n[PASS] test_transferToSelfKeepsBalance() (gas: 98263)\n[PASS] test_transferWholeBalance() (gas: 129891)\n[PASS] test_transferWholeSupplyFromDeployer() (gas: 72851)\n[PASS] test_transferZeroAmountSucceedsAndEmits() (gas: 46811)\nSuite result: ok. 36 passed; 0 failed; 0 skipped; finished in 14.24ms (60.45ms CPU time)\n\nRan 2 test suites in 14.90ms (14.68ms CPU time): 38 tests passed, 0 failed, 0 skipped (38 total tests)\n","passed":true},{"durationMs":40,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"ShiftToken.approve(address,uint256)\",\"ShiftToken.transfer(address,uint256)\",\"ShiftToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":130,\"foundry.toml\":23,\"launch.json\":24,\"remappings.txt\":1,\"script/DeployShiftToken.s.sol\":25,\"src/ShiftToken.sol\":165,\"test/DeployShiftToken.t.sol\":29,\"test/ShiftToken.t.sol\":413},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"57352b806a5c09b3be3d079818bdf7036bcaf9088fc25029539d6447c2248779","verifiedTreeHash":"67851716330bec29d5e83ddbd07117ca20a6bece","verifierVersion":"0.1.0+c3fba9eb"},{"checks":[{"durationMs":969,"exitCode":0,"name":"build","output":"Compiling 24 files with Solc 0.8.26\nSolc 0.8.26 finished in 893.92ms\nCompiler run successful!\n","passed":true},{"durationMs":89,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/DeployShiftToken.t.sol:DeployShiftTokenTest\n[PASS] test_deployMintsSupplyToTheScriptAsDeployer() (gas: 1174502)\n[PASS] test_everyDeploymentIsIndependent() (gas: 1619603)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 421.83µs (358.18µs CPU time)\n\nRan 36 tests for test/ShiftToken.t.sol:ShiftTokenTest\n[PASS] testFuzz_allowanceAccounting(uint256,uint256) (runs: 256, μ: 202011, ~: 205009)\nLogs:\n  Bound result 33428529671625043118757690\n  Bound result 2\n\n[PASS] testFuzz_supplyNeverChanges(address,address,uint256,uint256) (runs: 256, μ: 126116, ~: 129286)\nLogs:\n  Bound result 931346720027858003766464\n  Bound result 140429498346431866352602\n\n[PASS] testFuzz_transferAboveBalanceReverts(uint256,uint256) (runs: 256, μ: 102399, ~: 103336)\nLogs:\n  Bound result 0\n  Bound result 938463463374607431768211455\n\n[PASS] testFuzz_transferConservesSupply(address,uint256,uint256) (runs: 256, μ: 174820, ~: 176338)\nLogs:\n  Bound result 465955238269748856426792477\n  Bound result 3\n\n[PASS] testFuzz_transferFromAboveAllowanceReverts(uint256,uint256) (runs: 256, μ: 147928, ~: 148745)\nLogs:\n  Bound result 365382843355133552636218525\n  Bound result 365382843355133552636218528\n\n[PASS] test_approveDoesNotRequireBalance() (gas: 62401)\n[PASS] test_approveOverwritesNotAccumulates() (gas: 92488)\n[PASS] test_approveRevertsForZeroSpender() (gas: 32431)\n[PASS] test_approveSetsAllowanceAndEmits() (gas: 76875)\n[PASS] test_approveZeroClearsAllowance() (gas: 87548)\n[PASS] test_constructorEmitsMintTransfer() (gas: 238178)\n[PASS] test_constructorMakesNoExternalCalls() (gas: 9593)\n[PASS] test_constructorMintsWholeSupplyToDeployer() (gas: 25133)\n[PASS] test_contractRejectsEther() (gas: 38782)\n[PASS] test_deployerIsWhoeverCallsTheConstructor() (gas: 12434)\n[PASS] test_metadata() (gas: 47534)\n[PASS] test_noMintPauseBlocklistOrOwnerFunctionsExist() (gas: 865527)\n[PASS] test_runtimeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 759967)\n[PASS] test_supplyIsOneBillionWithEighteenDecimals() (gas: 11671)\n[PASS] test_transferFromCannotMoveTheDeployersSupplyWithoutApproval() (gas: 38430)\n[PASS] test_transferFromRevertsAboveAllowance() (gas: 150514)\n[PASS] test_transferFromRevertsToZeroAddress() (gas: 147959)\n[PASS] test_transferFromRevertsWhenOwnerBalanceTooLow() (gas: 157670)\n[PASS] test_transferFromRevertsWithoutAllowance() (gas: 102391)\n[PASS] test_transferFromSpendsAllowanceAndMovesTokens() (gas: 218981)\n[PASS] test_transferFromToSpender() (gas: 182912)\n[PASS] test_transferFromUnlimitedAllowanceIsNotReduced() (gas: 187814)\n[PASS] test_transferMovesExactAmount() (gas: 162493)\n[PASS] test_transferRevertsFromEmptyAccount() (gas: 37652)\n[PASS] test_transferRevertsOnInsufficientBalance() (gas: 109578)\n[PASS] test_transferRevertsToZeroAddress() (gas: 94662)\n[PASS] test_transferRevertsToZeroAddressEvenForZeroAmount() (gas: 32462)\n[PASS] test_transferToSelfKeepsBalance() (gas: 98263)\n[PASS] test_transferWholeBalance() (gas: 129891)\n[PASS] test_transferWholeSupplyFromDeployer() (gas: 72851)\n[PASS] test_transferZeroAmountSucceedsAndEmits() (gas: 46811)\nSuite result: ok. 36 passed; 0 failed; 0 skipped; finished in 12.58ms (62.52ms CPU time)\n\nRan 2 test suites in 13.45ms (13.00ms CPU time): 38 tests passed, 0 failed, 0 skipped (38 total tests)\n","passed":true},{"durationMs":41,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"ShiftToken.approve(address,uint256)\",\"ShiftToken.transfer(address,uint256)\",\"ShiftToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":130,\"foundry.toml\":23,\"remappings.txt\":1,\"script/DeployShiftToken.s.sol\":25,\"src/ShiftToken.sol\":165,\"test/DeployShiftToken.t.sol\":29,\"test/ShiftToken.t.sol\":413},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":338,"exitCode":0,"name":"slither","output":"slither: no results at low impact or above","passed":true},{"durationMs":198,"exitCode":0,"name":"aderyn","output":"[low] large-numeric-literal at src/ShiftToken.sol:43: Large Numeric Literal","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"78fb95a7afb9fd67ba370119cd16d4419e4a86359ace980dfe1ff4055ff5d144","verifiedTreeHash":"a39138757319bcb8665b841062ec6175c07827f9","verifierVersion":"0.1.0+c3fba9eb"},{"checks":[{"durationMs":3156,"exitCode":0,"name":"build","output":"Compiling 26 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.02s\nCompiler run successful!\n","passed":true},{"durationMs":8935,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/DeployShiftToken.t.sol:DeployShiftTokenTest\n[PASS] test_deployMintsSupplyToTheScriptAsDeployer() (gas: 1174502)\n[PASS] test_everyDeploymentIsIndependent() (gas: 1619603)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 908.23µs (786.23µs CPU time)\n\nRan 36 tests for test/ShiftToken.t.sol:ShiftTokenTest\n[PASS] testFuzz_allowanceAccounting(uint256,uint256) (runs: 256, μ: 202043, ~: 205031)\nLogs:\n  Bound result 33428529671625043118757690\n  Bound result 2\n\n[PASS] testFuzz_supplyNeverChanges(address,address,uint256,uint256) (runs: 256, μ: 126586, ~: 129286)\nLogs:\n  Bound result 931346720027858003766464\n  Bound result 140429498346431866352602\n\n[PASS] testFuzz_transferAboveBalanceReverts(uint256,uint256) (runs: 256, μ: 102496, ~: 103346)\nLogs:\n  Bound result 440\n  Bound result 1064470261\n\n[PASS] testFuzz_transferConservesSupply(address,uint256,uint256) (runs: 256, μ: 174910, ~: 176338)\nLogs:\n  Bound result 242\n  Bound result 242\n\n[PASS] testFuzz_transferFromAboveAllowanceReverts(uint256,uint256) (runs: 256, μ: 148014, ~: 148755)\nLogs:\n  Bound result 242302386000423191881256408\n  Bound result 351148541072066064046160238\n\n[PASS] test_approveDoesNotRequireBalance() (gas: 62401)\n[PASS] test_approveOverwritesNotAccumulates() (gas: 92488)\n[PASS] test_approveRevertsForZeroSpender() (gas: 32431)\n[PASS] test_approveSetsAllowanceAndEmits() (gas: 76875)\n[PASS] test_approveZeroClearsAllowance() (gas: 87548)\n[PASS] test_constructorEmitsMintTransfer() (gas: 238178)\n[PASS] test_constructorMakesNoExternalCalls() (gas: 9593)\n[PASS] test_constructorMintsWholeSupplyToDeployer() (gas: 25133)\n[PASS] test_contractRejectsEther() (gas: 38782)\n[PASS] test_deployerIsWhoeverCallsTheConstructor() (gas: 12434)\n[PASS] test_metadata() (gas: 47534)\n[PASS] test_noMintPauseBlocklistOrOwnerFunctionsExist() (gas: 865527)\n[PASS] test_runtimeHasNoDelegatecallCallcodeOrSelfdestruct() (gas: 759967)\n[PASS] test_supplyIsOneBillionWithEighteenDecimals() (gas: 11671)\n[PASS] test_transferFromCannotMoveTheDeployersSupplyWithoutApproval() (gas: 38430)\n[PASS] test_transferFromRevertsAboveAllowance() (gas: 150514)\n[PASS] test_transferFromRevertsToZeroAddress() (gas: 147959)\n[PASS] test_transferFromRevertsWhenOwnerBalanceTooLow() (gas: 157670)\n[PASS] test_transferFromRevertsWithoutAllowance() (gas: 102391)\n[PASS] test_transferFromSpendsAllowanceAndMovesTokens() (gas: 218981)\n[PASS] test_transferFromToSpender() (gas: 182912)\n[PASS] test_transferFromUnlimitedAllowanceIsNotReduced() (gas: 187814)\n[PASS] test_transferMovesExactAmount() (gas: 162493)\n[PASS] test_transferRevertsFromEmptyAccount() (gas: 37652)\n[PASS] test_transferRevertsOnInsufficientBalance() (gas: 109578)\n[PASS] test_transferRevertsToZeroAddress() (gas: 94662)\n[PASS] test_transferRevertsToZeroAddressEvenForZeroAmount() (gas: 32462)\n[PASS] test_transferToSelfKeepsBalance() (gas: 98263)\n[PASS] test_transferWholeBalance() (gas: 129891)\n[PASS] test_transferWholeSupplyFromDeployer() (gas: 72851)\n[PASS] test_transferZeroAmountSucceedsAndEmits() (gas: 46811)\nSuite result: ok. 36 passed; 0 failed; 0 skipped; finished in 46.66ms (224.92ms CPU time)\n\nRan 17 tests for test/ShiftToken.edges.t.sol:ShiftTokenEdgesTest\n[PASS] testFuzz_approveSetsExactly(address,address,uint256,uint256) (runs: 1000, μ: 88395, ~: 88664)\n[PASS] testFuzz_failedTransferChangesNothing(uint256) (runs: 1000, μ: 122776, ~: 122538)\nLogs:\n  Bound result 32785671848419777007529558352718689410\n\n[PASS] testFuzz_transferFromBothShortReportsAllowance(uint256,uint256) (runs: 1000, μ: 95156, ~: 95547)\nLogs:\n  Bound result 45954464891226444530\n  Bound result 115792089237316195423570985008687907853269984665640564039357584007913137307962\n\n[PASS] testFuzz_transferFromMovesExactlyAndSpendsExactly(uint256,uint256) (runs: 1000, μ: 159534, ~: 161549)\nLogs:\n  Bound result 4987788684906209300931606408067535650879531505992\n  Bound result 99999999999999999998\n\n[PASS] test_allowanceOneBelowMaxIsFiniteAndDecrements() (gas: 125242)\n[PASS] test_approveMaxThenZero() (gas: 113359)\n[PASS] test_returnDataIsAbiEncodedTrue() (gas: 171769)\n[PASS] test_transferFromExactAllowanceLeavesZero() (gas: 160189)\n[PASS] test_transferFromOwnerToOwnerKeepsBalanceButSpendsAllowance() (gas: 105037)\n[PASS] test_transferFromSelfRequiresOwnAllowance() (gas: 155580)\n[PASS] test_transferFromToZeroAddressRevertsAndKeepsAllowance() (gas: 104196)\n[PASS] test_transferFromZeroAddressOwnerReverts() (gas: 35960)\n[PASS] test_transferFromZeroAmountWithoutAllowanceSucceeds() (gas: 68508)\n[PASS] test_transferOneWei() (gas: 76663)\n[PASS] test_unknownSelectorReverts() (gas: 47856)\n[PASS] test_unlimitedAllowanceEmitsNoApprovalOnSpend() (gas: 119445)\n[PASS] test_unlimitedAllowanceStillBoundByBalance() (gas: 94916)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 46.66ms (185.62ms CPU time)\n\nRan 1 test for test/ShiftToken.invariant.t.sol:ShiftTokenInvariantTest\n[PASS]\nShiftTokenInvariantTest invariants:\n[PASS] invariant_allowancesMatchModel\n[PASS] invariant_balancesMatchModel\n[PASS] invariant_balancesSumToSupply\n[PASS] invariant_totalSupplyIsFixed\n ShiftTokenInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭-------------------+----------------------+-------+---------+----------╮\n| Contract          | Selector             | Calls | Reverts | Discards |\n+=======================================================================+\n| ShiftTokenHandler | approve              | 3299  | 0       | 0        |\n|-------------------+----------------------+-------+---------+----------|\n| ShiftTokenHandler | strangerTransferFrom | 3205  | 0       | 0        |\n|-------------------+----------------------+-------+---------+----------|\n| ShiftTokenHandler | transfer             | 3270  | 0       | 0        |\n|-------------------+----------------------+-------+---------+----------|\n| ShiftTokenHandler | transferFrom         | 3386  | 0       | 0        |\n|-------------------+----------------------+-------+---------+----------|\n| ShiftTokenHandler | transferToZero       | 3224  | 0       | 0        |\n╰-------------------+----------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 7842\n  Bound result 18\n  Bound result 4\n  Bound result 31\n  Bound result 606\n  Bound result 97838007625323273752395407535252187942972211875770442044916478217402\n  Bound result 244\n  Bound result 1767891015413097651796540752\n  Bound result 8833\n  Bound result 24\n  Bound result 2\n  Bound result 244\n  Bound result 7079\n  Bound result 286\n  Bound result 7345\n  Bound result 6767\n  Bound result 1522\n  Bound result 242\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913129639934\n  Bound result 255\n  Bound result 115792089237316195423570985008687907853269984665640564039457584007913129639934\n  Bound result 1000000000000000000\n  Bound result 1710\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.78s (8.78s CPU time)\n\nRan 4 test suites in 8.78s (8.87s CPU time): 56 tests passed, 0 failed, 0 skipped (56 total tests)\n","passed":true},{"durationMs":70,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"ShiftToken.approve(address,uint256)\",\"ShiftToken.transfer(address,uint256)\",\"ShiftToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":4,\"README.md\":130,\"foundry.toml\":23,\"remappings.txt\":1,\"script/DeployShiftToken.s.sol\":25,\"src/ShiftToken.sol\":165,\"test/DeployShiftToken.t.sol\":29,\"test/ShiftToken.edges.t.sol\":210,\"test/ShiftToken.invariant.t.sol\":225,\"test/ShiftToken.t.sol\":413},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"caa691dc31044fc644b39586de26408c7c600d3b86fbd57d1924ac7d5bf8107c","verifiedTreeHash":"6ceca8a8f6bb90b0bbcf6515e7cdbb6793fb4ae3","verifierVersion":"0.1.0+c3fba9eb"}]}