Glyfoc721Mono

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/Glyfoc721Mono.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {ERC721}    from "solady/src/tokens/ERC721.sol";
import {Ownable}   from "solady/src/auth/Ownable.sol";
import {SSTORE2}   from "solady/src/utils/SSTORE2.sol";
import {Base64}    from "solady/src/utils/Base64.sol";
import {LibString} from "solady/src/utils/LibString.sol";
import {ReentrancyGuard} from "solady/src/utils/ReentrancyGuard.sol";

interface IERC2981 {
    function royaltyInfo(uint256, uint256) external view returns (address, uint256);
}

contract Glyfoc721Mono is ERC721, Ownable, ReentrancyGuard {
    using LibString for uint256;

    address public immutable OFFICIAL_FACTORY;

    bool    public initialized;
    uint256 public MAX_SUPPLY;
    uint256 public mintPriceWei;
    uint256 public totalMinted;
    uint256 public maxPerTx;

    address public platformFeeRecipient;
    uint96  public platformFeeBps;

    uint16  public fontSize;
    uint16  public lineGap;
    uint16  public viewBoxW;
    uint16  public viewBoxH;
    bool    public themePerToken;

    bytes32 public salt;

    address public layersPtr;
    address public orderPtr;
    address public themesPtr;

    string  internal _nameHuman;
    string  internal _symbolHuman;
    string  internal _description;

    bool    public royaltyEnabled;
    address public royaltyReceiver;
    uint96  public royaltyBps;

    mapping(bytes32 => bool) public comboUsed;

    struct DeployParams {
        string  name;
        string  symbol;
        string  description;
        uint256 maxSupply;
        uint256 mintPriceWei;
        uint256 maxPerTx;
        uint16  fontSize;
        uint16  lineGap;
        uint16  viewBoxW;
        uint16  viewBoxH;
        bool    themePerToken;
        bytes32 salt;
        address owner;
        bool    royaltyEnabled;
        address royaltyReceiver;
        uint96  royaltyBps;
        address layersPtr;
        address orderPtr;
        address themesPtr;
    }

    modifier onlyFactory() {
        require(msg.sender == OFFICIAL_FACTORY, "factory");
        _;
    }

    constructor(address officialFactory) {
        require(officialFactory != address(0), "factory=0");
        OFFICIAL_FACTORY = officialFactory;
        initialized = true;
        _initializeOwner(address(this));
    }

    function initialize(
        DeployParams calldata p,
        address _platformFeeRecipient,
        uint96  _platformFeeBps
    ) external onlyFactory {
        require(!initialized, "init");
        initialized = true;

        require(p.layersPtr != address(0) && p.orderPtr != address(0), "data");
        require(_platformFeeBps <= 10_000, "fee");

        _nameHuman   = p.name;
        _symbolHuman = p.symbol;
        _description = p.description;

        MAX_SUPPLY   = p.maxSupply;
        mintPriceWei = p.mintPriceWei;
        maxPerTx     = p.maxPerTx == 0 ? 20 : p.maxPerTx;

        fontSize     = p.fontSize == 0 ? 64  : p.fontSize;
        lineGap      = p.lineGap  == 0 ? 80  : p.lineGap;
        viewBoxW     = p.viewBoxW == 0 ? 800 : p.viewBoxW;
        viewBoxH     = p.viewBoxH == 0 ? 600 : p.viewBoxH;
        themePerToken= p.themePerToken;

        salt         = p.salt;

        layersPtr    = p.layersPtr;
        orderPtr     = p.orderPtr;
        themesPtr    = p.themesPtr;

        platformFeeRecipient = _platformFeeRecipient;
        platformFeeBps       = _platformFeeBps;

        royaltyEnabled = p.royaltyEnabled;
        royaltyReceiver= p.royaltyReceiver;
        royaltyBps     = p.royaltyBps;

        _initializeOwner(p.owner == address(0) ? tx.origin : p.owner);
    }

    function mint(uint256 quantity) external payable nonReentrant {
        require(quantity > 0 && quantity <= maxPerTx, "qty");
        require(totalMinted + quantity <= MAX_SUPPLY, "soldout");
        require(msg.value / quantity == mintPriceWei && msg.value % quantity == 0, "value");

        uint256 platform = (msg.value * platformFeeBps) / 10_000;
        uint256 creator  = msg.value - platform;
        for (uint256 i = 0; i < quantity; ++i) {
            unchecked { ++totalMinted; }
            uint256 tokenId = totalMinted;
            bytes32 fp = _fingerprint(tokenId);
            require(!comboUsed[fp], "duplicate");
            comboUsed[fp] = true;
            _safeMint(msg.sender, tokenId);
        }

        _payout(platformFeeRecipient, platform);
        _payout(owner(), creator);
    }

    function airdrop(address[] calldata to) external onlyOwner {
        uint256 n = to.length;
        require(totalMinted + n <= MAX_SUPPLY, "soldout");
        for (uint256 i = 0; i < n; ++i) {
            unchecked { ++totalMinted; }
            uint256 tokenId = totalMinted;
            bytes32 fp = _fingerprint(tokenId);
            require(!comboUsed[fp], "duplicate");
            comboUsed[fp] = true;
            _mint(to[i], tokenId);
        }
    }

    function withdraw(address payable to) external onlyOwner nonReentrant {
        require(to != address(0), "zero");
        _payout(to, address(this).balance);
    }

    function name() public view override returns (string memory) { return _nameHuman; }
    function symbol() public view override returns (string memory) { return _symbolHuman; }

    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        require(_exists(tokenId), "id");
        bytes32 h = _hash(tokenId);

        (string[] memory layerNames, uint16[] memory variantIdx, string memory art) = _assemble(tokenId);
        (string memory bg, string memory fg, string memory tname) = _resolveTheme(h);

        string memory svg   = _buildSVG(art, bg, fg);
        string memory attrs = _attributes(layerNames, variantIdx, tname);
        string memory title = string.concat(_nameHuman, " #", tokenId.toString());

        bytes memory json = abi.encodePacked(
            '{"name":"', title,
            '","description":"', _description,
            '","attributes":', attrs,
            ',"image":"data:image/svg+xml;base64,', Base64.encode(bytes(svg)),
            '"}'
        );
        return string(abi.encodePacked("data:application/json;base64,", Base64.encode(json)));
    }

    function setRoyalty(address receiver, uint96 bps) external onlyOwner {
        require(bps <= 10_000, "royalty bps");
        royaltyEnabled  = true;
        royaltyReceiver = receiver;
        royaltyBps      = bps;
    }

    function royaltyInfo(uint256, uint256 salePrice) public view returns (address, uint256) {
        if (!royaltyEnabled) return (address(0), 0);
        address recv = royaltyReceiver == address(0) ? owner() : royaltyReceiver;
        return (recv, (salePrice * royaltyBps) / 10_000);
    }

    function supportsInterface(bytes4 iid) public view virtual override returns (bool) {
        bytes4 ERC2981ID = 0x2a55205a;
        return super.supportsInterface(iid) || (royaltyEnabled && iid == ERC2981ID);
    }

    function _assemble(uint256 tokenId)
        internal
        view
        returns (string[] memory layerNames, uint16[] memory variantIdx, string memory art)
    {
        uint16[] memory order = _readOrder();
        (uint16 L,,) = _layersCounts();
        require(order.length == L, "order");

        layerNames = new string[](L);
        variantIdx = new uint16[](L);
        string[] memory lines = new string[](L);

        bytes memory b = SSTORE2.read(layersPtr);
        uint256 off = 2;

        uint256[] memory layerStart = new uint256[](L);
        uint16[]  memory vCount     = new uint16[](L);

        for (uint16 i = 0; i < L; ++i) {
            layerStart[i] = off;

            uint16 nameLen = _u16(b, off); off += 2;
            layerNames[i] = string(_slice(b, off, nameLen)); off += nameLen;

            uint16 V = _u16(b, off); off += 2;
            vCount[i] = V;

            for (uint16 j = 0; j < V; ++j) {
                uint16 len = _u16(b, off); off += 2 + len;
            }
        }

        uint16[] memory vCountsOrdered = new uint16[](L);
        uint256 M = 1;
        for (uint16 pos = 0; pos < L; ++pos) {
            uint16 li = order[pos];
            uint16 V  = vCount[li];
            vCountsOrdered[pos] = V;
            uint256 base = V == 0 ? 1 : uint256(V);
            M *= base;
        }

        uint256 u = _comboIndex(tokenId, M);

        for (uint16 pos = 0; pos < L; ++pos) {
            uint16 li = order[pos];
            uint16 V  = vCount[li];

            uint256 o = layerStart[li];
            uint16 nameLen2 = _u16(b, o); o += 2 + nameLen2;
            uint16 V2 = _u16(b, o); o += 2; require(V2 == V, "v");

            uint16 pick;
            if (V == 0) {
                pick = 0;
            } else {
                uint16 base = V;
                pick = uint16(u % base);
                u   /= base;
            }

            for (uint16 j = 0; j < V; ++j) {
                uint16 len = _u16(b, o); o += 2;
                bytes memory ln = _slice(b, o, len); o += len;
                if (j == pick) lines[pos] = string(ln);
            }
            variantIdx[pos] = pick;
        }

        art = _joinLines(lines);
    }

    function _fingerprint(uint256 tokenId) internal view returns (bytes32) {
        uint16[] memory order = _readOrder();
        (uint16 L,,) = _layersCounts();

        bytes memory b = SSTORE2.read(layersPtr);
        uint256 off = 2;
        uint16[] memory vCounts = new uint16[](L);
        for (uint16 i = 0; i < L; ++i) {
            uint16 nameLen = _u16(b, off); off += 2 + nameLen;
            uint16 V = _u16(b, off); off += 2; vCounts[i] = V;
            for (uint16 j = 0; j < V; ++j) {
                uint16 len = _u16(b, off); off += 2 + len;
            }
        }

        uint16[] memory vCountsOrdered = new uint16[](L);
        uint256 M = 1;
        for (uint16 pos = 0; pos < L; ++pos) {
            uint16 li = order[pos];
            uint16 V  = vCounts[li];
            vCountsOrdered[pos] = V;
            uint256 base = V == 0 ? 1 : uint256(V);
            M *= base;
        }

        uint256 u = _comboIndex(tokenId, M);

        bytes memory buf = new bytes(2 + order.length * 2);
        _setU16(buf, 0, L);
        for (uint16 pos = 0; pos < L; ++pos) {
            uint16 V = vCountsOrdered[pos];
            uint16 base = V == 0 ? 1 : V;
            uint16 pick = V == 0 ? 0 : uint16(u % base);
            u /= base;
            _setU16(buf, 2 + pos * 2, pick);
        }

        return keccak256(buf);
    }

    function _isHexColor(string memory s) internal pure returns (bool) {
        bytes memory b = bytes(s);
        if (b.length != 4 && b.length != 7 && b.length != 9) return false;
        if (b[0] != "#") return false;
        for (uint i = 1; i < b.length; ++i) {
            bytes1 c = b[i];
            bool ok = (c >= "0" && c <= "9") || (c >= "a" && c <= "f") || (c >= "A" && c <= "F");
            if (!ok) return false;
        }
        return true;
    }

    function _resolveTheme(bytes32 h)
        internal
        view
        returns (string memory bg, string memory fg, string memory tname)
    {
        if (themesPtr == address(0)) return ("#0b0b10", "#ffffff", "Static");

        bytes memory t = SSTORE2.read(themesPtr);
        if (t.length < 2) return ("#0b0b10", "#ffffff", "Static");

        uint16 T = _u16(t, 0);
        if (T == 0) return ("#0b0b10", "#ffffff", "Static");

        uint16 idx = themePerToken ? _themeIndex(h) : uint16(0);

        uint256 off = 2;
        for (uint16 i = 0; i < T; ++i) {
            off += 2;
            uint16 bgLen = _u16(t, off); off += 2;
            string memory bgStr = string(_slice(t, off, bgLen)); off += bgLen;

            uint16 fgLen = _u16(t, off); off += 2;
            string memory fgStr = string(_slice(t, off, fgLen)); off += fgLen;

            uint16 nmLen = _u16(t, off); off += 2;
            string memory nm = string(_slice(t, off, nmLen)); off += nmLen;

            if (i == idx) {
                string memory _bg = _isHexColor(bgStr) ? bgStr : "#0b0b10";
                string memory _fg = _isHexColor(fgStr) ? fgStr : "#ffffff";
                return (_bg, _fg, nmLen == 0 ? "Theme" : nm);
            }
        }
        return ("#0b0b10", "#ffffff", "Static");
    }

    function _themeIndex(bytes32 h) internal view returns (uint16) {
        if (themesPtr == address(0)) return 0;
        bytes memory t = SSTORE2.read(themesPtr);
        if (t.length < 2) return 0;
        uint16 T = _u16(t, 0);
        if (T == 0) return 0;

        uint256 off = 2;
        uint256 totalW;
        uint16[] memory weights = new uint16[](T);
        for (uint16 i = 0; i < T; ++i) {
            uint16 w = _u16(t, off); off += 2;
            weights[i] = w;
            totalW += w;

            uint16 bgLen = _u16(t, off); off += 2 + bgLen;
            uint16 fgLen = _u16(t, off); off += 2 + fgLen;
            uint16 nmLen = _u16(t, off); off += 2 + nmLen;
        }

        if (totalW == 0) return uint16(uint256(_r(h, 777)) % T);

        uint256 r = uint256(_r(h, 777)) % totalW;
        uint256 acc;
        for (uint16 i = 0; i < T; ++i) {
            acc += weights[i];
            if (r < acc) return i;
        }
        return uint16(T - 1);
    }

    function _buildSVG(string memory multiline, string memory bg, string memory fg)
        internal
        view
        returns (string memory)
    {
        string memory style = string.concat(
            "text{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:",
            uint256(fontSize).toString(),
            "px;white-space:pre;text-anchor:middle;dominant-baseline:central}"
        );

        string memory escStr = _xmlEscape(multiline);
        bytes memory b = bytes(escStr);

        uint256 rows;
        for (uint256 k = 0; k <= b.length; ) {
            bool endLine = (k == b.length) || (b[k] == 0x0a);
            if (endLine) { unchecked { ++rows; } }
            if (k == b.length) break;
            unchecked { ++k; }
        }
        if (rows == 0) rows = 1;

        uint256 startY = (viewBoxH / 2) - (((rows - 1) * lineGap) / 2);

        return string(
            abi.encodePacked(
                '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ',
                uint256(viewBoxW).toString(),' ',uint256(viewBoxH).toString(),
                '"><rect width="100%" height="100%" fill="', bg, '"/>',
                "<style>", style, "</style>",
                '<text x="', uint256(viewBoxW/2).toString(),
                '" y="', startY.toString(),
                '" fill="', fg, '">', _tspanLines(escStr), "</text></svg>"
            )
        );
    }

    function _tspanLines(string memory s) internal view returns (string memory out) {
        bytes memory b = bytes(s);
        uint256 i; uint256 y; uint256 lineStart;
        while (i <= b.length) {
            if (i == b.length || b[i] == 0x0a) {
                bytes memory slice = new bytes(i - lineStart);
                for (uint256 j = 0; j < slice.length; ++j) { slice[j] = b[lineStart + j]; }
                out = string(
                    abi.encodePacked(
                        out,
                        '<tspan x="', uint256(viewBoxW/2).toString(),
                        '" dy="', y == 0 ? "0" : uint256(lineGap).toString(),
                        '">', string(slice), "</tspan>"
                    )
                );
                lineStart = i + 1;
                y += lineGap;
            }
            unchecked { ++i; }
        }
    }

    function _deriveAffine(bytes32 s, uint256 M) internal pure returns (uint256 _a, uint256 _b) {
        if (M <= 1) { return (1, 0); }
        _a = 1 + (uint256(keccak256(abi.encode(s, "A"))) % (M - 1));
        while (_gcd(_a, M) != 1) {
            unchecked { _a++; if (_a >= M) _a = 1; }
        }
        _b = uint256(keccak256(abi.encode(s, "B"))) % M;
    }

    function _gcd(uint256 x, uint256 y) internal pure returns (uint256) {
        while (y != 0) { (x, y) = (y, x % y); }
        return x;
    }

    function _comboIndex(uint256 tokenId, uint256 M) internal view returns (uint256) {
        if (M == 0) return 0;
        uint256 x = tokenId - 1;
        (uint256 a, uint256 b) = _deriveAffine(salt, M);
        unchecked { return (a * x + b) % M; }
    }

    function _attributes(string[] memory layerNames, uint16[] memory variantIdx, string memory themeName)
        internal
        pure
        returns (string memory)
    {
        bytes memory out = abi.encodePacked('[');
        for (uint256 i = 0; i < layerNames.length; ++i) {
            if (i != 0) out = abi.encodePacked(out, ',');
            out = abi.encodePacked(
                out,
                '{"trait_type":"', layerNames[i],
                '","value":"#', LibString.toString(uint256(variantIdx[i] + 1)), '"}'
            );
        }
        out = abi.encodePacked(out, ',{"trait_type":"Theme","value":"', themeName, '"}]');
        return string(out);
    }

    function _hash(uint256 tokenId) internal view returns (bytes32) {
        return keccak256(abi.encodePacked(salt, tokenId));
    }

    function _r(bytes32 h, uint256 n) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(h, n));
    }

    function _payout(address to, uint256 amount) internal {
        if (amount == 0) return;
        (bool ok,) = to.call{value: amount}("");
        require(ok, "pay");
    }

    function _layersCounts() internal view returns (uint16 L, uint32 totalVariants, uint16 maxV) {
        bytes memory b = SSTORE2.read(layersPtr);
        L = _u16(b, 0);
        uint256 off = 2;
        for (uint16 i = 0; i < L; ++i) {
            uint16 nameLen = _u16(b, off); off += 2 + nameLen;
            uint16 V = _u16(b, off); off += 2;
            if (V > maxV) maxV = V;
            totalVariants += V;
            for (uint16 j = 0; j < V; ++j) {
                uint16 len = _u16(b, off); off += 2 + len;
            }
        }
    }

    function _readOrder() internal view returns (uint16[] memory order) {
        bytes memory b = SSTORE2.read(orderPtr);
        uint16 N = _u16(b, 0);
        order = new uint16[](N);
        uint256 off = 2;
        for (uint16 i = 0; i < N; ++i) { order[i] = _u16(b, off); off += 2; }
    }

    function _u16(bytes memory b, uint256 off) internal pure returns (uint16 v) {
        v = (uint16(uint8(b[off])) << 8) | uint16(uint8(b[off + 1]));
    }

    function _setU16(bytes memory b, uint256 off, uint16 v) internal pure {
        b[off]     = bytes1(uint8(v >> 8));
        b[off + 1] = bytes1(uint8(v));
    }

    function _slice(bytes memory b, uint256 off, uint256 len) internal pure returns (bytes memory out) {
        out = new bytes(len);
        for (uint256 i = 0; i < len; ++i) { out[i] = b[off + i]; }
    }

    function _joinLines(string[] memory lines) internal pure returns (string memory out) {
        for (uint256 i = 0; i < lines.length; ++i) {
            if (i != 0) out = string(abi.encodePacked(out, "\
", lines[i]));
            else out = lines[i];
        }
    }

    function _xmlEscape(string memory s) internal pure returns (string memory) {
        bytes memory b = bytes(s);
        bytes memory tmp = new bytes(b.length * 5);
        uint256 k;
        for (uint256 i = 0; i < b.length; ++i) {
            bytes1 c = b[i];
            if (c == 0x26) { tmp[k++] = 0x26; tmp[k++] = 0x61; tmp[k++] = 0x6D; tmp[k++] = 0x70; tmp[k++] = 0x3B; }
            else if (c == 0x3C) { tmp[k++] = 0x26; tmp[k++] = 0x6C; tmp[k++] = 0x74; tmp[k++] = 0x3B; }
            else if (c == 0x3E) { tmp[k++] = 0x26; tmp[k++] = 0x67; tmp[k++] = 0x74; tmp[k++] = 0x3B; }
            else { tmp[k++] = c; }
        }
        bytes memory out = new bytes(k);
        for (uint256 i = 0; i < k; ++i) out[i] = tmp[i];
        return string(out);
    }

    function _baseURI() internal view virtual returns (string memory) { return ""; }

    event SupplyFinalized(uint256 newMaxSupply);

    function finishMint() external onlyOwner {
        require(initialized, "Not initialized");
        require(MAX_SUPPLY >= totalMinted, "Invariant");
        if (MAX_SUPPLY != totalMinted) {
            MAX_SUPPLY = totalMinted;
        }
        emit SupplyFinalized(MAX_SUPPLY);
    }
}
"
    },
    "solady/src/auth/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /// @dev Cannot double-initialize.
    error AlreadyInitialized();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The owner slot is given by:
    /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    bytes32 internal constant _OWNER_SLOT =
        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                if sload(ownerSlot) {
                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
                    revert(0x1c, 0x04)
                }
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(_OWNER_SLOT, newOwner)
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, newOwner)
            }
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(_OWNER_SLOT))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_OWNER_SLOT)
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         MODIFIERS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}
"
    },
    "solady/src/tokens/ERC721.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple ERC721 implementation with storage hitchhiking.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol)
