BaseBase
0x45...5D46
Piece of Shit

Piece of Shit

POS

收藏品
底价
1 ETH
$2,345.34
大小
1,743 件
1,895 版
所有者
425
22% 独特的所有者
此合同的源代码已经过验证!
合同元数据
编译器
0.8.25+commit.b61c2a91
语言
Solidity
合同源代码
文件 1 的 16:Base64.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Base64.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides a set of functions to operate with Base64 strings.
 */
library Base64 {
    /**
     * @dev Base64 Encoding/Decoding Table
     * See sections 4 and 5 of https://datatracker.ietf.org/doc/html/rfc4648
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    string internal constant _TABLE_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

    /**
     * @dev Converts a `bytes` to its Bytes64 `string` representation.
     */
    function encode(bytes memory data) internal pure returns (string memory) {
        return _encode(data, _TABLE, true);
    }

    /**
     * @dev Converts a `bytes` to its Bytes64Url `string` representation.
     * Output is not padded with `=` as specified in https://www.rfc-editor.org/rfc/rfc4648[rfc4648].
     */
    function encodeURL(bytes memory data) internal pure returns (string memory) {
        return _encode(data, _TABLE_URL, false);
    }

    /**
     * @dev Internal table-agnostic conversion
     */
    function _encode(bytes memory data, string memory table, bool withPadding) private pure returns (string memory) {
        /**
         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
         */
        if (data.length == 0) return "";

        // If padding is enabled, the final length should be `bytes` data length divided by 3 rounded up and then
        // multiplied by 4 so that it leaves room for padding the last chunk
        // - `data.length + 2`  -> Prepare for division rounding up
        // - `/ 3`              -> Number of 3-bytes chunks (rounded up)
        // - `4 *`              -> 4 characters for each chunk
        // This is equivalent to: 4 * Math.ceil(data.length / 3)
        //
        // If padding is disabled, the final length should be `bytes` data length multiplied by 4/3 rounded up as
        // opposed to when padding is required to fill the last chunk.
        // - `4 * data.length`  -> 4 characters for each chunk
        // - ` + 2`             -> Prepare for division rounding up
        // - `/ 3`              -> Number of 3-bytes chunks (rounded up)
        // This is equivalent to: Math.ceil((4 * data.length) / 3)
        uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3;

        string memory result = new string(resultLength);

        assembly ("memory-safe") {
            // Prepare the lookup table (skip the first "length" byte)
            let tablePtr := add(table, 1)

            // Prepare result pointer, jump over length
            let resultPtr := add(result, 0x20)
            let dataPtr := data
            let endPtr := add(data, mload(data))

            // In some cases, the last iteration will read bytes after the end of the data. We cache the value, and
            // set it to zero to make sure no dirty bytes are read in that section.
            let afterPtr := add(endPtr, 0x20)
            let afterCache := mload(afterPtr)
            mstore(afterPtr, 0x00)

            // Run over the input, 3 bytes at a time
            for {

            } lt(dataPtr, endPtr) {

            } {
                // Advance 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // To write each character, shift the 3 byte (24 bits) chunk
                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                // and apply logical AND with 0x3F to bitmask the least significant 6 bits.
                // Use this as an index into the lookup table, mload an entire word
                // so the desired character is in the least significant byte, and
                // mstore8 this least significant byte into the result and continue.

                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance
            }

            // Reset the value that was cached
            mstore(afterPtr, afterCache)

            if withPadding {
                // When data `bytes` is not exactly 3 bytes long
                // it is padded with `=` characters at the end
                switch mod(mload(data), 3)
                case 1 {
                    mstore8(sub(resultPtr, 1), 0x3d)
                    mstore8(sub(resultPtr, 2), 0x3d)
                }
                case 2 {
                    mstore8(sub(resultPtr, 1), 0x3d)
                }
            }
        }

        return result;
    }
}
合同源代码
文件 2 的 16:Canvas.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import "../lib/StringConverter.sol";
import "./Rects.sol";
import "../lib/Ownable.sol";

uint constant CANVAS_SIZE = 32;
uint constant CHUNK_SIZE = 8;
uint constant MAX_CHUNKS_TO_UPDATE = 2;

struct Pixel {
    uint x;
    uint y;
    string color;
}

library PixelLibrary {
    function to_rect(
        Pixel memory pixel
    ) internal pure returns (Rect memory svg) {
        return Rect(pixel.x, pixel.y, 1, 1, pixel.color);
    }
}

struct PixelData {
    Pixel pixel;
    address owner;
    bool minted;
}
struct Chunk {
    uint x;
    uint y;
}

