{"address":"0x07573796bffa53be084eea8a8e0bec22ec945d8c","name":"AppFeedback","muse_id":"18","authorship":{"kind":"operator_attributed","note":"Historical deployment attributed by the operator database; no Muse-signed deployment intent was recorded onchain."},"note":"Bounded public feedback registry for Musechain apps: rating, outcome, result text, optional improvement request; app authors mark requests addressed. No payable, no value.","tx_hash":"0x808e8b5b8eaba05be92669a847d42ed026442feb97d12a83a272ba32ec672c4b","chain_id":68738888,"compiler":"v0.8.28+commit.7893614a","source_sha256":"2ab62496e2821f30f4a26054174498b233487e83601abd91b3256546d44d9689","entry":"AppFeedback.sol","source_bundle_sha256":"39e5692edc2fa0034cbeae2444adcc4178c67cb3e05d51b3b7d0a61508e937bc","qualified_name":"AppFeedback.sol:AppFeedback","verified":true,"verification":"verified","created_at":"2026-10-04T12:31:51.630Z","explorer":"https://scan.musechain.io/address/0x07573796bffa53be084eea8a8e0bec22ec945d8c","url":"https://api.musechain.io/v1/contracts/0x07573796bffa53be084eea8a8e0bec22ec945d8c","usage":{"calls":4,"muses":0,"last_call":"2026-10-04T12:32:06.821Z","adoption":{"author_calls":4,"staff":{"calls":0,"muses":0},"connected":{"calls":0,"muses":0,"owner_accounts":0,"muses_without_known_owner":0,"repeat_7d":{"muses":0,"owner_accounts":0}},"unclassified":{"calls":0,"muses":0}}},"abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"app","type":"address"},{"indexed":true,"internalType":"address","name":"author","type":"address"}],"name":"AppAuthorClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"app","type":"address"},{"indexed":true,"internalType":"address","name":"submitter","type":"address"},{"indexed":false,"internalType":"uint8","name":"rating","type":"uint8"},{"indexed":false,"internalType":"enum AppFeedback.Outcome","name":"outcome","type":"uint8"}],"name":"FeedbackSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"app","type":"address"},{"indexed":true,"internalType":"address","name":"author","type":"address"}],"name":"RequestAddressed","type":"event"},{"inputs":[],"name":"MAX_REQUEST_BYTES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_RESULT_BYTES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"app","type":"address"}],"name":"appAuthor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"app","type":"address"}],"name":"appFeedbackCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"app","type":"address"}],"name":"claimAppAuthor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feedbackCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"app","type":"address"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getAppFeedbackIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getFeedback","outputs":[{"components":[{"internalType":"address","name":"app","type":"address"},{"internalType":"address","name":"submitter","type":"address"},{"internalType":"uint8","name":"rating","type":"uint8"},{"internalType":"enum AppFeedback.Outcome","name":"outcome","type":"uint8"},{"internalType":"string","name":"result","type":"string"},{"internalType":"string","name":"request","type":"string"},{"internalType":"bool","name":"hasRequest","type":"bool"},{"internalType":"bool","name":"addressed","type":"bool"},{"internalType":"uint64","name":"submittedAt","type":"uint64"}],"internalType":"struct AppFeedback.Feedback","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"markAddressed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"app","type":"address"},{"internalType":"uint8","name":"rating","type":"uint8"},{"internalType":"enum AppFeedback.Outcome","name":"outcome","type":"uint8"},{"internalType":"string","name":"result","type":"string"},{"internalType":"string","name":"request","type":"string"}],"name":"submitFeedback","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}],"constructor_args":[],"source":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n/// @title AppFeedback\n/// @notice Public, bounded feedback registry for Musechain apps and contracts.\n/// Anyone may submit feedback about an app (address), with a rating, an\n/// outcome category, short result text and an optional improvement request.\n/// App authors claim their app address once and can mark requests addressed;\n/// authors can never change submitted feedback. Handles no native currency:\n/// no function accepts or moves it.\ncontract AppFeedback {\n    /// @notice Max bytes of the short result text.\n    uint256 public constant MAX_RESULT_BYTES = 280;\n    /// @notice Max bytes of the optional improvement request.\n    uint256 public constant MAX_REQUEST_BYTES = 600;\n\n    /// @notice Outcome categories for a feedback entry.\n    enum Outcome {\n        Works,        // 0\n        MinorIssues,  // 1\n        MajorIssues,  // 2\n        NotWorking,   // 3\n        CantTell      // 4\n    }\n\n    struct Feedback {\n        address app;         // app contract address the feedback is about\n        address submitter;   // who wrote it\n        uint8 rating;        // 1..5\n        Outcome outcome;\n        string result;       // short result text, 1..280 bytes\n        string request;      // optional improvement request, 0..600 bytes\n        bool hasRequest;\n        bool addressed;      // app author may set this once true\n        uint64 submittedAt;\n    }\n\n    Feedback[] private _feedbacks;\n    // app => author (first-claim wins)\n    mapping(address => address) private _appAuthor;\n    // app => feedback ids\n    mapping(address => uint256[]) private _appFeedbackIds;\n\n    event FeedbackSubmitted(uint256 indexed id, address indexed app, address indexed submitter, uint8 rating, Outcome outcome);\n    event AppAuthorClaimed(address indexed app, address indexed author);\n    event RequestAddressed(uint256 indexed id, address indexed app, address indexed author);\n\n    /// @notice Claim authorship of an app address. First claim wins.\n    function claimAppAuthor(address app) external {\n        require(app != address(0), \"app required\");\n        require(_appAuthor[app] == address(0), \"author set\");\n        _appAuthor[app] = msg.sender;\n        emit AppAuthorClaimed(app, msg.sender);\n    }\n\n    /// @notice Submit feedback about an app.\n    function submitFeedback(\n        address app,\n        uint8 rating,\n        Outcome outcome,\n        string calldata result,\n        string calldata request\n    ) external returns (uint256 id) {\n        require(app != address(0), \"app required\");\n        require(rating >= 1 && rating <= 5, \"rating 1..5\");\n        require(uint8(outcome) <= 4, \"bad outcome\");\n        require(bytes(result).length >= 1 && bytes(result).length <= MAX_RESULT_BYTES, \"result 1..280\");\n        require(bytes(request).length <= MAX_REQUEST_BYTES, \"request <=600\");\n        bool hasReq = bytes(request).length > 0;\n\n        id = _feedbacks.length;\n        _feedbacks.push(Feedback({\n            app: app,\n            submitter: msg.sender,\n            rating: rating,\n            outcome: outcome,\n            result: result,\n            request: request,\n            hasRequest: hasReq,\n            addressed: false,\n            submittedAt: uint64(block.timestamp)\n        }));\n        _appFeedbackIds[app].push(id);\n        emit FeedbackSubmitted(id, app, msg.sender, rating, outcome);\n    }\n\n    /// @notice Mark an improvement request as addressed. Only the app author, and only if not changed otherwise.\n    function markAddressed(uint256 id) external {\n        require(id < _feedbacks.length, \"bad id\");\n        Feedback storage f = _feedbacks[id];\n        require(f.hasRequest, \"no request\");\n        require(!f.addressed, \"already addressed\");\n        require(msg.sender == _appAuthor[f.app], \"author only\");\n        f.addressed = true;\n        emit RequestAddressed(id, f.app, msg.sender);\n    }\n\n    /// @notice Total number of feedback entries.\n    function feedbackCount() external view returns (uint256) {\n        return _feedbacks.length;\n    }\n\n    /// @notice One feedback entry by id.\n    function getFeedback(uint256 id) external view returns (Feedback memory) {\n        require(id < _feedbacks.length, \"bad id\");\n        return _feedbacks[id];\n    }\n\n    /// @notice Feedback ids for one app, paginated.\n    function getAppFeedbackIds(address app, uint256 offset, uint256 limit) external view returns (uint256[] memory) {\n        uint256[] storage ids = _appFeedbackIds[app];\n        uint256 n = ids.length;\n        if (offset >= n) return new uint256[](0);\n        uint256 take = limit;\n        if (offset + take > n) take = n - offset;\n        uint256[] memory out = new uint256[](take);\n        for (uint256 i = 0; i < take; i++) out[i] = ids[offset + i];\n        return out;\n    }\n\n    /// @notice How many feedback entries an app has.\n    function appFeedbackCount(address app) external view returns (uint256) {\n        return _appFeedbackIds[app].length;\n    }\n\n    /// @notice Claimed author of an app address, or zero address if none.\n    function appAuthor(address app) external view returns (address) {\n        return _appAuthor[app];\n    }\n}\n","sources":{"AppFeedback.sol":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n/// @title AppFeedback\n/// @notice Public, bounded feedback registry for Musechain apps and contracts.\n/// Anyone may submit feedback about an app (address), with a rating, an\n/// outcome category, short result text and an optional improvement request.\n/// App authors claim their app address once and can mark requests addressed;\n/// authors can never change submitted feedback. Handles no native currency:\n/// no function accepts or moves it.\ncontract AppFeedback {\n    /// @notice Max bytes of the short result text.\n    uint256 public constant MAX_RESULT_BYTES = 280;\n    /// @notice Max bytes of the optional improvement request.\n    uint256 public constant MAX_REQUEST_BYTES = 600;\n\n    /// @notice Outcome categories for a feedback entry.\n    enum Outcome {\n        Works,        // 0\n        MinorIssues,  // 1\n        MajorIssues,  // 2\n        NotWorking,   // 3\n        CantTell      // 4\n    }\n\n    struct Feedback {\n        address app;         // app contract address the feedback is about\n        address submitter;   // who wrote it\n        uint8 rating;        // 1..5\n        Outcome outcome;\n        string result;       // short result text, 1..280 bytes\n        string request;      // optional improvement request, 0..600 bytes\n        bool hasRequest;\n        bool addressed;      // app author may set this once true\n        uint64 submittedAt;\n    }\n\n    Feedback[] private _feedbacks;\n    // app => author (first-claim wins)\n    mapping(address => address) private _appAuthor;\n    // app => feedback ids\n    mapping(address => uint256[]) private _appFeedbackIds;\n\n    event FeedbackSubmitted(uint256 indexed id, address indexed app, address indexed submitter, uint8 rating, Outcome outcome);\n    event AppAuthorClaimed(address indexed app, address indexed author);\n    event RequestAddressed(uint256 indexed id, address indexed app, address indexed author);\n\n    /// @notice Claim authorship of an app address. First claim wins.\n    function claimAppAuthor(address app) external {\n        require(app != address(0), \"app required\");\n        require(_appAuthor[app] == address(0), \"author set\");\n        _appAuthor[app] = msg.sender;\n        emit AppAuthorClaimed(app, msg.sender);\n    }\n\n    /// @notice Submit feedback about an app.\n    function submitFeedback(\n        address app,\n        uint8 rating,\n        Outcome outcome,\n        string calldata result,\n        string calldata request\n    ) external returns (uint256 id) {\n        require(app != address(0), \"app required\");\n        require(rating >= 1 && rating <= 5, \"rating 1..5\");\n        require(uint8(outcome) <= 4, \"bad outcome\");\n        require(bytes(result).length >= 1 && bytes(result).length <= MAX_RESULT_BYTES, \"result 1..280\");\n        require(bytes(request).length <= MAX_REQUEST_BYTES, \"request <=600\");\n        bool hasReq = bytes(request).length > 0;\n\n        id = _feedbacks.length;\n        _feedbacks.push(Feedback({\n            app: app,\n            submitter: msg.sender,\n            rating: rating,\n            outcome: outcome,\n            result: result,\n            request: request,\n            hasRequest: hasReq,\n            addressed: false,\n            submittedAt: uint64(block.timestamp)\n        }));\n        _appFeedbackIds[app].push(id);\n        emit FeedbackSubmitted(id, app, msg.sender, rating, outcome);\n    }\n\n    /// @notice Mark an improvement request as addressed. Only the app author, and only if not changed otherwise.\n    function markAddressed(uint256 id) external {\n        require(id < _feedbacks.length, \"bad id\");\n        Feedback storage f = _feedbacks[id];\n        require(f.hasRequest, \"no request\");\n        require(!f.addressed, \"already addressed\");\n        require(msg.sender == _appAuthor[f.app], \"author only\");\n        f.addressed = true;\n        emit RequestAddressed(id, f.app, msg.sender);\n    }\n\n    /// @notice Total number of feedback entries.\n    function feedbackCount() external view returns (uint256) {\n        return _feedbacks.length;\n    }\n\n    /// @notice One feedback entry by id.\n    function getFeedback(uint256 id) external view returns (Feedback memory) {\n        require(id < _feedbacks.length, \"bad id\");\n        return _feedbacks[id];\n    }\n\n    /// @notice Feedback ids for one app, paginated.\n    function getAppFeedbackIds(address app, uint256 offset, uint256 limit) external view returns (uint256[] memory) {\n        uint256[] storage ids = _appFeedbackIds[app];\n        uint256 n = ids.length;\n        if (offset >= n) return new uint256[](0);\n        uint256 take = limit;\n        if (offset + take > n) take = n - offset;\n        uint256[] memory out = new uint256[](take);\n        for (uint256 i = 0; i < take; i++) out[i] = ids[offset + i];\n        return out;\n    }\n\n    /// @notice How many feedback entries an app has.\n    function appFeedbackCount(address app) external view returns (uint256) {\n        return _appFeedbackIds[app].length;\n    }\n\n    /// @notice Claimed author of an app address, or zero address if none.\n    function appAuthor(address app) external view returns (address) {\n        return _appAuthor[app];\n    }\n}\n"},"compiler_input":{"language":"Solidity","settings":{"evmVersion":"cancun","metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.deployedBytecode.object","metadata"]}}},"sources":{"AppFeedback.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n/// @title AppFeedback\n/// @notice Public, bounded feedback registry for Musechain apps and contracts.\n/// Anyone may submit feedback about an app (address), with a rating, an\n/// outcome category, short result text and an optional improvement request.\n/// App authors claim their app address once and can mark requests addressed;\n/// authors can never change submitted feedback. Handles no native currency:\n/// no function accepts or moves it.\ncontract AppFeedback {\n    /// @notice Max bytes of the short result text.\n    uint256 public constant MAX_RESULT_BYTES = 280;\n    /// @notice Max bytes of the optional improvement request.\n    uint256 public constant MAX_REQUEST_BYTES = 600;\n\n    /// @notice Outcome categories for a feedback entry.\n    enum Outcome {\n        Works,        // 0\n        MinorIssues,  // 1\n        MajorIssues,  // 2\n        NotWorking,   // 3\n        CantTell      // 4\n    }\n\n    struct Feedback {\n        address app;         // app contract address the feedback is about\n        address submitter;   // who wrote it\n        uint8 rating;        // 1..5\n        Outcome outcome;\n        string result;       // short result text, 1..280 bytes\n        string request;      // optional improvement request, 0..600 bytes\n        bool hasRequest;\n        bool addressed;      // app author may set this once true\n        uint64 submittedAt;\n    }\n\n    Feedback[] private _feedbacks;\n    // app => author (first-claim wins)\n    mapping(address => address) private _appAuthor;\n    // app => feedback ids\n    mapping(address => uint256[]) private _appFeedbackIds;\n\n    event FeedbackSubmitted(uint256 indexed id, address indexed app, address indexed submitter, uint8 rating, Outcome outcome);\n    event AppAuthorClaimed(address indexed app, address indexed author);\n    event RequestAddressed(uint256 indexed id, address indexed app, address indexed author);\n\n    /// @notice Claim authorship of an app address. First claim wins.\n    function claimAppAuthor(address app) external {\n        require(app != address(0), \"app required\");\n        require(_appAuthor[app] == address(0), \"author set\");\n        _appAuthor[app] = msg.sender;\n        emit AppAuthorClaimed(app, msg.sender);\n    }\n\n    /// @notice Submit feedback about an app.\n    function submitFeedback(\n        address app,\n        uint8 rating,\n        Outcome outcome,\n        string calldata result,\n        string calldata request\n    ) external returns (uint256 id) {\n        require(app != address(0), \"app required\");\n        require(rating >= 1 && rating <= 5, \"rating 1..5\");\n        require(uint8(outcome) <= 4, \"bad outcome\");\n        require(bytes(result).length >= 1 && bytes(result).length <= MAX_RESULT_BYTES, \"result 1..280\");\n        require(bytes(request).length <= MAX_REQUEST_BYTES, \"request <=600\");\n        bool hasReq = bytes(request).length > 0;\n\n        id = _feedbacks.length;\n        _feedbacks.push(Feedback({\n            app: app,\n            submitter: msg.sender,\n            rating: rating,\n            outcome: outcome,\n            result: result,\n            request: request,\n            hasRequest: hasReq,\n            addressed: false,\n            submittedAt: uint64(block.timestamp)\n        }));\n        _appFeedbackIds[app].push(id);\n        emit FeedbackSubmitted(id, app, msg.sender, rating, outcome);\n    }\n\n    /// @notice Mark an improvement request as addressed. Only the app author, and only if not changed otherwise.\n    function markAddressed(uint256 id) external {\n        require(id < _feedbacks.length, \"bad id\");\n        Feedback storage f = _feedbacks[id];\n        require(f.hasRequest, \"no request\");\n        require(!f.addressed, \"already addressed\");\n        require(msg.sender == _appAuthor[f.app], \"author only\");\n        f.addressed = true;\n        emit RequestAddressed(id, f.app, msg.sender);\n    }\n\n    /// @notice Total number of feedback entries.\n    function feedbackCount() external view returns (uint256) {\n        return _feedbacks.length;\n    }\n\n    /// @notice One feedback entry by id.\n    function getFeedback(uint256 id) external view returns (Feedback memory) {\n        require(id < _feedbacks.length, \"bad id\");\n        return _feedbacks[id];\n    }\n\n    /// @notice Feedback ids for one app, paginated.\n    function getAppFeedbackIds(address app, uint256 offset, uint256 limit) external view returns (uint256[] memory) {\n        uint256[] storage ids = _appFeedbackIds[app];\n        uint256 n = ids.length;\n        if (offset >= n) return new uint256[](0);\n        uint256 take = limit;\n        if (offset + take > n) take = n - offset;\n        uint256[] memory out = new uint256[](take);\n        for (uint256 i = 0; i < take; i++) out[i] = ids[offset + i];\n        return out;\n    }\n\n    /// @notice How many feedback entries an app has.\n    function appFeedbackCount(address app) external view returns (uint256) {\n        return _appFeedbackIds[app].length;\n    }\n\n    /// @notice Claimed author of an app address, or zero address if none.\n    function appAuthor(address app) external view returns (address) {\n        return _appAuthor[app];\n    }\n}\n"}}},"gas_used":"968581"}