///
/// @dev Note:
/// - The ERC721 standard allows for self-approvals.
///   For performance, this implementation WILL NOT revert for such actions.
///   Please add any checks with overrides if desired.
/// - For performance, methods are made payable where permitted by the ERC721 standard.
/// - The `safeTransfer` functions use the identity precompile (0x4)
///   to copy memory internally.
///
/// If you are overriding:
/// - NEVER violate the ERC721 invariant:
///   the balance of an owner MUST always be equal to their number of ownership slots.
///   The transfer functions do not have an underflow guard for user token balances.
/// - Make sure all variables written to storage are properly cleaned
///   (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood).
/// - Check that the overridden function is actually used in the function you want to
///   change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC721 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev An account can hold up to 4294967295 tokens.
    uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Only the token owner or an approved account can manage the token.
    error NotOwnerNorApproved();

    /// @dev The token does not exist.
    error TokenDoesNotExist();

    /// @dev The token already exists.
    error TokenAlreadyExists();

    /// @dev Cannot query the balance for the zero address.
    error BalanceQueryForZeroAddress();

    /// @dev Cannot mint or transfer to the zero address.
    error TransferToZeroAddress();

    /// @dev The token must be owned by `from`.
    error TransferFromIncorrectOwner();

    /// @dev The recipient's balance has overflowed.
    error AccountBalanceOverflow();

    /// @dev Cannot safely transfer to a contract that does not implement
    /// the ERC721Receiver interface.
    error TransferToNonERC721ReceiverImplementer();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Emitted when token `id` is transferred from `from` to `to`.
    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    /// @dev Emitted when `owner` enables `account` to manage the `id` token.
    event Approval(address indexed owner, address indexed account, uint256 indexed id);

    /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.
    event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);

    /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
    uint256 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
    uint256 private constant _APPROVAL_EVENT_SIGNATURE =
        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;

    /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`.
    uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
        0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ownership data slot of `id` is given by:
    /// ```
    ///     mstore(0x00, id)
    ///     mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
    ///     let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
    /// ```
    /// Bits Layout:
    /// - [0..159]   `addr`
    /// - [160..255] `extraData`
    ///
    /// The approved address slot is given by: `add(1, ownershipSlot)`.
    ///
    /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip
    ///
    /// The balance slot of `owner` is given by:
    /// ```
    ///     mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
    ///     mstore(0x00, owner)
    ///     let balanceSlot := keccak256(0x0c, 0x1c)
    /// ```
    /// Bits Layout:
    /// - [0..31]   `balance`
    /// - [32..255] `aux`
    ///
    /// The `operator` approval slot of `owner` is given by:
    /// ```
    ///     mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator))
    ///     mstore(0x00, owner)
    ///     let operatorApprovalSlot := keccak256(0x0c, 0x30)
    /// ```
    uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192;

    /// @dev Pre-shifted and pre-masked constant.
    uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC721 METADATA                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the token collection name.
    function name() public view virtual returns (string memory);

    /// @dev Returns the token collection symbol.
    function symbol() public view virtual returns (string memory);

    /// @dev Returns the Uniform Resource Identifier (URI) for token `id`.
    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           ERC721                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function ownerOf(uint256 id) public view virtual returns (address result) {
        result = _ownerOf(id);
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(result) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns the number of tokens owned by `owner`.
    ///
    /// Requirements:
    /// - `owner` must not be the zero address.
    function balanceOf(address owner) public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Revert if the `owner` is the zero address.
            if iszero(owner) {
                mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`.
                revert(0x1c, 0x04)
            }
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE)
        }
    }

    /// @dev Returns the account approved to manage token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function getApproved(uint256 id) public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            if iszero(shl(96, sload(ownershipSlot))) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            result := sload(add(1, ownershipSlot))
        }
    }

    /// @dev Sets `account` as the approved account to manage token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    /// - The caller must be the owner of the token,
    ///   or an approved operator for the token owner.
    ///
    /// Emits an {Approval} event.
    function approve(address account, uint256 id) public payable virtual {
        _approve(msg.sender, account, id);
    }

    /// @dev Returns whether `operator` is approved to manage the tokens of `owner`.
    function isApprovedForAll(address owner, address operator)
        public
        view
        virtual
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, operator)
            mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
            mstore(0x00, owner)
            result := sload(keccak256(0x0c, 0x30))
        }
    }

    /// @dev Sets whether `operator` is approved to manage the tokens of the caller.
    ///
    /// Emits an {ApprovalForAll} event.
    function setApprovalForAll(address operator, bool isApproved) public virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Convert to 0 or 1.
            isApproved := iszero(iszero(isApproved))
            // Update the `isApproved` for (`msg.sender`, `operator`).
            mstore(0x1c, operator)
            mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x30), isApproved)
            // Emit the {ApprovalForAll} event.
            mstore(0x00, isApproved)
            // forgefmt: disable-next-item
            log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator)))
        }
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function transferFrom(address from, address to, uint256 id) public payable virtual {
        _beforeTokenTransfer(from, to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            from := and(bitmaskAddress, from)
            to := and(bitmaskAddress, to)
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller()))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            let owner := and(bitmaskAddress, ownershipPacked)
            // Revert if the token does not exist, or if `from` is not the owner.
            if iszero(mul(owner, eq(owner, from))) {
                // `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`.
                mstore(shl(2, iszero(owner)), 0xceea21b6a1148100)
                revert(0x1c, 0x04)
            }
            // Load, check, and update the token approval.
            {
                mstore(0x00, from)
                let approvedAddress := sload(add(1, ownershipSlot))
                // Revert if the caller is not the owner, nor approved.
                if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Update with the new owner.
            sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
            // Decrement the balance of `from`.
            {
                let fromBalanceSlot := keccak256(0x0c, 0x1c)
                sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
            }
            // Increment the balance of `to`.
            {
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x1c)
                let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(toBalanceSlot, toBalanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
        }
        _afterTokenTransfer(from, to, id);
    }

    /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`.
    function safeTransferFrom(address from, address to, uint256 id) public payable virtual {
        transferFrom(from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function safeTransferFrom(address from, address to, uint256 id, bytes calldata data)
        public
        payable
        virtual
    {
        transferFrom(from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /// @dev Returns true if this contract implements the interface defined by `interfaceId`.
    /// See: https://eips.ethereum.org/EIPS/eip-165
    /// This function call must use less than 30000 gas.
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let s := shr(224, interfaceId)
            // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f.
            result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL QUERY FUNCTIONS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns if token `id` exists.
    function _exists(uint256 id) internal view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))))
        }
    }

    /// @dev Returns the owner of token `id`.
    /// Returns the zero address instead of reverting if the token does not exist.
    function _ownerOf(uint256 id) internal view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*            INTERNAL DATA HITCHHIKING FUNCTIONS             */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // For performance, no events are emitted for the hitchhiking setters.
    // Please emit your own events if required.

    /// @dev Returns the auxiliary data for `owner`.
    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
    /// Auxiliary data can be set for any address, even if it does not have any tokens.
    function _getAux(address owner) internal view virtual returns (uint224 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            result := shr(32, sload(keccak256(0x0c, 0x1c)))
        }
    }

    /// @dev Set the auxiliary data for `owner` to `value`.
    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
    /// Auxiliary data can be set for any address, even if it does not have any tokens.
    function _setAux(address owner, uint224 value) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            let balanceSlot := keccak256(0x0c, 0x1c)
            let packed := sload(balanceSlot)
            sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed)))))
        }
    }

    /// @dev Returns the extra data for token `id`.
    /// Minting, transferring, burning a token will not change the extra data.
    /// The extra data can be set on a non-existent token.
    function _getExtraData(uint256 id) internal view virtual returns (uint96 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Sets the extra data for token `id` to `value`.
    /// Minting, transferring, burning a token will not change the extra data.
    /// The extra data can be set on a non-existent token.
    function _setExtraData(uint256 id, uint96 value) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let packed := sload(ownershipSlot)
            sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed)))))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL MINT FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Mints token `id` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must not exist.
    /// - `to` cannot be the zero address.
    ///
    /// Emits a {Transfer} event.
    function _mint(address to, uint256 id) internal virtual {
        _beforeTokenTransfer(address(0), to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            to := shr(96, shl(96, to))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            // Revert if the token already exists.
            if shl(96, ownershipPacked) {
                mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`.
                revert(0x1c, 0x04)
            }
            // Update with the owner.
            sstore(ownershipSlot, or(ownershipPacked, to))
            // Increment the balance of the owner.
            {
                mstore(0x00, to)
                let balanceSlot := keccak256(0x0c, 0x1c)
                let balanceSlotPacked := add(sload(balanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(balanceSlot, balanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id)
        }
        _afterTokenTransfer(address(0), to, id);
    }

    /// @dev Mints token `id` to `to`, and updates the extra data for token `id` to `value`.
    /// Does NOT check if token `id` already exists (assumes `id` is auto-incrementing).
    ///
    /// Requirements:
    ///
    /// - `to` cannot be the zero address.
    ///
    /// Emits a {Transfer} event.
    function _mintAndSetExtraDataUnchecked(address to, uint256 id, uint96 value) internal virtual {
        _beforeTokenTransfer(address(0), to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            to := shr(96, shl(96, to))
            // Update with the owner and extra data.
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            sstore(add(id, add(id, keccak256(0x00, 0x20))), or(shl(160, value), to))
            // Increment the balance of the owner.
            {
                mstore(0x00, to)
                let balanceSlot := keccak256(0x0c, 0x1c)
                let balanceSlotPacked := add(sload(balanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(balanceSlot, balanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id)
        }
        _afterTokenTransfer(address(0), to, id);
    }

    /// @dev Equivalent to `_safeMint(to, id, "")`.
    function _safeMint(address to, uint256 id) internal virtual {
        _safeMint(to, id, "");
    }

    /// @dev Mints token `id` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must not exist.
    /// - `to` cannot be the zero address.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function _safeMint(address to, uint256 id, bytes memory data) internal virtual {
        _mint(to, id);
        if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL BURN FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to `_burn(address(0), id)`.
    function _burn(uint256 id) internal virtual {
        _burn(address(0), id);
    }

    /// @dev Destroys token `id`, using `by`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - If `by` is not the zero address,
    ///   it must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function _burn(address by, uint256 id) internal virtual {
        address owner = ownerOf(id);
        _beforeTokenTransfer(owner, address(0), id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            by := shr(96, shl(96, by))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            // Reload the owner in case it is changed in `_beforeTokenTransfer`.
            owner := shr(96, shl(96, ownershipPacked))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // Load and check the token approval.
            {
                mstore(0x00, owner)
                let approvedAddress := sload(add(1, ownershipSlot))
                // If `by` is not the zero address, do the authorization check.
                // Revert if the `by` is not the owner, nor approved.
                if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Clear the owner.
            sstore(ownershipSlot, xor(ownershipPacked, owner))
            // Decrement the balance of `owner`.
            {
                let balanceSlot := keccak256(0x0c, 0x1c)
                sstore(balanceSlot, sub(sload(balanceSlot), 1))
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id)
        }
        _afterTokenTransfer(owner, address(0), id);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                INTERNAL APPROVAL FUNCTIONS                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns whether `account` is the owner of token `id`, or is approved to manage it.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function _isApprovedOrOwner(address account, uint256 id)
        internal
        view
        virtual
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            // Clear the upper 96 bits.
            account := shr(96, shl(96, account))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let owner := shr(96, shl(96, sload(ownershipSlot)))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // Check if `account` is the `owner`.
            if iszero(eq(account, owner)) {
                mstore(0x00, owner)
                // Check if `account` is approved to manage the token.
                if iszero(sload(keccak256(0x0c, 0x30))) {
                    result := eq(account, sload(add(1, ownershipSlot)))
                }
            }
        }
    }

    /// @dev Returns the account approved to manage token `id`.
    /// Returns the zero address instead of reverting if the token does not exist.
    function _getApproved(uint256 id) internal view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Equivalent to `_approve(address(0), account, id)`.
    function _approve(address account, uint256 id) internal virtual {
        _approve(address(0), account, id);
    }

    /// @dev Sets `account` as the approved account to manage token `id`, using `by`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    /// - If `by` is not the zero address, `by` must be the owner
    ///   or an approved operator for the token owner.
    ///
    /// Emits a {Approval} event.
    function _approve(address by, address account, uint256 id) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            account := and(bitmaskAddress, account)
            by := and(bitmaskAddress, by)
            // Load the owner of the token.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let owner := and(bitmaskAddress, sload(ownershipSlot))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // If `by` is not the zero address, do the authorization check.
            // Revert if `by` is not the owner, nor approved.
            if iszero(or(iszero(by), eq(by, owner))) {
                mstore(0x00, owner)
                if iszero(sload(keccak256(0x0c, 0x30))) {
                    mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                    revert(0x1c, 0x04)
                }
            }
            // Sets `account` as the approved account to manage `id`.
            sstore(add(1, ownershipSlot), account)
            // Emit the {Approval} event.
            log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id)
        }
    }

    /// @dev Approve or remove the `operator` as an operator for `by`,
    /// without authorization checks.
    ///
    /// Emits an {ApprovalForAll} event.
    function _setAppro

Tags:
ERC721, ERC165, Multisig, Non-Fungible, Upgradeable, Multi-Signature, Factory|addr:0xc4fe829bcd2f1e2e6f8aa1de78879f96c593fea5|verified:true|block:23670743|tx:0xe65f44115b89559d7517d836e0f1e61ba1d04fb3ac30a1cf208632b12869c876|first_check:1761641784

Submitted on: 2025-10-28 09:56:26

Comments

Log in to comment.

No comments yet.