abstract contract Canvas is Ownable {
    using RectLibrary for Rect;
    using PixelLibrary for Pixel;

    mapping(uint x => mapping(uint y => PixelData data)) data;
    mapping(uint x => mapping(uint y => string chunk)) chunks;
    uint32[] chunks_to_update;

    modifier chunks_late_update() {
        _;
        if (chunks_to_update.length == 0) return;

        for (
            uint i = 0;
            chunks_to_update.length > 0 && i < MAX_CHUNKS_TO_UPDATE;
            ++i
        ) {
            (uint chunk_x, uint chunk_y) = id_to_chunk(
                chunks_to_update[chunks_to_update.length - 1]
            );
            calculate_chunk(chunk_x, chunk_y);
            chunks_to_update.pop();
        }
        if (chunks_to_update.length == 0) delete chunks_to_update;
    }

    function get_chunks_for_update()
        public
        view
        returns (Chunk[] memory chunks)
    {
        chunks = new Chunk[](chunks_to_update.length);
        if (chunks_to_update.length == 0) return chunks;
        for (uint i = 0; i < chunks_to_update.length; ++i) {
            (uint chunk_x, uint chunk_y) = id_to_chunk(chunks_to_update[i]);
            chunks[i] = Chunk(chunk_x, chunk_y);
        }
    }

    function size() public pure returns (uint x, uint y) {
        return (CANVAS_SIZE, CANVAS_SIZE);
    }

    function get_pixel_data(
        uint x,
        uint y
    ) public view returns (PixelData memory) {
        return data[x][y];
    }

    function get_svg() public view returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "<svg xmlns='http://www.w3.org/2000/svg' ",
                    "viewBox='0 0 ",
                    StringConverter.to_string(CANVAS_SIZE),
                    " ",
                    StringConverter.to_string(CANVAS_SIZE),
                    "' fill='none'>",
                    get_all_chunks(),
                    "</svg>"
                )
            );
    }

    function get_pixel_svg(
        string memory color
    ) internal pure returns (bytes memory) {
        return
            abi.encodePacked(
                "<svg xmlns='http://www.w3.org/2000/svg' ",
                "viewBox='0 0 ",
                StringConverter.to_string(CANVAS_SIZE),
                " ",
                StringConverter.to_string(CANVAS_SIZE),
                "' fill='none'>",
                Rect(0, 0, CANVAS_SIZE, CANVAS_SIZE, color).to_svg(),
                "'>",
                "</svg>"
            );
    }

    function get_all_chunks() private view returns (string memory) {
        bytes memory str;
        uint x;
        uint y;
        for (y = 0; y < CANVAS_SIZE / CHUNK_SIZE; ++y) {
            for (x = 0; x < CANVAS_SIZE / CHUNK_SIZE; ++x) {
                str = abi.encodePacked(str, chunks[x][y]);
            }
        }
        return string(str);
    }

    function get_svg_internal() private view returns (bytes memory) {
        uint x;
        uint y;
        bytes memory str;
        for (x = 0; x < CANVAS_SIZE; ++x) {
            for (y = 0; y < CANVAS_SIZE; ++y) {
                PixelData memory d = data[x][y];
                Rect memory rect = d.minted
                    ? d.pixel.to_rect()
                    : Rect(x, y, 1, 1, "aaaaaa");
                str = abi.encodePacked(str, rect.to_svg());
            }
        }

        return str;
    }

    function upload_shit(Pixel[] calldata pixels) external onlyOwner {
        uint i;
        for (i = 0; i < pixels.length; ++i) {
            data[pixels[i].x][pixels[i].y].pixel = pixels[i];
            (uint chunk_x, uint chunk_y) = get_chunk(pixels[i].x, pixels[i].y);
            add_chunk_to_update(chunk_x, chunk_y);
        }

        calculate_all_chunks();
    }

    function get_chunk(
        uint x,
        uint y
    ) public pure returns (uint hunk_x, uint chunk_y) {
        return (x / CHUNK_SIZE, y / CHUNK_SIZE);
    }

    function calculate_chunk(uint chunk_x, uint chunk_y) public {
        chunks[chunk_x][chunk_y] = _calculate_chunk(chunk_x, chunk_y);
    }

    function calculate_chunks(Chunk[] calldata chunks) public {
        for (uint i = 0; i < chunks.length; ++i) {
            calculate_chunk(chunks[i].x, chunks[i].y);
            remove_chunk_from_update(chunks[i].x, chunks[i].y);
        }
    }

    function calculate_all_chunks() public {
        if (chunks_to_update.length == 0) return;

        for (uint i = 0; i < chunks_to_update.length; ++i) {
            (uint chunk_x, uint chunk_y) = id_to_chunk(chunks_to_update[i]);
            calculate_chunk(chunk_x, chunk_y);
        }
        delete chunks_to_update;
    }

    function _calculate_chunk(
        uint chunk_x,
        uint chunk_y
    ) private view returns (string memory) {
        bytes memory str;
        uint x;
        uint y;
        for (y = chunk_y * CHUNK_SIZE; y < (chunk_y + 1) * CHUNK_SIZE; ++y) {
            for (
                x = chunk_x * CHUNK_SIZE;
                x < (chunk_x + 1) * CHUNK_SIZE;
                ++x
            ) {
                PixelData memory d = data[x][y];
                Rect memory rect = d.minted //(x + y) % 2 == 0 it is for test
                    ? d.pixel.to_rect()
                    : Rect(x, y, 1, 1, "aaaaaa");
                str = abi.encodePacked(str, rect.to_svg());
            }
        }
        return string(str);
    }

    function _set_pixel_owner(uint x, uint y, address owner) internal {
        data[x][y].owner = owner;
        if (owner != address(0)) data[x][y].minted = true;
        (uint chunk_x, uint chunk_y) = get_chunk(x, y);
        add_chunk_to_update(chunk_x, chunk_y);
    }

    function _burn_pixel(uint x, uint y) internal {
        delete data[x][y];
        (uint chunk_x, uint chunk_y) = get_chunk(x, y);
        add_chunk_to_update(chunk_x, chunk_y);
    }

    function pixel_to_id(
        uint pixel_x,
        uint pixel_y
    ) internal pure returns (uint32 pixel_id) {
        return uint32(pixel_y * CANVAS_SIZE + pixel_x);
    }

    function id_to_chunk(
        uint32 pixel_id
    ) internal pure returns (uint chunk_x, uint chunk_y) {
        chunk_x = pixel_id % (CANVAS_SIZE / CHUNK_SIZE);
        chunk_y = pixel_id / (CANVAS_SIZE / CHUNK_SIZE);
    }

    function chunk_to_id(
        uint chunk_x,
        uint chunk_y
    ) internal pure returns (uint32) {
        return uint32(chunk_y * (CANVAS_SIZE / CHUNK_SIZE) + chunk_x);
    }

    function add_chunk_to_update(uint chunk_x, uint chunk_y) public {
        uint32 value = chunk_to_id(chunk_x, chunk_y);
        for (uint i = 0; i < chunks_to_update.length; i++) {
            if (chunks_to_update[i] == value) {
                return;
            }
        }
        chunks_to_update.push(value);
    }

    function remove_chunk_from_update(uint chunk_x, uint chunk_y) public {
        uint32 value = chunk_to_id(chunk_x, chunk_y);

        for (uint i = 0; i < chunks_to_update.length; i++) {
            if (chunks_to_update[i] == value) {
                chunks_to_update[i] = chunks_to_update[
                    chunks_to_update.length - 1
                ];
                chunks_to_update.pop();
                return;
            }
        }
    }

    function get_pixel_owner(
        uint32 pixel_id
    ) internal view virtual returns (address);
}
合同源代码
文件 3 的 16:ERC20Token.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import "./IERC20.sol";
import "./IERC20Events.sol";

