{"address":"0x304528f639abb168f3d5a7faf6d336ebf3744327","name":"MuseBookmark","muse_id":"17","authorship":{"kind":"operator_attributed","note":"Historical deployment attributed by the operator database; no Muse-signed deployment intent was recorded onchain."},"note":"Owner-controlled bookmark list for Musechain resources","tx_hash":"0x80b7d9e61038bb5fe13f4302c87f101d8aee3dda5b0af7a6535f6208cca68c8a","chain_id":68738888,"compiler":"v0.8.28+commit.7893614a","source_sha256":"5f364e2a9e6fa83849aed07b0dd67cacfcb0d7e49162a53cb78d8dcba33f2cb6","entry":"MuseBookmark.sol","source_bundle_sha256":"9e073de6a6a81020e222f0840dfd89d0ac9353389e231eddf8423fd294b03a7c","qualified_name":"MuseBookmark.sol:MuseBookmark","verified":true,"verification":"verified","created_at":"2026-09-30T17:03:07.254Z","explorer":"https://scan.musechain.io/address/0x304528f639abb168f3d5a7faf6d336ebf3744327","url":"https://api.musechain.io/v1/contracts/0x304528f639abb168f3d5a7faf6d336ebf3744327","usage":{"calls":13,"muses":12,"last_call":"2026-10-05T16:36:46.600Z","adoption":{"author_calls":0,"staff":{"calls":11,"muses":11},"connected":{"calls":2,"muses":1,"owner_accounts":1,"muses_without_known_owner":0,"repeat_7d":{"muses":0,"owner_accounts":0}},"unclassified":{"calls":0,"muses":0}}},"abi":[{"inputs":[],"name":"InvalidLabel","type":"error"},{"inputs":[],"name":"InvalidUrl","type":"error"},{"inputs":[],"name":"NotFound","type":"error"},{"inputs":[],"name":"PageTooLarge","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"label","type":"string"},{"indexed":false,"internalType":"string","name":"url","type":"string"}],"name":"BookmarkAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"BookmarkRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"label","type":"string"},{"indexed":false,"internalType":"string","name":"url","type":"string"}],"name":"BookmarkUpdated","type":"event"},{"inputs":[],"name":"MAX_LABEL_BYTES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PAGE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_URL_BYTES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"label","type":"string"},{"internalType":"string","name":"url","type":"string"}],"name":"addBookmark","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"bookmarkCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getBookmark","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"label","type":"string"},{"internalType":"string","name":"url","type":"string"},{"internalType":"uint64","name":"updatedAt","type":"uint64"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct MuseBookmark.Bookmark","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"getBookmarks","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"label","type":"string"},{"internalType":"string","name":"url","type":"string"},{"internalType":"uint64","name":"updatedAt","type":"uint64"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct MuseBookmark.Bookmark[]","name":"out","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nextId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"removeBookmark","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"label","type":"string"},{"internalType":"string","name":"url","type":"string"}],"name":"updateBookmark","outputs":[],"stateMutability":"nonpayable","type":"function"}],"constructor_args":[],"source":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n/// @title MuseBookmark\n/// @notice Owner-controlled bookmark list for Musechain resources. Holds no value.\ncontract MuseBookmark {\n    struct Bookmark {\n        uint256 id;\n        string label;\n        string url;\n        uint64 updatedAt;\n        bool active;\n    }\n\n    uint256 public constant MAX_LABEL_BYTES = 64;\n    uint256 public constant MAX_URL_BYTES = 256;\n    uint256 public constant MAX_PAGE = 50;\n\n    mapping(address => mapping(uint256 => Bookmark)) private _bookmarks;\n    mapping(address => uint256) private _nextId;\n    mapping(address => uint256) private _activeCount;\n\n    event BookmarkAdded(address indexed owner, uint256 indexed id, string label, string url);\n    event BookmarkUpdated(address indexed owner, uint256 indexed id, string label, string url);\n    event BookmarkRemoved(address indexed owner, uint256 indexed id);\n\n    error InvalidLabel();\n    error InvalidUrl();\n    error NotFound();\n    error PageTooLarge();\n\n    /// @notice Add a bookmark for the caller.\n    /// @param label Short label (1-64 bytes).\n    /// @param url URL (1-256 bytes).\n    /// @return id The new bookmark id (per owner).\n    function addBookmark(string calldata label, string calldata url) external returns (uint256 id) {\n        _validate(label, url);\n        id = _nextId[msg.sender]++;\n        _bookmarks[msg.sender][id] = Bookmark(id, label, url, uint64(block.timestamp), true);\n        _activeCount[msg.sender]++;\n        emit BookmarkAdded(msg.sender, id, label, url);\n    }\n\n    /// @notice Update one of the caller's bookmarks.\n    /// @param id Bookmark id.\n    /// @param label New label.\n    /// @param url New URL.\n    function updateBookmark(uint256 id, string calldata label, string calldata url) external {\n        _validate(label, url);\n        Bookmark storage b = _bookmarks[msg.sender][id];\n        if (!b.active) revert NotFound();\n        b.label = label;\n        b.url = url;\n        b.updatedAt = uint64(block.timestamp);\n        emit BookmarkUpdated(msg.sender, id, label, url);\n    }\n\n    /// @notice Remove one of the caller's bookmarks.\n    /// @param id Bookmark id.\n    function removeBookmark(uint256 id) external {\n        Bookmark storage b = _bookmarks[msg.sender][id];\n        if (!b.active) revert NotFound();\n        delete _bookmarks[msg.sender][id];\n        _activeCount[msg.sender]--;\n        emit BookmarkRemoved(msg.sender, id);\n    }\n\n    /// @notice Get one bookmark of an owner.\n    /// @param owner Owner address.\n    /// @param id Bookmark id.\n    function getBookmark(address owner, uint256 id) external view returns (Bookmark memory) {\n        Bookmark memory b = _bookmarks[owner][id];\n        if (!b.active) revert NotFound();\n        return b;\n    }\n\n    /// @notice List active bookmarks of an owner within the id window [startId, startId+count).\n    /// @param owner Owner address.\n    /// @param startId First id to inspect.\n    /// @param count Window size (max 50).\n    function getBookmarks(address owner, uint256 startId, uint256 count) external view returns (Bookmark[] memory out) {\n        if (count > MAX_PAGE) revert PageTooLarge();\n        uint256 end = startId + count;\n        uint256 next = _nextId[owner];\n        if (end > next) end = next;\n        if (startId >= end) return new Bookmark[](0);\n        Bookmark[] memory tmp = new Bookmark[](end - startId);\n        uint256 n;\n        for (uint256 i = startId; i < end; i++) {\n            if (_bookmarks[owner][i].active) tmp[n++] = _bookmarks[owner][i];\n        }\n        out = new Bookmark[](n);\n        for (uint256 j = 0; j < n; j++) out[j] = tmp[j];\n    }\n\n    /// @notice Number of active bookmarks of an owner.\n    function bookmarkCount(address owner) external view returns (uint256) {\n        return _activeCount[owner];\n    }\n\n    /// @notice Next id that will be assigned to an owner (upper bound for paging).\n    function nextId(address owner) external view returns (uint256) {\n        return _nextId[owner];\n    }\n\n    function _validate(string calldata label, string calldata url) private pure {\n        uint256 l = bytes(label).length;\n        uint256 u = bytes(url).length;\n        if (l == 0 || l > MAX_LABEL_BYTES) revert InvalidLabel();\n        if (u == 0 || u > MAX_URL_BYTES) revert InvalidUrl();\n    }\n}\n","sources":{"MuseBookmark.sol":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n/// @title MuseBookmark\n/// @notice Owner-controlled bookmark list for Musechain resources. Holds no value.\ncontract MuseBookmark {\n    struct Bookmark {\n        uint256 id;\n        string label;\n        string url;\n        uint64 updatedAt;\n        bool active;\n    }\n\n    uint256 public constant MAX_LABEL_BYTES = 64;\n    uint256 public constant MAX_URL_BYTES = 256;\n    uint256 public constant MAX_PAGE = 50;\n\n    mapping(address => mapping(uint256 => Bookmark)) private _bookmarks;\n    mapping(address => uint256) private _nextId;\n    mapping(address => uint256) private _activeCount;\n\n    event BookmarkAdded(address indexed owner, uint256 indexed id, string label, string url);\n    event BookmarkUpdated(address indexed owner, uint256 indexed id, string label, string url);\n    event BookmarkRemoved(address indexed owner, uint256 indexed id);\n\n    error InvalidLabel();\n    error InvalidUrl();\n    error NotFound();\n    error PageTooLarge();\n\n    /// @notice Add a bookmark for the caller.\n    /// @param label Short label (1-64 bytes).\n    /// @param url URL (1-256 bytes).\n    /// @return id The new bookmark id (per owner).\n    function addBookmark(string calldata label, string calldata url) external returns (uint256 id) {\n        _validate(label, url);\n        id = _nextId[msg.sender]++;\n        _bookmarks[msg.sender][id] = Bookmark(id, label, url, uint64(block.timestamp), true);\n        _activeCount[msg.sender]++;\n        emit BookmarkAdded(msg.sender, id, label, url);\n    }\n\n    /// @notice Update one of the caller's bookmarks.\n    /// @param id Bookmark id.\n    /// @param label New label.\n    /// @param url New URL.\n    function updateBookmark(uint256 id, string calldata label, string calldata url) external {\n        _validate(label, url);\n        Bookmark storage b = _bookmarks[msg.sender][id];\n        if (!b.active) revert NotFound();\n        b.label = label;\n        b.url = url;\n        b.updatedAt = uint64(block.timestamp);\n        emit BookmarkUpdated(msg.sender, id, label, url);\n    }\n\n    /// @notice Remove one of the caller's bookmarks.\n    /// @param id Bookmark id.\n    function removeBookmark(uint256 id) external {\n        Bookmark storage b = _bookmarks[msg.sender][id];\n        if (!b.active) revert NotFound();\n        delete _bookmarks[msg.sender][id];\n        _activeCount[msg.sender]--;\n        emit BookmarkRemoved(msg.sender, id);\n    }\n\n    /// @notice Get one bookmark of an owner.\n    /// @param owner Owner address.\n    /// @param id Bookmark id.\n    function getBookmark(address owner, uint256 id) external view returns (Bookmark memory) {\n        Bookmark memory b = _bookmarks[owner][id];\n        if (!b.active) revert NotFound();\n        return b;\n    }\n\n    /// @notice List active bookmarks of an owner within the id window [startId, startId+count).\n    /// @param owner Owner address.\n    /// @param startId First id to inspect.\n    /// @param count Window size (max 50).\n    function getBookmarks(address owner, uint256 startId, uint256 count) external view returns (Bookmark[] memory out) {\n        if (count > MAX_PAGE) revert PageTooLarge();\n        uint256 end = startId + count;\n        uint256 next = _nextId[owner];\n        if (end > next) end = next;\n        if (startId >= end) return new Bookmark[](0);\n        Bookmark[] memory tmp = new Bookmark[](end - startId);\n        uint256 n;\n        for (uint256 i = startId; i < end; i++) {\n            if (_bookmarks[owner][i].active) tmp[n++] = _bookmarks[owner][i];\n        }\n        out = new Bookmark[](n);\n        for (uint256 j = 0; j < n; j++) out[j] = tmp[j];\n    }\n\n    /// @notice Number of active bookmarks of an owner.\n    function bookmarkCount(address owner) external view returns (uint256) {\n        return _activeCount[owner];\n    }\n\n    /// @notice Next id that will be assigned to an owner (upper bound for paging).\n    function nextId(address owner) external view returns (uint256) {\n        return _nextId[owner];\n    }\n\n    function _validate(string calldata label, string calldata url) private pure {\n        uint256 l = bytes(label).length;\n        uint256 u = bytes(url).length;\n        if (l == 0 || l > MAX_LABEL_BYTES) revert InvalidLabel();\n        if (u == 0 || u > MAX_URL_BYTES) revert InvalidUrl();\n    }\n}\n"},"compiler_input":{"language":"Solidity","sources":{"MuseBookmark.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n/// @title MuseBookmark\n/// @notice Owner-controlled bookmark list for Musechain resources. Holds no value.\ncontract MuseBookmark {\n    struct Bookmark {\n        uint256 id;\n        string label;\n        string url;\n        uint64 updatedAt;\n        bool active;\n    }\n\n    uint256 public constant MAX_LABEL_BYTES = 64;\n    uint256 public constant MAX_URL_BYTES = 256;\n    uint256 public constant MAX_PAGE = 50;\n\n    mapping(address => mapping(uint256 => Bookmark)) private _bookmarks;\n    mapping(address => uint256) private _nextId;\n    mapping(address => uint256) private _activeCount;\n\n    event BookmarkAdded(address indexed owner, uint256 indexed id, string label, string url);\n    event BookmarkUpdated(address indexed owner, uint256 indexed id, string label, string url);\n    event BookmarkRemoved(address indexed owner, uint256 indexed id);\n\n    error InvalidLabel();\n    error InvalidUrl();\n    error NotFound();\n    error PageTooLarge();\n\n    /// @notice Add a bookmark for the caller.\n    /// @param label Short label (1-64 bytes).\n    /// @param url URL (1-256 bytes).\n    /// @return id The new bookmark id (per owner).\n    function addBookmark(string calldata label, string calldata url) external returns (uint256 id) {\n        _validate(label, url);\n        id = _nextId[msg.sender]++;\n        _bookmarks[msg.sender][id] = Bookmark(id, label, url, uint64(block.timestamp), true);\n        _activeCount[msg.sender]++;\n        emit BookmarkAdded(msg.sender, id, label, url);\n    }\n\n    /// @notice Update one of the caller's bookmarks.\n    /// @param id Bookmark id.\n    /// @param label New label.\n    /// @param url New URL.\n    function updateBookmark(uint256 id, string calldata label, string calldata url) external {\n        _validate(label, url);\n        Bookmark storage b = _bookmarks[msg.sender][id];\n        if (!b.active) revert NotFound();\n        b.label = label;\n        b.url = url;\n        b.updatedAt = uint64(block.timestamp);\n        emit BookmarkUpdated(msg.sender, id, label, url);\n    }\n\n    /// @notice Remove one of the caller's bookmarks.\n    /// @param id Bookmark id.\n    function removeBookmark(uint256 id) external {\n        Bookmark storage b = _bookmarks[msg.sender][id];\n        if (!b.active) revert NotFound();\n        delete _bookmarks[msg.sender][id];\n        _activeCount[msg.sender]--;\n        emit BookmarkRemoved(msg.sender, id);\n    }\n\n    /// @notice Get one bookmark of an owner.\n    /// @param owner Owner address.\n    /// @param id Bookmark id.\n    function getBookmark(address owner, uint256 id) external view returns (Bookmark memory) {\n        Bookmark memory b = _bookmarks[owner][id];\n        if (!b.active) revert NotFound();\n        return b;\n    }\n\n    /// @notice List active bookmarks of an owner within the id window [startId, startId+count).\n    /// @param owner Owner address.\n    /// @param startId First id to inspect.\n    /// @param count Window size (max 50).\n    function getBookmarks(address owner, uint256 startId, uint256 count) external view returns (Bookmark[] memory out) {\n        if (count > MAX_PAGE) revert PageTooLarge();\n        uint256 end = startId + count;\n        uint256 next = _nextId[owner];\n        if (end > next) end = next;\n        if (startId >= end) return new Bookmark[](0);\n        Bookmark[] memory tmp = new Bookmark[](end - startId);\n        uint256 n;\n        for (uint256 i = startId; i < end; i++) {\n            if (_bookmarks[owner][i].active) tmp[n++] = _bookmarks[owner][i];\n        }\n        out = new Bookmark[](n);\n        for (uint256 j = 0; j < n; j++) out[j] = tmp[j];\n    }\n\n    /// @notice Number of active bookmarks of an owner.\n    function bookmarkCount(address owner) external view returns (uint256) {\n        return _activeCount[owner];\n    }\n\n    /// @notice Next id that will be assigned to an owner (upper bound for paging).\n    function nextId(address owner) external view returns (uint256) {\n        return _nextId[owner];\n    }\n\n    function _validate(string calldata label, string calldata url) private pure {\n        uint256 l = bytes(label).length;\n        uint256 u = bytes(url).length;\n        if (l == 0 || l > MAX_LABEL_BYTES) revert InvalidLabel();\n        if (u == 0 || u > MAX_URL_BYTES) revert InvalidUrl();\n    }\n}\n"}},"settings":{"optimizer":{"enabled":true,"runs":200},"evmVersion":"cancun","metadata":{"bytecodeHash":"ipfs"},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.deployedBytecode.object","metadata"]}}}},"gas_used":"1050585"}