{"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":"b539989d-3302-4e7c-be6e-3449554fec16","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"955f5c20f73ddfcabbedda7e4fb6d60f4c9b25c3096d668bc6c0fb20633fe6f9","dependsOn":["manifest"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"9aa7ce4818e46e8b8771a512a3138c886d4fb6318f9410ee948d84c9ebbbdbea","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"}],"objective":"Sinopia: an onchain auction on Robinhood Chain (4663) where each winning bid commissions the IMD swarm, through Intake v2, to paint the winner's brief; the finished fresco is minted to the winner. Deploy the Sinopia contract from this repository as it arrived: evm_contracts, no token, no pool, constructor args in order (Intake v2 0xa43e6f75ee006411f79ac1c84120606c2330de82, then IMD 0x5f7bb59365ce557c26dbcaa4ee9d39a4b95b7127). Do not edit src/ unless an audit finding reproduces. The ERC-721 mint in reveal() is the product, not post-launch supply minting: it creates exactly one NFT per settled and delivered commission (token id = round id), only to that round's winning bidder, only after the Intake-delivered result hash matches; there is no owner, admin or other mint path. IMD has deployed the same NFT pattern: launch #1756 VeteransNFT.mint → _safeMint and launch #1716 KeelNotes.mint → _mint. Tests: offline suite plus a Robinhood fork test against the live Intake (README.md, docs/THREATS.md).","parentJobId":null,"planHash":"aae4b68c77a657475b28139fdc17fd6d4b1118897b584dc2f8d146aaa3d12b0a","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"b539989d-3302-4e7c-be6e-3449554fec16","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1942-sinopia"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51473","feedbackHash":"2634f872cdbcc6b687a74f6909a2f879f4ef5d26ba227a13d18ae9cba05bbd97","nodeKey":"audit_imported_code","submissionHash":"955f5c20f73ddfcabbedda7e4fb6d60f4c9b25c3096d668bc6c0fb20633fe6f9","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52341","feedbackHash":"e9c4bf0820d2f4e8712bdb63be5f6b883ac031eb71ed71c00feb538b0816a829","nodeKey":"manifest","submissionHash":"9aa7ce4818e46e8b8771a512a3138c886d4fb6318f9410ee948d84c9ebbbdbea","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"28e57c2429465eb359796ea7fdb8a68de1545b5a5bd7ea614ae649d167551c15","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"dc34db8e17664ebd","findings":[{"citation":"resolved","description":"expire() treats a Delivered round whose valid result nobody revealed for REVEAL_TIMEOUT (7 days) exactly like a failed commission, and claimRefund() then returns amount - JOB_PRICE to the winner. The only party with an incentive not to reveal is the winner: the Delivered event already published the result URI and the image is served by IMD at its SHA-256, so the winner has the painting. By simply not calling reveal() for 7 days the winner recovers the whole bid above the 0.5 IMD job fee, nothing is burned and no NFT is minted; afterwards reveal() is permanently impossible (status Expired). The README's guarantees that 'the rest of the winning bid is burned' and that the fresco 'is minted to the winner' therefore hold only if some third party spends gas to reveal within 7 days; nobody is paid to do so. Economically, every bid above 0.5 IMD is optional for the winner, so outbidding is free unless a keeper intervenes, which distorts the auction for the other bidders. Suggested direction for the adapter (design decision for the author): do not let a Delivered round expire into a winner refund; e.g. have the Delivered-state expiry burn the remainder, or drop the Delivered-state branch so a delivered round can only end in reveal() or rejectDelivery() (unparseable deliveries still have rejectDelivery for well-formed ones, and the author should decide how to handle a hash-matching but unparseable result, for example by letting expire() of a Delivered round burn instead of refund).","line":211,"path":"src/Sinopia.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {Sinopia, IIntake} from \"src/Sinopia.sol\";\n\ncontract ProofIMD is ERC20 {\n    constructor() ERC20(\"Mock IMD\", \"IMD\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\ncontract ProofIntake is IIntake {\n    IERC20 public immutable imd;\n    uint256 public count;\n\n    constructor(IERC20 imd_) {\n        imd = imd_;\n    }\n\n    function requestWithFailure(bytes32, bytes calldata, Callback calldata, bytes4, address, uint256 amount)\n        external\n        returns (bytes32 requestId)\n    {\n        imd.transferFrom(msg.sender, address(this), amount);\n        requestId = bytes32(++count);\n    }\n}\n\n/// A winner whose commission was delivered with a valid, revealable result must not be able to take\n/// the winning bid back. Today the winner waits out REVEAL_TIMEOUT, calls expire() and claimRefund(),\n/// pays only the 0.5 IMD job fee, nothing is burned and no NFT is minted, while the painting is public.\ncontract WinnerSkipsBurnTest is Test {\n    ProofIMD imd;\n    ProofIntake intake;\n    Sinopia fresco;\n    address alice = address(0xA11CE);\n    address bob = address(0xB0B);\n    string constant BRIEF = \"A blue river over warm hills\";\n\n    function setUp() public {\n        imd = new ProofIMD();\n        intake = new ProofIntake(imd);\n        fresco = new Sinopia(address(intake), address(imd));\n        imd.mint(alice, 100 ether);\n        imd.mint(bob, 100 ether);\n        vm.prank(alice);\n        imd.approve(address(fresco), type(uint256).max);\n        vm.prank(bob);\n        imd.approve(address(fresco), type(uint256).max);\n    }\n\n    function _validResult() internal pure returns (bytes memory) {\n        return bytes(\n            '{\"complete\":true,\"files\":[{\"hash\":\"a0caa7dcf140dc65ac5c606be9151dac6c7f00d021e288646a596c96c6ce5309\",\"mediaType\":\"image/png\",\"name\":\"image\"}],\"jobId\":\"23e66772-0986-4e80-b7f2-cd1882f5e634\",\"state\":\"completed\"}'\n        );\n    }\n\n    function testWinnerCannotRecoverBidAfterValidDelivery() public {\n        vm.prank(bob);\n        fresco.bid(1, 0.55 ether, BRIEF);\n        vm.prank(alice);\n        fresco.bid(1, 10 ether, BRIEF); // alice wins with 10 IMD\n        vm.warp(fresco.getRound(1).endTime);\n        fresco.settle(1);\n        bytes32 id = fresco.getRound(1).requestId;\n        bytes memory json = _validResult();\n        vm.prank(address(intake));\n        fresco.onResult(id, keccak256(json), \"ipfs://painting/result.json\");\n\n        // The result is valid: reveal(1, json) would mint and burn. Only the winner has a reason not to.\n        vm.warp(block.timestamp + 7 days + 1);\n        vm.startPrank(alice);\n        try fresco.expire(1) {} catch {}\n        try fresco.claimRefund(1) {} catch {}\n        try fresco.claim() {} catch {}\n        vm.stopPrank();\n\n        // Expected: the 9.5 IMD above the job fee stays committed (burned on reveal, or still escrowed).\n        assertEq(imd.balanceOf(alice), 90 ether, \"winner took the bid back after a valid delivery\");\n    }\n}","reproduction":"State: bob bids 0.55 IMD on round 1, alice outbids with 10 IMD, round ends, settle(1) pays the Intake 0.5 IMD. Intake calls onResult(requestId, keccak256(validResultJson), uri) where validResultJson is the fixture test/fixtures/image-23e66772.canonical.json (a result reveal() accepts). Nobody calls reveal. After deliveredAt + 7 days + 1 alice calls expire(1) then claimRefund(1). Expected: the 9.5 IMD above the job fee is burned (or stays committed) and token #1 is minted to alice. Actual: alice receives 9.5 IMD back (balance 99.5 of 100), BURN balance stays 0, ownerOf(1) reverts, and reveal(1, validResultJson) now reverts InvalidResult forever. Scratch test test/scratch/WinnerSkipsBurn.t.sol fails on the current code with '99500000000000000000 != 90000000000000000000'.","severity":"medium","snippet":"            || (round.status == Status.Delivered && block.timestamp > round.deliveredAt + REVEAL_TIMEOUT);","title":"Winner can take a delivered commission for 0.5 IMD by letting the reveal window lapse: no burn, no mint"},{"citation":"resolved","description":"expire() is permissionless. Once settledAt + DELIVERY_TIMEOUT (3 days) has passed, any address can flip a Commissioned round to Expired, after which onResult() reverts with InvalidRound. The Intake attempts a callback once and does not retry (oracle-consumer reference: 'A callback that reverts or runs out of gas is recorded as not delivered and is not retried'). A job that is merely queued or slow, or whose result transaction lands a block after a third party's expire(), is therefore lost to the contract: the 0.5 IMD was spent, IMD painted the brief, but the winner only gets amount - 0.5 IMD and never the NFT. The winner cannot prevent this; it costs the griefer one transaction. This is the documented timeout, so it is reported as low; the adapter may want the winner alone to be able to expire a Commissioned round, or a longer timeout, so an outsider cannot race the writer.","line":210,"path":"src/Sinopia.sol","reproduction":"alice bids 1 IMD on round 1, settle(1) at endTime. Warp to settledAt + 3 days + 1. bob (unrelated) calls expire(1): succeeds, status Expired. Intake then calls onResult(requestId, keccak256(validJson), uri): reverts InvalidRound, the delivery is never retried. claimRefund(1) returns 0.5 IMD to alice; ownerOf(1) reverts forever. Shown by testExpireFrontRunsLateDelivery in test/scratch/Probe.t.sol.","severity":"low","snippet":"        bool timedOut = (round.status == Status.Commissioned && block.timestamp > round.settledAt + DELIVERY_TIMEOUT)","title":"Anyone can expire a slow commission after 3 days and the Intake's one-shot delivery is then lost"},{"citation":"resolved","description":"settle() always approves and requests exactly JOB_PRICE for ACTION 'job.open@job-1' on the immutable intake. The live Intake v2 has owner-only setPrice(bytes32,address,uint256) and the oracle-consumer reference states that the intake, action id, asset and price are expected to be 'constructor input and owner-settable, never a constant', because a new action version or a moved price must not need a redeploy. Sinopia has, by the brief's design, no owner, so after a price increase (PriceNotMet) or a retired action (ActionNotSold) every settle() reverts, every round ends in cancelUnsettled() after a day, and the auction is permanently dead. No funds are lost (cancelUnsettled refunds the full bid), which is why this is low, and THREATS.md line 9 accepts it. Reported so the adapter makes a deliberate choice: keep the constant (documented trade-off), or read intake.priceOf(ACTION, imd) at settle time with the refund and burn math using the stored charge rather than the constant.","line":60,"path":"src/Sinopia.sol","reproduction":"Deploy Sinopia against an Intake whose price for job.open is 0.6 IMD (live Intake after owner calls setPrice). alice bids 1 IMD on round 1; at endTime settle(1) reverts (Intake price check). After endTime + 1 day cancelUnsettled(1) returns 1 IMD to alice. Round 2 behaves identically. Expected by the product: rounds settle at the Intake's current price. Actual: no round can ever be commissioned again. Shown by testPriceChangeBricksSettlement in test/scratch/Probe.t.sol.","severity":"low","snippet":"    uint256 public constant JOB_PRICE = 0.5 ether;","title":"Job price and action are constants with an immutable Intake: a price or action change at the Intake disables settlement for every round"},{"citation":"resolved","description":"Recorded for the adapter so it is not 'fixed'. A bidder that is a contract without ERC-721 receiver support gets a token it may be unable to move; that is the bidder's own choice. Switching to _safeMint would let a malicious bidder contract revert in onERC721Received and make reveal() impossible, which would route the round into the expiry refund of finding 1. The requester's cited precedent (KeelNotes.mint -> _mint) matches. No change recommended.","line":192,"path":"src/Sinopia.sol","reproduction":"Deploy a contract C with no onERC721Received. C bids 0.55 IMD, wins, settle, onResult with a valid result, reveal(1, json): succeeds, ownerOf(1) == C. With _safeMint the same reveal would revert and the round could only end via expire()/claimRefund().","severity":"info","snippet":"        _mint(round.bidder, roundId);","title":"reveal() uses _mint, so a contract winner without onERC721Received still receives the token; this is the right choice and should not be changed to _safeMint"}],"hash":"955f5c20f73ddfcabbedda7e4fb6d60f4c9b25c3096d668bc6c0fb20633fe6f9","nodeId":"93962d2e-296c-44c2-90c5-8005234878e9","outcome":"completed","summary":"The review is complete. The findings file is at the repository root with four findings and a 20-row coverage record, and the only files I created are `.imd-findings.json` and two scratch tests under `test/scratch/`.\n\n**Verdict.** No critical or high defect, and nothing the launch forbids. The compiled runtime has no DELEGATECALL, CALLCODE, SELFDESTRUCT or CREATE, the constructor is nonpayable and makes no external calls, there is no owner, pause, blacklist, seize or proxy, and the only mint is the product mint in `reveal`. One medium design defect and two lows are reported, each with a concrete reproduction.\n\n**Findings**\n\n- **Medium, `expire` on a Delivered round.** A winner whose painting was delivered with a valid result can simply not reveal for 7 days, then call expire and claimRefund. They get the whole bid back minus the 0.5 IMD fee, nothing burns, no NFT mints, and reveal becomes impossible forever, while the image is already public. Bids above 0.5 IMD are therefore optional for the winner unless an unpaid third party reveals in time. The attached proof test fails on the current code with the winner at 99.5 IMD instead of 90.\n- **Low, `expire` on a Commissioned round.** Any address can expire a slow job after 3 days, and the Intake's single delivery attempt then reverts and is never retried. The winner loses the painting and pays the fee. Documented timeout, but permissionless and raceable.\n- **Low, constant price and action with no owner.** If the Intake owner moves the price or retires `job.open@job-1`, every settle reverts and every round cancels after a day. Funds are recoverable, so low, but the pinned oracle reference expects these to be settable. The author accepted this in the threat model.\n- **Info, `_mint` in reveal.** Recorded so the adapter does not change it to `_safeMint`, which would let a malicious bidder contract block reveal.\n\n**What was read and verified.** Both source files in full, all tests, README, THREATS, LAUNCH and launch.json. The offline suite passes with 38 tests, and the fork test passes against the live Intake. The live Intake and IMD token are unverified bytecode, so I checked them by RPC: `job.open@job-1` costs 0.5 IMD, callback gas is 200000, the body cap is 16 KiB, and the exact body the contract builds passes IMD's free check with no blockers. Decoding a real completion transaction showed the callback payload is `abi.encode(requestId, resultHash, uri)`, which matches `onResult` exactly. The launch manifest matches the brief's constructor order.","treeHash":null,"usage":{"cachedInputTokens":1615859,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":38952,"runtime":"claude","turns":36,"wallClockMs":694076}},{"artifacts":[],"attempt":1,"bundleHash":"8e0165e186159daf76e5df1d91713e45be8b3d7a436fbd71b45ca55d4d84685f","device":"11f978978d1e9b55","findings":[],"hash":"9aa7ce4818e46e8b8771a512a3138c886d4fb6318f9410ee948d84c9ebbbdbea","nodeId":"962fb89c-5818-4f39-a0c2-d48e9b39946c","outcome":"completed","summary":"Created [launch.json](/home/imd/.identitymd/work/b539989d-3302-4e7c-be6e-3449554fec16/962fb89c-5818-4f39-a0c2-d48e9b39946c/launch.json) for Sinopia with the exact Intake v2 and IMD constructor arguments.\n\nValidated the schema and compiled ABI. `forge build`, the offline suite with the specified fuzz seed, and the live Robinhood fork test all passed.\n\nOnly `launch.json` changed.","treeHash":"5a2817eae0e67c9b5ef32c71ca4e35f8478c4252","usage":{"cachedInputTokens":608640,"inputTokens":37958,"model":"gpt-6-astra","outputTokens":4111,"runtime":"codex","turns":5,"wallClockMs":178697}}],"verification":[{"checks":[{"durationMs":23729,"exitCode":0,"name":"build","output":"Compiling 50 files with Solc 0.8.26\nSolc 0.8.26 finished in 23.64s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/Sinopia.t.sol:275:5:\n    |\n275 |     function testParserFixturesAndMalformed() public {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\n","passed":true},{"durationMs":19267,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/ResultJsonReview.t.sol:ResultJsonReviewTest\n[PASS] testImageFileWithBraceInEvaluationCannotBeRefunded() (gas: 3328073)\n[PASS] testNestedImageFileValueReveal() (gas: 2761009)\n[PASS] testTopLevelKeysAroundMarkersReveal() (gas: 2751121)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 6.37ms (11.65ms CPU time)\n\nRan 13 tests for test/Sinopia.t.sol:SinopiaTest\n[PASS] testAccountingInvariant() (gas: 1063854)\n[PASS] testBriefRulesAndBody() (gas: 130315)\n[PASS] testCallbackGuardsAndGas() (gas: 1007976)\n[PASS] testCancelAndNewRound() (gas: 607627)\n[PASS] testCommissionFailureRefund() (gas: 1005132)\n[PASS] testDeliveredExpiry() (gas: 1207749)\n[PASS] testExpireAndLateCallback() (gas: 978736)\n[PASS] testHappyPath() (gas: 3417199)\nLogs:\n  fixture reveal gas: 798634\n\n[PASS] testIntakeRevertLeavesOpen() (gas: 458945)\n[PASS] testParserFixturesAndMalformed() (gas: 2590128)\n[PASS] testPushFallbackBecomesClaimableCredit() (gas: 567384)\n[PASS] testRejectDelivery() (gas: 1523344)\n[PASS] testStaleRoundBidAfterEndReverts() (gas: 319409)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 869.01ms (38.35ms CPU time)\n\nRan 8 tests for test/Extra.t.sol:ExtraTest\n[PASS] testFuzz_bodyAndMetadataAreValidJson(uint256,uint8) (runs: 256, μ: 3016305, ~: 2858941)\n[PASS] testFuzz_parseNeverRevertsOnArbitraryBytes(bytes) (runs: 256, μ: 8244, ~: 7565)\n[PASS] testFuzz_parseNeverRevertsOnMutatedFixture(uint16,uint8,uint16,uint8,uint16) (runs: 256, μ: 131854, ~: 68088)\n[PASS] testOnResultGasLongUri() (gas: 1073138)\nLogs:\n  onResult gas, 1000-byte uri: 106421\n\n[PASS] testParseGasOnRealFixtures() (gas: 1043621)\nLogs:\n  parse gas, real image result (bytes follow): 562405\n     bytes: 1199\n  parse gas, real report result (reject path): 464894\n     bytes: 1070\n\n[PASS] testParseGasScaling() (gas: 17314479)\nLogs:\n  extra files=0 bytes: 739\n     parse gas: 413383\n  extra files=1 bytes: 1131\n     parse gas: 570152\n  extra files=5 bytes: 2699\n     parse gas: 1197427\n  extra files=20 bytes: 8579\n     parse gas: 3554272\n  extra files=60 bytes: 24259\n     parse gas: 9918743\n\n[PASS] testParserByteFlipsNeverRevert() (gas: 99189876)\nLogs:\n  flip parses: 212\n  flips that still parse as valid image: 126\n\n[PASS] testParserTruncationsNeverRevert() (gas: 519374612)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 869.01ms (1.36s CPU time)\n\nRan 13 tests for test/Guards.t.sol:GuardTests\n[PASS] testBriefCharsetAndLengthExact() (gas: 5844377)\n[PASS] testCancelBeforeGraceReverts() (gas: 309085)\n[PASS] testClaimWithNothingPendingReverts() (gas: 39833)\n[PASS] testCommissionedCannotExpireBeforeDeliveryTimeout() (gas: 905867)\n[PASS] testDeliveredCannotExpireBeforeRevealTimeout() (gas: 955927)\n[PASS] testFeeOnTransferTokenIsRejected() (gas: 5308004)\n[PASS] testFreshRoundBelowReserveReverts() (gas: 63404)\n[PASS] testIntakeReturningZeroOrDuplicateRequestIdReverts() (gas: 5571226)\n[PASS] testMinRaiseIsExactlyFivePercentRoundedUp() (gas: 451970)\n[PASS] testOnFailureOnlyFromIntakeAndOnlyForKnownCommissionedRequest() (gas: 898192)\n[PASS] testRejectDeliveryRejectsJsonWhoseHashDiffers() (gas: 980272)\n[PASS] testRevealRejectsJsonWhoseHashDiffers() (gas: 965204)\n[PASS] testSettleBeforeEndReverts() (gas: 273106)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 869.05ms (25.46ms CPU time)\n\nRan 1 test for test/Invariant.t.sol:InvariantSinopia\n[PASS]\nInvariantSinopia invariants:\n[PASS] invariant_atMostOneLiveOpenRoundAndItIsTheLatest\n[PASS] invariant_balanceEqualsEscrowPlusDonation\n[PASS] invariant_burnAndNftSupplyMatchRevealedRounds\n[PASS] invariant_escrowEqualsSumOfObligations\n[PASS] invariant_intakeReceivedExactlyJobPricePerSettledRound\n[PASS] invariant_noValueLeaksOutOfTheClosedSystem\n[PASS] invariant_onlyLegalStatusTransitions\n[PASS] invariant_solvent\n InvariantSinopia invariants (runs: 256, calls: 128000, reverts: 0)\n\n╭----------+----------------+-------+---------+----------╮\n| Contract | Selector       | Calls | Reverts | Discards |\n+========================================================+\n| Handler  | bid            | 8400  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | cancel         | 8404  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | claim          | 8540  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | claimRefund    | 8557  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | deliverGarbage | 8404  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | deliverNoImage | 8434  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | deliverOk      | 8594  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | expire         | 8515  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | failRound      | 8575  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | intakeDown     | 8513  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | reject         | 8666  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | reveal         | 8531  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | setBlocked     | 8619  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | settle         | 8619  | 0       | 0        |\n|----------+----------------+-------+---------+----------|\n| Handler  | warp           | 8629  | 0       | 0        |\n╰----------+----------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 19.14s (19.13s CPU time)\n\nRan 5 test suites in 19.14s (21.75s CPU time): 38 tests passed, 0 failed, 0 skipped (38 total tests)\n","passed":true},{"durationMs":56,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Sinopia.approve(address,uint256)\",\"Sinopia.bid(uint256,uint256,string)\",\"Sinopia.cancelUnsettled(uint256)\",\"Sinopia.claim()\",\"Sinopia.claimRefund(uint256)\",\"Sinopia.expire(uint256)\",\"Sinopia.onFailure(bytes32,uint8,bytes32,uint16,uint16,bytes)\",\"Sinopia.onResult(bytes32,bytes32,string)\",\"Sinopia.rejectDelivery(uint256,bytes)\",\"Sinopia.reveal(uint256,bytes)\",\"Sinopia.safeTransferFrom(address,address,uint256)\",\"Sinopia.safeTransferFrom(address,address,uint256,bytes)\",\"Sinopia.setApprovalForAll(address,bool)\",\"Sinopia.settle(uint256)\",\"Sinopia.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":13,\"LICENSE\":21,\"README.md\":165,\"docs/LAUNCH.md\":33,\"docs/THREATS.md\":28,\"docs/assets/imd-mark.svg\":5,\"docs/assets/robinhood-chain.svg\":1,\"docs/assets/sinopia-mark.png\":138,\"docs/assets/sinopia-wall.webp\":883,\"foundry.toml\":16,\"launch.json\":13,\"remappings.txt\":2,\"src/ResultJson.sol\":275,\"src/Sinopia.sol\":347,\"test/Extra.t.sol\":235,\"test/Guards.t.sol\":235,\"test/Invariant.t.sol\":343,\"test/ResultJsonReview.t.sol\":64,\"test/Sinopia.t.sol\":352,\"test/fixtures/image-23e66772.api.json\":1,\"test/fixtures/image-23e66772.canonical.json\":1,\"test/fixtures/report-08f59d80.result.json\":1,\"test/fixtures/report-0e288a21.result.json\":1,\"test/fork/SinopiaFork.t.sol\":39},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"9aa7ce4818e46e8b8771a512a3138c886d4fb6318f9410ee948d84c9ebbbdbea","verifiedTreeHash":"5a2817eae0e67c9b5ef32c71ca4e35f8478c4252","verifierVersion":"0.1.0+d952fceb"}]}