//address constant DEAD_ADDRESS = 0x000000000000000000000000000000000000dEaD;

abstract contract ERC20Token is IERC20 {
    string internal constant _name = "Piece of Shit";
    string internal constant _symbol = "POS";

    uint internal constant _decimals = 9;
    uint internal constant _totalIds = 1024;
    uint internal constant _totalSupply = _totalIds * 10 * 10 ** _decimals;
    address internal pool;
    uint256 constant _startMaxBuyCount = (_totalSupply * 5) / 10000;
    uint256 constant _addMaxBuyPercentPerSec = 5; // 100%=_addMaxBuyPrecesion
    uint256 constant _addMaxBuyPrecesion = 100000;
    uint256 internal _startTime;

    mapping(address => mapping(address => uint)) internal _allowance;
    mapping(address => uint) internal _balanceOf;

    constructor() {
        _balanceOf[msg.sender] = _totalSupply;
    }

    function name() public view virtual returns (string memory) {
        return _name;
    }

    function maxBuy() public view returns (uint256) {
        if (!erc20_started()) return _totalSupply;
        uint256 count = _startMaxBuyCount +
            (_totalSupply *
                (block.timestamp - _startTime) *
                _addMaxBuyPercentPerSec) /
            _addMaxBuyPrecesion;
        if (count > _totalSupply) count = _totalSupply;
        return count;
    }

    function dev_address() internal view virtual returns (address);

    function _start_erc20(address pool_address) internal {
        pool = pool_address;
        _startTime = block.timestamp;
    }

    function erc20_started() public view returns (bool) {
        return pool != address(0);
    }

    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    function decimals() public view virtual returns (uint) {
        return _decimals;
    }

    function totalSupply() public pure override returns (uint) {
        return _totalSupply;
    }

    function balanceOf_erc20(address account) public view returns (uint) {
        return _balanceOf[account];
    }

    function allowance(
        address owner,
        address spender
    ) public view override returns (uint) {
        return _allowance[owner][spender];
    }

    function _approve_erc20(
        address spender,
        uint amount
    ) internal returns (bool) {
        _allowance[msg.sender][spender] = amount;
        IERC20Events.emitApproval(msg.sender, spender, amount);
        return true;
    }

    function _spendAllowance(
        address owner,
        address spender,
        uint amount
    ) internal virtual {
        require(
            _allowance[owner][spender] >= amount,
            "TOKEN: insufficient allowance"
        );
        _allowance[owner][spender] -= amount;
    }

    function approve_erc20(address spender, uint amount) public returns (bool) {
        _allowance[msg.sender][spender] = amount;
        IERC20Events.emitApproval(msg.sender, spender, amount);
        return true;
    }

    function _transfer_erc20(
        address from,
        address to,
        uint256 amount
    ) internal {
        // system transfers
        if (
            !erc20_started() &&
            (from == address(0) ||
                from == address(this) ||
                from == dev_address() ||
                to == dev_address())
        ) {
            _balanceOf[from] -= amount;
            unchecked {
                _balanceOf[to] += amount;
            }
            IERC20Events.emitTransfer(from, to, amount);
            return;
        }

        require(erc20_started(), "token not started");
        if (from == pool) {
            require(amount <= maxBuy(), "max buy");
        }

        _balanceOf[from] -= amount;
        unchecked {
            _balanceOf[to] += amount;
        }
        IERC20Events.emitTransfer(from, to, amount);
    }
}
合同源代码
文件 4 的 16:ERC721Events.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

