{"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":"1d091aae-6d4d-4c64-959b-344d3865252c","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"49b57fa615b05d6a0f6409e6a598efc83878a978ceb29b3f53055327a5cbaee0","dependsOn":["build_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"1e97eb305fc0ab326ceec0086fa7286cc77135aaf4b46c0b378462bc943091e9","dependsOn":["build_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"99f240f726c4ae212481aa7e686de6ac9dcf1b8b2ee9d3e04bc546d37d72cc09","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"bee189c92cd5ffa853e7cf34305dce3064ea9b50ff1f3337ec5bb06d207aa12c","dependsOn":["build_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"acbbe0fa5cc7e62ea3f54dec879a3c80b02846568ec2afe7f4a7ae4d00e243b0","dependsOn":["build_contract_project","write_foundry_tests","manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"5f6475964505ac563196a4741d086038ac8e5d6464a611f96c5be547031e4101","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b6503de65ad02f845827887c23da4c3b56ccc5df7a459db263bae6e549d92f7f","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"b6503de65ad02f845827887c23da4c3b56ccc5df7a459db263bae6e549d92f7f","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"4dfe52817c58e5c45f19020e02c23587994b31c877bff5d00119c4d8dbb2171a","dependsOn":["build_contract_project","write_foundry_tests"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"184400a5966a4f87773de218d671ecdaf539118f1f1a2794fd0543fa7207ad12","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":"Memecoin Cemetery: a tokenless, ownerless, immutable contract on Robinhood Chain (chainId 4663) where dead ERC-20 tokens get a tombstone, a curated epitaph and an on-chain SVG headstone, but only if none of the token's holders objects. No token, no fees, no owner, no upgrade, no pause, no constructor arguments, no ETH accepted (receive and fallback revert).\n\nWhy: the swarm launches a lot of tokens. This is the other end of the lifecycle: a public, permissionless, funny place where tokens go to rest, where any real holder can stop a burial, where anyone can mourn, and where a buried token can come back as a zombie.\n\nState machine per token: None -> Wake -> Buried; Wake -> Saved; Buried -> Risen; Saved or Risen -> Wake again only after a 7-day cooldown. History counters never reset.\n\nWho counts as a holder (for objecting and rising): an account whose balanceOf(token) is at least min(10**decimals, totalSupply / 1000), i.e. one whole token or 0.1% of supply, whichever is smaller, and never less than 1 base unit (so a tiny-supply token cannot round the threshold down to zero). decimals() defaults to 18 if it reverts or returns more than 36. Borrowed or flash-loaned balances count; that is acceptable because a holder can only save or raise a token, never bury one. (The smaller-of rule matters: with 0.1% alone, nobody could defend a large live token.)\n\nEpitaphs are NOT free text (free text on an immutable contract would be abused). The contract stores exactly these 24 epitaphs, indexed 0 to 23, and dig() takes an index:\n0 Here lies a 1000x that never was | 1 Down only. Rest easy. | 2 LP pulled, soul released | 3 Died as it lived: illiquid | 4 Gone but not forgotten (mostly forgotten) | 5 Number go down | 6 It was never about the tech | 7 Community takeover pending since forever | 8 Wen moon? Never. | 9 Ser, this is a graveyard | 10 Bought the top so you did not have to | 11 Roadmap: complete. Token: deceased. | 12 Diamond hands, paper chart | 13 Last seen in a Telegram with 3 members | 14 Fair launch, unfair ending | 15 The dev is still typing... | 16 Not financial advice. Not financial anything. | 17 Ran out of greater fools | 18 Locked liquidity, lost hope | 19 It had a great logo | 20 Few understood. Fewer bought. | 21 Rug in peace | 22 Still waiting for the CEX listing | 23 Holders: 1 (the deployer)\n\nFunctions:\n- dig(address token, uint8 epitaphId): the token must have code, and totalSupply() must succeed and be > 0 (low-level staticcall with a fixed gas cap such as 50,000 and a return-data size check; a reverting or malformed token cannot be dug). epitaphId must be < 24. Allowed from None, or from Saved/Risen once the cooldown has passed. Starts a 72-hour wake. Emits WakeOpened(token, digger, epitaphId, endsAt).\n- itLives(address token): during the wake, a holder cancels the burial. State -> Saved, cooldown starts. Emits Resurrected(token, holder).\n- seal(address token): after the wake ends with no objection, anyone seals. State -> Buried, the burial is appended to a recent-burials list. Emits Buried(token, epitaphId, digger, sealedAt).\n- mourn(address token): while Buried, any address can pay respects once per burial (tracked per burial number). Increments that burial's mourner count. Emits Mourned(token, mourner, mourners).\n- rise(address token): while Buried, a holder marks the token as risen from the dead. The burial record is kept forever; state -> Risen, the rises counter increments, cooldown starts. Emits Rose(token, holder).\n- graveOf(address token) view: state, digger, epitaphId, dugAt, wakeEndsAt, sealedAt, burials, rises, saves, mourners (current burial). graveCount() view: number of tokens currently Buried. epitaph(uint8 id) view: the text. recentBurials(uint256 n) view: the last min(n, 20) sealed tokens, newest first.\n- headstone(address token) view: returns an SVG string drawing a tombstone with the token symbol (read with a gas-capped staticcall; if it fails or is not printable ASCII, use the shortened token address), the epitaph, the dig and seal dates as YYYY-MM-DD UTC computed on-chain (a dash for a date not yet set), the mourner count, and a RISEN banner with the rise count when state is Risen. The symbol is token-supplied, so it must be XML-escaped (& < > \" ') with non-printable bytes replaced by '?'. Reverts for tokens never dug.\n\nDeliverables: a complete Foundry project laid out like other live IMD launches (for example launch 849, SitOnHands). Three earlier attempts of this idea, launches 852, 853 and 862, were parked only because the builders were not allowed to write foundry.toml, so every file below is required:\n1. src/MemecoinCemetery.sol: NatSpec on every function, custom errors, solc 0.8.26, no external dependencies.\n2. test/MemecoinCemetery.t.sol: mock tokens (normal 18-decimal, 6-decimal, no symbol, a symbol containing < > & characters, reverting, plus an EOA address) covering every state transition and every revert; the holder rule at both thresholds and the 1-base-unit floor for a supply under 1000; the 72-hour wake and 7-day cooldowns; epitaphId 23 accepted and 24 rejected; mourn once per address per burial and again after a re-burial; recentBurials ordering and the cap of 20; headstone() showing the right epitaph, dates, mourners and an escaped symbol; ETH rejection. Fuzz: a sealed burial record (digger, epitaphId, sealedAt) never changes. Invariant: graveCount equals the number of tokens in state Buried.\n3. script/Deploy.s.sol: requires block.chainid == 4663 and deploys MemecoinCemetery with no arguments.\n4. docs/abi/MemecoinCemetery.json.\n5. foundry.toml at the repository root, exactly:\n[profile.default]\nsrc = \"src\"\ntest = \"test\"\nscript = \"script\"\nout = \"out\"\nlibs = [\"lib\"]\nsolc = \"0.8.26\"\nauto_detect_solc = false\nevm_version = \"cancun\"\noptimizer = true\noptimizer_runs = 200\nbytecode_hash = \"none\"\nffi = false\nfs_permissions = []\n[profile.default.fuzz]\nruns = 256\n[profile.default.invariant]\nruns = 128\ndepth = 64\nfail_on_revert = false\n6. remappings.txt and vendored lib/forge-std, so forge build and forge test --offline work.\n7. README.md: what it does, the state machine, the holder rule and its trade-offs (borrowed balances can save a token), why epitaphs are a fixed list, and the build, test, deploy and verify commands.\nThe deployed bytecode must be reproducible from this foundry.toml, and the source must be verified on the chain's block explorer.","parentJobId":null,"planHash":"0894d2b61590865d394fb5a22aff4089ee36f60bbf20ea8a5246b5f6162b6f04","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"1d091aae-6d4d-4c64-959b-344d3865252c","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-876-memecoin-cemetery-tokenless-ownerless"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52160","feedbackHash":"77c880c17e9ae091ee4b275947aff41c9055a5c4a90fc5c55cc3ed12b1aaa553","nodeKey":"audit_economics","submissionHash":"49b57fa615b05d6a0f6409e6a598efc83878a978ceb29b3f53055327a5cbaee0","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52173","feedbackHash":"6475d0846cbd02665825245ddee86a036f7b40661086683c9837b5aae531744e","nodeKey":"audit_flow","submissionHash":"1e97eb305fc0ab326ceec0086fa7286cc77135aaf4b46c0b378462bc943091e9","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"50907","feedbackHash":"a9054d321fe4fb9eddc663deb7f46257f6edac11bb507efb1f78eec123861c5c","nodeKey":"audit_judge","submissionHash":"3cf7fec6c9e5bcb61c6e28672149a79d91c8334cfb6f72f03435d10bf8127096","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51146","feedbackHash":"f670c6db2e965b1888c834e8757d99aa7e2855193cebf979dd8ddd0ec7ac6b2c","nodeKey":"audit_judge","submissionHash":"99f240f726c4ae212481aa7e686de6ac9dcf1b8b2ee9d3e04bc546d37d72cc09","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52161","feedbackHash":"c777e409fda26401e00764859fe6ae4604798b6fc3709ec300002275482f366b","nodeKey":"audit_math","submissionHash":"bee189c92cd5ffa853e7cf34305dce3064ea9b50ff1f3337ec5bb06d207aa12c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52232","feedbackHash":"e971e5038787c29302f167f8a5fea7b54b6961f9e6ad36c8773dbdf421e0fed5","nodeKey":"audit_permissions","submissionHash":"acbbe0fa5cc7e62ea3f54dec879a3c80b02846568ec2afe7f4a7ae4d00e243b0","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52140","feedbackHash":"3556f506bee78f6ad81f1148e384b6581d8923b0a0b6f7f8394a498d1b4e9a31","nodeKey":"build_contract_project","submissionHash":"ae3be5fcd5f9dd78eaf805026e7e9671b95bdaf869c57b9b5a63c884312830f7","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51151","feedbackHash":"2fba5d511f51540770068e4e0739ad77e7bd161df66ff37bfe396a5f15cf5964","nodeKey":"build_contract_project","submissionHash":"5f6475964505ac563196a4741d086038ac8e5d6464a611f96c5be547031e4101","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51044","feedbackHash":"f0c28267408f2c72fa835a580384bea44e0e80c45eb702a062af244b40b09db2","nodeKey":"manifest","submissionHash":"4dfe52817c58e5c45f19020e02c23587994b31c877bff5d00119c4d8dbb2171a","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51306","feedbackHash":"5aa00db8da6917c65159c63d85282fc37fbaf62264b8ba3db9525b6e2ef980e2","nodeKey":"manifest","submissionHash":"fcb0f0dfd3df845b1f2b18f42d5cc46ce3743b663356bc4306dd8a4873e25784","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52154","feedbackHash":"4e6cf0485a0ef5c13c6835d79a1fc5c1dc8d5988559f748cf745ff8a6f9f106a","nodeKey":"write_foundry_tests","submissionHash":"8b066cb42f91630ec35611ecbbad6bc4f1fe602994da8d5783434805c83f320f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51304","feedbackHash":"d0ba7534b65bab224d25752192af91ebdb12fcce94bb5679be739028fe4bf372","nodeKey":"write_foundry_tests","submissionHash":"184400a5966a4f87773de218d671ecdaf539118f1f1a2794fd0543fa7207ad12","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"0edade19a01ff7f21f844ba0619a8b30d801475c10476b9915ff1f7d6b84ef74","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"7056e3f82d8e35a6afdfa454283a488be3d50b324597bb4b859e246956b2b3fa","device":"4be5e039e1c77ce3","findings":[],"hash":"184400a5966a4f87773de218d671ecdaf539118f1f1a2794fd0543fa7207ad12","nodeId":"35d93ab6-9e65-421c-b25e-286eb7fe9b88","outcome":"completed","summary":"Updated [adversarial tests](/home/seat12/.identitymd/work/1d091aae-6d4d-4c64-959b-344d3865252c/35d93ab6-9e65-421c-b25e-286eb7fe9b88/test/MemecoinCemetery.adversarial.t.sol) to replace the stale holder gas ceiling with failure-atomicity checks and strengthen decimals fallback coverage.\n\nAll 50 tests pass, including a second-seed run with increased fuzz iterations. Offline build and formatting checks pass. Only the test file changed.","treeHash":"035316c0b12b5352882d0c604824989d543b450c","usage":{"cachedInputTokens":657664,"inputTokens":69090,"model":"gpt-6-astra","outputTokens":5557,"runtime":"codex","turns":4,"wallClockMs":215330}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"c2e167266d13dcf4","findings":[{"citation":"resolved","description":"_requireHolder reads balanceOf(msg.sender) through _readWord, which hard-caps the staticcall at TOKEN_GAS = 50_000 (line 59, line 293). dig() only needs totalSupply() to answer, which is O(1) on essentially every token, but the defensive paths itLives() and rise() need balanceOf(), and on the most common memecoin template (SafeMoon-style reflection tokens) balanceOf walks the _excluded array: measured 12.2k gas with 0 excluded accounts and +8.3k per excluded account, so the cap is exceeded at 5 excluded accounts (contract, burn address, pair, owner, marketing is a typical list). For such a token every itLives/rise call reverts with TokenReadFailed(token, 0x70a08231) regardless of the caller's balance, so anyone can dig a live reflection token, nobody can object, seal() buries it, and because Buried exits only through rise() the burial is permanent. This breaks the brief's central guarantee ('any real holder can stop a burial', 'a buried token can come back as a zombie') for a whole token class. The cap gives no safety benefit on this path: the reads are STATICCALLs whose gas is paid by the holder who chose to call, and a hostile token can only waste that caller's own gas. Minimal fix: use a much larger cap (or gasleft()) for the three reads inside _requireHolder (keep 50k for dig's totalSupply and for headstone's symbol if desired); the attached test passes with a 1,000,000-gas holder cap. Also plausible: proxied/diamond reflection tokens, tokens with vesting-aware balanceOf, which compound the per-call cost.","line":279,"path":"src/MemecoinCemetery.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {MemecoinCemetery} from \"src/MemecoinCemetery.sol\";\n\n/// @dev Faithful copy of the SafeMoon-style reflection balanceOf path (balanceOf -> tokenFromReflection ->\n///      _getRate -> _getCurrentSupply loop over _excluded). totalSupply() and decimals() are O(1), as upstream.\ncontract ReflectionToken {\n    string public constant symbol = \"RFLCT\";\n    uint8 public constant decimals = 9;\n\n    uint256 private constant MAX = ~uint256(0);\n    uint256 private _tTotal = 1_000_000_000_000_000 * 10 ** 9;\n    uint256 private _rTotal = (MAX - (MAX % _tTotal));\n\n    mapping(address => uint256) private _rOwned;\n    mapping(address => uint256) private _tOwned;\n    mapping(address => bool) private _isExcluded;\n    address[] private _excluded;\n\n    constructor(address holder, uint256 excludedCount) {\n        _rOwned[holder] = _rTotal / 100; // holder owns 1% of supply, far above the 0.1% threshold\n        for (uint256 i; i < excludedCount; ++i) {\n            address a = address(uint160(0x1000 + i));\n            _isExcluded[a] = true;\n            _excluded.push(a);\n            _rOwned[a] = _rTotal / 1000;\n            _tOwned[a] = _tTotal / 1000;\n        }\n    }\n\n    function totalSupply() external view returns (uint256) {\n        return _tTotal;\n    }\n\n    function balanceOf(address account) public view returns (uint256) {\n        if (_isExcluded[account]) return _tOwned[account];\n        return tokenFromReflection(_rOwned[account]);\n    }\n\n    function tokenFromReflection(uint256 rAmount) public view returns (uint256) {\n        require(rAmount <= _rTotal, \"Amount must be less than total reflections\");\n        uint256 currentRate = _getRate();\n        return rAmount / currentRate;\n    }\n\n    function _getRate() private view returns (uint256) {\n        (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();\n        return rSupply / tSupply;\n    }\n\n    function _getCurrentSupply() private view returns (uint256, uint256) {\n        uint256 rSupply = _rTotal;\n        uint256 tSupply = _tTotal;\n        for (uint256 i = 0; i < _excluded.length; i++) {\n            if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _tTotal);\n            rSupply = rSupply - _rOwned[_excluded[i]];\n            tSupply = tSupply - _tOwned[_excluded[i]];\n        }\n        if (rSupply < _rTotal / _tTotal) return (_rTotal, _tTotal);\n        return (rSupply, tSupply);\n    }\n}\n\ncontract ReflectionHolderGasTest is Test {\n    MemecoinCemetery internal cemetery;\n    address internal constant HOLDER = address(0xBEEF);\n    address internal constant DIGGER = address(0xD166E2);\n\n    function setUp() public {\n        vm.warp(1_709_164_800);\n        cemetery = new MemecoinCemetery();\n    }\n\n    function _gasOfBalanceOf(ReflectionToken t) internal view returns (uint256 used) {\n        uint256 before = gasleft();\n        t.balanceOf(HOLDER);\n        used = before - gasleft();\n    }\n\n    /// @dev Prints how much gas balanceOf needs for a growing excluded list; informational.\n    function test_printBalanceOfGasPerExcludedCount() public {\n        for (uint256 n = 0; n <= 12; n += 2) {\n            ReflectionToken t = new ReflectionToken(HOLDER, n);\n            emit log_named_uint(string.concat(\"excluded=\", vm.toString(n), \" balanceOf gas\"), _gasOfBalanceOf(t));\n        }\n    }\n\n    /// @dev A real 1% holder of a reflection token with 10 excluded accounts cannot save the wake:\n    ///      dig succeeds (totalSupply is O(1)), itLives reverts with TokenReadFailed(balanceOf).\n    function test_reflectionHolderCanSaveWake() public {\n        ReflectionToken t = new ReflectionToken(HOLDER, 10);\n        uint256 threshold = t.totalSupply() / 1000; // min(10**9, supply/1000) == supply/1000 here\n        assertGe(t.balanceOf(HOLDER), threshold, \"setup: holder qualifies by the stated rule\");\n\n        vm.prank(DIGGER);\n        cemetery.dig(address(t), 2);\n\n        vm.prank(HOLDER);\n        cemetery.itLives(address(t)); // expected: Saved. Actual on current code: TokenReadFailed(t, 0x70a08231)\n        assertEq(uint256(cemetery.graveOf(address(t)).state), uint256(MemecoinCemetery.State.Saved));\n    }\n\n    /// @dev Same holder cannot rise the token once sealed either, so the burial is permanent.\n    function test_reflectionHolderCanRise() public {\n        ReflectionToken t = new ReflectionToken(HOLDER, 10);\n        vm.prank(DIGGER);\n        cemetery.dig(address(t), 2);\n        vm.warp(block.timestamp + 72 hours);\n        cemetery.seal(address(t));\n\n        vm.prank(HOLDER);\n        cemetery.rise(address(t));\n        assertEq(uint256(cemetery.graveOf(address(t)).state), uint256(MemecoinCemetery.State.Risen));\n    }\n}","reproduction":"State: fresh MemecoinCemetery; ReflectionToken t (faithful SafeMoon balanceOf/tokenFromReflection/_getRate/_getCurrentSupply, decimals 9, totalSupply 1e24) with 10 excluded accounts and HOLDER owning 1% of supply (threshold is min(1e9, 1e24/1000) = 1e21, HOLDER balance 1e22). 1) DIGGER calls dig(t, 2): succeeds, state Wake. 2) HOLDER calls itLives(t) within 72h: expected state Saved and Resurrected event; actual revert TokenReadFailed(t, 0x70a08231) because balanceOf needs ~95k gas (>50k cap). 3) warp +72h, anyone calls seal(t): Buried. 4) HOLDER calls rise(t): expected Risen; actual revert TokenReadFailed(t, 0x70a08231). No call sequence can ever leave Buried for this token. Gas table from the proof test: excluded=0 12166, 2 28804, 4 45442, 6 62080, 8 78718, 10 95356, 12 111994. Run: forge test --offline --match-path test/scratch/ReflectionHolderGas.t.sol -vv","severity":"medium","snippet":"        uint256 balance = _requiredWord(token, abi.encodeWithSelector(BALANCE_OF, msg.sender), BALANCE_OF);\n        if (balance < threshold) revert NotHolder(msg.sender, threshold);","title":"Holder check forwards only 50,000 gas to balanceOf, so holders of reflection-style tokens can neither save nor rise; dig needs only the cheap totalSupply, making such burials permanent"}],"hash":"1e97eb305fc0ab326ceec0086fa7286cc77135aaf4b46c0b378462bc943091e9","nodeId":"0f84ba5b-15fc-4722-8e8e-e38eecbf6e1e","outcome":"completed","summary":"Review complete. No tracked files were changed; `.imd-findings.json` holds the report, and the proof lives under `test/scratch/`.\n\n## Result\n\n**One substantiated finding (medium), with a Foundry proof that fails on the current code and passes with the fix.**\n\n**`_requireHolder` forwards only 50,000 gas to `balanceOf`, so holders of reflection-style tokens can neither save nor rise — and since `dig` only needs the cheap `totalSupply`, such burials are permanent.** (`src/MemecoinCemetery.sol:279`, root at `TOKEN_GAS` line 59 / `_readWord` line 293)\n\n- The guides' lens: Execution Trace's *untrusted return values / query function differs from the operational one* and First Principles' *assumption chain*: `dig` validates the token via `totalSupply()` (O(1) everywhere), but the defensive paths `itLives`/`rise` depend on `balanceOf()` succeeding under the same 50k cap.\n- Measured with a faithful copy of the SafeMoon `balanceOf → tokenFromReflection → _getRate → _getCurrentSupply` loop: 12.2k gas with no excluded accounts, +8.3k per excluded account, so the cap is exceeded at **5** excluded accounts (contract, burn, pair, owner, marketing is a typical list). Every `itLives`/`rise` then reverts `TokenReadFailed(token, 0x70a08231)` regardless of balance; `Buried` has no other exit.\n- The cap buys nothing on this path: these are STATICCALLs whose gas is paid by the holder who chose to call. Fix: a much larger cap (or `gasleft()`) for the three reads inside `_requireHolder`; the proof passes with a 1,000,000-gas holder cap (verified against a scratch copy).\n\n## Coverage (15 rows in the file)\n\n- `dig`, `seal`, `mourn`, `receive`, `fallback` — **holds**; `itLives`, `rise` — **finding 1**.\n- Invariants `graveCount == |Buried|` and sealed-record immutability — hold.\n- Periphery: `_readWord` return-size/scratch handling, `_symbol` canonical-ABI bounds, `_escapeXML` buffer sizing, `_shortAddress` nibble math — hold. `_date` fuzzed 256 runs against BokkyPooBah's independent algorithm for 1970–9999 — matched, so slither's divide-before-multiply leads are the algorithm's intended floor steps.\n- Static-analysis leads (locked-ether, timestamp, uninitialized local, unused state) — reproduced as non-defects.\n- Deliverable checks outside my area: `docs/abi` equals the compiled ABI; runtime keccak `0x9056…80ed` and sizes match `build.json`; Deploy script guards chain 4663.\n\n**Not reached:** nothing within the assigned area; I did not independently re-verify the README prose or the model/invariant test harnesses beyond running them (all 43 existing tests pass).","treeHash":null,"usage":{"cachedInputTokens":1148774,"inputTokens":34,"model":"claude-fable-5-1","outputTokens":29790,"runtime":"claude","turns":18,"wallClockMs":402031}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"5fd2de06561c50a4","findings":[{"citation":"resolved","description":"_requireHolder reads balanceOf(msg.sender) through _readWord, which forwards exactly TOKEN_GAS = 50_000 (line 59, used at line 293: `ok := staticcall(TOKEN_GAS, token, add(data, 32), mload(data), 0, 32)`), and _requiredWord turns an out-of-gas or malformed result into TokenReadFailed. dig() only needs totalSupply(), which is one SLOAD on essentially every token, but the two defensive paths itLives() and rise() need balanceOf(). On SafeMoon-style reflection tokens (a large share of memecoins) balanceOf divides by _getRate(), which loops over every reward-excluded account at roughly 8.3k gas per entry; measured cold cost is 45,442 gas at 4 excluded accounts and 62,080 at 6, so with six or more excluded accounts (pair, dead address, token contract, marketing, locker, router is a common set) the read runs out of gas and every holder is rejected regardless of balance. The result is asymmetric: anyone can dig such a live token for one transaction, no holder can object, seal() buries it after 72 hours, and because Buried exits only through rise() the burial is permanent. This breaks the brief's central guarantee that any real holder can stop a burial and that a buried token can come back. The cap gives no safety benefit on these paths: the reads are STATICCALLs paid for by the holder who chose to call, and a hostile token can only waste that caller's own gas; the 32-byte return-size check already bounds memory. The README's note that such tokens 'may be unable to be nominated or defended' does not match the behaviour: nomination succeeds, only defence fails. Reported by audit_flow (medium), audit_math (low) and audit_economics (medium); merged into one finding. Minimal fix that preserves the design: forward a much larger cap (or gasleft()) for the totalSupply/decimals/balanceOf reads inside _requireHolder only, keeping 50,000 for dig()'s totalSupply read and for _symbol(); the attached proof passes on a copy with TOKEN_GAS raised to 500_000 for those reads.","line":279,"path":"src/MemecoinCemetery.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {MemecoinCemetery} from \"src/MemecoinCemetery.sol\";\n\n/// @dev SafeMoon-style reflection token. balanceOf() divides by _getRate(), which loops over every\n///      reward-excluded account (three cold SLOADs each). totalSupply() is one SLOAD, so dig() is cheap\n///      while balanceOf() with 8 excluded accounts needs ~81k gas, above the cemetery's 50,000 cap.\ncontract ReflectionToken {\n    string public constant symbol = \"RFI\";\n    uint8 public constant decimals = 9;\n    uint256 private constant MAX = ~uint256(0);\n    uint256 private immutable _tTotal;\n    uint256 private _rTotal;\n    mapping(address => uint256) private _rOwned;\n    mapping(address => uint256) private _tOwned;\n    mapping(address => bool) private _isExcluded;\n    address[] private _excluded;\n\n    constructor(uint256 tTotal, uint256 excludedCount) {\n        _tTotal = tTotal;\n        _rTotal = MAX - (MAX % tTotal);\n        _rOwned[msg.sender] = _rTotal;\n        for (uint256 i; i < excludedCount; ++i) {\n            address a = address(uint160(0xE0 + i));\n            _isExcluded[a] = true;\n            _excluded.push(a);\n            _tOwned[a] = 1;\n            _rOwned[a] = 1;\n        }\n    }\n\n    function totalSupply() external view returns (uint256) {\n        return _tTotal;\n    }\n\n    function transfer(address to, uint256 tAmount) external returns (bool) {\n        uint256 rate = _getRate();\n        _rOwned[msg.sender] -= tAmount * rate;\n        _rOwned[to] += tAmount * rate;\n        return true;\n    }\n\n    function balanceOf(address account) public view returns (uint256) {\n        if (_isExcluded[account]) return _tOwned[account];\n        return _rOwned[account] / _getRate();\n    }\n\n    function _getRate() private view returns (uint256) {\n        (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();\n        return rSupply / tSupply;\n    }\n\n    function _getCurrentSupply() private view returns (uint256, uint256) {\n        uint256 rSupply = _rTotal;\n        uint256 tSupply = _tTotal;\n        for (uint256 i = 0; i < _excluded.length; i++) {\n            if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _tTotal);\n            rSupply = rSupply - _rOwned[_excluded[i]];\n            tSupply = tSupply - _tOwned[_excluded[i]];\n        }\n        if (rSupply < _rTotal / _tTotal) return (_rTotal, _tTotal);\n        return (rSupply, tSupply);\n    }\n}\n\ncontract HolderGasCapTest is Test {\n    MemecoinCemetery internal cemetery;\n    ReflectionToken internal token;\n    address internal constant HOLDER = address(0xBEEF);\n    address internal constant DIGGER = address(0xD166E2);\n\n    function setUp() public {\n        vm.warp(1_735_689_600);\n        cemetery = new MemecoinCemetery();\n        // 1e15 whole tokens with 9 decimals, 8 reward-excluded accounts.\n        token = new ReflectionToken(1_000_000_000_000_000 * 1e9, 8);\n        // HOLDER owns 1% of supply: far above min(1 whole token, 0.1% of supply) = 1e9.\n        token.transfer(HOLDER, 10_000_000_000_000 * 1e9);\n    }\n\n    /// @dev Premise: a legitimate 1% holder whose balanceOf costs more than the 50k read cap.\n    function test_premiseHolderQualifiesButBalanceOfExceedsCap() public {\n        uint256 before = gasleft();\n        uint256 bal = token.balanceOf(HOLDER);\n        uint256 used = before - gasleft();\n        assertGe(bal, 1e9, \"HOLDER holds at least one whole token\");\n        assertGt(used, 50_000, \"balanceOf exceeds the 50,000-gas cap\");\n    }\n\n    /// @dev Fails on current code with TokenReadFailed(token, 0x70a08231); passes once _requireHolder\n    ///      forwards enough gas for the holder's own balanceOf read.\n    function test_realHolderCanSaveWake() public {\n        vm.prank(DIGGER);\n        cemetery.dig(address(token), 2);\n        assertEq(uint256(cemetery.graveOf(address(token)).state), uint256(MemecoinCemetery.State.Wake));\n\n        vm.prank(HOLDER);\n        cemetery.itLives(address(token));\n        assertEq(uint256(cemetery.graveOf(address(token)).state), uint256(MemecoinCemetery.State.Saved));\n    }\n\n    /// @dev Same holder cannot rise the token once sealed, so the burial is permanent on current code.\n    function test_realHolderCanRise() public {\n        vm.prank(DIGGER);\n        cemetery.dig(address(token), 2);\n        vm.warp(block.timestamp + 72 hours);\n        cemetery.seal(address(token));\n        assertEq(cemetery.graveCount(), 1);\n\n        vm.prank(HOLDER);\n        cemetery.rise(address(token));\n        assertEq(uint256(cemetery.graveOf(address(token)).state), uint256(MemecoinCemetery.State.Risen));\n        assertEq(cemetery.graveCount(), 0);\n    }\n}","reproduction":"State: fresh MemecoinCemetery; ReflectionToken T with totalSupply 1e24, decimals 9, 8 reward-excluded accounts, HOLDER holding 1% of supply (threshold is min(1e9, 1e21) = 1e9, HOLDER balance is 1e22; T.balanceOf(HOLDER) costs 80,976 gas cold). 1) DIGGER calls dig(T, 2): succeeds, state Wake. 2) HOLDER calls itLives(T) during the wake. Expected: state Saved, Resurrected(T, HOLDER). Actual: revert TokenReadFailed(T, 0x70a08231). 3) warp +72h, anyone calls seal(T): succeeds, state Buried, graveCount 1. 4) HOLDER calls rise(T). Expected: state Risen. Actual: revert TokenReadFailed(T, 0x70a08231); no call sequence can ever leave Buried for T. Run: forge test --offline --match-path test/scratch/HolderGasCap.t.sol -> test_realHolderCanSaveWake and test_realHolderCanRise fail with TokenReadFailed(..., 0x70a08231); test_premiseHolderQualifiesButBalanceOfExceedsCap passes. The same file passes against a copy of the contract with TOKEN_GAS = 500_000 (verified). Gas table measured with the audit_flow probe: excluded=0 12,166; 2 28,804; 4 45,442; 6 62,080; 8 78,718; 10 95,356.","severity":"medium","snippet":"        uint256 balance = _requiredWord(token, abi.encodeWithSelector(BALANCE_OF, msg.sender), BALANCE_OF);\n        if (balance < threshold) revert NotHolder(msg.sender, threshold);","title":"Holder reads reuse the 50,000-gas dig cap, so holders of reflection-style tokens can neither save (itLives) nor raise (rise) a token that anyone can dig and seal"},{"citation":"resolved","description":"The only token validation in dig() is code.length > 0 and a 32-byte non-zero totalSupply(). ERC-721 Enumerable collections expose totalSupply() and balanceOf(owner) (a count of NFTs) but no decimals(), so they pass dig(); _requireHolder then defaults decimals to 18 and computes the threshold as max(1, min(1e18, totalSupply/1000)) = totalSupply/1000 NFTs. For a 10,000-piece collection a holder needs 10 NFTs to call itLives or rise, so most real holders cannot contest the tombstone. This is exactly what the brief specifies for dig (code and totalSupply > 0) and for the holder rule, and the brief scopes the contract to ERC-20s, so it is a documented input-class limitation rather than a logic defect: no funds move and the only outcome is a joke headstone. Reported by audit_economics at low; recalibrated to info. If the author wants to close it, a gas-capped STATICCALL to supportsInterface(0x80ac58cd) returning true could revert InvalidToken, or the README's holder-rule section can state the limitation.","line":110,"path":"src/MemecoinCemetery.sol","reproduction":"Deploy N with totalSupply() = 10_000 and balanceOf(HOLDER) = 9, no decimals(). dig(N, 19): succeeds, state Wake. HOLDER calls itLives(N): reverts NotHolder(HOLDER, 10). Mint HOLDER one more (balance 10): itLives(N) succeeds. Verified in a scratch test (vm.expectRevert(abi.encodeWithSelector(NotHolder.selector, HOLDER, 10)) passes); after 72 hours seal(N) succeeds and the collection is Buried.","severity":"info","snippet":"        if (token.code.length == 0) revert InvalidToken(token);\n        uint256 supply = _requiredWord(token, abi.encodeWithSelector(TOTAL_SUPPLY), TOTAL_SUPPLY);\n        if (supply == 0) revert InvalidToken(token);","title":"dig() accepts any contract answering totalSupply(): an ERC-721 Enumerable collection can be dug, and its holders need totalSupply/1000 whole NFTs to object"},{"citation":"resolved","description":"_symbol accepts only canonical ABI string encodings (returndatasize >= 96, offset == 32). A token whose symbol() returns a raw bytes32 returns exactly 32 bytes, fails the `size < 96` check and the headstone shows 0x1234...abcd although the symbol is short printable ASCII. This matches the brief's fallback rule for a read that fails, never reverts and cannot affect state. Reported by audit_math at info; kept at info. Optional improvement: when returndatasize == 32, decode as bytes32 trimmed at the first zero byte before the printable-ASCII check.","line":313,"path":"src/MemecoinCemetery.sol","reproduction":"Token S: totalSupply() = 1e21, decimals() = 18, symbol() returns bytes32(\"MKR\"). dig(S, 1); headstone(S). Expected if bytes32 symbols were supported: the <text> at y=210 contains MKR. Actual (scratch test, vm.indexOf(svg, \"MKR\") == type(uint256).max): it contains the shortened lowercase address 0xf628...820a. No revert, no state effect.","severity":"info","snippet":"        if (!ok || size < 96 || size > result.length || offset != 32 || length == 0 || length > MAX_SYMBOL_BYTES) {\n            return _shortAddress(token);\n        }","title":"Tokens whose symbol() returns a raw bytes32 (MKR-style) always render the shortened address on the headstone"}],"hash":"3cf7fec6c9e5bcb61c6e28672149a79d91c8334cfb6f72f03435d10bf8127096","nodeId":"214cff1b-85f9-47aa-ba0d-93c1b727dae0","outcome":"completed","summary":"Taylor, the review is done. `.imd-findings.json` is written at the repository root with 3 findings and 10 coverage rows. No tracked file was changed; the scratch proof lives in the git-ignored `test/scratch/` directory.\n\n**Result: one real defect, two informational notes, otherwise the contract holds.**\n\n- **Medium, finding 1, merged from three specialists.** The holder check in `_requireHolder` forwards the same 50,000-gas cap used for dig's totalSupply read to `balanceOf`. On SafeMoon-style reflection tokens with six or more reward-excluded accounts, balanceOf exceeds that budget, so a legitimate holder is rejected with TokenReadFailed on both itLives and rise. Anyone can dig such a live token, nobody can object, seal buries it, and it can never rise. I reproduced it with a proof file that fails on the current code and passes against a copy with the holder-read cap raised to 500,000 gas. The audit_flow, audit_math and audit_economics reports described the same root cause and are merged at medium: no funds are lost, but the brief's central guarantee breaks for a common token class.\n- **Info, finding 2.** An ERC-721 Enumerable collection passes dig and its holders need totalSupply/1000 NFTs to object. Reproduced, but this is exactly what the brief specifies for dig and the holder rule, so I lowered it from low to info.\n- **Info, finding 3.** A bytes32 `symbol()` renders the shortened address instead of the symbol. Reproduced; it matches the brief's fallback rule.\n\n**What I checked beyond the specialists.** All 43 project tests pass offline. The committed ABI is byte-identical to the compiled ABI. The on-chain date routine matches Python's UTC calendar for 58 timestamps including leap-century edges. Every state transition, cooldown, counter and the two invariants trace correctly. The static-analysis lines are false positives: receive and fallback revert so no ether can be locked, the divide-before-multiply hits are intentional rounding, and TOKEN_GAS is used inside assembly.\n\n**Coverage.** dig, seal, mourn, receive and fallback hold. itLives and rise carry finding 1.","treeHash":null,"usage":{"cachedInputTokens":663443,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":19091,"runtime":"claude","turns":19,"wallClockMs":255137}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"cd8076510aad8b8e","findings":[{"citation":"resolved","description":"_requireHolder (src/MemecoinCemetery.sol:271-281) reads totalSupply() and balanceOf(msg.sender) through _readWord, which forwards exactly TOKEN_GAS = 50_000 (line 59, used at line 293). The brief asks for a gas-capped read of totalSupply() in dig() so a hostile token cannot burn the digger's gas, but the same cap is applied to the holder paths itLives() and rise(), where the caller is the holder who chose to pay for the call. The result is an asymmetry between attack and defence: dig() needs only a cheap totalSupply(), while defending needs balanceOf() to finish in 50k gas. Reflection/RFI tokens (SafeMoon and its thousands of forks, i.e. exactly the memecoins this contract targets) compute balanceOf() as _rOwned[account] / _getRate(), and _getRate() loops over every reward-excluded account with ~8.3k gas per iteration (measured: 1 excluded = 18.1k, 5 = 51.4k, 6 = 59.7k, 8 = 76.4k gas cold). With six or more excluded accounts (pair, dead address, the token itself, marketing, locker, router are typical) balanceOf() exceeds the budget, the STATICCALL runs out of gas, _requiredWord reverts with TokenReadFailed(token, 0x70a08231) and every holder, however large, is rejected. The token is sealed after 72 hours and cannot rise either, so a live token gets a permanent burial record that nobody can contest. This breaks the brief's central guarantee ('any real holder can stop a burial') and the README's promise that holders can always defend; the README only notes that such tokens 'may be unable to be nominated or defended', but here nomination succeeds while defence is impossible. Economic Security (dependency failure blocking the only defence) and Flow Gap seam execution x periphery x first principles. Who loses: holders of any reflection token with >=6 excluded accounts; cost to attacker: one dig() transaction. Proposed fix: in _requireHolder forward gasleft() (or a much larger cap such as 500_000) for the totalSupply/balanceOf/decimals reads; the 32-byte return-data check already bounds memory, and a gas bomb on these paths only costs the holder who called. Keep the 50k cap in dig() and _symbol().","line":279,"path":"src/MemecoinCemetery.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {MemecoinCemetery} from \"src/MemecoinCemetery.sol\";\n\n/// @dev Minimal reflection (\"RFI\"/SafeMoon-style) token. balanceOf() converts the reflected\n///      balance through _getRate(), which loops over every reward-excluded account exactly as\n///      the widely forked SafeMoon implementation does. totalSupply() is a single SLOAD.\n///      With 6+ excluded accounts (pair, dead address, contract, marketing, locker, router)\n///      balanceOf() needs more than the 50,000 gas the cemetery forwards.\ncontract ReflectionToken {\n    string public constant symbol = \"RFI\";\n    uint8 public constant decimals = 9;\n    uint256 private constant MAX = ~uint256(0);\n    uint256 private immutable _tTotal;\n    uint256 private _rTotal;\n    mapping(address => uint256) private _rOwned;\n    mapping(address => uint256) private _tOwned;\n    mapping(address => bool) private _isExcluded;\n    address[] private _excluded;\n\n    constructor(uint256 tTotal, uint256 excludedCount) {\n        _tTotal = tTotal;\n        _rTotal = MAX - (MAX % tTotal);\n        _rOwned[msg.sender] = _rTotal;\n        for (uint256 i; i < excludedCount; ++i) {\n            address a = address(uint160(0xE0 + i));\n            _isExcluded[a] = true;\n            _excluded.push(a);\n            _tOwned[a] = 1;\n            _rOwned[a] = 1;\n        }\n    }\n\n    function totalSupply() external view returns (uint256) {\n        return _tTotal;\n    }\n\n    function transfer(address to, uint256 tAmount) external returns (bool) {\n        uint256 rate = _getRate();\n        _rOwned[msg.sender] -= tAmount * rate;\n        _rOwned[to] += tAmount * rate;\n        return true;\n    }\n\n    function balanceOf(address account) public view returns (uint256) {\n        if (_isExcluded[account]) return _tOwned[account];\n        return _rOwned[account] / _getRate();\n    }\n\n    function _getRate() private view returns (uint256) {\n        (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();\n        return rSupply / tSupply;\n    }\n\n    function _getCurrentSupply() private view returns (uint256, uint256) {\n        uint256 rSupply = _rTotal;\n        uint256 tSupply = _tTotal;\n        for (uint256 i = 0; i < _excluded.length; i++) {\n            if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _tTotal);\n            rSupply = rSupply - _rOwned[_excluded[i]];\n            tSupply = tSupply - _tOwned[_excluded[i]];\n        }\n        if (rSupply < _rTotal / _tTotal) return (_rTotal, _tTotal);\n        return (rSupply, tSupply);\n    }\n}\n\ncontract HolderGasCapTest is Test {\n    MemecoinCemetery internal cemetery;\n    ReflectionToken internal token;\n    address internal constant HOLDER = address(0xBEEF);\n    address internal constant DIGGER = address(0xD166E2);\n\n    function setUp() public {\n        vm.warp(1_735_689_600);\n        cemetery = new MemecoinCemetery();\n        // 1e15 whole tokens with 9 decimals (SafeMoon's supply), 8 reward-excluded accounts.\n        token = new ReflectionToken(1_000_000_000_000_000 * 1e9, 8);\n        // HOLDER owns 1% of supply: far above min(1 whole token, 0.1% of supply).\n        token.transfer(HOLDER, 10_000_000_000_000 * 1e9);\n    }\n\n    /// @dev Documents the premise: an ordinary ERC-20 balanceOf that costs more than 50k gas.\n    function test_balanceOfCostsMoreThanTheReadCap() public {\n        uint256 before = gasleft();\n        uint256 bal = token.balanceOf(HOLDER);\n        uint256 used = before - gasleft();\n        emit log_named_uint(\"balanceOf gas (cold)\", used);\n        assertGt(bal, 1e9, \"HOLDER really holds more than a whole token\");\n        assertGt(used, 50_000, \"a reflection balanceOf with 8 excluded accounts exceeds 50k gas\");\n    }\n\n    /// @dev Fails on the current code with TokenReadFailed(token, balanceOf): a holder of 1% of\n    ///      supply cannot object to the wake, and after sealing cannot rise either. Passes once\n    ///      _requireHolder forwards enough gas for a legitimate balanceOf (the holder is the\n    ///      caller and pays for it, so the tight cap protects nobody on this path).\n    function test_realHolderCanSaveTokenWhoseBalanceOfIsExpensive() public {\n        vm.prank(DIGGER);\n        cemetery.dig(address(token), 2); // dig succeeds: totalSupply() is one SLOAD\n        assertEq(uint256(cemetery.graveOf(address(token)).state), uint256(MemecoinCemetery.State.Wake));\n\n        vm.prank(HOLDER);\n        cemetery.itLives(address(token));\n        assertEq(uint256(cemetery.graveOf(address(token)).state), uint256(MemecoinCemetery.State.Saved));\n    }\n}","reproduction":"1. Deploy a SafeMoon-style ReflectionToken with 8 reward-excluded accounts (see proof); totalSupply() is one SLOAD, balanceOf() costs ~81k gas. HOLDER receives 1% of supply (threshold is 1 whole token = 1e9 units).\n2. DIGGER calls dig(token, 2): succeeds, state = Wake.\n3. HOLDER calls itLives(token) during the wake. Expected: state = Saved, Resurrected emitted. Actual: revert TokenReadFailed(token, 0x70a08231) because the forwarded 50,000 gas is exhausted inside balanceOf().\n4. After 72 hours anyone calls seal(token): succeeds, state = Buried, burial #1 recorded forever.\n5. HOLDER calls rise(token): same TokenReadFailed revert. graveCount stays 1 and the token can never leave Buried.\nRun: forge test --offline --match-path test/scratch/HolderGasCap.t.sol  -> test_realHolderCanSaveTokenWhoseBalanceOfIsExpensive fails with TokenReadFailed(..., 0x70a08231). With TOKEN_GAS raised for the holder reads (verified on a patched copy with 500_000) the same test passes.","severity":"medium","snippet":"        uint256 balance = _requiredWord(token, abi.encodeWithSelector(BALANCE_OF, msg.sender), BALANCE_OF);","title":"Holder reads share the 50k-gas dig cap: tokens with an expensive balanceOf can be dug but no holder can ever save or raise them"},{"citation":"resolved","description":"The only token validation in dig() is code.length > 0 and a 32-byte, non-zero totalSupply() (lines 110-112). ERC-721 Enumerable collections expose totalSupply() and balanceOf(owner) (a count of NFTs) but no decimals(), so they pass dig(), and _requireHolder then defaults decimals to 18 and computes the threshold as max(1, min(1e18, totalSupply/1000)) = totalSupply/1000 NFTs. For a 10,000-piece collection a holder must own 10 NFTs to call itLives or rise; the typical holder with 1-9 pieces is rejected with NotHolder, so a live NFT collection can be given a permanent tombstone that almost none of its real holders can contest. The brief scopes the contract to ERC-20s and the holder rule to 'one whole token or 0.1% of supply', neither of which is meaningful for NFTs; the deviation is a Flow Gap seam (periphery x first principles). Low severity: no funds move and the digger gains only a joke headstone, but the 'any real holder can object' guarantee does not hold for this input class. Proposed fix: in dig() make a gas-capped STATICCALL to supportsInterface(0x80ac58cd) and revert InvalidToken when it returns true (a genuine ERC-20 either lacks ERC-165 or returns false), or document the limitation explicitly in the README's holder-rule section.","line":111,"path":"src/MemecoinCemetery.sol","reproduction":"1. Deploy a contract with totalSupply() = 10_000 and balanceOf(HOLDER) = 9, no decimals() (ERC-721 Enumerable surface). 2. dig(nft, 19): succeeds. 3. HOLDER (9 NFTs) calls itLives(nft): reverts NotHolder(HOLDER, 10) because threshold = min(10**18, 10000/1000) = 10. Expected per the brief: the contract is for ERC-20s and a real holder can stop a burial. 4. After 72 hours seal(nft) succeeds and the collection is Buried. Verified with a scratch test (test/scratch/Erc721Dig.t.sol, 1 passing test demonstrating the sequence).","severity":"low","snippet":"        uint256 supply = _requiredWord(token, abi.encodeWithSelector(TOTAL_SUPPLY), TOTAL_SUPPLY);","title":"dig() accepts any contract answering totalSupply(): an ERC-721 Enumerable collection can be buried while its holders need supply/1000 whole NFTs to object"}],"hash":"49b57fa615b05d6a0f6409e6a598efc83878a978ceb29b3f53055327a5cbaee0","nodeId":"75aec8ac-9dbe-4880-9785-6da1808c21ba","outcome":"completed","summary":"Review complete. The findings file is written with 2 findings and 12 coverage rows, and the proof test fails on the current code for the stated reason.\n\n**Outcome**\n\nThe contract's economics and invariants hold almost everywhere I checked. All 43 project tests pass, the committed ABI matches the compiled one, and the runtime bytecode hash matches the build record. The state machine, 72-hour wake, 7-day cooldown, grave count coupling, burial-record immutability, mourn-once-per-burial rule and the holder threshold formula all behave as the brief specifies. Two defects were substantiated, both in `.imd-findings.json`.\n\n**Findings**\n\n- **Medium, holder reads capped at 50k gas.** The read helper forwards exactly 50,000 gas for `balanceOf` and `totalSupply` inside `itLives` and `rise`, the same cap the brief asked for in `dig`. Reflection-style memecoins (SafeMoon and its forks) compute `balanceOf` by looping over reward-excluded accounts. With six or more such accounts the call needs more than 50k gas, so `dig` succeeds on a cheap `totalSupply` while every holder's objection reverts with a read failure. The token is sealed after 72 hours and can never rise. This breaks the brief's core guarantee that any real holder can stop a burial. A proof test under `test/scratch/HolderGasCap.t.sol` fails today and passes against a copy with a larger cap. Suggested fix: forward much more gas on the holder paths only, since the holder is the caller paying for it.\n- **Low, ERC-721 Enumerable collections pass `dig`.** The only token check is code plus a non-zero `totalSupply`. An NFT collection with 10,000 pieces is accepted, and the threshold becomes 10 whole NFTs, so typical holders cannot object. Suggested fix is a gas-capped ERC-165 probe for the ERC-721 interface, or an explicit README note.\n\n**Coverage**\n\nAll seven listed entry points have rows. `seal`, `mourn`, `receive` and `fallback` hold. `dig` carries finding 2. `itLives` and `rise` carry finding 1. Five additional rows record the invariants I verified. The static-analysis leads (divide-before-multiply in the calendar code, locked ether, timestamp comparisons) were checked and are not defects: the calendar arithmetic is the published algorithm and is tested at leap and century boundaries, and forced ETH has no victim and is documented.\n\n**Not covered**\n\nI did not evaluate Robinhood Chain sequencer timestamp drift against the 72-hour window, and I did not assess the explorer verification step, which needs a deployed address.","treeHash":null,"usage":{"cachedInputTokens":1387636,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":30306,"runtime":"claude","turns":25,"wallClockMs":503718}},{"artifacts":[],"attempt":1,"bundleHash":"8944751d9ea722fd2b883c6e31741e9d7b6f8e6c876e3893b2185254264702cb","device":"42423bf7250e09c0","findings":[],"hash":"4dfe52817c58e5c45f19020e02c23587994b31c877bff5d00119c4d8dbb2171a","nodeId":"028bd75e-8dac-470d-95fa-683dfae0cb7b","outcome":"completed","summary":"Updated only `launch.json`, correcting the gas-limit notes to match the accepted implementation.\n\nManifest and constructor checks passed. Offline build succeeded; all 50 tests passed on both runs, including a second fuzz seed with increased cases.","treeHash":"3396942c6ea4271dc085c24ba03cf9ca7b4e62b7","usage":{"cachedInputTokens":441216,"inputTokens":43705,"model":"gpt-6-astra","outputTokens":3511,"runtime":"codex","turns":4,"wallClockMs":158210}},{"artifacts":[],"attempt":1,"bundleHash":"24412fe0e57c0a8ffa972036aa180f5ea24efe65c0c42074fd7454a9d6aa6671","device":"868f4d64276861c0","findings":[],"hash":"5f6475964505ac563196a4741d086038ac8e5d6464a611f96c5be547031e4101","nodeId":"679b61b9-d18a-4d69-8272-418d3fc4b46f","outcome":"completed","summary":"Fixed holder reads to use available caller gas; nomination and symbol reads retain the 50,000-gas cap.\n\nAdded regression tests, documented the ERC-721 limitation, retained the documented bytes32 fallback, and answered all findings in `.imd-responses.json`. Updated bytecode verification artifacts.\n\nBuilds, reviewer proof, full suite, 1,024-run fuzz tests, invariants, and formatting checks pass.\n\nDeployment and explorer verification remain with the network deployer.","treeHash":"fe7986c7a047ad29a9b8a2a965ac752f9fdb1d30","usage":{"cachedInputTokens":1310592,"inputTokens":103446,"model":"gpt-6-astra","outputTokens":12768,"runtime":"codex","turns":6,"wallClockMs":427991}},{"artifacts":[],"attempt":1,"bundleHash":"f6534584f17b273c4938633094b5037de25fb6161ea0051275d7457fb2942239","device":"24282732aac890f7","findings":[],"hash":"8b066cb42f91630ec35611ecbbad6bc4f1fe602994da8d5783434805c83f320f","nodeId":"35d93ab6-9e65-421c-b25e-286eb7fe9b88","outcome":"completed","summary":"Added 10 tests under `test/`, covering hostile token responses, holder boundaries, failure atomicity, and an independent lifecycle/history invariant with 24,576 randomized calls.\n\nOffline build and full test suite passed: **43 tests, 0 failures, 0 skipped**.\n\nNo implementation defects reproduced. Only `test/` changed.","treeHash":"7355f5df9adcad22749386a106085e551ee6d531","usage":{"cachedInputTokens":726912,"inputTokens":57636,"model":"gpt-6-astra","outputTokens":12778,"runtime":"codex","turns":5,"wallClockMs":387359}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"824e6de6196c686f","findings":[],"hash":"99f240f726c4ae212481aa7e686de6ac9dcf1b8b2ee9d3e04bc546d37d72cc09","nodeId":"214cff1b-85f9-47aa-ba0d-93c1b727dae0","outcome":"completed","summary":"The review is complete and the findings file is written with an empty findings list.\n\n**Settlement of the prior round**\n\n- **Medium, holder reads capped at 50,000 gas: fixed.** The read helper now takes a gas limit. The nomination supply read and the headstone symbol read keep the 50,000 cap, while the holder check forwards the caller's remaining gas for totalSupply, decimals and balanceOf. I copied all three attached proofs under test/scratch and ran them against the revised contract. All eight proof tests pass, including the reflection-token save and rise cases that previously reverted with TokenReadFailed. The author also added a permanent regression file for expensive balance, supply and decimals reads on both defensive paths.\n- **Info, ERC-721 collections can be dug: closed.** The README now documents the input-class limitation with the 10-NFT example, and the contract behaviour stays as the brief specifies.\n- **Info, bytes32 symbols fall back to the address: dropped.** The author's dispute is correct. This is the documented fallback for a failed read, it never reverts, and the README states it.\n\n**Fresh pass on the changed code**\n\nI re-read the gas-forwarding change as new code. Forwarding gasleft() on STATICCALL paths only lets a hostile token waste the gas of the holder who chose to call. State cannot change inside a static call, and the return copy is still bounded to one word with an exact 32-byte size check. The static-analysis leads do not hold up. The locked-ether warnings are false positives because receive and fallback always revert. The divide-before-multiply lines are the standard Hinnant calendar arithmetic. The uninitialized local in the XML escaper is assigned on every path that reads it.\n\n**Artifact checks**\n\nThe committed ABI equals the offline build output. The creation and runtime bytecode keccak hashes and the source sha256 in the build record all match the compiled output. The manifest lists one contract with no constructor arguments and no owner. The full offline suite passes with 50 tests, including the invariant and model suites.\n\nThe scratch directory was removed, and the working tree holds only the required findings file.","treeHash":null,"usage":{"cachedInputTokens":512107,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":8591,"runtime":"claude","turns":16,"wallClockMs":187139}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"82692ab5f7f7e54e","findings":[],"hash":"acbbe0fa5cc7e62ea3f54dec879a3c80b02846568ec2afe7f4a7ae4d00e243b0","nodeId":"8c0fd947-e778-4b59-b38c-73f7a29a1bd4","outcome":"completed","summary":"## Scope\nFiles read: `src/MemecoinCemetery.sol` (403 lines, every line), `script/Deploy.s.sol`, `launch.json`, `README.md`, `test/MemecoinCemetery.t.sol` (mocks, boundary, threshold and transition tests), the test names of the adversarial, invariant and model suites, the protected floor test, and the Pashov Mindset plus the Access Control, Asymmetry, Trust Gap and Finding Validation guides. `forge build --offline` and `forge test --offline` pass with 43 tests. A scratch probe exercised a 24-decimal token, the deadline and cooldown boundaries, an escaped symbol and three ETH paths, then was deleted.\n\n**Severity counts:** 0 Critical · 0 High · 0 Medium · 0 Low\n\nNo defect survived the verification gate in the assigned area. `.imd-findings.json` holds an empty findings list and eleven coverage rows, one per entry point plus the two brief invariants, the trust surface and the artefacts.\n\n## Coverage\n- **Permission model.** There are no roles, setters, initializers, proxies or owner; the constructor hands nothing to the factory. Each storage variable has one writer per transition, so there is no weaker-guard parallel path. `receive` and `fallback` revert unconditionally and every application function is nonpayable.\n- **Asymmetry pairs.** `itLives` uses a strict less-than on the deadline and `seal` a greater-or-equal, so the two are complementary with no gap or overlap. `seal` increments both `burials` and `graveCount` and `rise` decrements only `graveCount`, which keeps the count equal to the Buried set because Buried has no other exit. `dig` resets the latest attempt's dates and mourners but never the lifetime counters. `mourn` mirrors its count into the numbered record and is blocked in Risen, freezing the record.\n- **Trust gap.** The only trusted input is token-supplied supply, decimals, balance and symbol. All four are read through a 50,000-gas static call with an exact 32-byte or bounded 128-byte size check, so a token cannot re-enter, bomb or corrupt state. I checked whether a caller could starve the `decimals` read of gas to lower the threshold for a token with more than 18 decimals. The fixed cap makes that impossible: if the call runs out of gas, the remaining sixty-fourth cannot finish the transaction.\n- **Holder rule.** The threshold is the maximum of one and the smaller of one whole token and a thousandth of supply, traced for 0, 6, 18, 24, 36 and over-36 decimals and for a supply under 1000.\n- **Artefacts.** The ABI file equals the compiled ABI, the manifest is schema-valid with empty constructor arguments, the deploy script rejects every chain but 4663 and reads no environment, and forge-std is vendored as ordinary tracked files.\n\n## Observations (non-blocking)\n- Anyone can re-dig a live token every ten days, so holders of a healthy token pay gas each cycle to object. The brief asks for exactly this.\n- A token can lie about balances or make its reads revert after being dug, which would stop its holders from saving it. The brief accepts token-supplied data and the README documents it.\n- Forced ETH through `SELFDESTRUCT` or block rewards is unrecoverable, which the static tools flag as locked ether. The brief forbids ETH and any withdraw path, and the README states it.","treeHash":null,"usage":{"cachedInputTokens":684126,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":18721,"runtime":"claude","turns":22,"wallClockMs":315884}},{"artifacts":[],"attempt":1,"bundleHash":"ffcc3e807b0c767c8161bbbb82455fd69cefc2cd937941fd0366ee5ac8e7ddf8","device":"04cf70660d4946e6","findings":[],"hash":"ae3be5fcd5f9dd78eaf805026e7e9671b95bdaf869c57b9b5a63c884312830f7","nodeId":"679b61b9-d18a-4d69-8272-418d3fc4b46f","outcome":"completed","summary":"Implemented all requested project files, including the contract, tests, deployment script, ABI, exact Foundry configuration, vendored forge-std, and documentation.\n\nPassed `forge build`, `forge test` (33 tests), `forge fmt --check`, and clean offline builds/tests. Exported verification input reproduces both creation and runtime bytecode.\n\nOn-chain deployment and explorer verification remain pending a confirmed deployment address. Verification artifacts and operator commands are included.","treeHash":"f8bdbbd891d009da563c2c2e0d899a834bd13576","usage":{"cachedInputTokens":1671680,"inputTokens":117358,"model":"gpt-6-astra","outputTokens":37301,"runtime":"codex","turns":7,"wallClockMs":1104206}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ca075d17c94a854b","findings":[{"citation":"resolved","description":"Boundary (external call, gas) x invariant (\"any real holder can stop a burial\"). _requireHolder reads balanceOf through _readWord, which forwards exactly TOKEN_GAS = 50,000 gas (line 293: `ok := staticcall(TOKEN_GAS, token, ...)`) and turns an out-of-gas result into TokenReadFailed via _requiredWord (line 279-280). The cap is fixed for every token. Reflection memecoins (SafeMoon family, a large share of the tokens this contract targets) compute balanceOf as _rOwned[a] / _getRate(), and _getRate() iterates the _excluded array reading three cold storage slots per entry. Measured cold cost in a Foundry probe with that exact shape: 3 excluded = 31,270 gas, 5 excluded = 45,844 gas (itLives succeeds), 6 excluded = 53,131 gas, 8 excluded = 67,705 gas (itLives and rise revert TokenReadFailed(token, 0x70a08231)). Six or more excluded accounts (burn address, pair, deployer, marketing, locker, router is a common set) is ordinary for these tokens. For such a token: dig succeeds (totalSupply is a plain sload), no holder can call itLives or rise however large their balance, seal buries it after 72 hours, and it can never be marked Risen. The headline guarantee in the brief that any real holder can stop a burial does not hold for this token class. The README does disclose that reads needing more gas may make a token undefendable, and the brief fixes a cap \"such as 50,000\", so this is reported as a design trade-off at low severity rather than a logic defect. The calls are STATICCALL so a larger cap cannot cause reentrancy or state change; raising TOKEN_GAS for balanceOf (e.g. 150,000-200,000) or making the forwarded gas gasleft()-bounded would cover these tokens at no safety cost. The same cap applies to totalSupply in dig; tokens whose totalSupply is computed could likewise be undiggable, which is harmless.","line":59,"path":"src/MemecoinCemetery.sol","reproduction":"Deploy a token T with ERC-20 totalSupply()=1e24, decimals()=18 and a reflection-style balanceOf that loops over 6 excluded accounts reading _excluded[i], _rOwned[_excluded[i]] and _tOwned[_excluded[i]] (cold SLOADs), then divides. Give holder H an effective balance of 1e22 (1% of supply; threshold is min(1e18, 1e21) = 1e18). 1) anyone: cemetery.dig(T, 2) -> succeeds, state Wake. 2) H: cemetery.itLives(T) -> EXPECTED: state Saved, Resurrected emitted. ACTUAL: revert TokenReadFailed(T, 0x70a08231) because the 50,000-gas staticcall runs out of gas (cold balanceOf costs 53,131 gas). 3) warp +72h; anyone: seal(T) -> Buried. 4) H: rise(T) -> ACTUAL: same TokenReadFailed revert; EXPECTED: Risen. With 5 excluded accounts (45,844 gas) both calls succeed, so the cut-off is between 5 and 6 excluded accounts for this layout. Scratch test used: a cemetery, the described mock, vm.cool(token) before each call to model a fresh transaction.","severity":"low","snippet":"    uint256 private constant TOKEN_GAS = 50_000;","title":"50,000-gas cap on balanceOf locks reflection-token holders out of itLives/rise, so a token with real holders is buried unopposed"},{"citation":"resolved","description":"Boundary on the symbol() return-data decoder. _symbol accepts only canonical ABI `string` encodings (size >= 96, offset == 32). A token whose symbol() returns a raw bytes32 (an older but still-seen pattern: MKR, SAI, some early memecoins) returns exactly 32 bytes, fails the `size < 96` check and the headstone shows `0x1234...abcd` even though the symbol is short printable ASCII. This matches the brief's fallback rule for a read that \"fails\", never reverts and cannot corrupt state, so it is informational. If desired, a 32-byte return could be decoded as bytes32 and trimmed at the first zero byte before applying the printable-ASCII check.","line":313,"path":"src/MemecoinCemetery.sol","reproduction":"Token S: totalSupply()=1e21, symbol() returns bytes32(\"MKR\") (returndata is exactly 32 bytes). dig(S, 1); headstone(S). EXPECTED (if bytes32 symbols were supported): the <text> at y=210 contains `MKR`. ACTUAL: it contains the shortened lowercase address of S (observed `0xf628...820a` in the probe). No revert, no state effect.","severity":"info","snippet":"        if (!ok || size < 96 || size > result.length || offset != 32 || length == 0 || length > MAX_SYMBOL_BYTES) {","title":"Tokens with bytes32 symbol() (MKR-style) always render the shortened address instead of their symbol"}],"hash":"bee189c92cd5ffa853e7cf34305dce3064ea9b50ff1f3337ec5bb06d207aa12c","nodeId":"cc32ed44-2366-4640-bc0d-91884ca807ea","outcome":"completed","summary":"The review is complete. The findings file is valid JSON, both snippets match the source lines, and the working tree is clean apart from the findings file (which is ignored by git).\n\n**Outcome.** The math in `src/MemecoinCemetery.sol` holds up. No critical, high or medium defects were found in the Math Precision, Boundary or Numerical Gap areas. The file `.imd-findings.json` carries two minor items and 13 coverage rows covering all 7 entry points plus the static-analysis leads and both stated invariants.\n\n**What I verified with concrete values**\n\n- Holder threshold `max(1, min(10**decimals, supply/1000))` behaves correctly at the 6-decimal boundary, the 1-base-unit floor for supply under 1000, decimals 36, and decimals 37 defaulting to 18.\n- The on-chain date algorithm matched an independent loop-based calendar across 2000 fuzz runs from 1970 through 9999, plus leap-year and 2038/2100 edges. Slither's divide-before-multiply lines there are the algorithm itself, not a bug.\n- Symbol decoding accepts a 64-byte symbol, rejects 65, rejects non-canonical sizes, and escapes all five XML metacharacters. The seal/itLives deadline comparisons are exact complements with no gap or overlap.\n- The full project suite passes, 43 tests including both invariants.\n\n**Findings reported**\n\n1. **Low.** The fixed 50,000-gas cap on `balanceOf` reads locks holders of reflection-style tokens out of `itLives` and `rise`. A SafeMoon-shaped mock with 6 excluded accounts costs about 53k gas cold, so both calls revert and the token is buried unopposed despite a holder owning 1% of supply. With 5 excluded accounts it works. The README discloses this trade-off and the brief names the cap, so this is a design decision to revisit rather than a logic defect. Since the calls are static, raising the cap carries no reentrancy cost.\n2. **Info.** Tokens returning a raw `bytes32` symbol (MKR-style) always render the shortened address on the headstone, which is consistent with the brief's fallback rule.\n\nNothing in my area was left unreached. The scratch tests were removed after use, as nothing under `test/scratch/` is kept.","treeHash":null,"usage":{"cachedInputTokens":1318244,"inputTokens":642,"model":"claude-fable-5-1","outputTokens":23287,"runtime":"claude","turns":21,"wallClockMs":429180}},{"artifacts":[],"attempt":1,"bundleHash":"4887581af834934d2e480d4a98b57e8a6be8951b9eff816af24eaf048886d50d","device":"d328e90a3d7134f5","findings":[],"hash":"fcb0f0dfd3df845b1f2b18f42d5cc46ce3743b663356bc4306dd8a4873e25784","nodeId":"028bd75e-8dac-470d-95fa-683dfae0cb7b","outcome":"completed","summary":"Created `launch.json` with kind `evm_contracts`, one `MemecoinCemetery` entry, empty constructor arguments, and implementation notes.\n\nValidation passed: schema and ABI matching, offline build, formatting, and all 43 tests on both runs, including a second fuzz seed.\n\nOnly `launch.json` is changed for submission.","treeHash":"87f3a9628bb30cf8dfbb66ca809d2dd398f0468c","usage":{"cachedInputTokens":270336,"inputTokens":32087,"model":"gpt-6-astra","outputTokens":3345,"runtime":"codex","turns":3,"wallClockMs":119878}}],"verification":[{"checks":[{"durationMs":2867,"exitCode":0,"name":"build","output":"Compiling 27 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.73s\nCompiler run successful!\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:109:13\n    │\n109 │         if (block.timestamp < _cooldownEnds[token]) revert CooldownActive(_cooldownEnds[token]);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:121:9\n    │\n121 │         emit WakeOpened(token, msg.sender, epitaphId, g.wakeEndsAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:128:13\n    │\n128 │         if (block.timestamp >= g.wakeEndsAt) revert WakeClosed(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:133:9\n    │\n133 │         emit Resurrected(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:140:13\n    │\n140 │         if (block.timestamp < g.wakeEndsAt) revert WakeStillOpen(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:170:9\n    │\n170 │         emit Rose(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:325:26\n    │\n325 │         if (size != 64 + ((length + 31) / 32) * 32) return _shortAddress(token);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:365:25\n    │\n365 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                         ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:365:69\n    │\n365 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                                                                     ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes1' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:385:36\n    │\n385 │         uint256 year = yearOfEra + era * 400;\n    │                                    ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:386:41\n    │\n386 │         uint256 dayOfYear = dayOfEra - (365 * yearOfEra + yearOfEra / 4 - yearOfEra / 100);\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:388:36\n    │\n388 │         uint256 day = dayOfYear - (153 * marchMonth + 2) / 5 + 1;\n    │                                    ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:402:15\n    │\n402 │             ++length;\n    │               ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:407:39\n    │\n407 │             result[--length] = bytes1(uint8(48 + value % 10));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:752:17\n    │\n752 │         vm.warp(block.timestamp + 72 hours);\n    │         ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:305:27\n    │\n305 │         uint256 risenAt = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n322 │         vm.warp(ready - 1);\n    │         ────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:724:21\n    │\n724 │             vm.warp(block.timestamp + 72 hours);\n    │             ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":12803,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/MemecoinCemetery.t.sol:DeployTest\n[PASS] testFuzz_deployRejectsEveryOtherChain(uint64) (runs: 256, μ: 2648876, ~: 2648876)\n[PASS] test_deployOn4663WithNoArguments() (gas: 5426455)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 20.97ms (21.17ms CPU time)\n\nRan 6 tests for test/MemecoinCemetery.holder-gas.t.sol:HolderReadGasRegressionTest\n[PASS] testFuzz_expensiveSupplyAndDecimalsCanDefend(bool,bool) (runs: 256, μ: 957387, ~: 837000)\n[PASS] test_expensiveBalanceCanRiseAndPreservesBurial() (gas: 1152907)\n[PASS] test_expensiveBalanceCanSaveWake() (gas: 843214)\n[PASS] test_expensiveBalanceStillRejectsBelowThreshold() (gas: 1648048)\n[PASS] test_nominationSupplyStillHasFixedCap() (gas: 142414)\n[PASS] test_symbolStillHasFixedCapAndFallsBack() (gas: 276059)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 49.89ms (51.10ms CPU time)\n\nRan 8 tests for test/MemecoinCemetery.adversarial.t.sol:MemecoinCemeteryAdversarialTest\n[PASS] testFuzz_malformedMandatoryWordsRevertWithoutChangingHistory(uint8,uint8,bool) (runs: 1000, μ: 479986, ~: 388858)\n[PASS] testFuzz_thresholdCrossoverAndFloor(uint8,uint16,bool) (runs: 1000, μ: 790221, ~: 688199)\n[PASS] test_codeDisappearingAfterDigCannotBlockSealingOrMourning() (gas: 546419)\n[PASS] test_currentDecimalsAndExactCallerBalanceDetermineHolderStatus() (gas: 786218)\n[PASS] test_holderReadGasExhaustionIsAtomicAndDecimalsDefaultTo18() (gas: 60702917)\n[PASS] test_nominationAndSymbolGasExhaustionRemainBounded() (gas: 543832)\n[PASS] test_returnDataBombsHaveBoundedCostAndCannotCorruptState() (gas: 889378)\n[PASS] test_sealAndMournRemainAvailableWhenEveryTokenReadFails() (gas: 10818995)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 50.08ms (99.64ms CPU time)\n\nRan 30 tests for test/MemecoinCemetery.t.sol:MemecoinCemeteryTest\n[PASS] testFuzz_holderThreshold(uint8,uint256,bool) (runs: 256, μ: 797094, ~: 879863)\nLogs:\n  Bound result 2911959521108029860509688657405459\n\n[PASS] testFuzz_sealedRecordsNeverChange(address,uint8,uint32,uint8) (runs: 256, μ: 2012731, ~: 1779845)\nLogs:\n  Bound result 7\n  Bound result 3\n\n[PASS] test_all24EpitaphsAreExact() (gas: 322979)\n[PASS] test_allInvalidStateTransitions() (gas: 1051543)\n[PASS] test_calendarUTCLeapCenturiesEpochAndYearBoundary() (gas: 4026918)\n[PASS] test_decimalsRevertDefaultsTo18() (gas: 347227)\n[PASS] test_digOpensWakeAndEmits() (gas: 151790)\n[PASS] test_headstoneEpitaphDatesMournersAndRisenBanner() (gas: 7291353)\n[PASS] test_headstoneEscapesAllXMLMetacharacters() (gas: 4211632)\n[PASS] test_headstoneMissingAndNonPrintableSymbolUseAddress() (gas: 4468518)\n[PASS] test_headstoneSymbolBoundsAndMalformedABINeverRevert() (gas: 4846302)\n[PASS] test_holderReadFailuresDoNotChangeState() (gas: 21184472)\n[PASS] test_holderThresholdFloorAndDecimalExtremes() (gas: 7606522)\n[PASS] test_holderThresholdWholeTokenAndFraction18And6Decimals() (gas: 6274042)\n[PASS] test_holderVetoAtLastSecondAndSavedCooldown() (gas: 433221)\n[PASS] test_initialStateAndUnknownQueries() (gas: 105322)\n[PASS] test_invalidEpitaph24And255() (gas: 47223)\n[PASS] test_lateSealUsesActualSealTime() (gas: 351888)\n[PASS] test_missingMalformedAndGasBombDecimalsDefaultTo18() (gas: 24760437)\n[PASS] test_mournOncePerAddressAndAgainAfterReburial() (gas: 1133001)\n[PASS] test_nonholderCannotVetoOrRise() (gas: 443714)\n[PASS] test_recentBurialsNewestFirstCapAndDuplicates() (gas: 16579185)\n[PASS] test_rejectsEOAZeroAddressAndZeroSupply() (gas: 125234)\n[PASS] test_rejectsETHReceiveFallbackAndNonpayableFunctions() (gas: 1643606)\n[PASS] test_rejectsRevertingMalformedAndGasBombSupplies() (gas: 1069868)\n[PASS] test_risePreservesRecordAndHasCooldown() (gas: 844877)\n[PASS] test_runtimeFitsAndHasNoForbiddenOpcodes() (gas: 3798724)\n[PASS] test_staticTokenReadCannotReenterMourn() (gas: 1056703)\n[PASS] test_thresholdUsesCurrentSupplyAndBalancesAndBorrowedBalanceCounts() (gas: 876396)\n[PASS] test_wakeBoundariesAndPermissionlessSeal() (gas: 486720)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 69.20ms (207.91ms CPU time)\n\nRan 1 test for test/MemecoinCemetery.invariant.t.sol:MemecoinCemeteryInvariantTest\n[PASS]\nMemecoinCemeteryInvariantTest invariants:\n[PASS] invariant_graveCountEqualsNumberOfBuriedTokens\n[PASS] invariant_sealedBurialIdentitiesNeverChange\n MemecoinCemeteryInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-----------------+----------+-------+---------+----------╮\n| Contract        | Selector | Calls | Reverts | Discards |\n+=========================================================+\n| CemeteryHandler | advance  | 1368  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | dig      | 1390  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | mourn    | 1326  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | rise     | 1391  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | save     | 1326  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | seal     | 1391  | 0       | 0        |\n╰-----------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.98s (1.98s CPU time)\n\nRan 3 tests for test/MemecoinCemetery.model.t.sol:MemecoinCemeteryModelTest\n[PASS] invariant_callsAndEntireHistoryMatchIndependentModel() (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------+-------+---------+----------╮\n| Contract             | Selector    | Calls | Reverts | Discards |\n+=================================================================+\n| CemeteryModelHandler | act         | 8125  | 0       | 0        |\n|----------------------+-------------+-------+---------+----------|\n| CemeteryModelHandler | advance     | 8194  | 0       | 0        |\n|----------------------+-------------+-------+---------+----------|\n| CemeteryModelHandler | changeToken | 8257  | 0       | 0        |\n╰----------------------+-------------+-------+---------+----------╯\n\n[PASS] test_modelExercisesEveryActionAndRejectedAction() (gas: 2015272)\n[PASS] test_modelTracksMourningAcrossRepeatedBurialsAndSaves() (gas: 19384942)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 12.70s (12.72s CPU time)\n\nRan 6 test suites in 12.71s (14.87s CPU time): 50 tests passed, 0 failed, 0 skipped (50 total tests)\n","passed":true},{"durationMs":38,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"MemecoinCemetery.dig(address,uint8)\",\"MemecoinCemetery.fallback()\",\"MemecoinCemetery.itLives(address)\",\"MemecoinCemetery.mourn(address)\",\"MemecoinCemetery.receive()\",\"MemecoinCemetery.rise(address)\",\"MemecoinCemetery.seal(address)\"],\"files\":{\".gitignore\":4,\"LICENSE\":21,\"README.md\":242,\"docs/abi/MemecoinCemetery.json\":572,\"docs/deployment/MemecoinCemetery.standard-input.json\":41,\"docs/deployment/build.json\":20,\"foundry.toml\":20,\"remappings.txt\":1,\"script/Deploy.s.sol\":19,\"src/MemecoinCemetery.sol\":412,\"test/MemecoinCemetery.adversarial.t.sol\":232,\"test/MemecoinCemetery.holder-gas.t.sol\":159,\"test/MemecoinCemetery.invariant.t.sol\":131,\"test/MemecoinCemetery.model.t.sol\":259,\"test/MemecoinCemetery.t.sol\":867},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"184400a5966a4f87773de218d671ecdaf539118f1f1a2794fd0543fa7207ad12","verifiedTreeHash":"035316c0b12b5352882d0c604824989d543b450c","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":3186,"exitCode":0,"name":"build","output":"Compiling 27 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.04s\nCompiler run successful!\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:109:13\n    │\n109 │         if (block.timestamp < _cooldownEnds[token]) revert CooldownActive(_cooldownEnds[token]);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:121:9\n    │\n121 │         emit WakeOpened(token, msg.sender, epitaphId, g.wakeEndsAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:128:13\n    │\n128 │         if (block.timestamp >= g.wakeEndsAt) revert WakeClosed(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:133:9\n    │\n133 │         emit Resurrected(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:140:13\n    │\n140 │         if (block.timestamp < g.wakeEndsAt) revert WakeStillOpen(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:170:9\n    │\n170 │         emit Rose(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:325:26\n    │\n325 │         if (size != 64 + ((length + 31) / 32) * 32) return _shortAddress(token);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:365:25\n    │\n365 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                         ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:365:69\n    │\n365 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                                                                     ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes1' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:385:36\n    │\n385 │         uint256 year = yearOfEra + era * 400;\n    │                                    ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:386:41\n    │\n386 │         uint256 dayOfYear = dayOfEra - (365 * yearOfEra + yearOfEra / 4 - yearOfEra / 100);\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:388:36\n    │\n388 │         uint256 day = dayOfYear - (153 * marchMonth + 2) / 5 + 1;\n    │                                    ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:402:15\n    │\n402 │             ++length;\n    │               ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:407:39\n    │\n407 │             result[--length] = bytes1(uint8(48 + value % 10));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:752:17\n    │\n752 │         vm.warp(block.timestamp + 72 hours);\n    │         ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:305:27\n    │\n305 │         uint256 risenAt = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n322 │         vm.warp(ready - 1);\n    │         ────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:724:21\n    │\n724 │             vm.warp(block.timestamp + 72 hours);\n    │             ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":13180,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/MemecoinCemetery.t.sol:DeployTest\n[PASS] testFuzz_deployRejectsEveryOtherChain(uint64) (runs: 256, μ: 2648876, ~: 2648876)\n[PASS] test_deployOn4663WithNoArguments() (gas: 5426455)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 39.42ms (39.63ms CPU time)\n\nRan 6 tests for test/MemecoinCemetery.holder-gas.t.sol:HolderReadGasRegressionTest\n[PASS] testFuzz_expensiveSupplyAndDecimalsCanDefend(bool,bool) (runs: 256, μ: 968763, ~: 1079671)\n[PASS] test_expensiveBalanceCanRiseAndPreservesBurial() (gas: 1152907)\n[PASS] test_expensiveBalanceCanSaveWake() (gas: 843214)\n[PASS] test_expensiveBalanceStillRejectsBelowThreshold() (gas: 1648048)\n[PASS] test_nominationSupplyStillHasFixedCap() (gas: 142414)\n[PASS] test_symbolStillHasFixedCapAndFallsBack() (gas: 276059)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 43.92ms (46.40ms CPU time)\n\nRan 8 tests for test/MemecoinCemetery.adversarial.t.sol:MemecoinCemeteryAdversarialTest\n[PASS] testFuzz_malformedMandatoryWordsRevertWithoutChangingHistory(uint8,uint8,bool) (runs: 1000, μ: 485165, ~: 397548)\n[PASS] testFuzz_thresholdCrossoverAndFloor(uint8,uint16,bool) (runs: 1000, μ: 796043, ~: 876668)\n[PASS] test_codeDisappearingAfterDigCannotBlockSealingOrMourning() (gas: 546419)\n[PASS] test_currentDecimalsAndExactCallerBalanceDetermineHolderStatus() (gas: 786218)\n[PASS] test_holderReadGasExhaustionIsAtomicAndDecimalsDefaultTo18() (gas: 60702917)\n[PASS] test_nominationAndSymbolGasExhaustionRemainBounded() (gas: 543832)\n[PASS] test_returnDataBombsHaveBoundedCostAndCannotCorruptState() (gas: 889378)\n[PASS] test_sealAndMournRemainAvailableWhenEveryTokenReadFails() (gas: 10818995)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 46.34ms (96.11ms CPU time)\n\nRan 30 tests for test/MemecoinCemetery.t.sol:MemecoinCemeteryTest\n[PASS] testFuzz_holderThreshold(uint8,uint256,bool) (runs: 256, μ: 806901, ~: 879995)\nLogs:\n  Bound result 19252\n\n[PASS] testFuzz_sealedRecordsNeverChange(address,uint8,uint32,uint8) (runs: 256, μ: 2030605, ~: 1779173)\nLogs:\n  Bound result 14\n  Bound result 3\n\n[PASS] test_all24EpitaphsAreExact() (gas: 322979)\n[PASS] test_allInvalidStateTransitions() (gas: 1051543)\n[PASS] test_calendarUTCLeapCenturiesEpochAndYearBoundary() (gas: 4026918)\n[PASS] test_decimalsRevertDefaultsTo18() (gas: 347227)\n[PASS] test_digOpensWakeAndEmits() (gas: 151790)\n[PASS] test_headstoneEpitaphDatesMournersAndRisenBanner() (gas: 7291353)\n[PASS] test_headstoneEscapesAllXMLMetacharacters() (gas: 4211632)\n[PASS] test_headstoneMissingAndNonPrintableSymbolUseAddress() (gas: 4468518)\n[PASS] test_headstoneSymbolBoundsAndMalformedABINeverRevert() (gas: 4846302)\n[PASS] test_holderReadFailuresDoNotChangeState() (gas: 21184472)\n[PASS] test_holderThresholdFloorAndDecimalExtremes() (gas: 7606522)\n[PASS] test_holderThresholdWholeTokenAndFraction18And6Decimals() (gas: 6274042)\n[PASS] test_holderVetoAtLastSecondAndSavedCooldown() (gas: 433221)\n[PASS] test_initialStateAndUnknownQueries() (gas: 105322)\n[PASS] test_invalidEpitaph24And255() (gas: 47223)\n[PASS] test_lateSealUsesActualSealTime() (gas: 351888)\n[PASS] test_missingMalformedAndGasBombDecimalsDefaultTo18() (gas: 24760437)\n[PASS] test_mournOncePerAddressAndAgainAfterReburial() (gas: 1133001)\n[PASS] test_nonholderCannotVetoOrRise() (gas: 443714)\n[PASS] test_recentBurialsNewestFirstCapAndDuplicates() (gas: 16579185)\n[PASS] test_rejectsEOAZeroAddressAndZeroSupply() (gas: 125234)\n[PASS] test_rejectsETHReceiveFallbackAndNonpayableFunctions() (gas: 1643606)\n[PASS] test_rejectsRevertingMalformedAndGasBombSupplies() (gas: 1069868)\n[PASS] test_risePreservesRecordAndHasCooldown() (gas: 844877)\n[PASS] test_runtimeFitsAndHasNoForbiddenOpcodes() (gas: 3798724)\n[PASS] test_staticTokenReadCannotReenterMourn() (gas: 1056703)\n[PASS] test_thresholdUsesCurrentSupplyAndBalancesAndBorrowedBalanceCounts() (gas: 876396)\n[PASS] test_wakeBoundariesAndPermissionlessSeal() (gas: 486720)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 59.90ms (176.83ms CPU time)\n\nRan 1 test for test/MemecoinCemetery.invariant.t.sol:MemecoinCemeteryInvariantTest\n[PASS]\nMemecoinCemeteryInvariantTest invariants:\n[PASS] invariant_graveCountEqualsNumberOfBuriedTokens\n[PASS] invariant_sealedBurialIdentitiesNeverChange\n MemecoinCemeteryInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-----------------+----------+-------+---------+----------╮\n| Contract        | Selector | Calls | Reverts | Discards |\n+=========================================================+\n| CemeteryHandler | advance  | 1329  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | dig      | 1404  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | mourn    | 1367  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | rise     | 1365  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | save     | 1325  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | seal     | 1402  | 0       | 0        |\n╰-----------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.09s (2.09s CPU time)\n\nRan 3 tests for test/MemecoinCemetery.model.t.sol:MemecoinCemeteryModelTest\n[PASS] invariant_callsAndEntireHistoryMatchIndependentModel() (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------+-------+---------+----------╮\n| Contract             | Selector    | Calls | Reverts | Discards |\n+=================================================================+\n| CemeteryModelHandler | act         | 8170  | 0       | 0        |\n|----------------------+-------------+-------+---------+----------|\n| CemeteryModelHandler | advance     | 8293  | 0       | 0        |\n|----------------------+-------------+-------+---------+----------|\n| CemeteryModelHandler | changeToken | 8113  | 0       | 0        |\n╰----------------------+-------------+-------+---------+----------╯\n\n[PASS] test_modelExercisesEveryActionAndRejectedAction() (gas: 2015272)\n[PASS] test_modelTracksMourningAcrossRepeatedBurialsAndSaves() (gas: 19384942)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 13.08s (13.09s CPU time)\n\nRan 6 test suites in 13.08s (15.36s CPU time): 50 tests passed, 0 failed, 0 skipped (50 total tests)\n","passed":true},{"durationMs":39,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"MemecoinCemetery.dig(address,uint8)\",\"MemecoinCemetery.fallback()\",\"MemecoinCemetery.itLives(address)\",\"MemecoinCemetery.mourn(address)\",\"MemecoinCemetery.receive()\",\"MemecoinCemetery.rise(address)\",\"MemecoinCemetery.seal(address)\"],\"files\":{\".gitignore\":4,\"LICENSE\":21,\"README.md\":242,\"docs/abi/MemecoinCemetery.json\":572,\"docs/deployment/MemecoinCemetery.standard-input.json\":41,\"docs/deployment/build.json\":20,\"foundry.toml\":20,\"launch.json\":10,\"remappings.txt\":1,\"script/Deploy.s.sol\":19,\"src/MemecoinCemetery.sol\":412,\"test/MemecoinCemetery.adversarial.t.sol\":232,\"test/MemecoinCemetery.holder-gas.t.sol\":159,\"test/MemecoinCemetery.invariant.t.sol\":131,\"test/MemecoinCemetery.model.t.sol\":259,\"test/MemecoinCemetery.t.sol\":867},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"4dfe52817c58e5c45f19020e02c23587994b31c877bff5d00119c4d8dbb2171a","verifiedTreeHash":"3396942c6ea4271dc085c24ba03cf9ca7b4e62b7","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":2118,"exitCode":0,"name":"build","output":"Compiling 25 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.00s\nCompiler run successful!\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:109:13\n    │\n109 │         if (block.timestamp < _cooldownEnds[token]) revert CooldownActive(_cooldownEnds[token]);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:121:9\n    │\n121 │         emit WakeOpened(token, msg.sender, epitaphId, g.wakeEndsAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:128:13\n    │\n128 │         if (block.timestamp >= g.wakeEndsAt) revert WakeClosed(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:133:9\n    │\n133 │         emit Resurrected(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:140:13\n    │\n140 │         if (block.timestamp < g.wakeEndsAt) revert WakeStillOpen(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:170:9\n    │\n170 │         emit Rose(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:325:26\n    │\n325 │         if (size != 64 + ((length + 31) / 32) * 32) return _shortAddress(token);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:365:25\n    │\n365 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                         ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:365:69\n    │\n365 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                                                                     ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes1' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:385:36\n    │\n385 │         uint256 year = yearOfEra + era * 400;\n    │                                    ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:386:41\n    │\n386 │         uint256 dayOfYear = dayOfEra - (365 * yearOfEra + yearOfEra / 4 - yearOfEra / 100);\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:388:36\n    │\n388 │         uint256 day = dayOfYear - (153 * marchMonth + 2) / 5 + 1;\n    │                                    ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:402:15\n    │\n402 │             ++length;\n    │               ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:407:39\n    │\n407 │             result[--length] = bytes1(uint8(48 + value % 10));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:752:17\n    │\n752 │         vm.warp(block.timestamp + 72 hours);\n    │         ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:305:27\n    │\n305 │         uint256 risenAt = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n322 │         vm.warp(ready - 1);\n    │         ────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:724:21\n    │\n724 │             vm.warp(block.timestamp + 72 hours);\n    │             ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":2150,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/MemecoinCemetery.t.sol:DeployTest\n[PASS] testFuzz_deployRejectsEveryOtherChain(uint64) (runs: 256, μ: 2648876, ~: 2648876)\n[PASS] test_deployOn4663WithNoArguments() (gas: 5426455)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.67ms (8.93ms CPU time)\n\nRan 6 tests for test/MemecoinCemetery.holder-gas.t.sol:HolderReadGasRegressionTest\n[PASS] testFuzz_expensiveSupplyAndDecimalsCanDefend(bool,bool) (runs: 256, μ: 944116, ~: 837000)\n[PASS] test_expensiveBalanceCanRiseAndPreservesBurial() (gas: 1152907)\n[PASS] test_expensiveBalanceCanSaveWake() (gas: 843214)\n[PASS] test_expensiveBalanceStillRejectsBelowThreshold() (gas: 1648048)\n[PASS] test_nominationSupplyStillHasFixedCap() (gas: 142414)\n[PASS] test_symbolStillHasFixedCapAndFallsBack() (gas: 276059)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 47.53ms (22.66ms CPU time)\n\nRan 30 tests for test/MemecoinCemetery.t.sol:MemecoinCemeteryTest\n[PASS] testFuzz_holderThreshold(uint8,uint256,bool) (runs: 256, μ: 785375, ~: 691614)\nLogs:\n  Bound result 511066074543596207\n\n[PASS] testFuzz_sealedRecordsNeverChange(address,uint8,uint32,uint8) (runs: 256, μ: 2008455, ~: 1779173)\nLogs:\n  Bound result 7\n  Bound result 2\n\n[PASS] test_all24EpitaphsAreExact() (gas: 322979)\n[PASS] test_allInvalidStateTransitions() (gas: 1051543)\n[PASS] test_calendarUTCLeapCenturiesEpochAndYearBoundary() (gas: 4026918)\n[PASS] test_decimalsRevertDefaultsTo18() (gas: 347227)\n[PASS] test_digOpensWakeAndEmits() (gas: 151790)\n[PASS] test_headstoneEpitaphDatesMournersAndRisenBanner() (gas: 7291353)\n[PASS] test_headstoneEscapesAllXMLMetacharacters() (gas: 4211632)\n[PASS] test_headstoneMissingAndNonPrintableSymbolUseAddress() (gas: 4468518)\n[PASS] test_headstoneSymbolBoundsAndMalformedABINeverRevert() (gas: 4846302)\n[PASS] test_holderReadFailuresDoNotChangeState() (gas: 21184472)\n[PASS] test_holderThresholdFloorAndDecimalExtremes() (gas: 7606522)\n[PASS] test_holderThresholdWholeTokenAndFraction18And6Decimals() (gas: 6274042)\n[PASS] test_holderVetoAtLastSecondAndSavedCooldown() (gas: 433221)\n[PASS] test_initialStateAndUnknownQueries() (gas: 105322)\n[PASS] test_invalidEpitaph24And255() (gas: 47223)\n[PASS] test_lateSealUsesActualSealTime() (gas: 351888)\n[PASS] test_missingMalformedAndGasBombDecimalsDefaultTo18() (gas: 24760437)\n[PASS] test_mournOncePerAddressAndAgainAfterReburial() (gas: 1133001)\n[PASS] test_nonholderCannotVetoOrRise() (gas: 443714)\n[PASS] test_recentBurialsNewestFirstCapAndDuplicates() (gas: 16579185)\n[PASS] test_rejectsEOAZeroAddressAndZeroSupply() (gas: 125234)\n[PASS] test_rejectsETHReceiveFallbackAndNonpayableFunctions() (gas: 1643606)\n[PASS] test_rejectsRevertingMalformedAndGasBombSupplies() (gas: 1069868)\n[PASS] test_risePreservesRecordAndHasCooldown() (gas: 844877)\n[PASS] test_runtimeFitsAndHasNoForbiddenOpcodes() (gas: 3798724)\n[PASS] test_staticTokenReadCannotReenterMourn() (gas: 1056703)\n[PASS] test_thresholdUsesCurrentSupplyAndBalancesAndBorrowedBalanceCounts() (gas: 876396)\n[PASS] test_wakeBoundariesAndPermissionlessSeal() (gas: 486720)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 50.29ms (150.12ms CPU time)\n\nRan 1 test for test/MemecoinCemetery.invariant.t.sol:MemecoinCemeteryInvariantTest\n[PASS]\nMemecoinCemeteryInvariantTest invariants:\n[PASS] invariant_graveCountEqualsNumberOfBuriedTokens\n[PASS] invariant_sealedBurialIdentitiesNeverChange\n MemecoinCemeteryInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-----------------+----------+-------+---------+----------╮\n| Contract        | Selector | Calls | Reverts | Discards |\n+=========================================================+\n| CemeteryHandler | advance  | 1359  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | dig      | 1310  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | mourn    | 1375  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | rise     | 1422  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | save     | 1351  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | seal     | 1375  | 0       | 0        |\n╰-----------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.06s (2.06s CPU time)\n\nRan 4 test suites in 2.06s (2.17s CPU time): 39 tests passed, 0 failed, 0 skipped (39 total tests)\n","passed":true},{"durationMs":40,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"MemecoinCemetery.dig(address,uint8)\",\"MemecoinCemetery.fallback()\",\"MemecoinCemetery.itLives(address)\",\"MemecoinCemetery.mourn(address)\",\"MemecoinCemetery.receive()\",\"MemecoinCemetery.rise(address)\",\"MemecoinCemetery.seal(address)\"],\"files\":{\".gitignore\":4,\"LICENSE\":21,\"README.md\":242,\"docs/abi/MemecoinCemetery.json\":572,\"docs/deployment/MemecoinCemetery.standard-input.json\":41,\"docs/deployment/build.json\":20,\"foundry.toml\":20,\"remappings.txt\":1,\"script/Deploy.s.sol\":19,\"src/MemecoinCemetery.sol\":412,\"test/MemecoinCemetery.holder-gas.t.sol\":159,\"test/MemecoinCemetery.invariant.t.sol\":131,\"test/MemecoinCemetery.t.sol\":867},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":741,"exitCode":0,"name":"slither","output":"[medium/medium] divide-before-multiply at src/MemecoinCemetery.sol:380: MemecoinCemetery._date(uint256) (src/MemecoinCemetery.sol#380-394) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/MemecoinCemetery.sol:309: MemecoinCemetery._symbol(address) (src/MemecoinCemetery.sol#309-333) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/MemecoinCemetery.sol:380: MemecoinCemetery._date(uint256) (src/MemecoinCemetery.sol#380-394) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/MemecoinCemetery.sol:380: MemecoinCemetery._date(uint256) (src/MemecoinCemetery.sol#380-394) performs a multiplication on the result of a division:\n[medium/high] locked-ether at src/MemecoinCemetery.sol:255: Contract locking ether found:\n[low/medium] timestamp at src/MemecoinCemetery.sol:185: MemecoinCemetery.burialOf(address,uint256) (src/MemecoinCemetery.sol#185-190) uses timestamp for comparisons\n[low/medium] timestamp at src/MemecoinCemetery.sol:138: MemecoinCemetery.seal(address) (src/MemecoinCemetery.sol#138-148) uses timestamp for comparisons\n[low/medium] timestamp at src/MemecoinCemetery.sol:126: MemecoinCemetery.itLives(address) (src/MemecoinCemetery.sol#126-134) uses timestamp for comparisons\n[low/medium] timestamp at src/MemecoinCemetery.sol:103: MemecoinCemetery.dig(address,uint8) (src/MemecoinCemetery.sol#103-122) uses timestamp for comparisons","passed":true},{"durationMs":327,"exitCode":0,"name":"aderyn","output":"[high] contract-locks-ether at src/MemecoinCemetery.sol:7: Contract locks Ether without a withdraw function\n[low] large-numeric-literal at src/MemecoinCemetery.sol:59: Large Numeric Literal\n[low] literal-instead-of-constant at src/MemecoinCemetery.sol:104: Literal Instead of Constant (37 places)\n[low] state-variable-could-be-constant at src/MemecoinCemetery.sol:73: State Variable Could Be Constant\n[low] uninitialized-local-variable at src/MemecoinCemetery.sol:351: Uninitialized Local Variable (2 places)","passed":true},{"durationMs":1158,"exitCode":0,"name":"proof 83b2404ff9b5","output":"Compiling 21 files with Solc 0.8.26\nSolc 0.8.26 finished in 692.26ms\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n  --> test/imd-proof-2a6dde41/Proof_83b2404ff9b5.t.sol:84:5:\n   |\n84 |     function test_premiseHolderQualifiesButBalanceOfExceedsCap() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n\nRan 3 tests for test/imd-proof-2a6dde41/Proof_83b2404ff9b5.t.sol:HolderGasCapTest\n[PASS] test_premiseHolderQualifiesButBalanceOfExceedsCap() (gas: 85127)\n[PASS] test_realHolderCanRise() (gas: 526926)\n[PASS] test_realHolderCanSaveWake() (gas: 319309)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.00ms (824.14µs CPU time)\n\nRan 1 test suite in 2.38ms (1.00ms CPU time): 3 tests passed, 0 failed, 0 skipped (3 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"5f6475964505ac563196a4741d086038ac8e5d6464a611f96c5be547031e4101","verifiedTreeHash":"fe7986c7a047ad29a9b8a2a965ac752f9fdb1d30","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":2629,"exitCode":0,"name":"build","output":"Compiling 26 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.50s\nCompiler run successful!\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:109:13\n    │\n109 │         if (block.timestamp < _cooldownEnds[token]) revert CooldownActive(_cooldownEnds[token]);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:121:9\n    │\n121 │         emit WakeOpened(token, msg.sender, epitaphId, g.wakeEndsAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:128:13\n    │\n128 │         if (block.timestamp >= g.wakeEndsAt) revert WakeClosed(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:133:9\n    │\n133 │         emit Resurrected(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:140:13\n    │\n140 │         if (block.timestamp < g.wakeEndsAt) revert WakeStillOpen(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:170:9\n    │\n170 │         emit Rose(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:316:26\n    │\n316 │         if (size != 64 + ((length + 31) / 32) * 32) return _shortAddress(token);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:356:25\n    │\n356 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                         ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:356:69\n    │\n356 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                                                                     ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes1' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:376:36\n    │\n376 │         uint256 year = yearOfEra + era * 400;\n    │                                    ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:377:41\n    │\n377 │         uint256 dayOfYear = dayOfEra - (365 * yearOfEra + yearOfEra / 4 - yearOfEra / 100);\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:379:36\n    │\n379 │         uint256 day = dayOfYear - (153 * marchMonth + 2) / 5 + 1;\n    │                                    ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:393:15\n    │\n393 │             ++length;\n    │               ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:398:39\n    │\n398 │             result[--length] = bytes1(uint8(48 + value % 10));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:751:17\n    │\n751 │         vm.warp(block.timestamp + 72 hours);\n    │         ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:305:27\n    │\n305 │         uint256 risenAt = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n322 │         vm.warp(ready - 1);\n    │         ────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:723:21\n    │\n723 │             vm.warp(block.timestamp + 72 hours);\n    │             ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":12148,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/MemecoinCemetery.t.sol:DeployTest\n[PASS] testFuzz_deployRejectsEveryOtherChain(uint64) (runs: 256, μ: 2647345, ~: 2647345)\n[PASS] test_deployOn4663WithNoArguments() (gas: 5423524)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 36.74ms (36.95ms CPU time)\n\nRan 7 tests for test/MemecoinCemetery.adversarial.t.sol:MemecoinCemeteryAdversarialTest\n[PASS] testFuzz_malformedMandatoryWordsRevertWithoutChangingHistory(uint8,uint8,bool) (runs: 1000, μ: 471725, ~: 372058)\n[PASS] testFuzz_thresholdCrossoverAndFloor(uint8,uint16,bool) (runs: 1000, μ: 798542, ~: 876592)\n[PASS] test_codeDisappearingAfterDigCannotBlockSealingOrMourning() (gas: 546402)\n[PASS] test_currentDecimalsAndExactCallerBalanceDetermineHolderStatus() (gas: 786231)\n[PASS] test_gasExhaustionIsBoundedForEveryTokenSelector() (gas: 2165094)\n[PASS] test_returnDataBombsHaveBoundedCostAndCannotCorruptState() (gas: 892202)\n[PASS] test_sealAndMournRemainAvailableWhenEveryTokenReadFails() (gas: 1038231)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 45.01ms (91.52ms CPU time)\n\nRan 30 tests for test/MemecoinCemetery.t.sol:MemecoinCemeteryTest\n[PASS] testFuzz_holderThreshold(uint8,uint256,bool) (runs: 256, μ: 802359, ~: 879875)\nLogs:\n  Bound result 4107542399\n\n[PASS] testFuzz_sealedRecordsNeverChange(address,uint8,uint32,uint8) (runs: 256, μ: 1965474, ~: 1779035)\nLogs:\n  Bound result 1\n  Bound result 4\n\n[PASS] test_all24EpitaphsAreExact() (gas: 322979)\n[PASS] test_allInvalidStateTransitions() (gas: 1051479)\n[PASS] test_calendarUTCLeapCenturiesEpochAndYearBoundary() (gas: 4025408)\n[PASS] test_decimalsRevertDefaultsTo18() (gas: 347173)\n[PASS] test_digOpensWakeAndEmits() (gas: 151780)\n[PASS] test_headstoneEpitaphDatesMournersAndRisenBanner() (gas: 7291257)\n[PASS] test_headstoneEscapesAllXMLMetacharacters() (gas: 4210122)\n[PASS] test_headstoneMissingAndNonPrintableSymbolUseAddress() (gas: 4468458)\n[PASS] test_headstoneSymbolBoundsAndMalformedABINeverRevert() (gas: 4846292)\n[PASS] test_holderReadFailuresDoNotChangeState() (gas: 1623391)\n[PASS] test_holderThresholdFloorAndDecimalExtremes() (gas: 7605982)\n[PASS] test_holderThresholdWholeTokenAndFraction18And6Decimals() (gas: 6273610)\n[PASS] test_holderVetoAtLastSecondAndSavedCooldown() (gas: 433179)\n[PASS] test_initialStateAndUnknownQueries() (gas: 105322)\n[PASS] test_invalidEpitaph24And255() (gas: 47223)\n[PASS] test_lateSealUsesActualSealTime() (gas: 351878)\n[PASS] test_missingMalformedAndGasBombDecimalsDefaultTo18() (gas: 5202777)\n[PASS] test_mournOncePerAddressAndAgainAfterReburial() (gas: 1132959)\n[PASS] test_nonholderCannotVetoOrRise() (gas: 443660)\n[PASS] test_recentBurialsNewestFirstCapAndDuplicates() (gas: 16578903)\n[PASS] test_rejectsEOAZeroAddressAndZeroSupply() (gas: 125224)\n[PASS] test_rejectsETHReceiveFallbackAndNonpayableFunctions() (gas: 1643482)\n[PASS] test_rejectsRevertingMalformedAndGasBombSupplies() (gas: 1069810)\n[PASS] test_risePreservesRecordAndHasCooldown() (gas: 844835)\n[PASS] test_runtimeFitsAndHasNoForbiddenOpcodes() (gas: 3793658)\n[PASS] test_staticTokenReadCannotReenterMourn() (gas: 1056693)\n[PASS] test_thresholdUsesCurrentSupplyAndBalancesAndBorrowedBalanceCounts() (gas: 876310)\n[PASS] test_wakeBoundariesAndPermissionlessSeal() (gas: 486710)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 62.25ms (174.10ms CPU time)\n\nRan 1 test for test/MemecoinCemetery.invariant.t.sol:MemecoinCemeteryInvariantTest\n[PASS]\nMemecoinCemeteryInvariantTest invariants:\n[PASS] invariant_graveCountEqualsNumberOfBuriedTokens\n[PASS] invariant_sealedBurialIdentitiesNeverChange\n MemecoinCemeteryInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-----------------+----------+-------+---------+----------╮\n| Contract        | Selector | Calls | Reverts | Discards |\n+=========================================================+\n| CemeteryHandler | advance  | 1448  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | dig      | 1401  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | mourn    | 1361  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | rise     | 1367  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | save     | 1305  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | seal     | 1310  | 0       | 0        |\n╰-----------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.88s (1.88s CPU time)\n\nRan 3 tests for test/MemecoinCemetery.model.t.sol:MemecoinCemeteryModelTest\n[PASS] invariant_callsAndEntireHistoryMatchIndependentModel() (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------+-------+---------+----------╮\n| Contract             | Selector    | Calls | Reverts | Discards |\n+=================================================================+\n| CemeteryModelHandler | act         | 8209  | 0       | 0        |\n|----------------------+-------------+-------+---------+----------|\n| CemeteryModelHandler | advance     | 8238  | 0       | 0        |\n|----------------------+-------------+-------+---------+----------|\n| CemeteryModelHandler | changeToken | 8129  | 0       | 0        |\n╰----------------------+-------------+-------+---------+----------╯\n\n[PASS] test_modelExercisesEveryActionAndRejectedAction() (gas: 2015250)\n[PASS] test_modelTracksMourningAcrossRepeatedBurialsAndSaves() (gas: 19384750)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 12.06s (12.08s CPU time)\n\nRan 5 test suites in 12.06s (14.09s CPU time): 43 tests passed, 0 failed, 0 skipped (43 total tests)\n","passed":true},{"durationMs":40,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"MemecoinCemetery.dig(address,uint8)\",\"MemecoinCemetery.fallback()\",\"MemecoinCemetery.itLives(address)\",\"MemecoinCemetery.mourn(address)\",\"MemecoinCemetery.receive()\",\"MemecoinCemetery.rise(address)\",\"MemecoinCemetery.seal(address)\"],\"files\":{\".gitignore\":4,\"LICENSE\":21,\"README.md\":230,\"docs/abi/MemecoinCemetery.json\":572,\"docs/deployment/MemecoinCemetery.standard-input.json\":41,\"docs/deployment/build.json\":20,\"foundry.toml\":20,\"remappings.txt\":1,\"script/Deploy.s.sol\":19,\"src/MemecoinCemetery.sol\":403,\"test/MemecoinCemetery.adversarial.t.sol\":222,\"test/MemecoinCemetery.invariant.t.sol\":131,\"test/MemecoinCemetery.model.t.sol\":259,\"test/MemecoinCemetery.t.sol\":866},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"8b066cb42f91630ec35611ecbbad6bc4f1fe602994da8d5783434805c83f320f","verifiedTreeHash":"7355f5df9adcad22749386a106085e551ee6d531","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":1839,"exitCode":0,"name":"build","output":"Compiling 24 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.73s\nCompiler run successful!\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:109:13\n    │\n109 │         if (block.timestamp < _cooldownEnds[token]) revert CooldownActive(_cooldownEnds[token]);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:121:9\n    │\n121 │         emit WakeOpened(token, msg.sender, epitaphId, g.wakeEndsAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:128:13\n    │\n128 │         if (block.timestamp >= g.wakeEndsAt) revert WakeClosed(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:133:9\n    │\n133 │         emit Resurrected(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:140:13\n    │\n140 │         if (block.timestamp < g.wakeEndsAt) revert WakeStillOpen(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:170:9\n    │\n170 │         emit Rose(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:316:26\n    │\n316 │         if (size != 64 + ((length + 31) / 32) * 32) return _shortAddress(token);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:356:25\n    │\n356 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                         ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:356:69\n    │\n356 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                                                                     ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes1' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:376:36\n    │\n376 │         uint256 year = yearOfEra + era * 400;\n    │                                    ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:377:41\n    │\n377 │         uint256 dayOfYear = dayOfEra - (365 * yearOfEra + yearOfEra / 4 - yearOfEra / 100);\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:379:36\n    │\n379 │         uint256 day = dayOfYear - (153 * marchMonth + 2) / 5 + 1;\n    │                                    ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:393:15\n    │\n393 │             ++length;\n    │               ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:398:39\n    │\n398 │             result[--length] = bytes1(uint8(48 + value % 10));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:751:17\n    │\n751 │         vm.warp(block.timestamp + 72 hours);\n    │         ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:305:27\n    │\n305 │         uint256 risenAt = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n322 │         vm.warp(ready - 1);\n    │         ────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:723:21\n    │\n723 │             vm.warp(block.timestamp + 72 hours);\n    │             ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":1928,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/MemecoinCemetery.t.sol:DeployTest\n[PASS] testFuzz_deployRejectsEveryOtherChain(uint64) (runs: 256, μ: 2647345, ~: 2647345)\n[PASS] test_deployOn4663WithNoArguments() (gas: 5423524)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.14ms (8.36ms CPU time)\n\nRan 30 tests for test/MemecoinCemetery.t.sol:MemecoinCemeteryTest\n[PASS] testFuzz_holderThreshold(uint8,uint256,bool) (runs: 256, μ: 794364, ~: 785669)\nLogs:\n  Bound result 8683512478\n\n[PASS] testFuzz_sealedRecordsNeverChange(address,uint8,uint32,uint8) (runs: 256, μ: 1955909, ~: 1779035)\nLogs:\n  Bound result 0\n  Bound result 1\n\n[PASS] test_all24EpitaphsAreExact() (gas: 322979)\n[PASS] test_allInvalidStateTransitions() (gas: 1051479)\n[PASS] test_calendarUTCLeapCenturiesEpochAndYearBoundary() (gas: 4025408)\n[PASS] test_decimalsRevertDefaultsTo18() (gas: 347173)\n[PASS] test_digOpensWakeAndEmits() (gas: 151780)\n[PASS] test_headstoneEpitaphDatesMournersAndRisenBanner() (gas: 7291257)\n[PASS] test_headstoneEscapesAllXMLMetacharacters() (gas: 4210122)\n[PASS] test_headstoneMissingAndNonPrintableSymbolUseAddress() (gas: 4468458)\n[PASS] test_headstoneSymbolBoundsAndMalformedABINeverRevert() (gas: 4846292)\n[PASS] test_holderReadFailuresDoNotChangeState() (gas: 1623391)\n[PASS] test_holderThresholdFloorAndDecimalExtremes() (gas: 7605982)\n[PASS] test_holderThresholdWholeTokenAndFraction18And6Decimals() (gas: 6273610)\n[PASS] test_holderVetoAtLastSecondAndSavedCooldown() (gas: 433179)\n[PASS] test_initialStateAndUnknownQueries() (gas: 105322)\n[PASS] test_invalidEpitaph24And255() (gas: 47223)\n[PASS] test_lateSealUsesActualSealTime() (gas: 351878)\n[PASS] test_missingMalformedAndGasBombDecimalsDefaultTo18() (gas: 5202777)\n[PASS] test_mournOncePerAddressAndAgainAfterReburial() (gas: 1132959)\n[PASS] test_nonholderCannotVetoOrRise() (gas: 443660)\n[PASS] test_recentBurialsNewestFirstCapAndDuplicates() (gas: 16578903)\n[PASS] test_rejectsEOAZeroAddressAndZeroSupply() (gas: 125224)\n[PASS] test_rejectsETHReceiveFallbackAndNonpayableFunctions() (gas: 1643482)\n[PASS] test_rejectsRevertingMalformedAndGasBombSupplies() (gas: 1069810)\n[PASS] test_risePreservesRecordAndHasCooldown() (gas: 844835)\n[PASS] test_runtimeFitsAndHasNoForbiddenOpcodes() (gas: 3793658)\n[PASS] test_staticTokenReadCannotReenterMourn() (gas: 1056693)\n[PASS] test_thresholdUsesCurrentSupplyAndBalancesAndBorrowedBalanceCounts() (gas: 876310)\n[PASS] test_wakeBoundariesAndPermissionlessSeal() (gas: 486710)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 44.95ms (136.62ms CPU time)\n\nRan 1 test for test/MemecoinCemetery.invariant.t.sol:MemecoinCemeteryInvariantTest\n[PASS]\nMemecoinCemeteryInvariantTest invariants:\n[PASS] invariant_graveCountEqualsNumberOfBuriedTokens\n[PASS] invariant_sealedBurialIdentitiesNeverChange\n MemecoinCemeteryInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-----------------+----------+-------+---------+----------╮\n| Contract        | Selector | Calls | Reverts | Discards |\n+=========================================================+\n| CemeteryHandler | advance  | 1329  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | dig      | 1418  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | mourn    | 1338  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | rise     | 1326  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | save     | 1418  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | seal     | 1363  | 0       | 0        |\n╰-----------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.85s (1.85s CPU time)\n\nRan 3 test suites in 1.86s (1.91s CPU time): 33 tests passed, 0 failed, 0 skipped (33 total tests)\n","passed":true},{"durationMs":28,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"MemecoinCemetery.dig(address,uint8)\",\"MemecoinCemetery.fallback()\",\"MemecoinCemetery.itLives(address)\",\"MemecoinCemetery.mourn(address)\",\"MemecoinCemetery.receive()\",\"MemecoinCemetery.rise(address)\",\"MemecoinCemetery.seal(address)\"],\"files\":{\".gitignore\":4,\"LICENSE\":21,\"README.md\":230,\"docs/abi/MemecoinCemetery.json\":572,\"docs/deployment/MemecoinCemetery.standard-input.json\":41,\"docs/deployment/build.json\":20,\"foundry.toml\":20,\"remappings.txt\":1,\"script/Deploy.s.sol\":19,\"src/MemecoinCemetery.sol\":403,\"test/MemecoinCemetery.invariant.t.sol\":131,\"test/MemecoinCemetery.t.sol\":866},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":548,"exitCode":0,"name":"slither","output":"[medium/medium] divide-before-multiply at src/MemecoinCemetery.sol:371: MemecoinCemetery._date(uint256) (src/MemecoinCemetery.sol#371-385) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/MemecoinCemetery.sol:371: MemecoinCemetery._date(uint256) (src/MemecoinCemetery.sol#371-385) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/MemecoinCemetery.sol:300: MemecoinCemetery._symbol(address) (src/MemecoinCemetery.sol#300-324) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/MemecoinCemetery.sol:371: MemecoinCemetery._date(uint256) (src/MemecoinCemetery.sol#371-385) performs a multiplication on the result of a division:\n[medium/high] locked-ether at src/MemecoinCemetery.sol:255: Contract locking ether found:\n[low/medium] timestamp at src/MemecoinCemetery.sol:185: MemecoinCemetery.burialOf(address,uint256) (src/MemecoinCemetery.sol#185-190) uses timestamp for comparisons\n[low/medium] timestamp at src/MemecoinCemetery.sol:138: MemecoinCemetery.seal(address) (src/MemecoinCemetery.sol#138-148) uses timestamp for comparisons\n[low/medium] timestamp at src/MemecoinCemetery.sol:126: MemecoinCemetery.itLives(address) (src/MemecoinCemetery.sol#126-134) uses timestamp for comparisons\n[low/medium] timestamp at src/MemecoinCemetery.sol:103: MemecoinCemetery.dig(address,uint8) (src/MemecoinCemetery.sol#103-122) uses timestamp for comparisons","passed":true},{"durationMs":247,"exitCode":0,"name":"aderyn","output":"[high] contract-locks-ether at src/MemecoinCemetery.sol:7: Contract locks Ether without a withdraw function\n[low] large-numeric-literal at src/MemecoinCemetery.sol:59: Large Numeric Literal\n[low] literal-instead-of-constant at src/MemecoinCemetery.sol:104: Literal Instead of Constant (37 places)\n[low] state-variable-could-be-constant at src/MemecoinCemetery.sol:73: State Variable Could Be Constant\n[low] uninitialized-local-variable at src/MemecoinCemetery.sol:342: Uninitialized Local Variable (2 places)\n[low] unused-state-variable at src/MemecoinCemetery.sol:59: Unused State Variable","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"ae3be5fcd5f9dd78eaf805026e7e9671b95bdaf869c57b9b5a63c884312830f7","verifiedTreeHash":"f8bdbbd891d009da563c2c2e0d899a834bd13576","verifierVersion":"0.1.0+be003835"},{"checks":[{"durationMs":3493,"exitCode":0,"name":"build","output":"Compiling 26 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.30s\nCompiler run successful!\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:109:13\n    │\n109 │         if (block.timestamp < _cooldownEnds[token]) revert CooldownActive(_cooldownEnds[token]);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:121:9\n    │\n121 │         emit WakeOpened(token, msg.sender, epitaphId, g.wakeEndsAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:128:13\n    │\n128 │         if (block.timestamp >= g.wakeEndsAt) revert WakeClosed(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:133:9\n    │\n133 │         emit Resurrected(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/MemecoinCemetery.sol:140:13\n    │\n140 │         if (block.timestamp < g.wakeEndsAt) revert WakeStillOpen(g.wakeEndsAt);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/MemecoinCemetery.sol:170:9\n    │\n170 │         emit Rose(token, msg.sender);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:316:26\n    │\n316 │         if (size != 64 + ((length + 31) / 32) * 32) return _shortAddress(token);\n    │                          ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:356:25\n    │\n356 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                         ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:356:69\n    │\n356 │                 escaped[used++] = uint8(c) < 32 || uint8(c) > 126 ? bytes1(\"?\") : c;\n    │                                                                     ━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes1' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:376:36\n    │\n376 │         uint256 year = yearOfEra + era * 400;\n    │                                    ━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:377:41\n    │\n377 │         uint256 dayOfYear = dayOfEra - (365 * yearOfEra + yearOfEra / 4 - yearOfEra / 100);\n    │                                         ━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/MemecoinCemetery.sol:379:36\n    │\n379 │         uint256 day = dayOfYear - (153 * marchMonth + 2) / 5 + 1;\n    │                                    ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/MemecoinCemetery.sol:393:15\n    │\n393 │             ++length;\n    │               ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/MemecoinCemetery.sol:398:39\n    │\n398 │             result[--length] = bytes1(uint8(48 + value % 10));\n    │                                       ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:751:17\n    │\n751 │         vm.warp(block.timestamp + 72 hours);\n    │         ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:305:27\n    │\n305 │         uint256 risenAt = block.timestamp;\n    │                           ━━━━━━━━━━━━━━━\n    ‡\n322 │         vm.warp(ready - 1);\n    │         ────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/MemecoinCemetery.t.sol:723:21\n    │\n723 │             vm.warp(block.timestamp + 72 hours);\n    │             ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":14072,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/MemecoinCemetery.t.sol:DeployTest\n[PASS] testFuzz_deployRejectsEveryOtherChain(uint64) (runs: 256, μ: 2647345, ~: 2647345)\n[PASS] test_deployOn4663WithNoArguments() (gas: 5423524)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 77.58ms (77.92ms CPU time)\n\nRan 7 tests for test/MemecoinCemetery.adversarial.t.sol:MemecoinCemeteryAdversarialTest\n[PASS] testFuzz_malformedMandatoryWordsRevertWithoutChangingHistory(uint8,uint8,bool) (runs: 1000, μ: 473229, ~: 385267)\n[PASS] testFuzz_thresholdCrossoverAndFloor(uint8,uint16,bool) (runs: 1000, μ: 785359, ~: 688075)\n[PASS] test_codeDisappearingAfterDigCannotBlockSealingOrMourning() (gas: 546402)\n[PASS] test_currentDecimalsAndExactCallerBalanceDetermineHolderStatus() (gas: 786231)\n[PASS] test_gasExhaustionIsBoundedForEveryTokenSelector() (gas: 2165094)\n[PASS] test_returnDataBombsHaveBoundedCostAndCannotCorruptState() (gas: 892202)\n[PASS] test_sealAndMournRemainAvailableWhenEveryTokenReadFails() (gas: 1038231)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 127.94ms (250.93ms CPU time)\n\nRan 30 tests for test/MemecoinCemetery.t.sol:MemecoinCemeteryTest\n[PASS] testFuzz_holderThreshold(uint8,uint256,bool) (runs: 256, μ: 792527, ~: 691686)\nLogs:\n  Bound result 31562\n\n[PASS] testFuzz_sealedRecordsNeverChange(address,uint8,uint32,uint8) (runs: 256, μ: 2097265, ~: 1779719)\nLogs:\n  Bound result 7\n  Bound result 2\n\n[PASS] test_all24EpitaphsAreExact() (gas: 322979)\n[PASS] test_allInvalidStateTransitions() (gas: 1051479)\n[PASS] test_calendarUTCLeapCenturiesEpochAndYearBoundary() (gas: 4025408)\n[PASS] test_decimalsRevertDefaultsTo18() (gas: 347173)\n[PASS] test_digOpensWakeAndEmits() (gas: 151780)\n[PASS] test_headstoneEpitaphDatesMournersAndRisenBanner() (gas: 7291257)\n[PASS] test_headstoneEscapesAllXMLMetacharacters() (gas: 4210122)\n[PASS] test_headstoneMissingAndNonPrintableSymbolUseAddress() (gas: 4468458)\n[PASS] test_headstoneSymbolBoundsAndMalformedABINeverRevert() (gas: 4846292)\n[PASS] test_holderReadFailuresDoNotChangeState() (gas: 1623391)\n[PASS] test_holderThresholdFloorAndDecimalExtremes() (gas: 7605982)\n[PASS] test_holderThresholdWholeTokenAndFraction18And6Decimals() (gas: 6273610)\n[PASS] test_holderVetoAtLastSecondAndSavedCooldown() (gas: 433179)\n[PASS] test_initialStateAndUnknownQueries() (gas: 105322)\n[PASS] test_invalidEpitaph24And255() (gas: 47223)\n[PASS] test_lateSealUsesActualSealTime() (gas: 351878)\n[PASS] test_missingMalformedAndGasBombDecimalsDefaultTo18() (gas: 5202777)\n[PASS] test_mournOncePerAddressAndAgainAfterReburial() (gas: 1132959)\n[PASS] test_nonholderCannotVetoOrRise() (gas: 443660)\n[PASS] test_recentBurialsNewestFirstCapAndDuplicates() (gas: 16578903)\n[PASS] test_rejectsEOAZeroAddressAndZeroSupply() (gas: 125224)\n[PASS] test_rejectsETHReceiveFallbackAndNonpayableFunctions() (gas: 1643482)\n[PASS] test_rejectsRevertingMalformedAndGasBombSupplies() (gas: 1069810)\n[PASS] test_risePreservesRecordAndHasCooldown() (gas: 844835)\n[PASS] test_runtimeFitsAndHasNoForbiddenOpcodes() (gas: 3793658)\n[PASS] test_staticTokenReadCannotReenterMourn() (gas: 1056693)\n[PASS] test_thresholdUsesCurrentSupplyAndBalancesAndBorrowedBalanceCounts() (gas: 876310)\n[PASS] test_wakeBoundariesAndPermissionlessSeal() (gas: 486710)\nSuite result: ok. 30 passed; 0 failed; 0 skipped; finished in 176.71ms (484.45ms CPU time)\n\nRan 1 test for test/MemecoinCemetery.invariant.t.sol:MemecoinCemeteryInvariantTest\n[PASS]\nMemecoinCemeteryInvariantTest invariants:\n[PASS] invariant_graveCountEqualsNumberOfBuriedTokens\n[PASS] invariant_sealedBurialIdentitiesNeverChange\n MemecoinCemeteryInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-----------------+----------+-------+---------+----------╮\n| Contract        | Selector | Calls | Reverts | Discards |\n+=========================================================+\n| CemeteryHandler | advance  | 1363  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | dig      | 1417  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | mourn    | 1358  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | rise     | 1329  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | save     | 1356  | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| CemeteryHandler | seal     | 1369  | 0       | 0        |\n╰-----------------+----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.74s (2.73s CPU time)\n\nRan 3 tests for test/MemecoinCemetery.model.t.sol:MemecoinCemeteryModelTest\n[PASS] invariant_callsAndEntireHistoryMatchIndependentModel() (runs: 256, calls: 24576, reverts: 0)\n\n╭----------------------+-------------+-------+---------+----------╮\n| Contract             | Selector    | Calls | Reverts | Discards |\n+=================================================================+\n| CemeteryModelHandler | act         | 8096  | 0       | 0        |\n|----------------------+-------------+-------+---------+----------|\n| CemeteryModelHandler | advance     | 8215  | 0       | 0        |\n|----------------------+-------------+-------+---------+----------|\n| CemeteryModelHandler | changeToken | 8265  | 0       | 0        |\n╰----------------------+-------------+-------+---------+----------╯\n\n[PASS] test_modelExercisesEveryActionAndRejectedAction() (gas: 2015250)\n[PASS] test_modelTracksMourningAcrossRepeatedBurialsAndSaves() (gas: 19384750)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 13.93s (13.93s CPU time)\n\nRan 5 test suites in 13.93s (17.04s CPU time): 43 tests passed, 0 failed, 0 skipped (43 total tests)\n","passed":true},{"durationMs":47,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"MemecoinCemetery.dig(address,uint8)\",\"MemecoinCemetery.fallback()\",\"MemecoinCemetery.itLives(address)\",\"MemecoinCemetery.mourn(address)\",\"MemecoinCemetery.receive()\",\"MemecoinCemetery.rise(address)\",\"MemecoinCemetery.seal(address)\"],\"files\":{\".gitignore\":4,\"LICENSE\":21,\"README.md\":230,\"docs/abi/MemecoinCemetery.json\":572,\"docs/deployment/MemecoinCemetery.standard-input.json\":41,\"docs/deployment/build.json\":20,\"foundry.toml\":20,\"launch.json\":10,\"remappings.txt\":1,\"script/Deploy.s.sol\":19,\"src/MemecoinCemetery.sol\":403,\"test/MemecoinCemetery.adversarial.t.sol\":222,\"test/MemecoinCemetery.invariant.t.sol\":131,\"test/MemecoinCemetery.model.t.sol\":259,\"test/MemecoinCemetery.t.sol\":866},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"fcb0f0dfd3df845b1f2b18f42d5cc46ce3743b663356bc4306dd8a4873e25784","verifiedTreeHash":"87f3a9628bb30cf8dfbb66ca809d2dd398f0468c","verifierVersion":"0.1.0+be003835"}]}