{"assessments":[],"deployments":[{"attestationHash":"c49e43789c56c4a029c9e14f98b17eb66dbc16b3ac4df7dc89d5869cbc14bd42","chainId":1,"contracts":[{"address":"0xd31b9b14bbb54d29352ff6d8830ca328c47d0f7d","blockNumber":26200634,"name":"SelloutMachine","role":"other","txHash":"0xdb67f90677ec8231884dade2de4b1d871885609f38e9f6a429ee23f9aaa14a3e"}],"id":"756fc3d1-7bd3-4060-acc6-8a64b0852248","manifestHash":"aff011f5f0833f5361c1053906c465d1ca2893bf8c7b9e35a8a1db779d356deb","status":"live"}],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"c5b6c8d8-0cfe-4109-9449-38866724eebc","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"b568ff18a18b5d00ff7c6e6db0988d18053d57a9554b21abc245c4ae3047616e","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"b65fc6996363e81bc6b677c510b281f2671ddc3766435f41ec5479e40886ec7f","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"060cf9e3c452e2a985cd1d4232f5b7ef7bf6f147e322728bcfbcdf6b8ddeea02","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"15e17df465cf3f2fd0753db1068921cd8201f14cf487a4b75a8fa09c7d3dfe16","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"eaa2a92f09ec37922c1a5cec20b7a8e00104b052c571b2100dcfe1aaa9e2728d","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"36cd4f199d916fe94425ff77a27af3dc9c7e9ebab79e7e1aaf3fd460d34b7f48","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"d59561da3b378461b7c749f6bd5084477d44993aa94972ddea90f542535751df","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"7d479444392832d2d87c351ef9cb63866061ee1f6466116cca7b70420a9bda0b","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"7254c2dedecf0095ec14b18f24bf74f5d7baa8db6c6195e11e49b89823f2e3f3","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"# The Sellout Machine\n\nBuild, test, security-review, and deploy `SelloutMachine.sol`, a standalone Solidity contract for The Vessel Craft #10000 on Ethereum mainnet.\n\nReferences:\n- https://www.thevessel.fun/docs/overview\n- https://www.thevessel.fun/docs/machines\n- https://machine.thevessel.fun/\n- https://github.com/producedbydav/The-Vessel\n\nVessel mainnet: `0xECb92Cc7112b80A2234936315BbB493fb48d1463`\n\nTarget: Machine Craft #10000, capacity 10,000 bytes.\n\nOwner: `0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a`\n\n## Concept\n\nVisualize the minting progress of a configurable 10,000-token NFT collection as a 100×100 black-and-white pixel grid.\n\nStart completely white. Each minted NFT turns one pixel black, beginning top-left, moving horizontally right, then continuing on the next row. At 10,000 mints, the grid is completely black.\n\nExamples:\n- 0 minted: All white.\n- 100: First row black.\n- 101: First pixel of second row black.\n- 5,000: First 50 rows black.\n- 9,999: Only bottom-right pixel white.\n- 10,000: All black.\n\nFor pixel index `i`, output black if `i < mintedCount`, otherwise white. Clamp supply to 10,000.\n\n## Vessel Compatibility\n\nImplement the existing `IMachine` interface:\n\n- `name() external view returns (string memory)` returns \"The Sellout Machine\".\n- `craftToPayload(uint256 tokenId) external view returns (bytes memory)` returns exactly 10,000 bytes for tokenId 10000.\n\nInspect the actual deployed Vessel ABI, Machine interface, and SVG renderer. Verify correct black/white byte encoding and pixel order. Reject unsupported Craft IDs.\n\nDo not modify or redeploy The Vessel.\n\n## Configurable Collection\n\nImplement:\n- `address public trackedCollection`\n- `setTrackedCollection(address newCollection)`\n- `mintedCount() external view returns (uint256)`\n- `mintProgress() external view returns (uint256)` (basis points, 0–10000)\n\nRead the tracked ERC-721 contract's `totalSupply()` dynamically via safe `staticcall`. Clamp to 10,000. Handle invalid, reverting, or malformed responses.\n\nAllow deployment without an initial collection, displaying all white until configured. Reject invalid addresses when setting a collection.\n\nOnly the authorized owner may call `setTrackedCollection()`. Emit `TrackedCollectionUpdated(previousCollection, newCollection)`.\n\nThe owner must be able to change the tracked NFT collection anytime through Etherscan without redeploying the Machine or changing Craft #10000's attachment.\n\nDocument that burns may decrease `totalSupply()` and reverse pixel progress.\n\nNo backend, oracle, keeper, per-mint transaction, or stored pixel state.\n\n## Ownership\n\nAssign exclusive configuration authority to:\n\n`0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a`\n\nUse IMD's supported `$owner` constructor mechanism. Never assign control to the deployment factory or `msg.sender`.\n\nNo proxies, ownership transfers, upgradeability, token launches, liquidity pools, or unnecessary admin privileges.\n\n## Testing\n\nCreate Foundry tests covering:\n- Pixel counts 0, 1, 100, 101, 5000, 9999, 10000.\n- Exact 10,000-byte payload and correct grayscale values.\n- Unauthorized access, collection changes, invalid addresses, and malicious/reverting supply contracts.\n- Gas usage and payload generation efficiency.\n\nMANDATORY: Run Foundry mainnet-fork integration tests against the actual Vessel contract at `0xECb92Cc7112b80A2234936315BbB493fb48d1463`.\n\nVerify Craft #10000 compatibility, simulate authorized Machine attachment on the fork, query its payload through Vessel, and check SVG rendering and gas usage. Report any blocked or failed tests accurately.\n\nPerform an independent adversarial security review.\n\n## Deployment\n\nDeploy through IMD's contracts-only Ethereum mainnet system, with NO token.\n\nEnsure constructor parameters are compatible with IMD's deployment factory. Deploy only after successful required tests and review.\n\nDo NOT automatically attach the Machine to Craft #10000. I will point the Craft to the deployed Machine address separately.\n\nNo post-deployment initialization by IMD workers should be required.\n\n## Deliverables\n\nPublish source code and Foundry tests to GitHub. Provide:\n- Verified mainnet contract address and deployment transaction.\n- GitHub repository and commit.\n- Security review and gas benchmarks.\n- Mainnet-fork test results.\n- Instructions to attach the Machine to Craft #10000.\n- Instructions for the owner to call `setTrackedCollection(address)` through Etherscan.\n\nThe result must be a minimal, gas-efficient, fully onchain Machine whose 10,000 pixels automatically reflect the minting progress of a collection selected by the authorized wallet.","parentJobId":null,"planHash":"34cf7b64efd25f6721ce6415671e91bad81d85d28e1be55e5feae56194a0382b","previousHash":"157eae4e54ed5c7203045d517ddd1776617529d2a4ad4e8721e456f396614db7","projectId":"c5b6c8d8-0cfe-4109-9449-38866724eebc","publication":{"commit":"a6fbd9086371a056c63134fcc3ee36916f96ffca","deliveredAt":"2026-10-15T21:33:10.321Z","repoUrl":"https://github.com/identity-md-launches/launch-1889-sellout-machine-build"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"bde531ac1f59d52a19830a6b788a2e9f35e9a7e78557e9047b1c4b013c698c11","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"ea30e435c4dd5aff","findings":[],"hash":"02e3ad92c5b28288bb7d03bc49cbeb4a8f28675cc144a4d531bc8c761cac7f01","nodeId":"7b256329-361f-466d-b619-996aaf8408d4","outcome":"failed","summary":"codex-devin wrapper: unhandled option --strict-config","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":"gpt-6-astra","outputTokens":0,"runtime":"codex","turns":0,"wallClockMs":37}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a7b8747ac077deb9","findings":[{"citation":"resolved","description":"Round-two settlement of my medium finding (id b5c092511feed7fae00f8dba1f280ea31adcd62b276f14efa2a1e56acf5c3f8d). The author's fix holds. launch.json line 6 now writes the static address 0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a instead of $owner, as the pinned recipe directs for a brief-stated owner, so the immutable owner no longer depends on how $owner resolves. The manifest is otherwise schema-valid: keys are exactly kind/contracts/notes, one contract named SelloutMachine (14 chars), one constructorArgs entry for the one constructor parameter (address owner_, nonpayable), notes 1,745 characters. Compiled artifact: creation 1,555 bytes, runtime 1,384 bytes, no DELEGATECALL/CALLCODE/CREATE/SELFDESTRUCT in runtime, constructor makes no external call, so the CREATE2 factory can deploy it on an empty chain. The pinned protected floor tests could not be executed here because their harness (test/floor/OwnerChecks.sol) is not shipped in the tree; their properties were checked by hand as listed. Residual, non-blocking: README.md line 22 ('| IMD constructor argument | `$owner` |') and docs/deployment.md line 16 and 27 still describe the argument as $owner; the manifest notes state the static address supersedes them and the author could not edit those files within the manifest assignment's write budget. This entry records the closure; it does not reopen anything.","line":6,"path":"launch.json","reproduction":"Scratch test test/scratch/ManifestOwner.t.sol (3 passing): new SelloutMachine(0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a) (the manifest's exact argument) -> owner() == 0xCcf0...; vm.prank(0xCcf0...); setTrackedCollection(validCollection) succeeds, trackedCollection updated, mintedCount()==5000; vm.prank(0xBEEF); setTrackedCollection(...) reverts Unauthorized(). The original mechanism (new SelloutMachine(0xBEEF); vm.prank(0xCcf0...); setTrackedCollection reverts Unauthorized()) still exists but is no longer reachable through the manifest. Full offline suite: forge test --no-match-path 'integration/*' with FOUNDRY_FUZZ_SEED=0x70400acffe2a4602ecfd12d07e8d6076229abeecfafc6e78631ab193db2b3f92 -> 68 passed, 0 failed. Expected: named wallet has exclusive configuration authority. Actual: it does.","severity":"info","snippet":"      \"constructorArgs\": [\"0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a\"]","title":"SETTLED (fixed): manifest now passes the brief-stated owner as a static address; prior medium finding b5c09251 closed"},{"citation":"resolved","description":"Carried over unchanged from round one (id de380d498f5c11eeb764b6746615fd270f9dd1325ba25880064088070eda3353); the source file did not change between rounds, so the behaviour is identical. setTrackedCollection (lines 42-46) requires three supportsInterface() replies, each made via _readWord with INTERFACE_GAS_LIMIT = 30,000 forwarded gas, while totalSupply() gets 100,000. ERC-165 lets an implementation spend up to 30,000 gas in supportsInterface(). When such an implementation sits behind a beacon/EIP-1967 proxy, the proxy's own SLOAD, STATICCALL to the beacon and DELEGATECALL come out of the same 30,000, the callee runs out of gas, _supports() returns false and the setter reverts InvalidCollection. Strictly the proxied contract as a whole then exceeds the ERC-165 ceiling, so the Machine is not violating the standard, and mainstream ERC-721 implementations (OpenZeppelin, ERC721A, Manifold) spend well under 5k here, so the precondition is rare. Owner-only, no exploit; advisory only, not blocking. A modest margin (e.g. 50,000 or SUPPLY_GAS_LIMIT) for the three probes would keep the return-data protections unchanged and remove the asymmetry. Also merges audit_permissions finding ef340927 (same root cause).","line":12,"path":"src/SelloutMachine.sol","reproduction":"Scratch Foundry test from round one (HeavyERC165.supportsInterface() runs a 95-iteration keccak loop then returns true for 0x01ffc9a7/0x80ac58cd and false otherwise; direct cold call ~21,423 gas, under the ERC-165 ceiling). vm.prank(0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a); machine.setTrackedCollection(address(heavy)) succeeds. The same implementation behind a Beacon + BeaconProxy (SLOAD beacon, STATICCALL implementation(), DELEGATECALL): cold supportsInterface(0x80ac58cd) ~31,580 gas and returns true; machine.setTrackedCollection(address(proxy)) reverts InvalidCollection(proxy). Expected: both deployments of the same compliant ERC-721 accepted (or both rejected). Actual: direct accepted, proxied rejected.","severity":"info","snippet":"    uint256 private constant INTERFACE_GAS_LIMIT = 30_000;","title":"ERC-165 probes forward exactly the 30,000-gas ERC-165 ceiling with no margin, so a compliant implementation near the ceiling is accepted directly but rejected behind a proxy (unchanged advisory)"},{"citation":"resolved","description":"Carried over unchanged from round one (id c2f9e38dc1c583f8e680e3fc51463bfe37a2923f4461a87168037aa7749544e6); merges audit_economics finding 6487f596. docs/reference/vessel.verified.sol.txt imports plain OpenZeppelin 5.0.2 ERC721 without ERC721Enumerable and defines no totalSupply(). setTrackedCollection requires a successful exactly-32-byte totalSupply() reply (lines 48-49), so the Vessel at 0xECb92Cc7112b80A2234936315BbB493fb48d1463 is rejected with InvalidCollection. This matches the brief (totalSupply() is the mandated read) and is not a contract defect; README 'Collection requirements' and docs/deployment.md 'Choose or change the collection' state the rule generically but never name the Vessel, so the owner's most likely first Etherscan attempt reverts without explanation. Documentation-only, not blocking.","line":48,"path":"src/SelloutMachine.sol","reproduction":"Mainnet fork at block >= 26200148: vm.prank(0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a); machine.setTrackedCollection(0xECb92Cc7112b80A2234936315BbB493fb48d1463). Vessel answers supportsInterface(0x01ffc9a7)=true, (0xffffffff)=false, (0x80ac58cd)=true, then the staticcall to totalSupply() (selector 0x18160ddd) hits no function and reverts with empty data, so _readWord returns valid=false. Expected by a reader of the docs: either the Vessel is tracked or the docs say it cannot be. Actual: revert InvalidCollection(0xECb92Cc7112b80A2234936315BbB493fb48d1463), undocumented.","severity":"info","snippet":"        (bool valid,) = _readWord(newCollection, abi.encodeWithSelector(TOTAL_SUPPLY), SUPPLY_GAS_LIMIT);","title":"The Vessel itself cannot be the tracked collection (no totalSupply()); the collection requirements do not say so (unchanged advisory)"}],"hash":"060cf9e3c452e2a985cd1d4232f5b7ef7bf6f147e322728bcfbcdf6b8ddeea02","nodeId":"bad50aca-4728-488f-9a89-8c0c6e07091d","outcome":"completed","summary":"The review is complete and written to the findings file. Nothing blocks this launch.\n\n**Settled finding (fixed).** The medium finding about the manifest passing `$owner` is closed. launch.json now writes the brief-stated owner address as a static constructor argument. I reproduced the author's check with a scratch test: constructing with that exact argument gives the named wallet exclusive authority over setTrackedCollection, and an unrelated wallet is rejected. The manifest is schema-valid with one argument for the one constructor parameter and notes well under the limit.\n\n**Advisories carried over unchanged.** The contract source did not change between rounds, so both info items still reproduce and remain non-blocking:\n- ERC-165 probes forward exactly the 30,000-gas ceiling, so a heavy but compliant implementation behind a proxy is rejected while the direct deployment is accepted.\n- The Vessel itself has no totalSupply and is rejected as a tracked collection, and the docs never say so.\n\n**Residual documentation drift.** README and docs/deployment.md still describe the constructor argument as `$owner`. The manifest notes state the static address supersedes them, and the author could not edit those files within the manifest assignment's write budget. I recorded this inside the settlement entry rather than as a new finding.\n\n**Verification run.** The full offline suite passed with 68 tests and no failures under the pinned fuzz seed. The protected floor harness is not shipped in the tree, so I checked its properties by hand: single nonpayable address constructor with no external calls, 1,555 creation bytes, 1,384 runtime bytes, and no DELEGATECALL, CALLCODE, CREATE or SELFDESTRUCT in the runtime. The slither output was empty and the aderyn large-literal lead is cosmetic, so neither produced a finding.\n\nCoverage marks the one listed entry point, setTrackedCollection, as holding, plus rows for the constructor, payload and count functions, and the manifest. Scratch tests were removed and the tree has no other changes.","treeHash":null,"usage":{"cachedInputTokens":603122,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":10251,"runtime":"claude","turns":11,"wallClockMs":211524}},{"artifacts":[],"attempt":1,"bundleHash":"706a8559bfc7da58a62f7a37b0aa543cbfa376885b0960716993eb9c7597fcca","device":"93678b4d542094a9","findings":[],"hash":"1324fd05c51a407d6fcff5c4eb29c83e02c0d780c05b124bbfc075720f9bca95","nodeId":"4af66160-169e-4e0e-b09a-0cf808ad642b","outcome":"completed","summary":"Created [launch.json](/home/imd/.identitymd/work/c5b6c8d8-0cfe-4109-9449-38866724eebc/4af66160-169e-4e0e-b09a-0cf808ad642b/launch.json) for `SelloutMachine` with `constructorArgs: [\"$owner\"]`.\n\n- Manifest structure and compiled constructor ABI checked.\n- `forge build` passed.\n- All 46 local tests passed using the required fuzz seed.\n- All 11 mainnet-fork tests passed at block 26,200,148.\n\nOnly `launch.json` is changed for submission. Deployment and publication remain with the launch pipeline; Craft attachment remains manual.","treeHash":"2ca2e0de064ba59682cb57ab16729c2dcc7f7236","usage":{"cachedInputTokens":290432,"inputTokens":34669,"model":"gpt-6-astra","outputTokens":3417,"runtime":"codex","turns":3,"wallClockMs":111851}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f96a0c89c039c22a","findings":[],"hash":"15e17df465cf3f2fd0753db1068921cd8201f14cf487a4b75a8fa09c7d3dfe16","nodeId":"d6dbb7d3-79bd-4c2a-9691-91b1e04bf046","outcome":"completed","summary":"I found no math defects I could back up in `src/SelloutMachine.sol`, so `.imd-findings.json` has an empty findings list plus coverage rows. I read the code and wrote no test files; the existing tests and the mainnet-fork tests were not run in this review.\n\n**What I checked and why it holds:**\n- **`setTrackedCollection(address)`** (the only entry point): every check runs before anything is stored. It requires the owner as caller, then a non-zero address that has code, the ERC-165 and ERC-721 interface checks, and a `totalSupply()` reply that is exactly one 32-byte word. There is no arithmetic on this path.\n- **Payload bounds:** the count is capped at 10,000. The 32-byte fill loop only runs while `cursor + 31 < end`, so its last write ends at or before the payload's end. A byte-by-byte loop handles the remaining 0–31 bytes. So the payload is always exactly 10,000 bytes and nothing is written outside it.\n- **Pixel boundaries:** byte `i` is black (`0x00`) exactly when `i < count`. This is exact for the brief's examples: 0, 1, 100, 101, 5,000, 9,999 and 10,000.\n- **`mintProgress`:** it returns the capped count directly. One NFT is one basis point of 10,000, so there is no division and no rounding.\n- **Bad supply replies:** a failed call, or a reply that is not exactly 32 bytes, returns 0 (all white). A huge value, including the largest possible `uint256`, is capped at 10,000 without overflowing.\n\n**Two things I noted but did not report**, because neither has a concrete failure against the brief:\n- If a collection's `totalSupply()` needs more than the 100,000 gas allowed for the call, or the caller supplies too little gas, the grid silently shows all white instead of reverting.\n- A collection that returns more than 32 bytes from `totalSupply()` is treated as broken, which is the intended \"reject malformed replies\" behaviour.\n\nThe static-analysis lead (aderyn's \"large numeric literal\" at line 10) is only about how `10_000` is written as a constant. It has no effect on behaviour.","treeHash":null,"usage":{"cachedInputTokens":107183,"inputTokens":6,"model":"claude-opus-5-5","outputTokens":1632,"runtime":"claude","turns":3,"wallClockMs":22968}},{"artifacts":[],"attempt":2,"bundleHash":null,"device":"575a41a8798743c2","findings":[],"hash":"2f539dff3918857ff1ea193e29d347bade0fb353295819cd284af9f091acc17b","nodeId":"7b256329-361f-466d-b619-996aaf8408d4","outcome":"failed","summary":"codex-devin wrapper: unhandled option --strict-config","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":"gpt-6-astra","outputTokens":0,"runtime":"codex","turns":0,"wallClockMs":39}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e8f1969b1b8ff9d4","findings":[],"hash":"2f7775de1de30acc465c3bfeb0f3f4ad1c3777edd133e879daa4b6c95065e805","nodeId":"4af66160-169e-4e0e-b09a-0cf808ad642b","outcome":"failed","summary":"codex-devin wrapper: unhandled option --strict-config","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":"gpt-6-astra","outputTokens":0,"runtime":"codex","turns":0,"wallClockMs":39}},{"artifacts":[],"attempt":1,"bundleHash":"84260ef6554379587db52fcbddecf1ac0b38f283f934aad7bfaffa9e42a8b7c7","device":"004eae350f695d24","findings":[],"hash":"36cd4f199d916fe94425ff77a27af3dc9c7e9ebab79e7e1aaf3fd460d34b7f48","nodeId":"e669b695-467b-4dbf-ab8f-ff87294fecf7","outcome":"completed","summary":"Implemented and documented in [README.md](/root/nft3/.identitymd/work/c5b6c8d8-0cfe-4109-9449-38866724eebc/e669b695-467b-4dbf-ab8f-ff87294fecf7/README.md).\n\n- Build and formatting checks passed.\n- 46 local tests and 11 actual mainnet-fork tests passed.\n- Independent AI security review found no reproduced vulnerability.\n- Deployment handoff, gas benchmarks, and Etherscan instructions included.\n\nVessel’s existing SVG renderer requires 422–471 million gas, which may exceed RPC limits.\n\nMainnet deployment, Etherscan verification, and GitHub publication remain pending IMD’s launch pipeline. No live Craft attachment was made.","treeHash":"fb5393f2ad55f82e369f042a70cb500a14ad097f","usage":{"cachedInputTokens":2863104,"inputTokens":107965,"model":"gpt-6-astra","outputTokens":35053,"runtime":"codex","turns":8,"wallClockMs":1085361}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"5c1e4764d4e20ef5","findings":[{"citation":"resolved","description":"Merged from audit_permissions and audit_flow (same root cause). SelloutMachine.owner is immutable (src/SelloutMachine.sol:17) and there is no transfer or renounce path, so the single constructor argument is the only chance to bind configuration authority. The brief names the owner explicitly: 0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a. The pinned evm-contracts launch recipe says a $owner placeholder resolves to 'the wallet that paid for the launch, or the owner the request's owner field names' and that 'an owner address the brief itself states for a contract is written as that static address instead of $owner'. launch.json line 6 nevertheless writes $owner, and docs/deployment.md line 16 ('| Constructor argument source | IMD `$owner` |') and README.md line 22 instruct the same. The manifest notes assert that $owner 'resolv[es] to 0xCcf0...', but nothing in the manifest or in any worker check enforces that: the protected Owners floor only rejects the factory or IMD as owner, so a paying wallet W != 0xCcf0... passes every check and is deployed as the permanent owner. The named wallet then can never call setTrackedCollection, and the only remedy is redeploying and re-pointing Craft #10000. Writing the static address in constructorArgs (as the recipe directs for a brief-stated owner) removes the dependency on how $owner resolves while still satisfying the brief's 'assign exclusive configuration authority to 0xCcf0...'. Fix: launch.json constructorArgs: [\"0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a\"], and align docs/deployment.md line 16 and README.md line 22.","line":6,"path":"launch.json","reproduction":"State: launch.json as in the tree ({\"contract\":\"SelloutMachine\",\"constructorArgs\":[\"$owner\"]}) and a launch whose paying wallet / request owner field resolves $owner to W != 0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a. The factory runs constructor(W); Owners.protected passes because W is neither the factory nor IMD. Then: vm.prank(0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a); machine.setTrackedCollection(validCollection). Expected per brief: the named wallet has exclusive configuration authority. Actual: revert Unauthorized() (src/SelloutMachine.sol:41) permanently; machine.owner() == W and no function can change it. Local equivalent: m = new SelloutMachine(W); vm.prank(0xCcf0...); vm.expectRevert(SelloutMachine.Unauthorized.selector); m.setTrackedCollection(c). With the static address in constructorArgs this mis-instantiation is impossible regardless of who paid.","severity":"medium","snippet":"      \"constructorArgs\": [\"$owner\"]","title":"Manifest passes $owner although the brief states the owner address; a $owner that resolves to any other wallet sets an unrecoverable wrong immutable owner"},{"citation":"resolved","description":"From audit_permissions; reproduced. setTrackedCollection (lines 42-46) requires three supportsInterface() replies, each made via _readWord with INTERFACE_GAS_LIMIT = 30,000 forwarded gas, while totalSupply() gets 100,000. ERC-165 lets an implementation spend up to 30,000 gas in supportsInterface(). When such an implementation sits behind a beacon/EIP-1967 proxy, the proxy's own SLOAD, STATICCALL to the beacon and DELEGATECALL come out of the same 30,000, the callee runs out of gas, _supports() returns false and the setter reverts InvalidCollection. Strictly the proxied contract as a whole then exceeds the ERC-165 ceiling, so the Machine is not violating the standard, and mainstream ERC-721 implementations (OpenZeppelin, ERC721A, Manifold) spend well under 5k here, so the precondition is rare. Owner-only, no exploit; recorded as a boundary note. A modest margin (e.g. 50,000 or SUPPLY_GAS_LIMIT) for the three probes would keep the return-data protections unchanged and remove the asymmetry.","line":12,"path":"src/SelloutMachine.sol","reproduction":"Scratch Foundry test (test/scratch/Repro.t.sol, ReproTest.test_proxiedHeavyERC165): HeavyERC165.supportsInterface() runs a 95-iteration keccak loop then returns true for 0x01ffc9a7/0x80ac58cd and false otherwise; direct cold call measured 21,423 gas (under the ERC-165 ceiling). vm.prank(0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a); machine.setTrackedCollection(address(heavy)) succeeds. The same implementation behind a Beacon + BeaconProxy (SLOAD beacon, STATICCALL implementation(), DELEGATECALL): cold supportsInterface(0x80ac58cd) measured 31,580 gas and returned true; machine.setTrackedCollection(address(proxy)) reverts InvalidCollection(proxy). Logged: 'direct heavy gas 21423', 'direct accepted', 'proxied heavy gas 31580 true true', 'proxied accepted false'. Expected: both deployments of the same compliant ERC-721 accepted (or both rejected). Actual: direct accepted, proxied rejected.","severity":"info","snippet":"    uint256 private constant INTERFACE_GAS_LIMIT = 30_000;","title":"ERC-165 probes forward exactly the 30,000-gas ERC-165 ceiling with no margin, so a compliant implementation near the ceiling is accepted directly but rejected behind a proxy"},{"citation":"resolved","description":"From audit_economics; verified against the saved reference source. docs/reference/vessel.verified.sol.txt imports plain OpenZeppelin 5.0.2 ERC721 (line 12) without ERC721Enumerable, and the file defines no totalSupply(). setTrackedCollection requires a successful exactly-32-byte totalSupply() reply (src/SelloutMachine.sol:48-49), so the Vessel at 0xECb92Cc7112b80A2234936315BbB493fb48d1463, the one 10,000-token collection every reader of the brief knows, is rejected with InvalidCollection. This matches the brief (totalSupply() is the mandated read) and is not a contract defect; README line 40 states the rule generically but never names the Vessel, and docs/deployment.md 'Choose or change the collection' does not either, so the owner's most likely first Etherscan attempt reverts without explanation. Documentation-only: name the Vessel (and other totalSupply-less ERC-721s such as Manifold creator cores and CryptoPunks) as incompatible in README 'Collection requirements' and docs/deployment.md step 1.","line":40,"path":"README.md","reproduction":"Mainnet fork at block >= 26200148: vm.prank(0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a); machine.setTrackedCollection(0xECb92Cc7112b80A2234936315BbB493fb48d1463). Vessel answers supportsInterface(0x01ffc9a7)=true, (0xffffffff)=false, (0x80ac58cd)=true, then the staticcall to totalSupply() (selector 0x18160ddd) hits no function and reverts with empty data (the saved source has no totalSupply and no fallback), so _readWord returns valid=false. Expected by a reader of the docs: either the Vessel is tracked or the docs say it cannot be. Actual: revert InvalidCollection(0xECb92Cc7112b80A2234936315BbB493fb48d1463), undocumented.","severity":"info","snippet":"`totalSupply()` is optional in basic ERC-721; an otherwise valid NFT without that method is incompatible.","title":"The Vessel itself cannot be the tracked collection (no totalSupply()); the collection requirements do not say so"}],"hash":"3a0eba7eff7802e7dad09eebad9d2ca5b3a7f1835617a04030b22151093cf592","nodeId":"bad50aca-4728-488f-9a89-8c0c6e07091d","outcome":"completed","summary":"The review is complete. The findings file is written at the repository root, the working tree has no other changes, and the scratch tests were removed.\n\n**Outcome:** the contract itself holds. All 65 offline tests pass, the payload and pixel logic trace correctly against the saved Vessel renderer, and the single state-changing entry point is sound. One substantive finding survives, in the manifest rather than the Solidity.\n\n**Findings kept (3):**\n\n- **Medium, `launch.json` line 6.** The manifest writes `$owner` even though the brief states the owner address. The pinned launch recipe says a brief-stated owner is written as the static address. The owner is immutable with no transfer path, and the protected Owners floor only rejects the factory or IMD, so a `$owner` that resolves to the paying wallet deploys a permanently wrong owner. The two specialist reports on this were merged into one. The fix is the static address in constructorArgs plus matching text in the deployment doc and README.\n- **Info, `src/SelloutMachine.sol` line 12.** The three ERC-165 probes forward exactly the 30,000-gas ceiling with no margin. I reproduced the specialist's case: the same implementation is accepted directly at 21,423 gas and rejected behind a beacon proxy at 31,580 gas. Strictly the proxied contract exceeds the ERC-165 ceiling, so this is a boundary note, not a defect.\n- **Info, `README.md` line 40.** The Vessel itself has no `totalSupply()` in its verified source, so it is rejected as a tracked collection, and the docs never say so.\n\n**Dropped:** the audit_flow claim that a gas-starved `craftToPayload` returns an all-white image. My scratch run showed the starved payload call reverts at every budget below the supply cost. Only `mintedCount` returns zero there, which the README already documents as the failure policy.\n\n**Coverage:** `setTrackedCollection(address)` holds. Additional rows record the constructor and manifest (finding 1), payload generation, supply reads, the staticcall helper, and factory deployability, all holding. The static-analysis line about large numeric literals is style only and was left out.","treeHash":null,"usage":{"cachedInputTokens":944465,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":21184,"runtime":"claude","turns":28,"wallClockMs":353524}},{"artifacts":[],"attempt":3,"bundleHash":"f697dfe0a0c098c4a917233c791f4f8c5f246f61525e382bd6f751cc68d0ed6c","device":"294694a214b6ec04","findings":[],"hash":"7254c2dedecf0095ec14b18f24bf74f5d7baa8db6c6195e11e49b89823f2e3f3","nodeId":"7b256329-361f-466d-b619-996aaf8408d4","outcome":"completed","summary":"Added 19 tests, modifying only `test/`.\n\n- Build passes.\n- 65 offline tests pass.\n- 11 actual-mainnet fork tests pass.\n- Invariant campaign passes 16,384 randomized actions.\n\nNo application defect found. [Review and gas results](test/REVIEW.md) document the initial RPC failure and the existing renderer’s 422–471 million gas cost.\n\nNo deployment or mainnet attachment performed.","treeHash":"37082877a786d410aabe7bc8c2bc30e165a922d4","usage":{"cachedInputTokens":1942016,"inputTokens":101099,"model":"gpt-6-astra","outputTokens":23384,"runtime":"codex","turns":7,"wallClockMs":687030}},{"artifacts":[],"attempt":1,"bundleHash":"aa5905353f14f9827ac74465ead77d044dcaf5f2fa396076ec5d2ad5178e5773","device":"f009de0ce52c7b3a","findings":[],"hash":"7d479444392832d2d87c351ef9cb63866061ee1f6466116cca7b70420a9bda0b","nodeId":"4af66160-169e-4e0e-b09a-0cf808ad642b","outcome":"completed","summary":"The revision is complete.\n\n**Finding reproduced and fixed.** A scratch test confirmed that deploying `SelloutMachine` with any constructor argument other than the brief-named wallet permanently locks that wallet out of `setTrackedCollection`, since the owner is immutable with no transfer path. The pinned recipe directs that an owner address stated in the brief be written as a static address rather than `$owner`.\n\n**Change made.** Only launch.json changed. Its single constructor argument is now the static address `0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a`, and the notes explain why the static form is used and state that it supersedes the `$owner` wording in README.md and docs/deployment.md. Those two docs are outside the paths this assignment may modify, so they were left alone and the response file says so.\n\n**Verification.**\n\n| Check | Result |\n|---|---|\n| Manifest schema (kind, contracts, notes only; notes length) | ok |\n| `forge build` | success, lint warnings only |\n| `forge test` with the pinned fuzz seed | 48 passed, 0 failed |\n| `git diff --stat` | launch.json only |\n\nThe answer to the finding is recorded in `.imd-responses.json` with verdict `fixed`. The scratch test lives in test/scratch/ and is gitignored, so nothing else enters the submission.","treeHash":"1082ad16afe83a57819fd7d2ce6bcec70cdbb4cb","usage":{"cachedInputTokens":368217,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":4935,"runtime":"claude","turns":10,"wallClockMs":110968}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"cdeffb0cd839cbf7","findings":[{"citation":"resolved","description":"setTrackedCollection requires a successful 32-byte totalSupply() reply. The deployed Vessel (0xECb92Cc7112b80A2234936315BbB493fb48d1463) is a plain OpenZeppelin v5 ERC721 (docs/reference/vessel.verified.sol.txt line 12 and 40) without ERC721Enumerable, so totalSupply() is not a function on it and the call reverts. Live check at block 26200258: supportsInterface(0x01ffc9a7)=true, supportsInterface(0xffffffff)=false, supportsInterface(0x80ac58cd)=true, totalSupply() -> 'execution reverted'. The machine therefore rejects the Vessel with InvalidCollection(0xECb9...). This matches the brief (totalSupply() is the required read) and is not a contract defect, but the brief describes 'a configurable 10,000-token NFT collection' and the Vessel is exactly that, so the owner may try it first through Etherscan and see an unexplained revert. README 'Collection requirements' and docs/deployment.md 'Choose or change the collection' should state explicitly that the Vessel contract and other ERC-721s without totalSupply() (Manifold creator contracts, Art Blocks cores, CryptoPunks) are rejected. All thirteen major ERC-721 collections I checked live (BAYC, Azuki, Doodles, Pudgy Penguins, Milady, CloneX, Moonbirds, Cool Cats, World of Women, Nouns, Autoglyphs, Chromie Squiggle, Meebits) pass all four gates with totalSupply() costing roughly 2,700-4,800 gas, so the 30,000/100,000 budgets are not a practical obstacle for standard collections.","line":48,"path":"src/SelloutMachine.sol","reproduction":"Mainnet (or fork at block >= 26200148): owner 0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a calls SelloutMachine.setTrackedCollection(0xECb92Cc7112b80A2234936315BbB493fb48d1463). Expected by a reader of the brief: the Vessel's own mint progress is tracked. Actual: revert InvalidCollection(0xECb92Cc7112b80A2234936315BbB493fb48d1463) because the staticcall to totalSupply() fails (cast call 0xECb9... 'totalSupply()(uint256)' returns 'execution reverted, data: 0x'). Documentation-only fix: list this exclusion in README.md 'Collection requirements and failure policy' and docs/deployment.md step 1.","severity":"info","snippet":"        (bool valid,) = _readWord(newCollection, abi.encodeWithSelector(TOTAL_SUPPLY), SUPPLY_GAS_LIMIT);","title":"The Vessel itself (an obvious 10,000-token candidate) cannot be the tracked collection; docs do not say so"}],"hash":"b568ff18a18b5d00ff7c6e6db0988d18053d57a9554b21abc245c4ae3047616e","nodeId":"b726bcaa-9141-4bba-b154-69d3d3fbd1ea","outcome":"completed","summary":"Review complete. The findings file is written and validated, the scratch directory is removed, and the working tree holds no other changes.\n\n**Outcome.** No defect in the economic, invariant, or flow-gap area was found in `src/SelloutMachine.sol`. I report one informational documentation gap and nine coverage rows.\n\n**What I checked against the three guides**\n\n- **Economic Security.** The contract holds no value, has no payable path, and its only dependency is a view read of the tracked collection's totalSupply. Every dependency failure mode (revert, short or long reply, return or revert bomb, infinite loop, state write, removed code) degrades to a white image and recovers automatically. Nothing can be stranded or extracted.\n- **Invariant.** Pixel i is black exactly when i is below the clamped supply, the payload is always 10,000 bytes, the ABI padding stays zero, and progress in basis points is an identity with no rounding. I confirmed the renderer places byte i at column i mod 100, row i div 100, with grayscale mode 0 as rgb(v,v,v).\n- **Flow Gap.** I probed three seams with scratch tests. An underfunded outer call reverts rather than returning a wrong image. A delegatecall proxy collection selects and reads correctly under the cold 30k and 100k budgets. A collection with an O(n) totalSupply loop falls to white once past the budget, which is the documented limitation and matches no common ERC-721 implementation.\n\n**Live evidence.** Thirteen major mainnet ERC-721 collections (BAYC, Azuki, Doodles, Pudgy Penguins, Milady, CloneX, Moonbirds, Cool Cats, World of Women, Nouns, Autoglyphs, Chromie Squiggle, Meebits) pass all four selection gates with totalSupply reads of roughly 2,700 to 4,800 gas.\n\n**The one finding (info).** The Vessel itself is a plain OpenZeppelin v5 ERC721 without totalSupply, so the owner calling setTrackedCollection with the Vessel address reverts with InvalidCollection. This follows the brief, but neither the README nor the deployment guide says that the Vessel, Manifold, Art Blocks, or CryptoPunks contracts are rejected. A sentence in each would prevent a confusing first Etherscan attempt.\n\n**Not reached.** No mainnet-fork run was executed by me. I relied on the integration test source, the saved verified Vessel and renderer code, and live read-only calls to the Vessel for the selection gates.","treeHash":null,"usage":{"cachedInputTokens":1071459,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":31199,"runtime":"claude","turns":41,"wallClockMs":503112}},{"artifacts":[],"attempt":2,"bundleHash":null,"device":"f801e761d7a1ec94","findings":[],"hash":"b63785ec46746c97570808ace7ca6b2eaff0e6dc7fd75bce960fda5c7b17aeb5","nodeId":"4af66160-169e-4e0e-b09a-0cf808ad642b","outcome":"failed","summary":"codex-devin wrapper: unhandled option --strict-config","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":"gpt-6-astra","outputTokens":0,"runtime":"codex","turns":0,"wallClockMs":39}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"6b0a28df3d585600","findings":[{"citation":"resolved","description":"SelloutMachine.owner is immutable and there is no transfer or renounce path (src/SelloutMachine.sol:17, 29-32), so the constructor argument is the only chance to bind configuration authority. The launch recipe supplied with this task says a `$owner` placeholder is 'the wallet that paid, or the owner the request named' and that 'an owner address the brief itself states for a contract is written as that static address instead of $owner'. The brief states the owner (0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a), but docs/deployment.md line 16 and README.md line 22 instruct the manifest step to write `$owner`. If the manifest author follows the handoff and the request's owner field is empty or differs from the paying wallet, `$owner` resolves to another address; the deployed Machine then rejects every setTrackedCollection call from 0xCcf0... with Unauthorized() forever and must be redeployed and re-attached. The code itself is correct; this is a handoff instruction that conflicts with the pinned recipe for a value that cannot be corrected after deployment. Fix: state in the handoff that the manifest's constructorArgs entry is the static address 0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a (per the recipe for a brief-stated owner), or at minimum that `$owner` may only be used after confirming it resolves to exactly that address.","line":16,"path":"docs/deployment.md","reproduction":"State: launch.json written as {\"contract\":\"SelloutMachine\",\"constructorArgs\":[\"$owner\"]} following docs/deployment.md, with the launch paid by wallet W != 0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a and no owner named in the request's owner field. Factory runs constructor(W). Then: vm.prank(0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a); machine.setTrackedCollection(validCollection) -> reverts Unauthorized() (src/SelloutMachine.sol:41). Expected: the stated owner configures the Machine. Actual: only W can, permanently. Equivalent local check: new SelloutMachine(W); vm.prank(0xCcf0...); setTrackedCollection(...) reverts.","severity":"low","snippet":"| Constructor argument source | IMD `$owner` |","title":"Deployment handoff tells the manifest to pass `$owner` although the brief states the owner; a `$owner` that resolves to the paying wallet makes the immutable owner wrong and unrecoverable"},{"citation":"resolved","description":"By design every failed supply read (revert, malformed reply, out of gas inside the callee) falls back to count 0 and renders white (README 'failure policy'). One consequence is not documented: the callee's out-of-gas can be caused by the *caller's* gas budget rather than by the collection. _readWord forwards min(100000, 63/64 of remaining gas) (line 104). If the outer call carries slightly less gas than the collection's totalSupply needs, the staticcall fails from starvation, the 1/64 remainder is enough to build the 10,000-byte payload, and the call succeeds with a fully white grid that is indistinguishable from supply 0. With cheap collections (ERC721A, OZ Enumerable: a few thousand gas) the window is too small to finish the payload, so this only matters for collections whose totalSupply costs tens of thousands of gas. Vessel's renderer always carries far more gas, so the on-chain image path is unaffected; a direct eth_call to craftToPayload or mintedCount with an explicit low gas value is the only trigger. No code change is required; documenting that a reader must not cap gas near SUPPLY_GAS_LIMIT (or that mintedCount() == 0 can mean 'read failed') is enough.","line":63,"path":"src/SelloutMachine.sol","reproduction":"Collection whose totalSupply() burns ~85,000 gas then returns 5000 (ERC-165 compliant). Owner selects it (passes: 100,000 budget suffices). Then address(machine).staticcall{gas: g}(abi.encodeCall(SelloutMachine.craftToPayload,(10000))) for g in 86,000..95,000 -> returns success with payload[0] == 0xff (white) although supply is 5000; mintedCount() with gas 87,000..98,000 -> success, returns 0. With gas >= 100,000 the same calls return the correct 5,000 black pixels / 5000. Expected by a reader: either the correct count or a revert; actual: a plausible but wrong all-white image. Reproduced with a scratch Foundry test (loop over gas budgets, see description).","severity":"info","snippet":"        if (!valid) return 0;","title":"A gas-starved craftToPayload/mintedCount call returns an all-white image or zero instead of reverting when the caller's budget lands just under the collection's totalSupply cost"}],"hash":"b65fc6996363e81bc6b677c510b281f2671ddc3766435f41ec5479e40886ec7f","nodeId":"d7405b7f-6d0e-41bb-971e-7108428190ab","outcome":"completed","summary":"Review complete. The findings file is written and validated, the scratch tests are removed, and the tree is otherwise unchanged.\n\n**Outcome: no exploitable defect in `SelloutMachine.sol`.** I traced the Execution Trace, Periphery and First Principles guides against the contract and found the control flow sound. Two low-impact items are recorded in `.imd-findings.json`.\n\n**What I verified**\n\n- **setTrackedCollection** checks the owner first, then zero address, code presence, three bounded ERC-165 reads and one 32-byte `totalSupply` read, all via STATICCALL, before a single state write and the event. A failed selection leaves the previous collection intact, and an owner-contract callback cannot re-enter from the static context.\n- **craftToPayload** clamps the count before using it as a memory offset. Both fill loops stay inside the 10,000-byte buffer at every alignment, including counts 0, 9968, 9969 and 10000. The ABI return is exactly 10,016 padded bytes.\n- **The read helper** copies at most one word into scratch space, requires success and an exact 32-byte reply, and compares booleans canonically. I added a probe confirming a 32-byte revert reads as zero and a same-address reselect emits the event.\n- **Vessel periphery**: Vessel routes Craft #10000 straight to the attached Machine with tokenId 10000. The renderer builds a 100x100 grid, places byte i at (i%100, i/100) and writes rgb(v,v,v) in grayscale mode, so 0x00 is black and 0xff is white. The renderer calls `name()` inside try/catch.\n- **Live state** through the mainnet endpoint: the lock clock has not started, the stated owner holds Craft #10000, and no delegate is set.\n- **Fork re-run** against the real Vessel at block 26,200,148: the four routing and payload tests plus the SVG-101 render passed with gas figures identical to the recorded run. The default suite of 46 tests also passed.\n\n**Findings recorded**\n\n1. **Low, docs/deployment.md line 16.** The handoff tells the manifest step to pass `$owner`, while the pinned launch recipe says a brief-stated owner is written as the static address. The owner is immutable with no transfer path, so a `$owner` resolving to a different paying wallet would leave the intended wallet locked out permanently.\n2. **Info, src/SelloutMachine.sol line 63.** A caller whose gas budget sits just under an expensive collection's `totalSupply` cost gets a successful all-white payload rather than a revert. Reproduced with an 85k-gas collection and caller budgets of 86k to 95k. This follows from the documented white fallback and needs documentation only.\n\n**Coverage**: 10 rows, including the single listed entry point as `holds`. One row is `unreached`: I did not survey mainnet collections for ones whose `supportsInterface(0xffffffff)` reverts or exceeds 30k gas, and I did not re-run the six remaining SVG fork tests beyond the one I chose.","treeHash":null,"usage":{"cachedInputTokens":1624386,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":40123,"runtime":"claude","turns":46,"wallClockMs":605191}},{"artifacts":[],"attempt":3,"bundleHash":null,"device":"d2bae9a4a05e8265","findings":[],"hash":"da74e5c0a7a38ec09aeef584b5c6da28d2fed17b2c2e0af235365cd7cd872b91","nodeId":"4af66160-169e-4e0e-b09a-0cf808ad642b","outcome":"failed","summary":"codex-devin wrapper: unhandled option --strict-config","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":"gpt-6-astra","outputTokens":0,"runtime":"codex","turns":0,"wallClockMs":42}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"789312fc56d3f446","findings":[{"citation":"resolved","description":"Asymmetry between the selection gate and the read path. setTrackedCollection() (lines 42-46) requires three supportsInterface() replies, each made through _readWord() with INTERFACE_GAS_LIMIT = 30,000 forwarded gas, while the only call that matters at render time, totalSupply(), gets 100,000. ERC-165 allows an implementation to spend up to 30,000 gas inside supportsInterface(). When such a collection sits behind a beacon or EIP-1967 proxy, the proxy's own SLOAD of the implementation slot, the (beacon) STATICCALL and the DELEGATECALL are paid out of the same forwarded 30,000, so the callee runs out of gas, the staticcall returns false, _supports() returns false and the setter reverts InvalidCollection. The identical implementation deployed without a proxy is accepted. The owner is the only caller, so there is no exploit; the impact is that the brief's 'owner must be able to change the tracked NFT collection anytime' is not met for a standards-compliant collection of this shape, and the owner cannot work around it without redeploying the Machine and re-attaching Craft #10000 (which may be locked). Most mainstream ERC-721 implementations (OpenZeppelin, ERC721A, Manifold) spend well under 5k in supportsInterface, so the precondition is uncommon; this is a boundary/asymmetry note, not a permission bypass. Suggested minimal fix that preserves the design: give the three interface probes a modest margin above the ERC-165 ceiling (e.g. 50,000) or reuse SUPPLY_GAS_LIMIT, keeping the 32-byte copy and exact-length checks so the bomb protections are unchanged.","line":12,"path":"src/SelloutMachine.sol","reproduction":"Scratch Foundry test (test/scratch/Gates.t.sol, GatesTest.test_heavyButCompliantERC165): 1) deploy OZLikeEnumerable subclass HeavyERC165 whose supportsInterface() runs a 95-iteration loop before returning true for 0x01ffc9a7/0x80ac58cd and false for 0xffffffff; direct cold call measures 21,294 gas (under the ERC-165 30k rule). 2) vm.prank(0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a); machine.setTrackedCollection(address(heavy)) -> succeeds. 3) Deploy Beacon(heavy) and a BeaconProxy that SLOADs the beacon, STATICCALLs implementation(), then DELEGATECALLs; cold call to proxy.supportsInterface(0x80ac58cd) measures 31,284 gas and returns true. 4) vm.prank(owner); machine.setTrackedCollection(address(proxy)) -> reverts InvalidCollection(proxy). Expected: both the direct and the proxied deployment of the same compliant ERC-721 are accepted (or both rejected). Actual: direct accepted, proxied rejected. Logged output: 'heavy supportsInterface gas (cold, direct): 21294', 'direct heavy accepted', 'heavy supportsInterface gas (cold, via beacon proxy): 31284', 'proxied heavy accepted: 0'. Control: a trivial OpenZeppelin-shaped implementation behind the same beacon proxy (10,878 gas cold) is accepted, so the gate only fails near the ceiling.","severity":"low","snippet":"    uint256 private constant INTERFACE_GAS_LIMIT = 30_000;","title":"Selection gate forwards exactly the ERC-165 30k ceiling, so a compliant collection behind a proxy can be rejected while the same implementation is accepted directly"},{"citation":"resolved","description":"Access-control at the deployment boundary. SelloutMachine.owner is immutable, there is no transfer or renounce path (by design), and the constructor only rejects address(0) (src/SelloutMachine.sol:30). The brief names the owner explicitly: 0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a. The launch recipe this task is governed by says '$owner is the wallet that paid for the launch, or the owner the request's owner field names' and 'An owner address the brief itself states for a contract is written as that static address instead of $owner.' docs/deployment.md (line 16, and README.md line 22 'IMD constructor argument | $owner') tell the manifest step to use $owner instead of the static address. If the launch's owner field is unset or differs from the brief (e.g. the paying wallet is a different address), $owner resolves to that wallet, the Machine is deployed with the wrong immutable owner, and the intended owner can never call setTrackedCollection; the only remedy is redeploying and re-pointing Craft #10000. No launch.json exists yet, so this is a correctable guidance defect rather than a shipped one, but it is the one place where the otherwise sound permission model can be mis-instantiated. Suggested fix: in docs/deployment.md and README.md, state that constructorArgs must be the static address 0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a (as the recipe requires for a brief-stated owner), and keep the post-deploy owner() check.","line":16,"path":"docs/deployment.md","reproduction":"State: manifest contract entry {\"contract\":\"SelloutMachine\",\"constructorArgs\":[\"$owner\"]} with $owner resolving to any address A != 0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a (for example the paying wallet). Equivalent local reproduction: m = new SelloutMachine(A); then vm.prank(0xCcf0a1307E5e5Ad04E85d94d7f9D400390F0118a); m.setTrackedCollection(validCollection). Expected per brief: the named wallet has exclusive configuration authority. Actual: reverts Unauthorized() (src/SelloutMachine.sol:41) forever, m.owner() == A, and no function exists to correct it. With the static address in constructorArgs the mistake is impossible regardless of who paid.","severity":"low","snippet":"| Constructor argument source | IMD `$owner` |","title":"Deployment docs instruct the manifest to pass $owner although the brief states the owner address; a $owner that resolves to the paying wallet sets an unrecoverable wrong immutable owner"}],"hash":"eaa2a92f09ec37922c1a5cec20b7a8e00104b052c571b2100dcfe1aaa9e2728d","nodeId":"8fa9def1-1350-408d-9a9e-d4f42c018c2d","outcome":"completed","summary":"Review complete. The findings file is written and validated, snippets match the tree, and the scratch directory is removed so no tracked file changed.\n\n**Outcome:** the permission model of `SelloutMachine.sol` holds. No critical, high or medium defect in the Access Control, Trust Gap or Asymmetry areas. Two low findings are recorded in `.imd-findings.json`.\n\n**What I verified**\n- Only the immutable owner can call `setTrackedCollection`. The factory, `tx.origin`, and any callee reached during validation are rejected, and all probes are `STATICCALL`s, so no re-entry or log fabrication is possible.\n- Failed selections are atomic and leave the previous collection intact. There is no transfer, renounce, initializer, proxy, `DELEGATECALL`, `SELFDESTRUCT`, `receive` or `fallback` path.\n- The read path degrades to white on reverts, bombs, short or long replies, state-writing or recursive callees, so Vessel's `tokenURI` never reverts for Craft #10000.\n- Byte encoding and ordering match the mainnet renderer source: grayscale mode writes `rgb(v,v,v)` at `(i % 100, i / 100)`, so 0x00 is black and 0xff is white.\n- The full existing suite passes with 46 tests and 0 failures.\n\n**Findings (both low)**\n1. **Gate asymmetry at the ERC-165 ceiling.** The three interface probes forward exactly 30,000 gas, the ERC-165 allowance for the callee itself. Behind a beacon or EIP-1967 proxy, the proxy's own overhead comes out of that budget. A compliant implementation measuring about 21k gas directly was accepted, but the same implementation behind a beacon proxy measured about 31k and was rejected with `InvalidCollection`. Uncommon precondition, owner-only impact, but it contradicts \"change the collection anytime\" for that class of collection.\n2. **Deployment guidance uses `$owner` for a brief-stated owner.** The launch recipe says a brief-stated owner is written as the static address. If `$owner` resolves to a paying wallet other than the named one, the immutable owner is wrong with no recovery path. This is in the docs and the pending manifest, not in the contract logic.\n\n**Coverage:** the one listed entry point, the constructor, all four view functions, and two trust-assumption rows are recorded. Nothing in my area was left unreached.","treeHash":null,"usage":{"cachedInputTokens":1329760,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":25562,"runtime":"claude","turns":38,"wallClockMs":387014}}],"verification":[{"checks":[{"durationMs":1351,"exitCode":0,"name":"build","output":"Compiling 25 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.28s\nCompiler run successful!\n","passed":true},{"durationMs":895,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/Gas.t.sol:SelloutMachineGasTest\n[PASS] test_gasCollectionReplacement() (gas: 592780)\nLogs:\n  replacement selection call gas (cold): 42156\n\n[PASS] test_gasDeployment() (gas: 393866)\nLogs:\n  CREATE deployment gas (excludes transaction intrinsic gas): 387288\n\n[PASS] test_gasFirstCollectionSelection() (gas: 460324)\nLogs:\n  first selection call gas (cold): 56739\n\n[PASS] test_gasMaliciousSupplyIsBounded() (gas: 200939)\nLogs:\n  gas-bomb fallback payload call gas: 140599\n\n[PASS] test_gasPayload0() (gas: 90890)\nLogs:\n  supply: 0\n  cold payload call gas (includes caller ABI decoding): 45553\n  cold Machine execution gas (callee only): 37669\n\n[PASS] test_gasPayload1() (gas: 110741)\nLogs:\n  supply: 1\n  cold payload call gas (includes caller ABI decoding): 45493\n  cold Machine execution gas (callee only): 37609\n\n[PASS] test_gasPayload100() (gas: 110421)\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\nLogs:\n  supply: 100\n  cold payload call gas (includes caller ABI decoding): 45106\n  cold Machine execution gas (callee only): 37222\n\n[PASS] test_gasPayload10000() (gas: 88348)\nLogs:\n  supply: 10000\n  cold payload call gas (includes caller ABI decoding): 23065\n  cold Machine execution gas (callee only): 15181\n\n[PASS] test_gasPayload101() (gas: 110295)\nLogs:\n  supply: 101\n  cold payload call gas (includes caller ABI decoding): 45046\n  cold Machine execution gas (callee only): 37162\n\n[PASS] test_gasPayload5000() (gas: 99591)\nLogs:\n  supply: 5000\n  cold payload call gas (includes caller ABI decoding): 34309\n  cold Machine execution gas (callee only): 26425\n\n[PASS] test_gasPayload9999() (gas: 88475)\nLogs:\n  supply: 9999\n  cold payload call gas (includes caller ABI decoding): 23125\n  cold Machine execution gas (callee only): 15241\n\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 9.32ms (1.82ms CPU time)\n\nRan 28 tests for test/SelloutMachine.t.sol:SelloutMachineTest\n[PASS] testFuzz_fullUintSupplyRange(uint256) (runs: 256, μ: 126799, ~: 126908)\n[PASS] testFuzz_payloadAgainstReference(uint256) (runs: 256, μ: 2868810, ~: 2869532)\nLogs:\n  Bound result 10050\n\n[PASS] testFuzz_rejectsEveryOtherCraft(uint256) (runs: 256, μ: 11191, ~: 11191)\n[PASS] testFuzz_unauthorizedConfiguration(address) (runs: 256, μ: 38969, ~: 38969)\n[PASS] test_collectionChangeAndEvents() (gas: 3205274)\n[PASS] test_factoryNeverReceivesConfigurationAuthority() (gas: 898290)\n[PASS] test_faultySupplyAfterSelectionFallsBackToWhiteAndRecovers() (gas: 23683894)\n[PASS] test_liveMintsAndBurnsNeedNoMachineTransaction() (gas: 7550250)\n[PASS] test_noTransferRenounceUpgradeOrEtherAcceptance() (gas: 106915)\n[PASS] test_payloadABIHasExactLengthAndZeroPadding() (gas: 83090970)\n[PASS] test_pixels0() (gas: 2576094)\n[PASS] test_pixels1() (gas: 2595982)\n[PASS] test_pixels100() (gas: 2601259)\n[PASS] test_pixels10000() (gas: 3143487)\n[PASS] test_pixels101() (gas: 2601280)\n[PASS] test_pixels5000() (gas: 2869753)\n[PASS] test_pixels9999() (gas: 3143555)\n[PASS] test_rejectsBadSupplyAtSelection() (gas: 916169)\n[PASS] test_rejectsInvalidERC165Responses() (gas: 2143346)\n[PASS] test_rejectsNonNFTAndMissingSupply() (gas: 325924)\n[PASS] test_rejectsZeroEOASelfAndPrecompile() (gas: 240205)\n[PASS] test_rejectsZeroOwner() (gas: 113034)\n[PASS] test_removedCollectionCodeFallsBackToWhite() (gas: 2521855)\n[PASS] test_supply10001IsClamped() (gas: 3143469)\n[PASS] test_supplyCallbackCannotChangeConfiguration() (gas: 860834)\n[PASS] test_supplyOverflowIsClamped() (gas: 3143852)\n[PASS] test_unconfiguredIsWhite() (gas: 2492120)\n[PASS] test_wordAndTailBoundaries() (gas: 27844843)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 775.18ms (1.16s CPU time)\n\nRan 7 tests for test/AdversarialReview.t.sol:AdversarialReviewTest\n[PASS] testFuzz_RawABIHasExactPixelsAndZeroPadding(uint256) (runs: 256, μ: 6312779, ~: 6312105)\nLogs:\n  Bound result 9342\n\n[PASS] test_BoundedFailureModesDoNotCorruptOrRevertPayload() (gas: 32454254)\n[PASS] test_EvenOwnerContractCannotReconfigureThroughStaticCallback() (gas: 1116012)\n[PASS] test_EveryAssemblyAlignment() (gas: 8264405)\n[PASS] test_FactoryHasNoConfigurationAuthority() (gas: 911817)\n[PASS] test_RecursiveReadCannotExceedOuterSupplyBudget() (gas: 154640)\n[PASS] test_RejectsMalformedERC165AndInvalidInterfaceSupport() (gas: 2117788)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 803.50ms (909.46ms CPU time)\n\nRan 3 test suites in 804.94ms (1.59s CPU time): 46 tests passed, 0 failed, 0 skipped (46 total tests)\n","passed":true},{"durationMs":59,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SelloutMachine.setTrackedCollection(address)\"],\"files\":{\".gitignore\":4,\"README.md\":86,\"THIRD_PARTY.md\":11,\"docs/deployment.md\":77,\"docs/gas.md\":56,\"docs/reference/provenance.json\":30,\"docs/reference/renderer.abi.json\":261,\"docs/reference/renderer.verified.sol.txt\":428,\"docs/reference/vessel.abi.json\":1503,\"docs/reference/vessel.verified.sol.txt\":518,\"docs/results/build.txt\":41,\"docs/results/mainnet-fork.txt\":85,\"docs/results/source-hashes.json\":5,\"docs/results/unit-tests.txt\":144,\"docs/security-review.md\":68,\"docs/verification.md\":84,\"foundry.toml\":26,\"integration/IVessel.sol\":22,\"integration/VesselMainnet.t.sol\":156,\"launch.json\":10,\"src/SelloutMachine.sol\":109,\"src/interfaces/IMachine.sol\":8,\"test/AdversarialReview.t.sol\":228,\"test/Gas.t.sol\":109,\"test/SelloutMachine.t.sol\":268,\"test/mocks/SupplyMocks.sol\":142,\"tools/svg_vectors.py\":31},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"1324fd05c51a407d6fcff5c4eb29c83e02c0d780c05b124bbfc075720f9bca95","verifiedTreeHash":"2ca2e0de064ba59682cb57ab16729c2dcc7f7236","verifierVersion":"0.1.0+63e0a393"},{"checks":[{"durationMs":958,"exitCode":0,"name":"build","output":"Compiling 25 files with Solc 0.8.26\nSolc 0.8.26 finished in 907.01ms\nCompiler run successful!\n","passed":true},{"durationMs":799,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 28 tests for test/SelloutMachine.t.sol:SelloutMachineTest\n[PASS] testFuzz_fullUintSupplyRange(uint256) (runs: 256, μ: 126799, ~: 126908)\n[PASS] testFuzz_payloadAgainstReference(uint256) (runs: 256, μ: 2868810, ~: 2869532)\nLogs:\n  Bound result 8100\n\n[PASS] testFuzz_rejectsEveryOtherCraft(uint256) (runs: 256, μ: 11191, ~: 11191)\n[PASS] testFuzz_unauthorizedConfiguration(address) (runs: 256, μ: 38969, ~: 38969)\n[PASS] test_collectionChangeAndEvents() (gas: 3205274)\n[PASS] test_factoryNeverReceivesConfigurationAuthority() (gas: 898290)\n[PASS] test_faultySupplyAfterSelectionFallsBackToWhiteAndRecovers() (gas: 23683894)\n[PASS] test_liveMintsAndBurnsNeedNoMachineTransaction() (gas: 7550250)\n[PASS] test_noTransferRenounceUpgradeOrEtherAcceptance() (gas: 106915)\n[PASS] test_payloadABIHasExactLengthAndZeroPadding() (gas: 83090970)\n[PASS] test_pixels0() (gas: 2576094)\n[PASS] test_pixels1() (gas: 2595982)\n[PASS] test_pixels100() (gas: 2601259)\n[PASS] test_pixels10000() (gas: 3143487)\n[PASS] test_pixels101() (gas: 2601280)\n[PASS] test_pixels5000() (gas: 2869753)\n[PASS] test_pixels9999() (gas: 3143555)\n[PASS] test_rejectsBadSupplyAtSelection() (gas: 916169)\n[PASS] test_rejectsInvalidERC165Responses() (gas: 2143346)\n[PASS] test_rejectsNonNFTAndMissingSupply() (gas: 325924)\n[PASS] test_rejectsZeroEOASelfAndPrecompile() (gas: 240205)\n[PASS] test_rejectsZeroOwner() (gas: 113034)\n[PASS] test_removedCollectionCodeFallsBackToWhite() (gas: 2521855)\n[PASS] test_supply10001IsClamped() (gas: 3143469)\n[PASS] test_supplyCallbackCannotChangeConfiguration() (gas: 860834)\n[PASS] test_supplyOverflowIsClamped() (gas: 3143852)\n[PASS] test_unconfiguredIsWhite() (gas: 2492120)\n[PASS] test_wordAndTailBoundaries() (gas: 27844843)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 698.23ms (655.73ms CPU time)\n\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\nRan 11 tests for test/Gas.t.sol:SelloutMachineGasTest\n[PASS] test_gasCollectionReplacement() (gas: 592780)\nLogs:\n  replacement selection call gas (cold): 42156\n\n[PASS] test_gasDeployment() (gas: 393866)\nLogs:\n  CREATE deployment gas (excludes transaction intrinsic gas): 387288\n\n[PASS] test_gasFirstCollectionSelection() (gas: 460324)\nLogs:\n  first selection call gas (cold): 56739\n\n[PASS] test_gasMaliciousSupplyIsBounded() (gas: 200939)\nLogs:\n  gas-bomb fallback payload call gas: 140599\n\n[PASS] test_gasPayload0() (gas: 90890)\nLogs:\n  supply: 0\n  cold payload call gas (includes caller ABI decoding): 45553\n  cold Machine execution gas (callee only): 37669\n\n[PASS] test_gasPayload1() (gas: 110741)\nLogs:\n  supply: 1\n  cold payload call gas (includes caller ABI decoding): 45493\n  cold Machine execution gas (callee only): 37609\n\n[PASS] test_gasPayload100() (gas: 110421)\nLogs:\n  supply: 100\n  cold payload call gas (includes caller ABI decoding): 45106\n  cold Machine execution gas (callee only): 37222\n\n[PASS] test_gasPayload10000() (gas: 88348)\nLogs:\n  supply: 10000\n  cold payload call gas (includes caller ABI decoding): 23065\n  cold Machine execution gas (callee only): 15181\n\n[PASS] test_gasPayload101() (gas: 110295)\nLogs:\n  supply: 101\n  cold payload call gas (includes caller ABI decoding): 45046\n  cold Machine execution gas (callee only): 37162\n\n[PASS] test_gasPayload5000() (gas: 99591)\nLogs:\n  supply: 5000\n  cold payload call gas (includes caller ABI decoding): 34309\n  cold Machine execution gas (callee only): 26425\n\n[PASS] test_gasPayload9999() (gas: 88475)\nLogs:\n  supply: 9999\n  cold payload call gas (includes caller ABI decoding): 23125\n  cold Machine execution gas (callee only): 15241\n\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 699.76ms (1.81ms CPU time)\n\nRan 7 tests for test/AdversarialReview.t.sol:AdversarialReviewTest\n[PASS] testFuzz_RawABIHasExactPixelsAndZeroPadding(uint256) (runs: 256, μ: 6312779, ~: 6312105)\nLogs:\n  Bound result 9997\n\n[PASS] test_BoundedFailureModesDoNotCorruptOrRevertPayload() (gas: 32454254)\n[PASS] test_EvenOwnerContractCannotReconfigureThroughStaticCallback() (gas: 1116012)\n[PASS] test_EveryAssemblyAlignment() (gas: 8264405)\n[PASS] test_FactoryHasNoConfigurationAuthority() (gas: 911817)\n[PASS] test_RecursiveReadCannotExceedOuterSupplyBudget() (gas: 154640)\n[PASS] test_RejectsMalformedERC165AndInvalidInterfaceSupport() (gas: 2117788)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 726.78ms (790.69ms CPU time)\n\nRan 3 test suites in 727.53ms (2.12s CPU time): 46 tests passed, 0 failed, 0 skipped (46 total tests)\n","passed":true},{"durationMs":30,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SelloutMachine.setTrackedCollection(address)\"],\"files\":{\".gitignore\":4,\"README.md\":86,\"THIRD_PARTY.md\":11,\"docs/deployment.md\":77,\"docs/gas.md\":56,\"docs/reference/provenance.json\":30,\"docs/reference/renderer.abi.json\":261,\"docs/reference/renderer.verified.sol.txt\":428,\"docs/reference/vessel.abi.json\":1503,\"docs/reference/vessel.verified.sol.txt\":518,\"docs/results/build.txt\":41,\"docs/results/mainnet-fork.txt\":85,\"docs/results/source-hashes.json\":5,\"docs/results/unit-tests.txt\":144,\"docs/security-review.md\":68,\"docs/verification.md\":84,\"foundry.toml\":26,\"integration/IVessel.sol\":22,\"integration/VesselMainnet.t.sol\":156,\"src/SelloutMachine.sol\":109,\"src/interfaces/IMachine.sol\":8,\"test/AdversarialReview.t.sol\":228,\"test/Gas.t.sol\":109,\"test/SelloutMachine.t.sol\":268,\"test/mocks/SupplyMocks.sol\":142,\"tools/svg_vectors.py\":31},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":311,"exitCode":0,"name":"slither","output":"slither: no results at low impact or above","passed":true},{"durationMs":238,"exitCode":0,"name":"aderyn","output":"[low] large-numeric-literal at src/SelloutMachine.sol:10: Large Numeric Literal (3 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"36cd4f199d916fe94425ff77a27af3dc9c7e9ebab79e7e1aaf3fd460d34b7f48","verifiedTreeHash":"fb5393f2ad55f82e369f042a70cb500a14ad097f","verifierVersion":"0.1.0+8fbf00a5"},{"checks":[{"durationMs":2223,"exitCode":0,"name":"build","output":"Compiling 29 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.14s\nCompiler run successful!\n","passed":true},{"durationMs":17335,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/Gas.t.sol:SelloutMachineGasTest\n[PASS] test_gasCollectionReplacement() (gas: 592780)\nLogs:\n  replacement selection call gas (cold): 42156\n\n[PASS] test_gasDeployment() (gas: 393866)\nLogs:\n  CREATE deployment gas (excludes transaction intrinsic gas): 387288\n\n[PASS] test_gasFirstCollectionSelection() (gas: 460324)\nLogs:\n  first selection call gas (cold): 56739\n\n[PASS] test_gasMaliciousSupplyIsBounded() (gas: 200939)\nLogs:\n  gas-bomb fallback payload call gas: 140599\n\n[PASS] test_gasPayload0() (gas: 90890)\nLogs:\n  supply: 0\n  cold payload call gas (includes caller ABI decoding): 45553\n  cold Machine execution gas (callee only): 37669\n\n[PASS] test_gasPayload1() (gas: 110741)\nLogs:\n  supply: 1\n  cold payload call gas (includes caller ABI decoding): 45493\n  cold Machine execution gas (callee only): 37609\n\n[PASS] test_gasPayload100() (gas: 110421)\nLogs:\n  supply: 100\n  cold payload call gas (includes caller ABI decoding): 45106\n  cold Machine execution gas (callee only): 37222\n\n[PASS] test_gasPayload10000() (gas: 88348)\nLogs:\n  supply: 10000\n  cold payload call gas (includes caller ABI decoding): 23065\n  cold Machine execution gas (callee only): 15181\n\n[PASS] test_gasPayload101() (gas: 110295)\nLogs:\n  supply: 101\n  cold payload call gas (includes caller ABI decoding): 45046\n  cold Machine execution gas (callee only): 37162\n\n[PASS] test_gasPayload5000() (gas: 99591)\nLogs:\n  supply: 5000\n  cold payload call gas (includes caller ABI decoding): 34309\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\n  cold Machine execution gas (callee only): 26425\n\n[PASS] test_gasPayload9999() (gas: 88475)\nLogs:\n  supply: 9999\n  cold payload call gas (includes caller ABI decoding): 23125\n  cold Machine execution gas (callee only): 15241\n\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 437.62ms (2.55ms CPU time)\n\nRan 6 tests for test/OfflineVesselCompatibility.t.sol:OfflineVesselCompatibilityTest\n[PASS] test_offlineAttachmentSupportsMachineABIAndEmptyCollection() (gas: 2093391)\n[PASS] test_offlineCollectionLifecycleNeedsOnlyOneAttachment() (gas: 12830130)\n[PASS] test_offlineDispatchPreservesUnsupportedCraftError() (gas: 15763)\n[PASS] test_offlineSVGLastWhitePixel9999() (gas: 207550139)\n[PASS] test_offlineSVGRowBoundary101() (gas: 226448773)\n[PASS] test_offlineUnauthorizedAttachmentAndConfigurationAreSeparateChecks() (gas: 76361)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 538.84ms (946.69ms CPU time)\n\nRan 28 tests for test/SelloutMachine.t.sol:SelloutMachineTest\n[PASS] testFuzz_fullUintSupplyRange(uint256) (runs: 256, μ: 126646, ~: 126920)\n[PASS] testFuzz_payloadAgainstReference(uint256) (runs: 256, μ: 2874824, ~: 2879228)\nLogs:\n  Bound result 33\n\n[PASS] testFuzz_rejectsEveryOtherCraft(uint256) (runs: 256, μ: 11191, ~: 11191)\n[PASS] testFuzz_unauthorizedConfiguration(address) (runs: 256, μ: 38969, ~: 38969)\n[PASS] test_collectionChangeAndEvents() (gas: 3205274)\n[PASS] test_factoryNeverReceivesConfigurationAuthority() (gas: 898290)\n[PASS] test_faultySupplyAfterSelectionFallsBackToWhiteAndRecovers() (gas: 23683894)\n[PASS] test_liveMintsAndBurnsNeedNoMachineTransaction() (gas: 7550250)\n[PASS] test_noTransferRenounceUpgradeOrEtherAcceptance() (gas: 106915)\n[PASS] test_payloadABIHasExactLengthAndZeroPadding() (gas: 83090970)\n[PASS] test_pixels0() (gas: 2576094)\n[PASS] test_pixels1() (gas: 2595982)\n[PASS] test_pixels100() (gas: 2601259)\n[PASS] test_pixels10000() (gas: 3143487)\n[PASS] test_pixels101() (gas: 2601280)\n[PASS] test_pixels5000() (gas: 2869753)\n[PASS] test_pixels9999() (gas: 3143555)\n[PASS] test_rejectsBadSupplyAtSelection() (gas: 916169)\n[PASS] test_rejectsInvalidERC165Responses() (gas: 2143346)\n[PASS] test_rejectsNonNFTAndMissingSupply() (gas: 325924)\n[PASS] test_rejectsZeroEOASelfAndPrecompile() (gas: 240205)\n[PASS] test_rejectsZeroOwner() (gas: 113034)\n[PASS] test_removedCollectionCodeFallsBackToWhite() (gas: 2521855)\n[PASS] test_supply10001IsClamped() (gas: 3143469)\n[PASS] test_supplyCallbackCannotChangeConfiguration() (gas: 860834)\n[PASS] test_supplyOverflowIsClamped() (gas: 3143852)\n[PASS] test_unconfiguredIsWhite() (gas: 2492120)\n[PASS] test_wordAndTailBoundaries() (gas: 27844843)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 960.32ms (2.14s CPU time)\n\nRan 11 tests for test/ResponseValidation.t.sol:ResponseValidationTest\n[PASS] testFuzz_eachERC165StageRequiresExactWordAndLength(uint256,uint256,uint256) (runs: 1000, μ: 138218, ~: 140444)\nLogs:\n  Bound result 1\n  Bound result 38\n\n[PASS] testFuzz_supplyResponseLengthBeforeAndAfterSelection(uint256,uint256) (runs: 1000, μ: 2431056, ~: 2432996)\nLogs:\n  Bound result 5\n\n[PASS] test_eachERC165StageBoundaryMatrix() (gas: 2554143)\n[PASS] test_eachERC165StageChecksCanonicalBooleanAndExpectedClaim() (gas: 1575254)\n[PASS] test_eachERC165StageRejectsSideEffectsRevertAndGasExhaustion() (gas: 2100607)\n[PASS] test_ownerOriginDoesNotAuthorizeAnIntermediary() (gas: 256930)\n[PASS] test_payloadReadsSupplyExactlyOnceAndWritesNoStorage() (gas: 67591)\n[PASS] test_reselectingSameCollectionEmitsAccurateEventAndRevalidates() (gas: 2379949)\n[PASS] test_revertingWithExactlyOneSupplyWordIsNotASuccessfulRead() (gas: 4145930)\n[PASS] test_supplyCannotWriteLogsStorageOrTransientStorage() (gas: 8471730)\n[PASS] test_unsupportedCraftRejectedBeforeCallingHostileCollection() (gas: 65329)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 962.59ms (966.57ms CPU time)\n\nRan 7 tests for test/AdversarialReview.t.sol:AdversarialReviewTest\n[PASS] testFuzz_RawABIHasExactPixelsAndZeroPadding(uint256) (runs: 256, μ: 6312735, ~: 6311928)\nLogs:\n  Bound result 9997\n\n[PASS] test_BoundedFailureModesDoNotCorruptOrRevertPayload() (gas: 32454254)\n[PASS] test_EvenOwnerContractCannotReconfigureThroughStaticCallback() (gas: 1116012)\n[PASS] test_EveryAssemblyAlignment() (gas: 8264405)\n[PASS] test_FactoryHasNoConfigurationAuthority() (gas: 911817)\n[PASS] test_RecursiveReadCannotExceedOuterSupplyBudget() (gas: 154640)\n[PASS] test_RejectsMalformedERC165AndInvalidInterfaceSupport() (gas: 2117788)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 962.60ms (1.08s CPU time)\n\nRan 2 tests for test/SelloutMachineInvariant.t.sol:SelloutMachineInvariantTest\n[PASS] invariant_configurationAndImageAlwaysMatchActionHistory() (runs: 256, calls: 16384, reverts: 0)\n\n╭-----------------------+-----------------------+-------+---------+----------╮\n| Contract              | Selector              | Calls | Reverts | Discards |\n+============================================================================+\n| SelloutMachineHandler | changeBehavior        | 3306  | 0       | 0        |\n|-----------------------+-----------------------+-------+---------+----------|\n| SelloutMachineHandler | changeSupply          | 3264  | 0       | 0        |\n|-----------------------+-----------------------+-------+---------+----------|\n| SelloutMachineHandler | invalidSelection      | 3305  | 0       | 0        |\n|-----------------------+-----------------------+-------+---------+----------|\n| SelloutMachineHandler | selectCollection      | 3205  | 0       | 0        |\n|-----------------------+-----------------------+-------+---------+----------|\n| SelloutMachineHandler | unauthorizedSelection | 3304  | 0       | 0        |\n╰-----------------------+-----------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 3\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 7\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 101\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 8\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 8\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 2\n  Bound result 8\n  Bound result 2\n  Bound result 2\n  Bound result 2\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 6\n  Bound result 2\n  Bound result 2\n  Bound result 0\n  Bound result 5\n  Bound result 2\n  Bound result 9990\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 2\n  Bound result 96\n  Bound result 1\n  Bound result 9361\n  Bound result 2\n  Bound result 7\n  Bound result 0\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 2\n  Bound result 9988\n  Bound result 2\n  Bound result 2\n  Bound result 0\n  Bound result 10001\n  Bound result 1\n  Bound result 2\n  Bound result 2\n  Bound result 2\n  Bound result 1\n  Bound result 0\n  Bound result 2\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 2\n  Bound result 0\n  Bound result 6\n  Bound result 0\n\n[PASS] test_handlerExercisesReplacementBurnFailureRecoveryAndOldCollectionIsolation() (gas: 9790817)\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 7\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 17.23s (17.24s CPU time)\n\nRan 6 test suites in 17.24s (21.10s CPU time): 65 tests passed, 0 failed, 0 skipped (65 total tests)\n","passed":true},{"durationMs":43,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SelloutMachine.setTrackedCollection(address)\"],\"files\":{\".gitignore\":4,\"README.md\":86,\"THIRD_PARTY.md\":11,\"docs/deployment.md\":77,\"docs/gas.md\":56,\"docs/reference/provenance.json\":30,\"docs/reference/renderer.abi.json\":261,\"docs/reference/renderer.verified.sol.txt\":428,\"docs/reference/vessel.abi.json\":1503,\"docs/reference/vessel.verified.sol.txt\":518,\"docs/results/build.txt\":41,\"docs/results/mainnet-fork.txt\":85,\"docs/results/source-hashes.json\":5,\"docs/results/unit-tests.txt\":144,\"docs/security-review.md\":68,\"docs/verification.md\":84,\"foundry.toml\":26,\"integration/IVessel.sol\":22,\"integration/VesselMainnet.t.sol\":156,\"src/SelloutMachine.sol\":109,\"src/interfaces/IMachine.sol\":8,\"test/AdversarialReview.t.sol\":228,\"test/Gas.t.sol\":109,\"test/OfflineVesselCompatibility.t.sol\":170,\"test/REVIEW.md\":154,\"test/ResponseValidation.t.sol\":218,\"test/SelloutMachine.t.sol\":268,\"test/SelloutMachineInvariant.t.sol\":201,\"test/mocks/ResponseCollection.sol\":72,\"test/mocks/SupplyMocks.sol\":142,\"test/results/build.txt\":11,\"test/results/mainnet-fork.txt\":83,\"test/results/offline-tests.txt\":316,\"tools/svg_vectors.py\":31},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"7254c2dedecf0095ec14b18f24bf74f5d7baa8db6c6195e11e49b89823f2e3f3","verifiedTreeHash":"37082877a786d410aabe7bc8c2bc30e165a922d4","verifierVersion":"0.1.0+63e0a393"},{"checks":[{"durationMs":1588,"exitCode":0,"name":"build","output":"Compiling 25 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.49s\nCompiler run successful!\n","passed":true},{"durationMs":1039,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 11 tests for test/Gas.t.sol:SelloutMachineGasTest\n[PASS] test_gasCollectionReplacement() (gas: 592780)\nLogs:\n  replacement selection call gas (cold): 42156\n\n[PASS] test_gasDeployment() (gas: 393866)\nLogs:\n  CREATE deployment gas (excludes transaction intrinsic gas): 387288\n\n[PASS] test_gasFirstCollectionSelection() (gas: 460324)\nLogs:\n  first selection call gas (cold): 56739\n\n[PASS] test_gasMaliciousSupplyIsBounded() (gas: 200939)\nLogs:\n  gas-bomb fallback payload call gas: 140599\n\n[PASS] test_gasPayload0() (gas: 90890)\nLogs:\n  supply: 0\n  cold payload call gas (includes caller ABI decoding): 45553\n  cold Machine execution gas (callee only): 37669\n\n[PASS] test_gasPayload1() (gas: 110741)\nLogs:\n  supply: 1\n  cold payload call gas (includes caller ABI decoding): 45493\n  cold Machine execution gas (callee only): 37609\n\n[PASS] test_gasPayload100() (gas: 110421)\nLogs:\n  supply: 100\n  cold payload call gas (includes caller ABI decoding): 45106\n  cold Machine execution gas (callee only): 37222\n\n[PASS] test_gasPayload10000() (gas: 88348)\nLogs:\n  supply: 10000\n  cold payload call gas (includes caller ABI decoding): 23065\n  cold Machine execution gas (callee only): 15181\n\n[PASS] test_gasPayload101() (gas: 110295)\nLogs:\n  supply: 101\n  cold payload call gas (includes caller ABI decoding): 45046\n  cold Machine execution gas (callee only): 37162\n\n[PASS] test_gasPayload5000() (gas: 99591)\nLogs:\n  supply: 5000\n  cold payload call gas (includes caller ABI decoding): 34309\n  cold Machine execution gas (callee only): 26425\n\n[PASS] test_gasPayload9999() (gas: 88475)\nLogs:\n  supply: 9999\n  cold payload call gas (includes caller ABI decoding): 23125\n  cold Machine execution gas (callee only): 15241\n\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  lastCallGas(): replaced by `lastFrameGas`\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 13.44ms (2.09ms CPU time)\n\nRan 28 tests for test/SelloutMachine.t.sol:SelloutMachineTest\n[PASS] testFuzz_fullUintSupplyRange(uint256) (runs: 256, μ: 126799, ~: 126908)\n[PASS] testFuzz_payloadAgainstReference(uint256) (runs: 256, μ: 2868810, ~: 2869532)\nLogs:\n  Bound result 8100\n\n[PASS] testFuzz_rejectsEveryOtherCraft(uint256) (runs: 256, μ: 11191, ~: 11191)\n[PASS] testFuzz_unauthorizedConfiguration(address) (runs: 256, μ: 38969, ~: 38969)\n[PASS] test_collectionChangeAndEvents() (gas: 3205274)\n[PASS] test_factoryNeverReceivesConfigurationAuthority() (gas: 898290)\n[PASS] test_faultySupplyAfterSelectionFallsBackToWhiteAndRecovers() (gas: 23683894)\n[PASS] test_liveMintsAndBurnsNeedNoMachineTransaction() (gas: 7550250)\n[PASS] test_noTransferRenounceUpgradeOrEtherAcceptance() (gas: 106915)\n[PASS] test_payloadABIHasExactLengthAndZeroPadding() (gas: 83090970)\n[PASS] test_pixels0() (gas: 2576094)\n[PASS] test_pixels1() (gas: 2595982)\n[PASS] test_pixels100() (gas: 2601259)\n[PASS] test_pixels10000() (gas: 3143487)\n[PASS] test_pixels101() (gas: 2601280)\n[PASS] test_pixels5000() (gas: 2869753)\n[PASS] test_pixels9999() (gas: 3143555)\n[PASS] test_rejectsBadSupplyAtSelection() (gas: 916169)\n[PASS] test_rejectsInvalidERC165Responses() (gas: 2143346)\n[PASS] test_rejectsNonNFTAndMissingSupply() (gas: 325924)\n[PASS] test_rejectsZeroEOASelfAndPrecompile() (gas: 240205)\n[PASS] test_rejectsZeroOwner() (gas: 113034)\n[PASS] test_removedCollectionCodeFallsBackToWhite() (gas: 2521855)\n[PASS] test_supply10001IsClamped() (gas: 3143469)\n[PASS] test_supplyCallbackCannotChangeConfiguration() (gas: 860834)\n[PASS] test_supplyOverflowIsClamped() (gas: 3143852)\n[PASS] test_unconfiguredIsWhite() (gas: 2492120)\n[PASS] test_wordAndTailBoundaries() (gas: 27844843)\nSuite result: ok. 28 passed; 0 failed; 0 skipped; finished in 543.23ms (1.79s CPU time)\n\nRan 7 tests for test/AdversarialReview.t.sol:AdversarialReviewTest\n[PASS] testFuzz_RawABIHasExactPixelsAndZeroPadding(uint256) (runs: 256, μ: 6312779, ~: 6312105)\nLogs:\n  Bound result 9997\n\n[PASS] test_BoundedFailureModesDoNotCorruptOrRevertPayload() (gas: 32454254)\n[PASS] test_EvenOwnerContractCannotReconfigureThroughStaticCallback() (gas: 1116012)\n[PASS] test_EveryAssemblyAlignment() (gas: 8264405)\n[PASS] test_FactoryHasNoConfigurationAuthority() (gas: 911817)\n[PASS] test_RecursiveReadCannotExceedOuterSupplyBudget() (gas: 154640)\n[PASS] test_RejectsMalformedERC165AndInvalidInterfaceSupport() (gas: 2117788)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 924.34ms (1.05s CPU time)\n\nRan 3 test suites in 926.75ms (1.48s CPU time): 46 tests passed, 0 failed, 0 skipped (46 total tests)\n","passed":true},{"durationMs":76,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"SelloutMachine.setTrackedCollection(address)\"],\"files\":{\".gitignore\":4,\"README.md\":86,\"THIRD_PARTY.md\":11,\"docs/deployment.md\":77,\"docs/gas.md\":56,\"docs/reference/provenance.json\":30,\"docs/reference/renderer.abi.json\":261,\"docs/reference/renderer.verified.sol.txt\":428,\"docs/reference/vessel.abi.json\":1503,\"docs/reference/vessel.verified.sol.txt\":518,\"docs/results/build.txt\":41,\"docs/results/mainnet-fork.txt\":85,\"docs/results/source-hashes.json\":5,\"docs/results/unit-tests.txt\":144,\"docs/security-review.md\":68,\"docs/verification.md\":84,\"foundry.toml\":26,\"integration/IVessel.sol\":22,\"integration/VesselMainnet.t.sol\":156,\"launch.json\":10,\"src/SelloutMachine.sol\":109,\"src/interfaces/IMachine.sol\":8,\"test/AdversarialReview.t.sol\":228,\"test/Gas.t.sol\":109,\"test/SelloutMachine.t.sol\":268,\"test/mocks/SupplyMocks.sol\":142,\"tools/svg_vectors.py\":31},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"7d479444392832d2d87c351ef9cb63866061ee1f6466116cca7b70420a9bda0b","verifiedTreeHash":"1082ad16afe83a57819fd7d2ce6bcec70cdbb4cb","verifierVersion":"0.1.0+63e0a393"}]}