library ERC721Events {
    event Transfer(
        address indexed _from,
        address indexed _to,
        uint indexed _tokenId
    );
    event Approval(
        address indexed _owner,
        address indexed _approved,
        uint indexed _tokenId
    );
    event ApprovalForAll(
        address indexed _owner,
        address indexed _operator,
        bool _approved
    );

    function emitTransfer(address _from, address _to, uint _tokenId) internal {
        emit Transfer(_from, _to, _tokenId);
    }

    function emitApproval(
        address _owner,
        address _approve,
        uint _tokenId
    ) internal {
        emit Approval(_owner, _approve, _tokenId);
    }

    function emitApprovalForAll(
        address _owner,
        address _operator,
        bool _approved
    ) internal {
        emit ApprovalForAll(_owner, _operator, _approved);
    }
}
合同源代码
文件 5 的 16:ERC721Token.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import "./IERC721.sol";
import "./ERC721Events.sol";
import "./IERC721TokenReceiver.sol";
import "../../canvas/Canvas.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "../../lib/StringConverter.sol";
import "../../lib/String.sol";

uint32 constant MAX_MINTED_TOKENS_COUNT = 1024;

abstract contract ERC721Token is IERC721, Canvas {
    mapping(uint256 tokenId => address) public ownerOf;
    mapping(uint256 => address) private _nftApprovals;
    mapping(address => uint32[]) public ownedNFTs;
    mapping(address account => uint count) public balanceOfNft;
    mapping(uint32 => uint256) private idToIndex;
    mapping(address => mapping(address => bool)) private _operatorApprovals;
    uint32 public minted; // number of ID mints
    uint32 public mint_seed;

    error UnsupportedReceiver();

    constructor() {
        // mint picture
        minted = 1;
        ERC721Events.emitTransfer(address(0), address(this), 1);
        ownerOf[1] = address(this);
    }

    function pool_address() public view virtual returns (address);

    // Handles the transfer of an ERC721 token, ensuring proper ownership and event emission
    function _transfer_erc721(
        address from,
        address to,
        uint32 tokenId
    ) internal {
        if (to == pool_address()) {
            _burn_erc721(from, tokenId);
            return;
        }
        _transfer_erc721_internal(from, to, tokenId);
    }

    function _transfer_erc721_internal(
        address from,
        address to,
        uint32 tokenId
    ) private {
        require(from == ownerOf[tokenId], "ERC721: Incorrect owner"); // Ensure 'from' is the current owner

        delete _nftApprovals[tokenId]; // Clear any approvals for this token
        ownerOf[tokenId] = to; // Transfer ownership of the token to 'to'
        (uint x, uint y) = nft_id_to_pixel(tokenId);
        _set_pixel_owner(x, y, to);
        _updateOwnedNFTs(from, to, tokenId, false); // Update ownership tracking structures
        ERC721Events.emitTransfer(from, to, tokenId); // Emit an ERC721 transfer event
    }

    function _burn_erc721(address from, uint32 tokenId) internal {
        require(from == ownerOf[tokenId], "ERC721: Incorrect owner"); // Ensure 'from' is the current owner

        delete _nftApprovals[tokenId]; // Clear any approvals for this token
        ownerOf[tokenId] = address(0); // Transfer ownership of the token to 'to'
        (uint x, uint y) = nft_id_to_pixel(tokenId);
        _set_pixel_owner(x, y, address(0));

        _burn_pixel(x, y);

        _updateOwnedNFTs(from, address(0), tokenId, true); // Update ownership tracking structures
        ERC721Events.emitTransfer(from, address(0), tokenId); // Emit an ERC721 transfer event
    }

    // erc721
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public payable virtual;

    // erc721
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public payable virtual;

    function getApproved(uint256 tokenId) public view returns (address) {
        if (ownerOf[tokenId] == address(0)) revert();
        return _nftApprovals[tokenId];
    }

    function isApprovedForAll(
        address owner,
        address operator
    ) public view override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    function setApprovalForAll(
        address operator,
        bool approved
    ) public override {
        _operatorApprovals[msg.sender][operator] = approved;
        ERC721Events.emitApprovalForAll(msg.sender, operator, approved);
    }

    // payable removed for erc20 etherscan compatibility
    function approve_erc721(
        address spender,
        uint256 tokenId
    ) internal returns (bool) {
        address owner = ownerOf[tokenId]; // getting the owner of token ID via the `amount` input
        if (owner == address(0)) return false;
        if (msg.sender != owner && !isApprovedForAll(owner, msg.sender))
            revert("TOKEN: You are not approved");
        _nftApprovals[tokenId] = spender; // calling nft approval for the token and spender
        ERC721Events.emitApproval(owner, spender, tokenId);
        return true;
    }

    function picture_pixels_state() internal view returns (string memory) {
        return
            string(
                abi.encodePacked(
                    StringConverter.to_string(minted > 0 ? minted - 1 : minted),
                    "/",
                    StringConverter.to_string(MAX_MINTED_TOKENS_COUNT)
                )
            );
    }

    function picture_meta() private view returns (bytes memory) {
        return
            abi.encodePacked(
                '{"name": "Shit Painting", "description": "Own a piece of Doge\'s shit on the blockchain. A piece of pure decentralized art online that no one can take down or steal from its collective owners.", "attributes": [{"trait_type": "Pixels", "value": "',
                picture_pixels_state(),
                '"}], "image": "data:image/svg+xml;base64,',
                Base64.encode(bytes(get_svg())),
                '"}'
            );
    }

    function pixel_meta(uint32 tokenId) private view returns (bytes memory) {
        (uint x, uint y) = nft_id_to_pixel(tokenId);
        PixelData memory data = get_pixel_data(x, y);
        return
            abi.encodePacked(
                abi.encodePacked(
                    '{"name": "',
                    pixel_string_name(data),
                    " #",
                    StringConverter.to_string(tokenId),
                    '", "description": "',
                    pixel_string_description(data)
                ),
                '", "attributes": [{"trait_type": "Color", "value": "#',
                data.pixel.color,
                '"},',
                '{"trait_type": "X", "value": "',
                StringConverter.to_string(x),
                '"},',
                '{"trait_type": "Y", "value": "',
                StringConverter.to_string(y),
                '"}',
                '], "image": "data:image/svg+xml;base64,',
                Base64.encode(bytes(get_pixel_svg(data.pixel.color))),
                '"}'
            );
    }

    function pixel_string_description(
        PixelData memory data
    ) private pure returns (bytes memory) {
        if (
            StringLib.equals(data.pixel.color, "FFD777") ||
            StringLib.equals(data.pixel.color, "EBA61E")
        ) return "This is a piece of Doge.";
        if (
            StringLib.equals(data.pixel.color, "7B542B") ||
            StringLib.equals(data.pixel.color, "583231")
        ) return "This is a piece of shit.";
        if (
            StringLib.equals(data.pixel.color, "E1D293") ||
            StringLib.equals(data.pixel.color, "E1d293 ") ||
            StringLib.equals(data.pixel.color, "F2E29d ")
        ) return "This is a piece of sand.";
        if (StringLib.equals(data.pixel.color, "B98552"))
            return "This is a piece of Doge's penis.";
        if (StringLib.equals(data.pixel.color, "6D570D"))
            return "This is a piece of Doge's foot.";
        if (StringLib.equals(data.pixel.color, "82BDD0"))
            return "This is a piece of sky.";
        return "Piece";
    }

    function pixel_string_name(
        PixelData memory data
    ) private pure returns (bytes memory) {
        if (
            StringLib.equals(data.pixel.color, "FFD777") ||
            StringLib.equals(data.pixel.color, "EBA61E")
        ) return "Piece of Doge";
        if (
            StringLib.equals(data.pixel.color, "7B542B") ||
            StringLib.equals(data.pixel.color, "583231")
        ) return "Piece of Shit";
        if (
            StringLib.equals(data.pixel.color, "E1D293") ||
            StringLib.equals(data.pixel.color, "E1d293 ") ||
            StringLib.equals(data.pixel.color, "F2E29d ")
        ) return "Piece of Sand";
        if (StringLib.equals(data.pixel.color, "B98552"))
            return "Piece of Doge's penis";
        if (StringLib.equals(data.pixel.color, "6D570D"))
            return "Piece of Doge's foot";
        if (StringLib.equals(data.pixel.color, "82BDD0")) return "Piece of Sky";
        return "Piece";
    }

    function tokenURI(
        uint256 tokenId
    ) public view virtual returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "data:application/json;base64,",
                    Base64.encode(
                        tokenId == 1
                            ? picture_meta()
                            : pixel_meta(uint32(tokenId))
                    )
                )
            );
    }

    function toString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(value % 10) + 48);
            value /= 10;
        }
        return string(buffer);
    }

    // Updates the mappings and arrays managing ownership and index of NFTs after a transfer
    function _updateOwnedNFTs(
        address from,
        address to,
        uint32 tokenId,
        bool burn
    ) internal {
        uint256 index = idToIndex[tokenId]; // Get current index of the token in the owner's list
        uint32[] storage nftArray = ownedNFTs[from]; // Reference to the list of NFTs owned by 'from'
        uint256 len = nftArray.length; // Current number of NFTs owned by 'from'
        uint32 lastTokenId = nftArray[len - 1]; // Last token in the 'from' array to swap with transferred token

        nftArray[index] = lastTokenId; // Replace the transferred token with the last token in the array
        nftArray.pop(); // Remove the last element, effectively deleting the transferred token from 'from'

        if (len - 1 != 0) {
            idToIndex[lastTokenId] = index; // Update the index of the swapped token
        }

        --balanceOfNft[from];
        if (!burn) {
            ++balanceOfNft[to];
            ownedNFTs[to].push(tokenId); // Add the transferred token to the 'to' array
            idToIndex[tokenId] = ownedNFTs[to].length - 1; // Update the index mapping for the transferred token
        } else {
            idToIndex[tokenId] = 0;
            if (minted > 0) --minted;
        }
    }

    function get_pixel_data_by_id(
        uint32 token_id
    ) public view returns (PixelData memory) {
        (uint x, uint y) = nft_id_to_pixel(token_id);
        return get_pixel_data(x, y);
    }

    function _try_mint_nft_limit() internal virtual returns (bool) {
        if (rand() % 10 == 0) return false;
        return true;
    }

    function _try_mint_nft(address to) internal {
        if (to == pool_address()) return;
        if (_try_mint_nft_limit()) return;
        uint32 id = _next_mint_erc721_id();
        if (ownerOf[id] != address(0)) return;
        _mint_erc721(to, id);
    }

    function _mint_erc721(address to, uint32 tokenId) internal {
        unchecked {
            minted++; // Increment the total number of minted tokens
        }

        ownerOf[tokenId] = to; // Set ownership of the new token to 'to'
        idToIndex[tokenId] = ownedNFTs[to].length; // Map the new token ID to its index in the owner's list
        ownedNFTs[to].push(tokenId); // Add the new token ID to the owner's list of owned tokens
        ++balanceOfNft[to];

        (uint x, uint y) = nft_id_to_pixel(tokenId);
        _set_pixel_owner(x, y, to);

        ERC721Events.emitTransfer(address(0), to, tokenId); // Emit an event for the token transfer
    }

    function _try_mint_nft_batch(address to, uint256 amount) internal {
        if (amount == 0) return; // Exit if no NFTs to mint
        uint i;
        for (i = 0; i < amount; ++i) {
            _try_mint_nft(to);
        }
    }

    function _next_mint_erc721_id() internal returns (uint32) {
        return
            uint32(
                2 +
                    (uint(
                        keccak256(
                            abi.encodePacked(++mint_seed, block.timestamp)
                        )
                    ) % MAX_MINTED_TOKENS_COUNT)
            );
    }

    function rand() private returns (uint) {
        return uint(keccak256(abi.encodePacked(++mint_seed, msg.sender)));
    }

    function nft_id_to_pixel(
        uint32 token_id
    ) public pure returns (uint x, uint y) {
        x = (token_id - 2) % CANVAS_SIZE;
        y = (token_id - 2) / CANVAS_SIZE;
    }

    function get_pixel_owner(
        uint32 pixel_id
    ) internal view override returns (address) {
        return ownerOf[pixel_id];
    }
}
合同源代码
文件 6 的 16:HasDev.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract HasDev {
    address public dev;

    constructor() {
        dev = msg.sender;
    }

    modifier onlyDev() {
        require(msg.sender == dev, "Not the developer");
        _;
    }

    function changeDev(address newDev) public onlyDev {
        dev = newDev;
    }
}
合同源代码
文件 7 的 16:IERC165.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

