// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /** * @title MuseContractReview * @notice Append-only review registry for Musechain contracts. * Any muse can submit one immutable review per contract address, recording whether * the review passed and an evidence summary. */ contract MuseContractReview { struct Review { bool exists; bool passed; uint64 timestamp; string summary; } /// @notice reviewedContract => reviewer => Review mapping(address => mapping(address => Review)) private _reviews; /// @notice Emitted when a new contract review is submitted. /// @param reviewedContract The address of the reviewed contract. /// @param reviewer The address of the muse who submitted the review. /// @param passed Whether the contract passed review. /// @param summary Summary/notes of the review. /// @param timestamp Block timestamp when the review was submitted. event ReviewSubmitted( address indexed reviewedContract, address indexed reviewer, bool passed, string summary, uint64 timestamp ); error InvalidContractAddress(); error EmptySummary(); error AlreadyReviewed(); error ReviewNotFound(); /** * @notice Submits a review for a specific contract address. * @dev Reviews cannot be modified or deleted once submitted. * @param reviewedContract Address of the contract under review. * @param passed True if the contract meets verification/security standards, false otherwise. * @param summary Concise summary or evidence description. */ function submitReview( address reviewedContract, bool passed, string calldata summary ) external { if (reviewedContract == address(0)) revert InvalidContractAddress(); if (bytes(summary).length == 0) revert EmptySummary(); if (_reviews[reviewedContract][msg.sender].exists) revert AlreadyReviewed(); uint64 ts = uint64(block.timestamp); _reviews[reviewedContract][msg.sender] = Review({ exists: true, passed: passed, timestamp: ts, summary: summary }); emit ReviewSubmitted(reviewedContract, msg.sender, passed, summary, ts); } /** * @notice Checks whether a reviewer has submitted a review for a contract. * @param reviewedContract Address of the contract. * @param reviewer Address of the reviewer. * @return True if a review exists, false otherwise. */ function hasReviewed(address reviewedContract, address reviewer) external view returns (bool) { return _reviews[reviewedContract][reviewer].exists; } /** * @notice Retrieves the review details submitted by a reviewer for a contract. * @param reviewedContract Address of the reviewed contract. * @param reviewer Address of the reviewer. * @return passed Whether the review passed. * @return timestamp The block timestamp when submitted. * @return summary The summary text of the review. */ function getReview(address reviewedContract, address reviewer) external view returns ( bool passed, uint64 timestamp, string memory summary ) { Review memory r = _reviews[reviewedContract][reviewer]; if (!r.exists) revert ReviewNotFound(); return (r.passed, r.timestamp, r.summary); } }