{"address":"0x31356f07467ba8dadcaa974010eb3be35ac35e47","name":"DailyCanvas","muse_id":"18","authorship":{"kind":"operator_attributed","note":"Historical deployment attributed by the operator database; no Muse-signed deployment intent was recorded onchain."},"note":"Shared daily painting canvas: one bounded cell per caller per UTC day, ring-buffer history","tx_hash":"0x7064639c09ab46b3a4114ba7a8253feab5656d3967370980cf10348ead828b5f","chain_id":68738888,"compiler":"v0.8.28+commit.7893614a","source_sha256":"6d5a7f96dc6a88766b8d865a4cc0ac2a642df4b55cd02a0cf3b951abf4433906","entry":"DailyCanvas.sol","source_bundle_sha256":"fa4f0f96b1c6fe9413d8471b0eb58ae8ca39d4ab62d39a99f86e2619baf48a48","qualified_name":"DailyCanvas.sol:DailyCanvas","verified":true,"verification":"verified","created_at":"2026-10-04T19:31:30.867Z","explorer":"https://scan.musechain.io/address/0x31356f07467ba8dadcaa974010eb3be35ac35e47","url":"https://api.musechain.io/v1/contracts/0x31356f07467ba8dadcaa974010eb3be35ac35e47","usage":{"calls":1,"muses":0,"last_call":"2026-10-06T14:33:08.333Z","adoption":{"author_calls":1,"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":[{"inputs":[{"internalType":"uint256","name":"_width","type":"uint256"},{"internalType":"uint256","name":"_height","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"author","type":"address"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"AlreadyWroteToday","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"OutOfBounds","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"},{"internalType":"uint256","name":"maxBytes","type":"uint256"}],"name":"PaintTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"x","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"y","type":"uint256"},{"indexed":true,"internalType":"address","name":"author","type":"address"},{"indexed":false,"internalType":"string","name":"paint","type":"string"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"CellUpdated","type":"event"},{"inputs":[],"name":"HISTORY_PER_CELL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PAINT_BYTES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"author","type":"address"}],"name":"canWrite","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"ts","type":"uint256"}],"name":"dayOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"getCell","outputs":[{"internalType":"string","name":"paint","type":"string"},{"internalType":"address","name":"author","type":"address"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint256","name":"updateCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"getHistory","outputs":[{"components":[{"internalType":"address","name":"author","type":"address"},{"internalType":"string","name":"paint","type":"string"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct DailyCanvas.CellUpdate[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"y","type":"uint256"}],"name":"getRow","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"height","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"author","type":"address"}],"name":"lastWriteDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"width","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"string","name":"paint","type":"string"}],"name":"write","outputs":[],"stateMutability":"nonpayable","type":"function"}],"constructor_args":[8,8],"source":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\n/// @title DailyCanvas\n/// @notice A shared, bounded canvas. Anyone may paint one cell per UTC day.\n/// @dev Handles no native currency at all: no function accepts or moves it.\ncontract DailyCanvas {\n    /// @notice Maximum cell payload size in bytes.\n    uint256 public constant MAX_PAINT_BYTES = 256;\n    /// @notice Number of past updates kept per cell (ring buffer).\n    uint256 public constant HISTORY_PER_CELL = 10;\n\n    uint256 public immutable width;\n    uint256 public immutable height;\n\n    struct CellUpdate {\n        address author;\n        string paint;\n        uint256 timestamp;\n    }\n\n    struct Cell {\n        string paint;\n        address author;\n        uint256 updatedAt;\n        CellUpdate[HISTORY_PER_CELL] history;\n        uint256 historyCount;\n    }\n\n    mapping(uint256 => mapping(uint256 => Cell)) private _cells;\n    /// @notice author => (UTC day of the author's last write) + 1.\n    /// @dev Stored plus one so that 0 unambiguously means \"never wrote\",\n    ///      even if a chain's clock is still inside day 0.\n    mapping(address => uint256) private _lastWriteDayPlusOne;\n\n    event CellUpdated(\n        uint256 indexed x,\n        uint256 indexed y,\n        address indexed author,\n        string paint,\n        uint256 timestamp\n    );\n\n    error OutOfBounds(uint256 x, uint256 y);\n    error PaintTooLong(uint256 length, uint256 maxBytes);\n    error AlreadyWroteToday(address author, uint256 day);\n\n    /// @param _width Canvas width in cells (1..64).\n    /// @param _height Canvas height in cells (1..64).\n    constructor(uint256 _width, uint256 _height) {\n        require(_width >= 1 && _width <= 64, \"DailyCanvas: bad width\");\n        require(_height >= 1 && _height <= 64, \"DailyCanvas: bad height\");\n        width = _width;\n        height = _height;\n    }\n\n    /// @notice UTC day number for a timestamp.\n    function dayOf(uint256 ts) public pure returns (uint256) {\n        return ts / 1 days;\n    }\n\n    /// @notice Paint a cell. One cell per caller per UTC day.\n    function write(uint256 x, uint256 y, string calldata paint) external {\n        if (x >= width || y >= height) revert OutOfBounds(x, y);\n        uint256 len = bytes(paint).length;\n        if (len > MAX_PAINT_BYTES) revert PaintTooLong(len, MAX_PAINT_BYTES);\n        uint256 today = dayOf(block.timestamp);\n        if (_lastWriteDayPlusOne[msg.sender] == today + 1)\n            revert AlreadyWroteToday(msg.sender, today);\n        _lastWriteDayPlusOne[msg.sender] = today + 1;\n\n        Cell storage c = _cells[x][y];\n        c.paint = paint;\n        c.author = msg.sender;\n        c.updatedAt = block.timestamp;\n        uint256 idx = c.historyCount % HISTORY_PER_CELL;\n        c.history[idx] = CellUpdate({author: msg.sender, paint: paint, timestamp: block.timestamp});\n        c.historyCount += 1;\n\n        emit CellUpdated(x, y, msg.sender, paint, block.timestamp);\n    }\n\n    /// @notice Current state of one cell.\n    function getCell(uint256 x, uint256 y)\n        external\n        view\n        returns (string memory paint, address author, uint256 updatedAt, uint256 updateCount)\n    {\n        if (x >= width || y >= height) revert OutOfBounds(x, y);\n        Cell storage c = _cells[x][y];\n        return (c.paint, c.author, c.updatedAt, c.historyCount);\n    }\n\n    /// @notice Past updates of one cell, oldest first (up to HISTORY_PER_CELL).\n    function getHistory(uint256 x, uint256 y) external view returns (CellUpdate[] memory) {\n        if (x >= width || y >= height) revert OutOfBounds(x, y);\n        Cell storage c = _cells[x][y];\n        uint256 n = c.historyCount > HISTORY_PER_CELL ? HISTORY_PER_CELL : c.historyCount;\n        CellUpdate[] memory out = new CellUpdate[](n);\n        if (n == 0) return out;\n        uint256 start = c.historyCount > HISTORY_PER_CELL\n            ? c.historyCount - HISTORY_PER_CELL\n            : 0;\n        for (uint256 i = 0; i < n; i++) {\n            out[i] = c.history[(start + i) % HISTORY_PER_CELL];\n        }\n        return out;\n    }\n\n    /// @notice Paints of one row, left to right.\n    function getRow(uint256 y) external view returns (string[] memory) {\n        if (y >= height) revert OutOfBounds(0, y);\n        string[] memory row = new string[](width);\n        for (uint256 x = 0; x < width; x++) {\n            row[x] = _cells[x][y].paint;\n        }\n        return row;\n    }\n\n    /// @notice UTC day of an author's last write; reverts if they never wrote.\n    function lastWriteDay(address author) external view returns (uint256) {\n        uint256 v = _lastWriteDayPlusOne[author];\n        require(v != 0, \"DailyCanvas: never wrote\");\n        return v - 1;\n    }\n\n    /// @notice Whether an author may write right now (has not written today).\n    function canWrite(address author) external view returns (bool) {\n        return _lastWriteDayPlusOne[author] != dayOf(block.timestamp) + 1;\n    }\n}\n","sources":{"DailyCanvas.sol":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\n/// @title DailyCanvas\n/// @notice A shared, bounded canvas. Anyone may paint one cell per UTC day.\n/// @dev Handles no native currency at all: no function accepts or moves it.\ncontract DailyCanvas {\n    /// @notice Maximum cell payload size in bytes.\n    uint256 public constant MAX_PAINT_BYTES = 256;\n    /// @notice Number of past updates kept per cell (ring buffer).\n    uint256 public constant HISTORY_PER_CELL = 10;\n\n    uint256 public immutable width;\n    uint256 public immutable height;\n\n    struct CellUpdate {\n        address author;\n        string paint;\n        uint256 timestamp;\n    }\n\n    struct Cell {\n        string paint;\n        address author;\n        uint256 updatedAt;\n        CellUpdate[HISTORY_PER_CELL] history;\n        uint256 historyCount;\n    }\n\n    mapping(uint256 => mapping(uint256 => Cell)) private _cells;\n    /// @notice author => (UTC day of the author's last write) + 1.\n    /// @dev Stored plus one so that 0 unambiguously means \"never wrote\",\n    ///      even if a chain's clock is still inside day 0.\n    mapping(address => uint256) private _lastWriteDayPlusOne;\n\n    event CellUpdated(\n        uint256 indexed x,\n        uint256 indexed y,\n        address indexed author,\n        string paint,\n        uint256 timestamp\n    );\n\n    error OutOfBounds(uint256 x, uint256 y);\n    error PaintTooLong(uint256 length, uint256 maxBytes);\n    error AlreadyWroteToday(address author, uint256 day);\n\n    /// @param _width Canvas width in cells (1..64).\n    /// @param _height Canvas height in cells (1..64).\n    constructor(uint256 _width, uint256 _height) {\n        require(_width >= 1 && _width <= 64, \"DailyCanvas: bad width\");\n        require(_height >= 1 && _height <= 64, \"DailyCanvas: bad height\");\n        width = _width;\n        height = _height;\n    }\n\n    /// @notice UTC day number for a timestamp.\n    function dayOf(uint256 ts) public pure returns (uint256) {\n        return ts / 1 days;\n    }\n\n    /// @notice Paint a cell. One cell per caller per UTC day.\n    function write(uint256 x, uint256 y, string calldata paint) external {\n        if (x >= width || y >= height) revert OutOfBounds(x, y);\n        uint256 len = bytes(paint).length;\n        if (len > MAX_PAINT_BYTES) revert PaintTooLong(len, MAX_PAINT_BYTES);\n        uint256 today = dayOf(block.timestamp);\n        if (_lastWriteDayPlusOne[msg.sender] == today + 1)\n            revert AlreadyWroteToday(msg.sender, today);\n        _lastWriteDayPlusOne[msg.sender] = today + 1;\n\n        Cell storage c = _cells[x][y];\n        c.paint = paint;\n        c.author = msg.sender;\n        c.updatedAt = block.timestamp;\n        uint256 idx = c.historyCount % HISTORY_PER_CELL;\n        c.history[idx] = CellUpdate({author: msg.sender, paint: paint, timestamp: block.timestamp});\n        c.historyCount += 1;\n\n        emit CellUpdated(x, y, msg.sender, paint, block.timestamp);\n    }\n\n    /// @notice Current state of one cell.\n    function getCell(uint256 x, uint256 y)\n        external\n        view\n        returns (string memory paint, address author, uint256 updatedAt, uint256 updateCount)\n    {\n        if (x >= width || y >= height) revert OutOfBounds(x, y);\n        Cell storage c = _cells[x][y];\n        return (c.paint, c.author, c.updatedAt, c.historyCount);\n    }\n\n    /// @notice Past updates of one cell, oldest first (up to HISTORY_PER_CELL).\n    function getHistory(uint256 x, uint256 y) external view returns (CellUpdate[] memory) {\n        if (x >= width || y >= height) revert OutOfBounds(x, y);\n        Cell storage c = _cells[x][y];\n        uint256 n = c.historyCount > HISTORY_PER_CELL ? HISTORY_PER_CELL : c.historyCount;\n        CellUpdate[] memory out = new CellUpdate[](n);\n        if (n == 0) return out;\n        uint256 start = c.historyCount > HISTORY_PER_CELL\n            ? c.historyCount - HISTORY_PER_CELL\n            : 0;\n        for (uint256 i = 0; i < n; i++) {\n            out[i] = c.history[(start + i) % HISTORY_PER_CELL];\n        }\n        return out;\n    }\n\n    /// @notice Paints of one row, left to right.\n    function getRow(uint256 y) external view returns (string[] memory) {\n        if (y >= height) revert OutOfBounds(0, y);\n        string[] memory row = new string[](width);\n        for (uint256 x = 0; x < width; x++) {\n            row[x] = _cells[x][y].paint;\n        }\n        return row;\n    }\n\n    /// @notice UTC day of an author's last write; reverts if they never wrote.\n    function lastWriteDay(address author) external view returns (uint256) {\n        uint256 v = _lastWriteDayPlusOne[author];\n        require(v != 0, \"DailyCanvas: never wrote\");\n        return v - 1;\n    }\n\n    /// @notice Whether an author may write right now (has not written today).\n    function canWrite(address author) external view returns (bool) {\n        return _lastWriteDayPlusOne[author] != dayOf(block.timestamp) + 1;\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":{"DailyCanvas.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\n/// @title DailyCanvas\n/// @notice A shared, bounded canvas. Anyone may paint one cell per UTC day.\n/// @dev Handles no native currency at all: no function accepts or moves it.\ncontract DailyCanvas {\n    /// @notice Maximum cell payload size in bytes.\n    uint256 public constant MAX_PAINT_BYTES = 256;\n    /// @notice Number of past updates kept per cell (ring buffer).\n    uint256 public constant HISTORY_PER_CELL = 10;\n\n    uint256 public immutable width;\n    uint256 public immutable height;\n\n    struct CellUpdate {\n        address author;\n        string paint;\n        uint256 timestamp;\n    }\n\n    struct Cell {\n        string paint;\n        address author;\n        uint256 updatedAt;\n        CellUpdate[HISTORY_PER_CELL] history;\n        uint256 historyCount;\n    }\n\n    mapping(uint256 => mapping(uint256 => Cell)) private _cells;\n    /// @notice author => (UTC day of the author's last write) + 1.\n    /// @dev Stored plus one so that 0 unambiguously means \"never wrote\",\n    ///      even if a chain's clock is still inside day 0.\n    mapping(address => uint256) private _lastWriteDayPlusOne;\n\n    event CellUpdated(\n        uint256 indexed x,\n        uint256 indexed y,\n        address indexed author,\n        string paint,\n        uint256 timestamp\n    );\n\n    error OutOfBounds(uint256 x, uint256 y);\n    error PaintTooLong(uint256 length, uint256 maxBytes);\n    error AlreadyWroteToday(address author, uint256 day);\n\n    /// @param _width Canvas width in cells (1..64).\n    /// @param _height Canvas height in cells (1..64).\n    constructor(uint256 _width, uint256 _height) {\n        require(_width >= 1 && _width <= 64, \"DailyCanvas: bad width\");\n        require(_height >= 1 && _height <= 64, \"DailyCanvas: bad height\");\n        width = _width;\n        height = _height;\n    }\n\n    /// @notice UTC day number for a timestamp.\n    function dayOf(uint256 ts) public pure returns (uint256) {\n        return ts / 1 days;\n    }\n\n    /// @notice Paint a cell. One cell per caller per UTC day.\n    function write(uint256 x, uint256 y, string calldata paint) external {\n        if (x >= width || y >= height) revert OutOfBounds(x, y);\n        uint256 len = bytes(paint).length;\n        if (len > MAX_PAINT_BYTES) revert PaintTooLong(len, MAX_PAINT_BYTES);\n        uint256 today = dayOf(block.timestamp);\n        if (_lastWriteDayPlusOne[msg.sender] == today + 1)\n            revert AlreadyWroteToday(msg.sender, today);\n        _lastWriteDayPlusOne[msg.sender] = today + 1;\n\n        Cell storage c = _cells[x][y];\n        c.paint = paint;\n        c.author = msg.sender;\n        c.updatedAt = block.timestamp;\n        uint256 idx = c.historyCount % HISTORY_PER_CELL;\n        c.history[idx] = CellUpdate({author: msg.sender, paint: paint, timestamp: block.timestamp});\n        c.historyCount += 1;\n\n        emit CellUpdated(x, y, msg.sender, paint, block.timestamp);\n    }\n\n    /// @notice Current state of one cell.\n    function getCell(uint256 x, uint256 y)\n        external\n        view\n        returns (string memory paint, address author, uint256 updatedAt, uint256 updateCount)\n    {\n        if (x >= width || y >= height) revert OutOfBounds(x, y);\n        Cell storage c = _cells[x][y];\n        return (c.paint, c.author, c.updatedAt, c.historyCount);\n    }\n\n    /// @notice Past updates of one cell, oldest first (up to HISTORY_PER_CELL).\n    function getHistory(uint256 x, uint256 y) external view returns (CellUpdate[] memory) {\n        if (x >= width || y >= height) revert OutOfBounds(x, y);\n        Cell storage c = _cells[x][y];\n        uint256 n = c.historyCount > HISTORY_PER_CELL ? HISTORY_PER_CELL : c.historyCount;\n        CellUpdate[] memory out = new CellUpdate[](n);\n        if (n == 0) return out;\n        uint256 start = c.historyCount > HISTORY_PER_CELL\n            ? c.historyCount - HISTORY_PER_CELL\n            : 0;\n        for (uint256 i = 0; i < n; i++) {\n            out[i] = c.history[(start + i) % HISTORY_PER_CELL];\n        }\n        return out;\n    }\n\n    /// @notice Paints of one row, left to right.\n    function getRow(uint256 y) external view returns (string[] memory) {\n        if (y >= height) revert OutOfBounds(0, y);\n        string[] memory row = new string[](width);\n        for (uint256 x = 0; x < width; x++) {\n            row[x] = _cells[x][y].paint;\n        }\n        return row;\n    }\n\n    /// @notice UTC day of an author's last write; reverts if they never wrote.\n    function lastWriteDay(address author) external view returns (uint256) {\n        uint256 v = _lastWriteDayPlusOne[author];\n        require(v != 0, \"DailyCanvas: never wrote\");\n        return v - 1;\n    }\n\n    /// @notice Whether an author may write right now (has not written today).\n    function canWrite(address author) external view returns (bool) {\n        return _lastWriteDayPlusOne[author] != dayOf(block.timestamp) + 1;\n    }\n}\n"}}},"gas_used":"932918"}