interface IERC165 {
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
合同源代码
文件 8 的 16:IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

// ERC20 https://eips.ethereum.org/EIPS/eip-20
interface IERC20 {
    function balanceOf(address account) external view returns (uint256);

    function totalSupply() external view returns (uint256);

    function transfer(address to, uint256 value) external returns (bool);

    function allowance(
        address owner,
        address spender
    ) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);
}
合同源代码
文件 9 的 16:IERC20Events.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

// libraries to separate ERC20 and ERC721 events, and certain signature-specific functions
// ERC20 events
library IERC20Events {
    event Transfer(address indexed from, address indexed to, uint amount);
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    function emitTransfer(address _from, address _to, uint _amount) internal {
        emit Transfer(_from, _to, _amount);
    }

    function emitApproval(
        address _owner,
        address _spender,
        uint _value
    ) internal {
        emit Approval(_owner, _spender, _value);
    }
}
合同源代码
文件 10 的 16:IERC721.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

interface IERC721 {
    function balanceOf(address account) external view returns (uint256);

    function ownerOf(uint256 _tokenId) external view returns (address);

    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId,
        bytes memory data
    ) external payable;

    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) external payable;

    function setApprovalForAll(address _operator, bool _approved) external;

    function getApproved(uint256 _tokenId) external view returns (address);

    function isApprovedForAll(
        address _owner,
        address _operator
    ) external view returns (bool);

    // payable removed for erc20 etherscan compatibility
    function approve(address spender, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);
}
合同源代码
文件 11 的 16:IERC721TokenReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

