{"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":"5e4dbb87-917a-470c-a3ee-d70cc41d9acb","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"2f134f1824a5c6a0b6a0d273dae73c1d84b57446d8bd24d9bf626371b5e81662","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":"1ae549e4adbdad8e78dc8200e167c17b57c3d3320a7b4e90cbc60216cafd9719","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":"9284d49781beeec41b3e273afb709ebff5e6c6adbca577ee5448cefa25b71ae4","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":"accd63103e5be94a8955e3559a2cd0acd65306716b13a01fa30676ea7e56f67f","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":"47cf0c3667fec1b1b7a821a8edfd10378c24bf43e16ab103b58f1bc626f446cd","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":"0327db56df4df956f7b5605c87d6f49c7e6a001d5fd1fa17e6cd6a17a66bb0c3","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"b6eb182d20c430d9fb49d01fc197600046137f398c6b64e6e0ca13bca1d1b2dd","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"a1fc4c6a104bba5e881f71887b3e79bf17dbaf6c25e5500e8fd2403cc058c743","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"A custom token: IMDCred (IMDCRED).\nToken name: IMDCred\nToken symbol: IMDCRED\nToken supply: 1,000,000,000 with 18 decimals, all minted once to the deployer in the constructor.\nWhat it does: imdcred is a Proof-of-Work NFT game on Robinhood Chain with 4,444 collectible NFTs. Mine, mint, and stake NFTs, share in project revenue, and redeem eligible NFTs against the floor reserve. Powered by IMD, with project-token buybacks and burns.\n\nWebsite: https://imdcred.fun\nX (Twitter): https://x.com/Imdcred","parentJobId":null,"planHash":"afdb316132e0245f927e8d7f5ee5065b4143b818e1d1d6b355be218832cea2ca","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"5e4dbb87-917a-470c-a3ee-d70cc41d9acb","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1583-imdcred"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"50976","feedbackHash":"5f28dcbf5086c5a25c7eba0674cdfe43497320dba158dfcc254f7a24ccb971a3","nodeKey":"audit_economics","submissionHash":"2f134f1824a5c6a0b6a0d273dae73c1d84b57446d8bd24d9bf626371b5e81662","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52681","feedbackHash":"cfcacbc3262c2c47c5acf13d640fbd3fd0848c5546baa9702f15ba875c5e5e9e","nodeKey":"audit_flow","submissionHash":"1ae549e4adbdad8e78dc8200e167c17b57c3d3320a7b4e90cbc60216cafd9719","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51346","feedbackHash":"951b8e9e5d015c410d561172b0dbb09e0106145254525e43e787a3cd5b0ef8b2","nodeKey":"audit_judge","submissionHash":"9284d49781beeec41b3e273afb709ebff5e6c6adbca577ee5448cefa25b71ae4","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52256","feedbackHash":"dd8b16a23cc83a67b73645ea78730dd23df0a212b1c32b713972c0161490ba75","nodeKey":"audit_math","submissionHash":"accd63103e5be94a8955e3559a2cd0acd65306716b13a01fa30676ea7e56f67f","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51509","feedbackHash":"89862404cc4b63401c2a6253f4300b306b4f1424f9620ee0180abf2dc72dfa91","nodeKey":"audit_permissions","submissionHash":"47cf0c3667fec1b1b7a821a8edfd10378c24bf43e16ab103b58f1bc626f446cd","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52608","feedbackHash":"a9ebd38214c6e44b435eb0d65a2dc0118372edf6ee18ef3a6364dfcac3ed3f0a","nodeKey":"build_contract_project","submissionHash":"0327db56df4df956f7b5605c87d6f49c7e6a001d5fd1fa17e6cd6a17a66bb0c3","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52619","feedbackHash":"cd7a814fe006a5759a31e94df36e2a8a26042eb9d05b59f4c132dd07a7d16049","nodeKey":"manifest","submissionHash":"b6eb182d20c430d9fb49d01fc197600046137f398c6b64e6e0ca13bca1d1b2dd","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52609","feedbackHash":"d00fbcc54ba6106c82369d9666ece66efefe5e17bf798d5e59e8da6c80e0d7ac","nodeKey":"write_foundry_tests","submissionHash":"a1fc4c6a104bba5e881f71887b3e79bf17dbaf6c25e5500e8fd2403cc058c743","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"55fd1c688ff7b2cadfed351639154f08b440987fe58b15435a1c1f659f390531","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"0b84f7640465507035874d9a3e0674824ade4dd7c41438d68d33540168d57306","device":"3c9b660ee1938912","findings":[],"hash":"0327db56df4df956f7b5605c87d6f49c7e6a001d5fd1fa17e6cd6a17a66bb0c3","nodeId":"6ecabecc-2aee-4ce2-83d4-f574a03e42c5","outcome":"completed","summary":"The IMDCred token is delivered and committed on main as commit 2220bd7. A fresh offline clone builds, passes all 27 tests, and passes the format check.\n\n**What was built**\n\n- `src/IMDCred.sol` is a fixed-supply ERC-20 built on OpenZeppelin v5.4.0 with EIP-2612 permit and a holder-only burn. The constructor takes no arguments and mints 1,000,000,000 tokens (18 decimals) once to msg.sender, which is the launch factory.\n- There is no owner, mint, pause, blocklist, tax, exemption, burnFrom, or ether path. The runtime bytecode has no DELEGATECALL, CALLCODE or SELFDESTRUCT, no link references, and sits well under the EIP-170 limit.\n- `foundry.toml` pins solc 0.8.26, evm_version cancun, optimizer on, and bytecode_hash none. ffi is off and fs_permissions is empty.\n- Dependencies are vendored as ordinary files under `lib/` with no submodules: forge-std v1.9.7 and the OpenZeppelin contracts directory.\n- `script/DeployIMDCred.s.sol` offers a tested `deploy()` function and a broadcast wrapper for local or testnet use only.\n- `README.md` documents the token parameters, launch values, supply split, the empty \"After launch\" section, operational responsibilities, assumptions, scope, and test coverage.\n\n**Tests** in `test/IMDCred.t.sol` cover metadata and supply, CREATE2 deployment from a factory stand-in, launch flows arriving whole, ERC-20 success and failure paths, burn and over-burn, every common mint and privileged selector reverting from both a stranger and the deployer, the opcode scan, five permit cases, and two fuzz invariants. Tests read no environment variables.\n\n**Points to note**\n\n- The NFT game contracts described in the brief (mining, staking, revenue share, floor reserve, buyback) are not part of a custom token launch and are documented as a later contracts launch. The token is designed as their plain dependency.\n- I could not run the protected floor test itself, since it imports the verifier's own v4 harness. Its individual checks are mirrored in my suite.\n- One leftover file, a husky pre-commit hook inside the vendored OpenZeppelin folder, could not be deleted because the sandbox treats it as sensitive. It is inert plain text.\n- No security tooling beyond forge build, forge test and forge fmt was available. Tests passing are not an audit.","treeHash":"87e4bddc3376add9a364fe2c2bb1364aad81cdeb","usage":{"cachedInputTokens":1033520,"inputTokens":610,"model":"claude-fable-5-1","outputTokens":24708,"runtime":"claude","turns":27,"wallClockMs":330326}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"1a7606be97f168d4","findings":[],"hash":"1ae549e4adbdad8e78dc8200e167c17b57c3d3320a7b4e90cbc60216cafd9719","nodeId":"bd08b382-0f95-428b-a3e5-d318fa3328e7","outcome":"completed","summary":"The review is complete. `.imd-findings.json` holds an empty findings list and a coverage row for every listed entry point.\n\n**Outcome:** no defects found in IMDCred for the Execution Trace, Periphery and First Principles areas.\n\n**What the token is.** `src/IMDCred.sol` is 36 lines: OpenZeppelin ERC20 plus ERC20Permit, a constructor that mints the full one billion tokens with 18 decimals to the deployer, and a `burn` that only touches the caller's own balance. It has no owner, no mint path, no transfer hook, no tax, no exemptions, no receive or fallback.\n\n**What I verified.**\n- The vendored OpenZeppelin copy is byte-identical to the upstream v5.4.0 tag, and forge-std to v1.9.7, so the inherited transfer, allowance and permit logic is the audited upstream code with no hidden side effects.\n- The project builds and all 27 of its tests pass, including the launch-flow test that moves the swarm share, pool seed and claims whole.\n- Scratch probes confirmed permit fails across a chain-id change and succeeds again on the original chain, rejects high-s malleable signatures, and consumes a nonce only on success. Approving the zero address reverts, self-transfer conserves balance, and burning the full balance or supply behaves as documented.\n- The runtime contains no DELEGATECALL, CALLCODE or SELFDESTRUCT, the constructor takes no arguments and makes no external calls, and no common admin or freeze selector exists.\n\n**Static-analysis lead.** The aderyn large-numeric-literal note at line 24 is a style remark about the supply constant. The constant evaluates to exactly the manifest supply and the project test asserts it, so it was not reported as a defect.\n\n**Coverage.** All five listed entry points are marked `holds`, with three extra rows for the constructor and supply, vendored library integrity, and the aderyn lead. The scratch test directory was removed, so the tree is unchanged apart from the findings file.","treeHash":null,"usage":{"cachedInputTokens":581058,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":9643,"runtime":"claude","turns":21,"wallClockMs":147723}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"9b06782c7559b54c","findings":[{"citation":"resolved","description":"The token inherits OpenZeppelin v5.4.0 ERC20Permit unchanged (vendored files are byte-identical to the published package). Its permit consumes the owner's nonce and then approves; a second submission of the same signature reverts with ERC2612InvalidSigner because the nonce has moved. Any party watching the mempool can therefore submit a holder's permit before the contract that was meant to use it, so a game contract that bundles permit + transferFrom in one call (the README promises 'gasless approvals for the game contracts') has its whole transaction reverted even though the allowance it needs is already in place. This is the standard EIP-2612 behaviour and the correct one for the token itself: the token is not at fault and nothing is lost. It is recorded so the authors of the mining, staking and buyback contracts, which are out of this tree, wrap permit in try/catch (or check allowance >= value before calling permit) rather than treating a permit revert as fatal. No change to IMDCred is recommended; changing permit semantics would break EIP-2612 compliance.","line":22,"path":"src/IMDCred.sol","reproduction":"State: chainId 4663, token deployed by factory, factory.transfer(owner, 100) where owner = vm.addr(KEY). Owner signs Permit(owner, game, 100, nonce 0, deadline now+1h). Step 1: an unrelated address 0xBAD calls token.permit(owner, game, 100, deadline, v, r, s) -> succeeds, nonces(owner)=1, allowance(owner,game)=100. Step 2: the game contract calls the same token.permit(owner, game, 100, deadline, v, r, s) as the first instruction of its bundled call -> reverts ERC2612InvalidSigner (recovered signer differs since the struct now hashes nonce 1), so the bundled transferFrom never runs. Expected by an integrator that does not guard for this: the bundle succeeds. Actual: it reverts while allowance(owner,game) is already 100. Verified with a Foundry test (test_permitFrontRunGriefsBundledCall) that passed on this tree.","severity":"info","snippet":"contract IMDCred is ERC20, ERC20Permit {","title":"permit can be front-run to make a bundled permit-then-transferFrom call revert (integration hazard for the game contracts, not a token defect)"}],"hash":"2f134f1824a5c6a0b6a0d273dae73c1d84b57446d8bd24d9bf626371b5e81662","nodeId":"669b4eb1-489d-45ac-b678-2b07b7355de8","outcome":"completed","summary":"The review is complete. The findings file is valid JSON, the quoted snippet matches line 22 of the source, the scratch directory is removed, and `git status` shows only the untracked findings file.\n\n**Outcome: no defects in the assigned area.** The economics, invariant and flow-gap checks all hold on `src/IMDCred.sol`. The file `.imd-findings.json` holds one info-level note and ten coverage rows.\n\n**What I checked**\n\n- **Conservation and supply cap.** A Foundry invariant suite with a handler driving transfer, approve, transferFrom, burn and permit across five actors never broke `sum(balances) == totalSupply` or `totalSupply + burned == TOTAL_SUPPLY`. The only mint is in the constructor and nothing else reaches `_update` with a zero sender.\n- **Launch flows arrive whole.** There is no `_update` override, no tax, no exemption list and no external call, so the distributor, claimant, pool-seed and both swap legs move exactly the stated amount. The project's own tests already exercise this and all 27 pass.\n- **ERC-2612 permit.** Domain separator matches the spec for name `IMDCred`, version `1`, chain 4663 and the token address, and rebuilds if the chain id changes. High-s signatures, a zero owner and a zero spender all revert. A deadline equal to the current timestamp is accepted.\n- **Sentinel and boundary paths.** Transfer and approve to the zero address revert, burn of the whole supply leaves zero and nothing further burnable, self-transfer conserves, ether and unknown selectors revert.\n- **Dependency integrity.** Every vendored OpenZeppelin file the token uses is byte-identical to the published v5.4.0 npm package.\n- **Economics parameters.** The pool share and opening cap are copied from the job. The derived price for either currency ordering sits well inside Uniswap v4's sqrt-price bounds. Price derivation belongs to the deployer, not the token.\n\n**The one item recorded (info).** OpenZeppelin's `permit` consumes the nonce before approving, so anyone can submit a holder's permit first and make a game contract's bundled permit-then-transferFrom revert even though the allowance is already set. That is correct EIP-2612 behaviour and no change to the token is recommended. It is noted so the out-of-tree game contracts wrap permit defensively.\n\n**Not reached.** The protected launch test could not be run here because it needs v4-core and the launch helpers, which are not in this tree. Static analysis reported only a large-numeric-literal style note, which is not a defect.","treeHash":null,"usage":{"cachedInputTokens":601961,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":16370,"runtime":"claude","turns":22,"wallClockMs":266195}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"74a99f640688d37b","findings":[],"hash":"47cf0c3667fec1b1b7a821a8edfd10378c24bf43e16ab103b58f1bc626f446cd","nodeId":"b1015685-1c3f-4ce5-8e76-8053726d410e","outcome":"completed","summary":"The review is complete. No defects were found in the assigned area, and the findings file records that with a full coverage table.\n\n**Outcome.** The findings file holds an empty list and nine coverage rows, one for each of the five state-changing entry points plus four invariants. Every row is `holds`. The tree is clean apart from that file. No git status output means the findings file is ignored or untracked as intended, and the scratch tests were removed.\n\n**What I checked, against the Access Control, Trust Gap and Asymmetry guides:**\n\n- **Permission model.** The token inherits only ERC20 and ERC20Permit from OpenZeppelin. The compiled ABI exposes no owner, role, mint, pause, blocklist, upgrade or initialize selector, and no receive or fallback. The storage layout contains only ERC20 state, the short-string fallbacks and permit nonces. The deployer keeps no power after its balance leaves it.\n- **Burn.** `burn` in `src/IMDCred.sol` acts on the caller's own balance only. A spender holding an unlimited allowance, and the deployer calling a `burnFrom` selector, cannot touch another holder. Burning leaves allowances intact, and the balance check still binds a later transferFrom.\n- **Permit.** Deadline, nonce, signer and high-s malleability checks are the unmodified OpenZeppelin ones. The EIP-712 domain name equals `name()`, the separator is rebuilt on a chain fork, and a signature for one spender cannot be redeemed by another.\n- **Asymmetry.** Mint exists only in the constructor and burn only on the caller, both through the same `_update`. Approve and permit write the same allowance slot and both emit Approval. Transfer and transferFrom move exactly the requested amount with no exempt or taxed branch.\n- **Trust gap in the supply chain.** The vendored OpenZeppelin contracts directory is byte-identical to the v5.4.0 release tarball, and forge-std to v1.9.7. This closes the only place a backdoor could hide in a thin composition like this one.\n\n**Tools run.** `forge build`, the existing 27-test suite, `forge fmt --check`, and seven adversarial scratch tests I wrote for this area. All passed. Slither and aderyn output from the verifier reported nothing above the large-numeric-literal style note, which is not a defect.\n\n**Not findings, but worth passing to the game-contract builders.** EIP-2612 permits can be front-run by anyone who sees the signature, so a contract that calls permit and transferFrom in one transaction should tolerate the permit already having been consumed. Permit uses ECDSA only, so smart-contract wallets must use `approve`. Both are inherent to the standard OpenZeppelin implementation, not defects in this token.\n\n**Not reached.** The README's chain id and paired-currency address are documentation values I could not verify against a supplied network file. They do not affect the token's code.","treeHash":null,"usage":{"cachedInputTokens":615654,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":14654,"runtime":"claude","turns":24,"wallClockMs":208344}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"78d8eb9b16352a18","findings":[{"citation":"resolved","description":"Kept from audit_math at info. IMDCred inherits OpenZeppelin v5.4.0 ERC20Permit unchanged (every vendored file the token compiles was hashed against the upstream v5.4.0 tag and is byte-identical). Its permit() recovers an EOA with ECDSA.recover and requires signer == owner; it never consults IERC1271.isValidSignature. For any owner whose address is a contract (multisig, account-abstraction wallet) no (v,r,s) can satisfy the check, so permit always reverts ERC2612InvalidSigner and the wallet must use approve() in its own transaction. This is standard EIP-2612 behaviour and the README's own specification (OZ v5 ERC20Permit); no allowance can be set wrongly and no funds are at risk. It matters only to the out-of-tree game contracts: an entry point that accepts permit only would exclude contract wallets. No change to IMDCred is needed; the game contracts should offer an approve-based path too.","line":22,"path":"src/IMDCred.sol","reproduction":"Deploy IMDCred from factory 0xFAC7 on chainId 4663. Wallet w = new Wallet() (a contract whose isValidSignature returns the ERC-1271 magic value). (v,r,s) = vm.sign(KEY, keccak256(\"\\x19\\x01\" || DOMAIN_SEPARATOR || keccak256(abi.encode(PERMIT_TYPEHASH, address(w), 0x6A3E, 1, 0, block.timestamp)))). Call token.permit(address(w), 0x6A3E, 1, block.timestamp, v, r, s). Expected if ERC-1271 were supported: allowance(w, 0x6A3E) == 1. Actual: reverts ERC2612InvalidSigner(vm.addr(KEY), address(w)) and allowance(w, 0x6A3E) stays 0. Reproduced in a scratch Foundry test (test_permitContractWalletOwnerAlwaysReverts) against the compiled contract; it passed with the expectRevert in place.","severity":"info","snippet":"contract IMDCred is ERC20, ERC20Permit {","title":"permit() has no ERC-1271 path: a smart-contract-wallet holder can never approve by signature (integration note, not a token defect)"},{"citation":"resolved","description":"Kept from audit_economics at info. ERC20Permit.permit consumes the owner's nonce (_useNonce) and then calls _approve. Anyone who sees the signature in the mempool can submit it before the game contract does; the allowance is then already set, but the game contract's own permit call reverts with ERC2612InvalidSigner because the struct now hashes nonce 1, so a call that bundles permit + transferFrom without a guard reverts as a whole. The token is correct and EIP-2612 compliant; nothing is lost and the allowance the integrator wanted is in place. The out-of-tree game contracts should wrap permit in try/catch or check allowance(owner, this) >= value before calling permit. No change to IMDCred is recommended: altering permit semantics would break EIP-2612.","line":22,"path":"src/IMDCred.sol","reproduction":"Deploy IMDCred from factory 0xFAC7 on chainId 4663; factory.transfer(owner, 100) with owner = vm.addr(0xA11CE). Owner signs Permit(owner, game=0x6A3E, 100, nonce 0, deadline = now + 1h). Step 1: vm.prank(0xBAD); token.permit(owner, game, 100, deadline, v, r, s) succeeds; nonces(owner) == 1, allowance(owner, game) == 100. Step 2: vm.prank(game); token.permit(owner, game, 100, deadline, v, r, s) reverts (ERC2612InvalidSigner, recovered signer differs since nonce moved). Step 3: vm.prank(game); token.transferFrom(owner, game, 100) succeeds, balanceOf(game) == 100, showing the allowance was already usable. Reproduced in a scratch Foundry test (test_permitFrontRunGriefsBundledCall) against the compiled contract.","severity":"info","snippet":"contract IMDCred is ERC20, ERC20Permit {","title":"A permit signature submitted first by a third party makes a bundled permit-then-transferFrom call revert (integration note, not a token defect)"}],"hash":"9284d49781beeec41b3e273afb709ebff5e6c6adbca577ee5448cefa25b71ae4","nodeId":"14038888-451e-4832-9680-2839b44378d7","outcome":"completed","summary":"The review is complete and the findings file is written. The tree is otherwise untouched.\n\n**Outcome: no defects.** The token at `src/IMDCred.sol` is a 36-line fixed-supply OpenZeppelin v5.4.0 ERC20 with EIP-2612 permit and a self-only burn. Both specialist notes reproduced, but both are standard EIP-2612 behaviour rather than defects, so I kept them at info and they open no revision.\n\nWhat I verified against the code:\n\n- **Vendored library integrity.** All 18 OpenZeppelin files in the token's compile closure hash byte-identical to the upstream v5.4.0 tag.\n- **Deployability.** Creation code and runtime are well under the size limits. An opcode scan of both finds no DELEGATECALL, CALLCODE, SELFDESTRUCT, CALL or CREATE, only the STATICCALL to the ecrecover precompile. The constructor takes no arguments and mints exactly 1e27 to the factory.\n- **Manifest.** The launch.json in the tree uses only schema keys, its supply, decimals, name, symbol and empty constructor arguments match the contract, and the notes are under the length limit.\n- **Protected floor.** The verifier's protected test cannot run here because it imports v4-core and factory sources outside this tree. I read every assertion in it. A plain OZ ERC20 with no tax, exemptions, owner or mint path satisfies each one.\n- **Entry points.** All five are answered. Four hold and permit is marked finding only because the two info notes attach to it.\n- **Static analysis.** The aderyn large-literal lead evaluates to exactly the manifest supply.\n\nScratch tests I wrote reproduced the contract-wallet permit revert and the permit front-run griefing, and confirmed burn cannot exceed balance, the EIP-712 domain binds the chain id, and ETH is refused. The scratch directory was removed afterwards. The project's own 69 tests all pass.","treeHash":null,"usage":{"cachedInputTokens":751237,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":11573,"runtime":"claude","turns":15,"wallClockMs":223182}},{"artifacts":[],"attempt":1,"bundleHash":"d7ba9d5aa366dc33633256e4327164e76dbe58dc71b1f7187ea545d6cac00680","device":"8e25456c4ae69acf","findings":[],"hash":"a1fc4c6a104bba5e881f71887b3e79bf17dbaf6c25e5500e8fd2403cc058c743","nodeId":"47fddcdf-cac6-4cf1-a34e-02fc884f436f","outcome":"completed","summary":"Done. The build is clean with zero warnings, and `forge test` passes across all three suites.\n\n**What I found**\n\nThe token at `src/IMDCred.sol` is a thin composition of OpenZeppelin v5.4.0 ERC20 and ERC20Permit plus a one-line self-burn. I read it adversarially and drove it with random sequences, zero and one-wei inputs, the whole supply, repeated calls, self-as-counterparty, and malleated or cross-chain signatures. No defect surfaced, so no findings file was written. The only behaviour worth noting is that tokens sent to the token's own address are stuck forever, which is standard for an ownerless ERC20 and is pinned as a test rather than reported.\n\n**What I added**\n\n- `test/IMDCred.invariant.t.sol`: a handler with six keyed actors plus the deployer, ghost accounting per address and per allowance pair, and seven invariants checked after every call with `fail_on_revert` on. Clamped handlers reach the success paths; unclamped handlers pass raw inputs and assert the exact revert the token must produce for over-balance transfers, zero receivers, over-allowance pulls, over-burns, replayed permits, expired permits and forged permits. Invariants: supply equals the mint minus burns and never grows, tracked balances sum to supply, every holder holds received minus sent minus burned, allowances and nonces match the ghosts, the zero address holds nothing, and metadata and the permit domain stay fixed.\n- `test/IMDCred.edges.t.sol`: 41 unit and fuzz tests for edges the existing suite did not reach: whole-supply transfer and burn, one-wei and max-uint inputs, self-transfer, self-transferFrom, approve to zero spender, approve overwrite, allowance above balance, burn not touching allowances, permit at the exact deadline, zero value, high-s malleability, garbage signatures, wrong spender or owner, future nonce, chain binding, per-owner nonces, distinct domains across deployments, and EIP-5267 domain fields.\n\n**How I checked it**\n\nBefore trusting the invariants I ran the same handler against a scratch mutant token that mints 1% of every transfer to the deployer. Every invariant failed on the first run, so the suite is not vacuous. That mutant lived in the scratch directory and has been removed.\n\n| Suite | Tests | Result |\n|---|---|---|\n| existing `IMDCred.t.sol` | 27 | pass |\n| new `IMDCred.edges.t.sol` | 41 | pass |\n| new `IMDCred.invariant.t.sol` | 7 invariants, 256 runs, depth 64 | pass |\n\nOne thing to be aware of: forge persists shrunk invariant failures under the cache directory, and a stale entry from my mutant run made the suite fail once until I cleared it. The cache is gitignored, so the verifier starts clean. The two new files are uncommitted in the working tree, ready for the harness to pick up.","treeHash":"121758612a291387760124eaa0b8b953d4003e7d","usage":{"cachedInputTokens":1518387,"inputTokens":610,"model":"claude-fable-5-1","outputTokens":34231,"runtime":"claude","turns":28,"wallClockMs":533367}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"72f49cf84b9ab056","findings":[{"citation":"resolved","description":"Not a defect of the token as specified, recorded as a boundary note because the README advertises permit as the gasless-approval path for the game contracts. OpenZeppelin ERC20Permit v5.4.0 recovers an EOA with ECDSA.recover and compares it to `owner`; it never consults IERC1271.isValidSignature. For any `owner` whose address is a contract (multisig, account-abstraction wallet) the recovered address is an EOA and `signer != owner`, so permit reverts with ERC2612InvalidSigner for every possible (v, r, s). Such holders must use approve() in their own transaction. Game contracts that only offer a permit-based entry would exclude them; offering an approve-based fallback resolves it without changing the token. No funds are at risk and no allowance can be set wrongly.","line":22,"path":"src/IMDCred.sol","reproduction":"State: Wallet w = new Wallet() (any contract, even one whose isValidSignature returns the magic value). Input: (v,r,s) = vm.sign(anyKey, EIP-712 digest for owner=address(w), spender=BOB, value=1, nonce=0, deadline=block.timestamp); call token.permit(address(w), BOB, 1, block.timestamp, v, r, s). Expected if ERC-1271 were supported: allowance(w, BOB) == 1. Actual: reverts ERC2612InvalidSigner(vm.addr(anyKey), address(w)); allowance(w, BOB) stays 0. Verified in a scratch Foundry test (test_permitContractWalletOwnerAlwaysReverts) against the compiled contract.","severity":"info","snippet":"contract IMDCred is ERC20, ERC20Permit {","title":"permit() has no ERC-1271 path: a holder that is a smart-contract wallet can never approve by signature"}],"hash":"accd63103e5be94a8955e3559a2cd0acd65306716b13a01fa30676ea7e56f67f","nodeId":"6f19f836-9b0c-46b4-b02b-fad0bc3da4ae","outcome":"completed","summary":"The review is complete. The findings file is in place, the scratch tests are removed, and the tree holds no other changes.\n\n**Outcome:** no math, boundary or numerical-gap defect in IMDCred. One informational note is recorded.\n\n**What I covered**\n- The token itself is a two-line composition of OpenZeppelin v5.4.0 ERC20 and ERC20Permit plus a holder-only `burn`. It contains no division, no scaling, no casts and no external calls beyond the ecrecover precompile.\n- I diffed the vendored OpenZeppelin tree against the pristine 5.4.0 npm release. Every Solidity file is byte-identical, so the arithmetic under review is the audited upstream code.\n- I wrote and ran a 22-test scratch suite against the five entry points: zero and max amounts, self-transfers, burning the whole supply, the infinite-allowance sentinel at max and max-minus-one, zero-address sender, receiver, spender and permit owner, high-s and bad-v signatures, deadline equal to now and at max, chain-id change, nonce sequencing and permit front-running. All passed, confirming the guards hold before each unchecked block and that sum of balances always equals total supply.\n- The aderyn large-literal lead resolves to exactly 1e27 at compile time, and the launch split of 10 and 90 percent is exact with no dust.\n\n**What I reported**\n- Info: `permit` has no ERC-1271 path, so a holder that is a smart-contract wallet can never approve by signature and must use `approve`. Reproduced with a contract owner and any EOA signature, which reverts with ERC2612InvalidSigner. This is standard OpenZeppelin behaviour, not a token defect, but the README advertises permit as the gasless path for the game contracts.\n\n**Coverage record:** all five listed entry points have rows, four as holds and permit as finding 1, plus rows for the supply invariant, the literal constant, the vendored dependency and the ETH boundary. Nothing was left unreached. The pool price derivation and Uniswap v4 seed math are outside the token and the deployer's responsibility, so they were not audited here.","treeHash":null,"usage":{"cachedInputTokens":690639,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":17437,"runtime":"claude","turns":21,"wallClockMs":221319}},{"artifacts":[],"attempt":1,"bundleHash":"73820dc40c41514f438af21099f1c66de7662c1f7d2bca914db61fb8b141929e","device":"523b06a3dd921f5d","findings":[],"hash":"b6eb182d20c430d9fb49d01fc197600046137f398c6b64e6e0ca13bca1d1b2dd","nodeId":"2b039271-d9a8-4f2d-88a8-8bfcd3e89082","outcome":"completed","summary":"Done. I wrote launch.json for the accepted IMDCred token and verified it against the tree.\n\n**What the manifest says**\n- Kind is custom_token, token contract IMDCred, name IMDCred, symbol IMDCRED, 18 decimals.\n- Constructor arguments are empty, matching the accepted constructor in src/IMDCred.sol which takes none.\n- Total supply is 1000000000000000000000000000 minor units, exactly what the constructor mints to msg.sender.\n- Contracts list is empty, since the accepted tree contains only the token.\n- Pool and economics are copied verbatim from the launch reference: IMD as paired currency, fee 12500, tick spacing 60, the provenance-only initial price, poolBps 9000 and a 500 IMD opening cap.\n- Notes describe the token's fixed supply, no-admin design, holder-only burn, and that no application contracts ship in this launch.\n\n**Verification**\n- A JSON check confirmed only schema keys are present, the supply and economics match, the address is lowercase, and notes are well under the limit.\n- forge build compiled cleanly and forge test passed all 27 existing tests.\n- git status shows launch.json as the only new file; nothing else was changed.","treeHash":"1e2bcdf003c8eee91159789b17a80a2d23c33632","usage":{"cachedInputTokens":203970,"inputTokens":162,"model":"claude-fable-5-1","outputTokens":2796,"runtime":"claude","turns":9,"wallClockMs":43921}}],"verification":[{"checks":[{"durationMs":917,"exitCode":0,"name":"build","output":"Compiling 42 files with Solc 0.8.26\nSolc 0.8.26 finished in 814.61ms\nCompiler run successful!\n","passed":true},{"durationMs":99,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 27 tests for test/IMDCred.t.sol:IMDCredTest\n[PASS] testFuzz_burnOnlyShrinksSupply(uint256,uint256) (runs: 256, μ: 122726, ~: 123512)\nLogs:\n  Bound result 1\n  Bound result 1\n\n[PASS] testFuzz_transfersConserveSupply(uint256,uint256,uint256) (runs: 256, μ: 249758, ~: 253702)\nLogs:\n  Bound result 9000\n  Bound result 4919\n  Bound result 127\n\n[PASS] test_approveAndTransferFrom() (gas: 209157)\n[PASS] test_burnMoreThanBalanceReverts() (gas: 96669)\n[PASS] test_burnReducesBalanceAndSupply() (gas: 118400)\n[PASS] test_burnZeroIsANoOp() (gas: 41988)\n[PASS] test_constructorMintsWholeSupplyToDeployer() (gas: 52969)\n[PASS] test_constructorTakesNoArguments() (gas: 1276496)\n[PASS] test_deployScriptMintsToTheCaller() (gas: 2267219)\n[PASS] test_infiniteAllowanceIsNotDecremented() (gas: 173789)\n[PASS] test_launchFlowsArriveWhole() (gas: 395301)\n[PASS] test_metadata() (gas: 32058)\n[PASS] test_mintedEventIsEmittedOnce() (gas: 1254243)\n[PASS] test_noMintOrAdminSelectorExists() (gas: 591749)\n[PASS] test_noPrivilegedCallMovesOrFreezesAHolder() (gas: 429108)\n[PASS] test_permitRejectsExpiredDeadline() (gas: 43269)\n[PASS] test_permitRejectsReplay() (gas: 127614)\n[PASS] test_permitRejectsTamperedValue() (gas: 75749)\n[PASS] test_permitRejectsWrongSigner() (gas: 76677)\n[PASS] test_permitSetsAllowanceAndSpendsNonce() (gas: 237016)\n[PASS] test_rejectsEther() (gas: 36837)\n[PASS] test_runtimeCodeHasNoDelegatecallOrSelfdestruct() (gas: 4914723)\n[PASS] test_transferFromRevertsOnInsufficientAllowance() (gas: 138696)\n[PASS] test_transferFromWithoutAllowanceReverts() (gas: 98802)\n[PASS] test_transferMovesExactAmount() (gas: 136499)\n[PASS] test_transferRevertsOnInsufficientBalance() (gas: 91231)\n[PASS] test_transferToZeroAddressReverts() (gas: 88696)\nSuite result: ok. 27 passed; 0 failed; 0 skipped; finished in 13.24ms (34.63ms CPU time)\n\nRan 1 test suite in 13.91ms (13.24ms CPU time): 27 tests passed, 0 failed, 0 skipped (27 total tests)\n","passed":true},{"durationMs":36,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDCred.approve(address,uint256)\",\"IMDCred.burn(uint256)\",\"IMDCred.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMDCred.transfer(address,uint256)\",\"IMDCred.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":164,\"foundry.toml\":24,\"remappings.txt\":2,\"script/DeployIMDCred.s.sol\":25,\"src/IMDCred.sol\":36,\"test/IMDCred.t.sol\":393},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":1315,"exitCode":0,"name":"slither","output":"slither: no results at low impact or above","passed":true},{"durationMs":447,"exitCode":0,"name":"aderyn","output":"[low] large-numeric-literal at src/IMDCred.sol:24: Large Numeric Literal","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"0327db56df4df956f7b5605c87d6f49c7e6a001d5fd1fa17e6cd6a17a66bb0c3","verifiedTreeHash":"87e4bddc3376add9a364fe2c2bb1364aad81cdeb","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":2317,"exitCode":0,"name":"build","output":"Compiling 44 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.14s\nCompiler run successful!\n","passed":true},{"durationMs":15652,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 27 tests for test/IMDCred.t.sol:IMDCredTest\n[PASS] testFuzz_burnOnlyShrinksSupply(uint256,uint256) (runs: 256, μ: 122696, ~: 123584)\nLogs:\n  Bound result 10110902791\n  Bound result 5875999202\n\n[PASS] testFuzz_transfersConserveSupply(uint256,uint256,uint256) (runs: 256, μ: 249119, ~: 253702)\nLogs:\n  Bound result 2140848617607534659225\n  Bound result 3\n  Bound result 2\n\n[PASS] test_approveAndTransferFrom() (gas: 209157)\n[PASS] test_burnMoreThanBalanceReverts() (gas: 96669)\n[PASS] test_burnReducesBalanceAndSupply() (gas: 118400)\n[PASS] test_burnZeroIsANoOp() (gas: 41988)\n[PASS] test_constructorMintsWholeSupplyToDeployer() (gas: 52969)\n[PASS] test_constructorTakesNoArguments() (gas: 1276496)\n[PASS] test_deployScriptMintsToTheCaller() (gas: 2267219)\n[PASS] test_infiniteAllowanceIsNotDecremented() (gas: 173789)\n[PASS] test_launchFlowsArriveWhole() (gas: 395301)\n[PASS] test_metadata() (gas: 32058)\n[PASS] test_mintedEventIsEmittedOnce() (gas: 1254243)\n[PASS] test_noMintOrAdminSelectorExists() (gas: 591749)\n[PASS] test_noPrivilegedCallMovesOrFreezesAHolder() (gas: 429108)\n[PASS] test_permitRejectsExpiredDeadline() (gas: 43269)\n[PASS] test_permitRejectsReplay() (gas: 127614)\n[PASS] test_permitRejectsTamperedValue() (gas: 75749)\n[PASS] test_permitRejectsWrongSigner() (gas: 76677)\n[PASS] test_permitSetsAllowanceAndSpendsNonce() (gas: 237016)\n[PASS] test_rejectsEther() (gas: 36837)\n[PASS] test_runtimeCodeHasNoDelegatecallOrSelfdestruct() (gas: 4914723)\n[PASS] test_transferFromRevertsOnInsufficientAllowance() (gas: 138696)\n[PASS] test_transferFromWithoutAllowanceReverts() (gas: 98802)\n[PASS] test_transferMovesExactAmount() (gas: 136499)\n[PASS] test_transferRevertsOnInsufficientBalance() (gas: 91231)\n[PASS] test_transferToZeroAddressReverts() (gas: 88696)\nSuite result: ok. 27 passed; 0 failed; 0 skipped; finished in 66.33ms (125.69ms CPU time)\n\nRan 41 tests for test/IMDCred.edges.t.sol:IMDCredEdgesTest\n[PASS] testFuzz_burnsFromSeveralHoldersSumExactly(uint256,uint256,uint256) (runs: 1000, μ: 288055, ~: 289313)\nLogs:\n  Bound result 148435872689490040972238884\n  Bound result 111032464984124980003944165\n  Bound result 15671924825377448922627734\n\n[PASS] testFuzz_permitFromAnyKeyThenPullExactly(uint256,uint256,uint256) (runs: 1000, μ: 252187, ~: 253165)\nLogs:\n  Bound result 4723\n  Bound result 10\n  Bound result 5000000000000000000\n\n[PASS] testFuzz_permitWithTamperedDeadlineIsRejected(uint256,uint256) (runs: 1000, μ: 82681, ~: 82643)\nLogs:\n  Bound result 11029301\n  Bound result 1\n\n[PASS] testFuzz_pullsDecrementAllowanceExactly(uint256,uint256,uint256) (runs: 1000, μ: 223672, ~: 228590)\nLogs:\n  Bound result 1287\n  Bound result 1223\n  Bound result 64\n\n[PASS] testFuzz_transferAboveBalanceAlwaysReverts(uint256,uint256) (runs: 1000, μ: 99649, ~: 99765)\nLogs:\n  Bound result 7486\n  Bound result 24059\n\n[PASS] testFuzz_transferRoundTripRestoresBalances(uint256,uint256) (runs: 1000, μ: 165323, ~: 166284)\nLogs:\n  Bound result 1202\n  Bound result 1202\n\n[PASS] test_allowanceIsExhaustedExactlyThenRefused() (gas: 192303)\n[PASS] test_allowanceMayExceedBalanceButPullIsCappedByBalance() (gas: 192772)\n[PASS] test_allowanceSurvivesAnOrdinaryTransfer() (gas: 160597)\n[PASS] test_approveOverwritesRatherThanAdds() (gas: 128945)\n[PASS] test_approveToZeroSpenderReverts() (gas: 30847)\n[PASS] test_balanceOfZeroAddressIsZero() (gas: 10701)\n[PASS] test_burnDoesNotTouchAllowances() (gas: 179620)\n[PASS] test_burnFromAnEmptyAccountRevertsForOneWei() (gas: 32918)\n[PASS] test_burnOfMaxUintReverts() (gas: 91474)\n[PASS] test_burnTwiceSumsAndStopsAtBalance() (gas: 160132)\n[PASS] test_deployerCanMoveTheWholeSupplyInOneTransfer() (gas: 102241)\n[PASS] test_eip712DomainMatchesSeparator() (gas: 22952)\n[PASS] test_permitAtExactDeadlineIsAccepted() (gas: 152266)\n[PASS] test_permitForZeroSpenderReverts() (gas: 70139)\n[PASS] test_permitIsBoundToTheChain() (gas: 191093)\n[PASS] test_permitMovesNoTokensAndApproveOverridesIt() (gas: 237254)\n[PASS] test_permitNoncesAreIndependentPerOwner() (gas: 221028)\n[PASS] test_permitRejectsGarbageSignature() (gas: 117314)\n[PASS] test_permitRejectsHighSMalleatedSignature() (gas: 85902)\n[PASS] test_permitRejectsWrongSpenderAndWrongOwner() (gas: 151380)\n[PASS] test_permitSignedForFutureNonceIsRejectedUntilItsTurn() (gas: 217147)\n[PASS] test_permitWithMaxDeadlineAndZeroValue() (gas: 140715)\n[PASS] test_selfTransferKeepsBalance() (gas: 134511)\n[PASS] test_strangerCannotPullFromTheDeployer() (gas: 40393)\n[PASS] test_supplyConstantIsExactlyOneBillionAtEighteenDecimals() (gas: 22567)\n[PASS] test_transferFromBySelfStillNeedsAllowance() (gas: 204032)\n[PASS] test_transferFromOfZeroSpendsNoAllowance() (gas: 93659)\n[PASS] test_transferFromToZeroRevertsEvenWithAllowance() (gas: 143672)\n[PASS] test_transferOfMaxUintRevertsWithoutMovingAnything() (gas: 103317)\n[PASS] test_transferOfOneWeiMovesOneWei() (gas: 123533)\n[PASS] test_transferOfZeroSucceedsAndEmits() (gas: 45453)\n[PASS] test_transferToTheTokenItselfIsAllowedAndStuck() (gas: 154932)\n[PASS] test_twoDeploymentsHaveDistinctDomains() (gas: 82859)\n[PASS] test_unknownSelectorAndEmptyCalldataRevert() (gas: 73898)\n[PASS] test_wholeSupplyCanBeBurnedAndNothingWorksAfter() (gas: 117864)\nSuite result: ok. 41 passed; 0 failed; 0 skipped; finished in 74.01ms (431.39ms CPU time)\n\nRan 1 test for test/IMDCred.invariant.t.sol:IMDCredInvariantTest\n[PASS]\nIMDCredInvariantTest invariants:\n[PASS] invariant_allowancesMatchGhost\n[PASS] invariant_everyHolderHasExactlyWhatItWasSent\n[PASS] invariant_metadataAndDomainAreFixed\n[PASS] invariant_noncesCountSuccessfulPermitsOnly\n[PASS] invariant_sumOfBalancesEqualsSupply\n[PASS] invariant_supplyIsInitialMinusBurned\n[PASS] invariant_zeroAddressNeverHoldsTokens\n IMDCredInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭----------------+-----------------------+-------+---------+----------╮\n| Contract       | Selector              | Calls | Reverts | Discards |\n+=====================================================================+\n| IMDCredHandler | approve               | 929   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | approveInfinite       | 931   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | burn                  | 949   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | burnAll               | 926   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | burnUnclamped         | 848   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | deployerBurn          | 850   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | permit                | 933   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | permitExpired         | 922   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | permitForged          | 934   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | permitReplay          | 892   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | seed                  | 921   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | selfTransfer          | 920   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | transfer              | 897   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | transferAll           | 918   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | transferFrom          | 933   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | transferFromUnclamped | 868   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | transferUnclamped     | 908   | 0       | 0        |\n|----------------+-----------------------+-------+---------+----------|\n| IMDCredHandler | warp                  | 905   | 0       | 0        |\n╰----------------+-----------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 104243511398230060904803724072340173124482190028433672226829340961155445984980\n  Bound result 64926621109963998056977323151234341542324310819634670044698250838988456004199\n  Bound result 40771130236698873039762942671161911291941539969339862979153628878712375051883\n  Bound result 100748464875981708303836335223369555137134919815301742565804256155551445379990\n  Bound result 102353445158822689330352505367904842688662080362451539642405930443271077967417\n  Bound result 80178760909328648119114485938516002827813151411509814482211575711862629793884\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 4\n  Bound result 4\n  Bound result 5\n  Bound result 4\n  Bound result 5\n  Bound result 15763\n  Bound result 0\n  Bound result 5\n  Bound result 4\n  Bound result 1\n  Bound result 4\n  Bound result 3\n  Bound result 0\n  Bound result 2\n  Bound result 4\n  Bound result 1\n  Bound result 4\n  Bound result 2\n  Bound result 5\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 95\n  Bound result 0\n  Bound result 0\n  Bound result 5\n  Bound result 3\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 4\n  Bound result 3\n  Bound result 0\n  Bound result 3\n  Bound result 4\n  Bound result 1345\n  Bound result 2\n  Bound result 3\n  Bound result 242\n  Bound result 4\n  Bound result 5\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 11296\n  Bound result 0\n  Bound result 4\n  Bound result 5\n  Bound result 0\n  Bound result 4\n  Bound result 2\n  Bound result 36876\n  Bound result 5\n  Bound result 4\n  Bound result 4\n  Bound result 8469109\n  Bound result 2\n  Bound result 0\n  Bound result 5\n  Bound result 4\n  Bound result 2\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 138327986\n  Bound result 4\n  Bound result 2\n  Bound result 127\n  Bound result 5\n  Bound result 2\n  Bound result 127\n  Bound result 4058\n  Bound result 343\n  Bound result 15090\n  Bound result 1\n  Bound result 3\n  Bound result 4\n  Bound result 4\n  Bound result 5\n  Bound result 0\n  Bound result 5\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 5\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 4\n  Bound result 623156605759691788867987060\n  Bound result 2\n  Bound result 0\n  Bound result 5\n  Bound result 0\n  Bound result 4\n  Bound result 2\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 9155\n  Bound result 5\n  Bound result 0\n  Bound result 7748559\n  Bound result 0\n  Bound result 0\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 15.52s (15.51s CPU time)\n\nRan 3 test suites in 15.52s (15.66s CPU time): 69 tests passed, 0 failed, 0 skipped (69 total tests)\n","passed":true},{"durationMs":51,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDCred.approve(address,uint256)\",\"IMDCred.burn(uint256)\",\"IMDCred.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMDCred.transfer(address,uint256)\",\"IMDCred.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":164,\"foundry.toml\":24,\"remappings.txt\":2,\"script/DeployIMDCred.s.sol\":25,\"src/IMDCred.sol\":36,\"test/IMDCred.edges.t.sol\":524,\"test/IMDCred.invariant.t.sol\":482,\"test/IMDCred.t.sol\":393},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"a1fc4c6a104bba5e881f71887b3e79bf17dbaf6c25e5500e8fd2403cc058c743","verifiedTreeHash":"121758612a291387760124eaa0b8b953d4003e7d","verifierVersion":"0.1.0+327e1e9f"},{"checks":[{"durationMs":1006,"exitCode":0,"name":"build","output":"Compiling 42 files with Solc 0.8.26\nSolc 0.8.26 finished in 893.74ms\nCompiler run successful!\n","passed":true},{"durationMs":131,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 27 tests for test/IMDCred.t.sol:IMDCredTest\n[PASS] testFuzz_burnOnlyShrinksSupply(uint256,uint256) (runs: 256, μ: 122657, ~: 123512)\nLogs:\n  Bound result 505517625643565902363225825\n  Bound result 46367492351501487832782180\n\n[PASS] testFuzz_transfersConserveSupply(uint256,uint256,uint256) (runs: 256, μ: 250237, ~: 253714)\nLogs:\n  Bound result 795738583079192394424142868\n  Bound result 448289079398148500862241398\n  Bound result 3\n\n[PASS] test_approveAndTransferFrom() (gas: 209157)\n[PASS] test_burnMoreThanBalanceReverts() (gas: 96669)\n[PASS] test_burnReducesBalanceAndSupply() (gas: 118400)\n[PASS] test_burnZeroIsANoOp() (gas: 41988)\n[PASS] test_constructorMintsWholeSupplyToDeployer() (gas: 52969)\n[PASS] test_constructorTakesNoArguments() (gas: 1276496)\n[PASS] test_deployScriptMintsToTheCaller() (gas: 2267219)\n[PASS] test_infiniteAllowanceIsNotDecremented() (gas: 173789)\n[PASS] test_launchFlowsArriveWhole() (gas: 395301)\n[PASS] test_metadata() (gas: 32058)\n[PASS] test_mintedEventIsEmittedOnce() (gas: 1254243)\n[PASS] test_noMintOrAdminSelectorExists() (gas: 591749)\n[PASS] test_noPrivilegedCallMovesOrFreezesAHolder() (gas: 429108)\n[PASS] test_permitRejectsExpiredDeadline() (gas: 43269)\n[PASS] test_permitRejectsReplay() (gas: 127614)\n[PASS] test_permitRejectsTamperedValue() (gas: 75749)\n[PASS] test_permitRejectsWrongSigner() (gas: 76677)\n[PASS] test_permitSetsAllowanceAndSpendsNonce() (gas: 237016)\n[PASS] test_rejectsEther() (gas: 36837)\n[PASS] test_runtimeCodeHasNoDelegatecallOrSelfdestruct() (gas: 4914723)\n[PASS] test_transferFromRevertsOnInsufficientAllowance() (gas: 138696)\n[PASS] test_transferFromWithoutAllowanceReverts() (gas: 98802)\n[PASS] test_transferMovesExactAmount() (gas: 136499)\n[PASS] test_transferRevertsOnInsufficientBalance() (gas: 91231)\n[PASS] test_transferToZeroAddressReverts() (gas: 88696)\nSuite result: ok. 27 passed; 0 failed; 0 skipped; finished in 13.82ms (36.40ms CPU time)\n\nRan 1 test suite in 14.49ms (13.82ms CPU time): 27 tests passed, 0 failed, 0 skipped (27 total tests)\n","passed":true},{"durationMs":32,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"IMDCred.approve(address,uint256)\",\"IMDCred.burn(uint256)\",\"IMDCred.permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\",\"IMDCred.transfer(address,uint256)\",\"IMDCred.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":3,\"README.md\":164,\"foundry.toml\":24,\"launch.json\":23,\"remappings.txt\":2,\"script/DeployIMDCred.s.sol\":25,\"src/IMDCred.sol\":36,\"test/IMDCred.t.sol\":393},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"b6eb182d20c430d9fb49d01fc197600046137f398c6b64e6e0ca13bca1d1b2dd","verifiedTreeHash":"1e2bcdf003c8eee91159789b17a80a2d23c33632","verifierVersion":"0.1.0+327e1e9f"}]}