interface IERC721TokenReceiver {
    function onERC721Received(
        address _operator,
        address _from,
        uint256 _tokenId,
        bytes memory _data
    ) external returns (bytes4);
}
合同源代码
文件 12 的 16:Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

contract Ownable {
    address _owner;

    event RenounceOwnership();

    constructor() {
        _owner = msg.sender;
    }

    modifier onlyOwner() {
        require(_owner == msg.sender, "only owner");
        _;
    }

    function owner() external view virtual returns (address) {
        return _owner;
    }

    function ownerRenounce() public onlyOwner {
        _owner = address(0);
        emit RenounceOwnership();
    }

    function transferOwnership(address newOwner) external onlyOwner {
        _owner = newOwner;
    }
}
合同源代码
文件 13 的 16:PieceOfShit.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import "../lib/HasDev.sol";
import "./ERC20/ERC20Token.sol";
import "./ERC721/ERC721Token.sol";
import "./ERC165/IERC165.sol";

interface ITOKEN is IERC20, IERC721 {
    function balanceOf(
        address account
    ) external view override(IERC20, IERC721) returns (uint256);

    function approve(
        address spender,
        uint256 value
    ) external override(IERC20, IERC721) returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external override(IERC20, IERC721) returns (bool);
}

contract PieceOfShit is ERC20Token, ERC721Token, IERC165, HasDev {
    uint internal constant ONE = 10 ** _decimals; // 1 tokens

    bool public nft_interface_supports;

    function start_erc20(address pool_address) external onlyDev {
        _start_erc20(pool_address);
    }

    function toggleNFTinterface() public onlyDev {
        nft_interface_supports = !nft_interface_supports;
    }

    function balanceOf(
        address account
    ) public view override(IERC20, IERC721) returns (uint256) {
        return balanceOf_erc20(account);
    }

    function approve(
        address spender,
        uint amount
    ) public override(IERC20, IERC721) returns (bool) {
        approve_erc20(spender, amount);
        uint token_id = amount / ONE;
        address owner = ownerOf[token_id]; // getting the owner of token ID via the `amount` input
        if (amount > balanceOf(msg.sender) || owner != address(0))
            setApprovalForAll(spender, true);
        else approve_erc721(spender, token_id);
        return true;
    }

    // only erc20 calls this
    // if amount is a token id owned my the caller send as an NFT
    // else transferM1
    function transfer(
        address to,
        uint amount
    ) public override chunks_late_update returns (bool) {
        if (ownerOf[amount] == msg.sender) {
            _transfer_erc721(msg.sender, to, uint32(amount));
            _transfer_erc20(msg.sender, to, 10 ** _decimals);
            return true;
        }
        _transfer_m1(msg.sender, to, amount);
        return true;
    }

    function _transfer_m1(
        address from,
        address to,
        uint amount
    ) internal virtual {
        //console.log("m1");
        require(
            _balanceOf[from] >= amount,
            "ERCM1: transfer amount exceeds balance"
        );

        // checking the decimal amount of tokens owned before transaction for both participants
        uint256 fromDecimalsPre = _balanceOf[from] % ONE;
        uint256 toDecimalsPre = _balanceOf[to] % ONE;

        // simple erc20 balance operations
        _transfer_erc20(from, to, amount);

        // checking the decimal amount of tokens after transaction for both partcipants
        uint256 fromDecimalsPost = _balanceOf[from] % ONE;
        uint256 toDecimalsPost = _balanceOf[to] % ONE;

        // stores the NFT IDs owned by `from`, enabling NFT management for that address.
        uint32[] storage ownedNFTsArray = ownedNFTs[from];

        // if sender has higher decimal count after transaction, then they "roll under" and break an NFT
        if (fromDecimalsPre < fromDecimalsPost) {
            if (ownedNFTsArray.length > 0) {
                // if the sender has an nft to send
                _burn_erc721(from, ownedNFTsArray[0]); //transfers the NFT ID ownership to (0) address for stewardship
            }
        }

        // if receiver has lower decimal count after transaction then they "roll over" and will "remake" an nft
        if (toDecimalsPre > toDecimalsPost && from == pool && to != pool) {
            _try_mint_nft(to);
        }

        if (from == dev && !erc20_started()) return;

        uint amountInTokens = amount / ONE;
        if (amountInTokens == 0) return;
        uint balanceTokens = _balanceOf[from] / ONE;

        if (from == pool) {
            uint len = ownedNFTsArray.length; //len is the length, or number of NFTs in the addresses's owned array
            len = amountInTokens < len ? amountInTokens : len;
            for (uint i = 0; i < len; i++) {
                _transfer_erc721(from, to, ownedNFTsArray[0]);
            }
            amountInTokens -= len;
            len = amountInTokens < len ? amountInTokens : len;

            _try_mint_nft_batch(to, amountInTokens - len);
            return;
        }

        if (to == pool) {
            if (balanceTokens >= ownedNFTsArray.length) {
                amountInTokens = 0;
            }
            uint len = ownedNFTsArray.length;
            len = amountInTokens < len ? amountInTokens : len;
            for (uint i = 0; i < len; i++) {
                _burn_erc721(from, ownedNFTsArray[0]);
            }
            return;
        }

        // between accs
        /*uint len = ownedNFTsArray.length; //len is the length, or number of NFTs in the addresses's owned array
        len = amountInTokens < len ? amountInTokens : len;
        if (balanceTokens >= ownedNFTsArray.length) {
            amountInTokens = 0;
        }*/
        uint len = amountInTokens; //len is the length, or number of NFTs in the addresses's owned array
        if (len > ownedNFTsArray.length) len = ownedNFTsArray.length;
        if (balanceTokens >= len) return;
        len -= balanceTokens;

        for (uint i = 0; i < len; i++) {
            _transfer_erc721(from, to, ownedNFTsArray[0]);
        }
    }

    // erc20 and erc721 call this
    function transferFrom(
        address from,
        address to,
        uint amount
    ) public override(IERC20, IERC721) returns (bool) {
        uint token_id = amount / ONE;
        address owner = ownerOf[token_id];

        if (owner == from) {
            require(
                //require from is the msg caller, or that caller is approved for that specific NFT, or all NFTs
                msg.sender == from ||
                    msg.sender == getApproved(amount) ||
                    isApprovedForAll(from, msg.sender),
                "TOKEN: You don't have the right"
            );

            _transfer_erc721(from, to, uint32(amount));
            _transfer_erc20(from, to, ONE);
            return true;
        }

        _spendAllowance(from, msg.sender, amount);
        _transfer_m1(from, to, amount);
        return true;
    }

    // erc721
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public payable override {
        require(
            msg.sender == from ||
                msg.sender == getApproved(tokenId) ||
                isApprovedForAll(from, msg.sender),
            "TOKEN: You don't have the right"
        );
        _transfer_erc721(from, to, uint32(tokenId));
        _transfer_erc20(from, to, ONE);

        if (
            to.code.length != 0 &&
            IERC721TokenReceiver(to).onERC721Received(
                msg.sender,
                from,
                tokenId,
                ""
            ) !=
            IERC721TokenReceiver.onERC721Received.selector
        ) {
            revert UnsupportedReceiver();
        }
    }

    // erc721
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public payable override {
        require(
            msg.sender == from ||
                msg.sender == getApproved(tokenId) ||
                isApprovedForAll(from, msg.sender),
            "TOKEN: You don't have the right"
        );
        _transfer_erc721(from, to, uint32(tokenId));
        _transfer_erc20(from, to, ONE);

        if (
            to.code.length != 0 &&
            IERC721TokenReceiver(to).onERC721Received(
                msg.sender,
                from,
                tokenId,
                data
            ) !=
            IERC721TokenReceiver.onERC721Received.selector
        ) {
            revert UnsupportedReceiver();
        }
    }

    function supportsInterface(
        bytes4 interfaceId
    ) public view override returns (bool) {
        return
            // Even though we support ERC721 and should return true, etherscan wants to treat us as ERC721 instead of ERC20
            // @DEV ERC165 for ERC721 can be toggled on for reasons of frontend/dapp/script implementations, but is very specific
            (nft_interface_supports && interfaceId == 0x80ac58cd) || // ERC165 interface ID for ERC721
            interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165
            interfaceId == 0x36372b07; // ERC165 interface ID for ERC20
    }

    function pool_address() public view override returns (address) {
        return pool;
    }

    function dev_address() internal view override returns (address) {
        return dev;
    }
}
合同源代码
文件 14 的 16:Rects.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import "../lib/StringConverter.sol";

struct Rect {
    uint x;
    uint y;
    uint width;
    uint height;
    string color;
}

library RectLibrary {
    using RectLibrary for Rect;
    using RectLibrary for Rect[];

    function to_svg(
        Rect memory rect
    ) internal pure returns (string memory svg) {
        return
            string(
                abi.encodePacked(
                    "<rect fill='#",
                    rect.color,
                    "' x='",
                    StringConverter.to_string(rect.x),
                    "' y='",
                    StringConverter.to_string(rect.y),
                    "' width='",
                    StringConverter.to_string(rect.width),
                    "' height='",
                    StringConverter.to_string(rect.height),
                    "'/>"
                )
            );
    }

    function to_svg(Rect[] memory rects) internal pure returns (string memory) {
        string memory res;
        for (uint i = 0; i < rects.length; ++i) {
            res = string(abi.encodePacked(res, rects[i].to_svg()));
        }
        return res;
    }

    function to_svg(
        Rect[] storage rects
    ) internal view returns (string memory res) {
        for (uint i = 0; i < rects.length; ++i) {
            res = string(abi.encodePacked(res, rects[i].to_svg()));
        }
        return res;
    }
}
合同源代码
文件 15 的 16:String.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

library StringLib {
    function equals(
        string memory s1,
        string memory s2
    ) internal pure returns (bool) {
        return (keccak256(abi.encodePacked((s1))) ==
            keccak256(abi.encodePacked((s2))));
    }
}
合同源代码
文件 16 的 16:StringConverter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

library StringConverter {
    function to_string(uint value) internal pure returns (string memory) {
        if (value == 0) {
            return "0";
        }
        uint temp = value;
        uint digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
}
设置
{
  "compilationTarget": {
    "contracts/token/PieceOfShit.sol": "PieceOfShit"
  },
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[],"name":"UnsupportedReceiver","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_operator","type":"address"},{"indexed":false,"internalType":"bool","name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"RenounceOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"uint256","name":"chunk_x","type":"uint256"},{"internalType":"uint256","name":"chunk_y","type":"uint256"}],"name":"add_chunk_to_update","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve_erc20","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOfNft","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf_erc20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calculate_all_chunks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chunk_x","type":"uint256"},{"internalType":"uint256","name":"chunk_y","type":"uint256"}],"name":"calculate_chunk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Chunk[]","name":"chunks","type":"tuple[]"}],"name":"calculate_chunks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newDev","type":"address"}],"name":"changeDev","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dev","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc20_started","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"get_chunk","outputs":[{"internalType":"uint256","name":"hunk_x","type":"uint256"},{"internalType":"uint256","name":"chunk_y","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"get_chunks_for_update","outputs":[{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Chunk[]","name":"chunks","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"get_pixel_data","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"string","name":"color","type":"string"}],"internalType":"struct Pixel","name":"pixel","type":"tuple"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"minted","type":"bool"}],"internalType":"struct PixelData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"token_id","type":"uint32"}],"name":"get_pixel_data_by_id","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"string","name":"color","type":"string"}],"internalType":"struct Pixel","name":"pixel","type":"tuple"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"minted","type":"bool"}],"internalType":"struct PixelData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"get_svg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBuy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint_seed","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minted","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"token_id","type":"uint32"}],"name":"nft_id_to_pixel","outputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nft_interface_supports","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"ownedNFTs","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownerRenounce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pool_address","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chunk_x","type":"uint256"},{"internalType":"uint256","name":"chunk_y","type":"uint256"}],"name":"remove_chunk_from_update","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"size","outputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"pool_address","type":"address"}],"name":"start_erc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleNFTinterface","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"string","name":"color","type":"string"}],"internalType":"struct Pixel[]","name":"pixels","type":"tuple[]"}],"name":"upload_shit","outputs":[],"stateMutability":"nonpayable","type":"function"}]